shithub: rgbds

Download patch

ref: 45b6872e2ad5374c146d1ddca61487976ba65f84
parent: 056109652d78701062ff0bb925a07c2c6ad33a2c
author: Anthony J. Bentley <[email protected]>
date: Tue Sep 23 20:23:40 EDT 2014

rgbasm: Fix TOCTOU and reduce buffering.

--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,9 @@
 	src/asm/output.o \
 	src/asm/rpn.o \
 	src/asm/symbol.o \
-	src/asm/gameboy/locallex.o
+	src/asm/gameboy/locallex.o \
+	src/extern/strlcpy.o \
+	src/extern/strlcat.o
 
 rgblib_obj := \
 	src/lib/library.o \
--- a/include/asm/fstack.h
+++ b/include/asm/fstack.h
@@ -9,6 +9,8 @@
 #ifndef ASMOTOR_ASM_FSTACK_H
 #define ASMOTOR_ASM_FSTACK_H
 
+#include <stdio.h>
+
 #include "asm/asm.h"
 #include "asm/types.h"
 #include "asm/lexer.h"
@@ -27,14 +29,17 @@
 	ULONG nREPTBlockSize;
 };
 
-extern ULONG fstk_RunInclude(char *s);
+void
+fstk_RunInclude(char *);
 extern void fstk_RunMacroArg(SLONG s);
-extern ULONG fstk_Init(char *s);
+void
+fstk_Init(char *);
 extern void fstk_Dump(void);
 extern void fstk_AddIncludePath(char *s);
 extern ULONG fstk_RunMacro(char *s);
 extern void fstk_RunRept(ULONG count);
-extern void fstk_FindFile(char *s);
+FILE *
+fstk_FindFile(char *);
 
 extern int yywrap(void);
 
--- a/src/asm/fstack.c
+++ b/src/asm/fstack.c
@@ -5,10 +5,19 @@
  *
  */
 
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef STRL_IN_LIBC
+#define strlcpy rgbds_strlcpy
+#define strlcat rgbds_strlcat
+size_t strlcpy(char *, const char *, size_t);
+size_t strlcat(char *, const char *, size_t);
+#endif
+
 #include "asm/symbol.h"
 #include "asm/fstack.h"
 #include "asm/types.h"
@@ -195,28 +204,33 @@
 	strcpy(IncludePaths[NextIncPath++], s);
 }
 
-void 
-fstk_FindFile(char *s)
+FILE *
+fstk_FindFile(char *fname)
 {
-	char t[_MAX_PATH + 1];
-	SLONG i = -1;
+	char path[PATH_MAX];
+	int i;
+	FILE *f;
 
-	strcpy(t, s);
+	if ((f = fopen(fname, "rb")) != NULL || errno != ENOENT) {
+		return f;
+	}
 
-	while (i < NextIncPath) {
-		FILE *f;
-
-		if ((f = fopen(t, "rb")) != NULL) {
-			fclose(f);
-			strcpy(s, t);
-			return;
+	for (i = 0; i < NextIncPath; ++i) {
+		if (strlcpy(path, IncludePaths[i], sizeof path) >= 
+		    sizeof path) {
+			continue;
 		}
-		i += 1;
-		if (i < NextIncPath) {
-			strcpy(t, IncludePaths[i]);
-			strcat(t, s);
+		if (strlcat(path, fname, sizeof path) >= sizeof path) {
+			continue;
 		}
+
+		if ((f = fopen(path, "rb")) != NULL || errno != ENOENT) {
+			return f;
+		}
 	}
+
+	errno = ENOENT;
+	return NULL;
 }
 /*
  * RGBAsm - FSTACK.C (FileStack routines)
@@ -225,33 +239,32 @@
  *
  */
 
-ULONG 
+void
 fstk_RunInclude(char *tzFileName)
 {
 	FILE *f;
 
-	//printf("INCLUDE: %s\n", s);
+	f = fstk_FindFile(tzFileName);
 
-	fstk_FindFile(tzFileName);
-	//printf("INCLUDING: %s\n", tzFileName);
+	if (f == NULL) {
+		fprintf(stderr, "Unable to open included file '%s': ",
+		    tzFileName);
+		perror(NULL);
+		exit(1);
+	}
 
-	if ((f = fopen(tzFileName, "r")) != NULL) {
-		pushcontext();
-		nLineNo = 1;
-		nCurrentStatus = STAT_isInclude;
-		strcpy(tzCurrentFileName, tzFileName);
-		pCurrentFile = f;
-		CurrentFlexHandle = yy_create_buffer(pCurrentFile);
-		yy_switch_to_buffer(CurrentFlexHandle);
+	pushcontext();
+	nLineNo = 1;
+	nCurrentStatus = STAT_isInclude;
+	strcpy(tzCurrentFileName, tzFileName);
+	pCurrentFile = f;
+	CurrentFlexHandle = yy_create_buffer(pCurrentFile);
+	yy_switch_to_buffer(CurrentFlexHandle);
 
-		//Dirty hack to give the INCLUDE directive a linefeed
+	//Dirty hack to give the INCLUDE directive a linefeed
 
-		    yyunput('\n');
-		nLineNo -= 1;
-
-		return (1);
-	} else
-		return (0);
+	yyunput('\n');
+	nLineNo -= 1;
 }
 /*
  * RGBAsm - FSTACK.C (FileStack routines)
@@ -360,7 +373,7 @@
  *
  */
 
-ULONG 
+void
 fstk_Init(char *s)
 {
 	char tzFileName[_MAX_PATH + 1];
@@ -368,17 +381,19 @@
 	sym_AddString("__FILE__", s);
 
 	strcpy(tzFileName, s);
-	fstk_FindFile(tzFileName);
-
 	pFileStack = NULL;
-	if ((pCurrentFile = fopen(tzFileName, "r")) != NULL) {
-		nMacroCount = 0;
-		nCurrentStatus = STAT_isInclude;
-		strcpy(tzCurrentFileName, tzFileName);
-		CurrentFlexHandle = yy_create_buffer(pCurrentFile);
-		yy_switch_to_buffer(CurrentFlexHandle);
-		nLineNo = 1;
-		return (1);
-	} else
-		return (0);
+	pCurrentFile = fopen(tzFileName, "rb");
+	if (pCurrentFile == NULL) {
+		fprintf(stderr, "Unable to open file '%s': ",
+		    tzFileName);
+		perror(NULL);
+		exit(1);
+	}
+
+	nMacroCount = 0;
+	nCurrentStatus = STAT_isInclude;
+	strcpy(tzCurrentFileName, tzFileName);
+	CurrentFlexHandle = yy_create_buffer(pCurrentFile);
+	yy_switch_to_buffer(CurrentFlexHandle);
+	nLineNo = 1;
 }
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -348,7 +348,6 @@
 
 	DefaultOptions = CurrentOptions;
 
-	/* tzMainfile=argv[argn++]; argc-=1; */
 	tzMainfile = argv[argc - 1];
 
 	setuplex();
@@ -366,75 +365,71 @@
 	nPass = 1;
 	nErrors = 0;
 	sym_PrepPass1();
-	if (fstk_Init(tzMainfile)) {
-		if (CurrentOptions.verbose) {
-			printf("Pass 1...\n");
-		}
+	fstk_Init(tzMainfile);
+	if (CurrentOptions.verbose) {
+		printf("Pass 1...\n");
+	}
 
-		yy_set_state(LEX_STATE_NORMAL);
-		opt_SetCurrentOptions(&DefaultOptions);
+	yy_set_state(LEX_STATE_NORMAL);
+	opt_SetCurrentOptions(&DefaultOptions);
 
-		if (yyparse() == 0 && nErrors == 0) {
-			if (nIFDepth == 0) {
-				nTotalLines = 0;
-				nLineNo = 1;
-				nIFDepth = 0;
-				nPC = 0;
-				nPass = 2;
-				nErrors = 0;
-				sym_PrepPass2();
-				out_PrepPass2();
-				fstk_Init(tzMainfile);
-				yy_set_state(LEX_STATE_NORMAL);
-				opt_SetCurrentOptions(&DefaultOptions);
+	if (yyparse() == 0 && nErrors == 0) {
+		if (nIFDepth == 0) {
+			nTotalLines = 0;
+			nLineNo = 1;
+			nIFDepth = 0;
+			nPC = 0;
+			nPass = 2;
+			nErrors = 0;
+			sym_PrepPass2();
+			out_PrepPass2();
+			fstk_Init(tzMainfile);
+			yy_set_state(LEX_STATE_NORMAL);
+			opt_SetCurrentOptions(&DefaultOptions);
 
-				if (CurrentOptions.verbose) {
-					printf("Pass 2...\n");
-				}
+			if (CurrentOptions.verbose) {
+				printf("Pass 2...\n");
+			}
 
-				if (yyparse() == 0 && nErrors == 0) {
-					double timespent;
+			if (yyparse() == 0 && nErrors == 0) {
+				double timespent;
 
-					nEndClock = clock();
-					timespent =
-					    ((double) (nEndClock - nStartClock))
-					    / (double) CLOCKS_PER_SEC;
-					if (CurrentOptions.verbose) {
-						printf
-						    ("Success! %ld lines in %d.%02d seconds ",
-						    nTotalLines, (int) timespent,
-						    ((int) (timespent * 100.0)) % 100);
-						if (timespent == 0)
-							printf
-							    ("(INFINITY lines/minute)\n");
-						else
-							printf("(%d lines/minute)\n",
-							    (int) (60 / timespent *
-								nTotalLines));
-					}
-					out_WriteObject();
-				} else {
+				nEndClock = clock();
+				timespent =
+				    ((double) (nEndClock - nStartClock))
+				    / (double) CLOCKS_PER_SEC;
+				if (CurrentOptions.verbose) {
 					printf
-					    ("Assembly aborted in pass 2 (%ld errors)!\n",
-					    nErrors);
-					//sym_PrintSymbolTable();
-					exit(5);
+					    ("Success! %ld lines in %d.%02d seconds ",
+					    nTotalLines, (int) timespent,
+					    ((int) (timespent * 100.0)) % 100);
+					if (timespent == 0)
+						printf
+						    ("(INFINITY lines/minute)\n");
+					else
+						printf("(%d lines/minute)\n",
+						    (int) (60 / timespent *
+							nTotalLines));
 				}
+				out_WriteObject();
 			} else {
-				fprintf(stderr,
-				    "Unterminated IF construct (%ld levels)!\n",
-				    nIFDepth);
-				exit(1);
+				printf
+				    ("Assembly aborted in pass 2 (%ld errors)!\n",
+				    nErrors);
+				//sym_PrintSymbolTable();
+				exit(5);
 			}
 		} else {
 			fprintf(stderr,
-			    "Assembly aborted in pass 1 (%ld errors)!\n",
-			    nErrors);
+			    "Unterminated IF construct (%ld levels)!\n",
+			    nIFDepth);
 			exit(1);
 		}
 	} else {
-		printf("File '%s' not found\n", tzMainfile);
-		exit(5);
+		fprintf(stderr,
+		    "Assembly aborted in pass 1 (%ld errors)!\n",
+		    nErrors);
+		exit(1);
 	}
-	return (0);
+	return 0;
 }
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -907,30 +907,33 @@
 {
 	FILE *f;
 
-	fstk_FindFile(s);
+	f = fstk_FindFile(s);
+	if (f == NULL) {
+		fprintf(stderr, "Unable to open incbin file '%s': ",
+		    s);
+		perror(NULL);
+		exit(1);
+	}
 
-	if ((f = fopen(s, "rb")) != NULL) {
-		SLONG fsize;
+	SLONG fsize;
 
-		fseek(f, 0, SEEK_END);
-		fsize = ftell(f);
-		fseek(f, 0, SEEK_SET);
+	fseek(f, 0, SEEK_END);
+	fsize = ftell(f);
+	fseek(f, 0, SEEK_SET);
 
-		checkcodesection(fsize);
+	checkcodesection(fsize);
 
-		if (nPass == 2) {
-			SLONG dest = nPC;
-			SLONG todo = fsize;
+	if (nPass == 2) {
+		SLONG dest = nPC;
+		SLONG todo = fsize;
 
-			while (todo--)
-				pCurrentSection->tData[dest++] = fgetc(f);
-		}
-		pCurrentSection->nPC += fsize;
-		nPC += fsize;
-		pPCSymbol->nValue += fsize;
-		fclose(f);
-	} else
-		fatalerror("Could not open file '%s': %s", s, strerror(errno));
+		while (todo--)
+			pCurrentSection->tData[dest++] = fgetc(f);
+	}
+	pCurrentSection->nPC += fsize;
+	nPC += fsize;
+	pPCSymbol->nValue += fsize;
+	fclose(f);
 }
 
 void 
@@ -944,36 +947,39 @@
 	if (length < 0)
 		fatalerror("Number of bytes to read must be greater than zero");
 
-	fstk_FindFile(s);
+	f = fstk_FindFile(s);
+	if (f == NULL) {
+		fprintf(stderr, "Unable to open included file '%s': ",
+		    s);
+		perror(NULL);
+		exit(1);
+	}
 
-	if ((f = fopen(s, "rb")) != NULL) {
-		SLONG fsize;
+	SLONG fsize;
 
-		fseek(f, 0, SEEK_END);
-		fsize = ftell(f);
+	fseek(f, 0, SEEK_END);
+	fsize = ftell(f);
 
-		if (start_pos >= fsize)
-			fatalerror("Specified start position is greater than length of file");
+	if (start_pos >= fsize)
+		fatalerror("Specified start position is greater than length of file");
 
-		if ((start_pos + length) > fsize)
-			fatalerror("Specified range in INCBIN is out of bounds");
+	if ((start_pos + length) > fsize)
+		fatalerror("Specified range in INCBIN is out of bounds");
 
-		fseek(f, start_pos, SEEK_SET);
+	fseek(f, start_pos, SEEK_SET);
 
-		checkcodesection(length);
+	checkcodesection(length);
 
-		if (nPass == 2) {
-			SLONG dest = nPC;
-			SLONG todo = length;
+	if (nPass == 2) {
+		SLONG dest = nPC;
+		SLONG todo = length;
 
-			while (todo--)
-				pCurrentSection->tData[dest++] = fgetc(f);
-		}
-		pCurrentSection->nPC += length;
-		nPC += length;
-		pPCSymbol->nValue += length;
+		while (todo--)
+			pCurrentSection->tData[dest++] = fgetc(f);
+	}
+	pCurrentSection->nPC += length;
+	nPC += length;
+	pPCSymbol->nValue += length;
 
-		fclose(f);
-	} else
-		fatalerror("Could not open file '%s': %s", s, strerror(errno));
+	fclose(f);
 }
--- a/src/asm/yaccprt3.y
+++ b/src/asm/yaccprt3.y
@@ -265,10 +265,7 @@
 
 include			:	T_POP_INCLUDE string
 					{
-						if( !fstk_RunInclude($2) )
-						{
-							yyerror("Could not open file '%s' : %s\n", $2, strerror(errno));
-						}
+						fstk_RunInclude($2);
 					}
 ;
 
--- /dev/null
+++ b/src/extern/strlcat.c
@@ -1,0 +1,55 @@
+/*	$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+rgbds_strlcat(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end */
+	while (n-- != 0 && *d != '\0')
+		d++;
+	dlen = d - dst;
+	n = siz - dlen;
+
+	if (n == 0)
+		return(dlen + strlen(s));
+	while (*s != '\0') {
+		if (n != 1) {
+			*d++ = *s;
+			n--;
+		}
+		s++;
+	}
+	*d = '\0';
+
+	return(dlen + (s - src));	/* count does not include NUL */
+}
--- /dev/null
+++ b/src/extern/strlcpy.c
@@ -1,0 +1,51 @@
+/*	$OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+rgbds_strlcpy(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0) {
+		while (--n != 0) {
+			if ((*d++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}