rgbasm: Fix TOCTOU and reduce buffering.

This commit is contained in:
Anthony J. Bentley
2014-09-24 00:23:40 -06:00
parent 056109652d
commit 45b6872e2a
8 changed files with 282 additions and 156 deletions

View File

@@ -22,7 +22,9 @@ rgbasm_obj := \
src/asm/output.o \ src/asm/output.o \
src/asm/rpn.o \ src/asm/rpn.o \
src/asm/symbol.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 := \ rgblib_obj := \
src/lib/library.o \ src/lib/library.o \

View File

@@ -9,6 +9,8 @@
#ifndef ASMOTOR_ASM_FSTACK_H #ifndef ASMOTOR_ASM_FSTACK_H
#define ASMOTOR_ASM_FSTACK_H #define ASMOTOR_ASM_FSTACK_H
#include <stdio.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/types.h" #include "asm/types.h"
#include "asm/lexer.h" #include "asm/lexer.h"
@@ -27,14 +29,17 @@ struct sContext {
ULONG nREPTBlockSize; ULONG nREPTBlockSize;
}; };
extern ULONG fstk_RunInclude(char *s); void
fstk_RunInclude(char *);
extern void fstk_RunMacroArg(SLONG s); extern void fstk_RunMacroArg(SLONG s);
extern ULONG fstk_Init(char *s); void
fstk_Init(char *);
extern void fstk_Dump(void); extern void fstk_Dump(void);
extern void fstk_AddIncludePath(char *s); extern void fstk_AddIncludePath(char *s);
extern ULONG fstk_RunMacro(char *s); extern ULONG fstk_RunMacro(char *s);
extern void fstk_RunRept(ULONG count); extern void fstk_RunRept(ULONG count);
extern void fstk_FindFile(char *s); FILE *
fstk_FindFile(char *);
extern int yywrap(void); extern int yywrap(void);

View File

@@ -5,10 +5,19 @@
* *
*/ */
#include <errno.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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/symbol.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/types.h" #include "asm/types.h"
@@ -195,28 +204,33 @@ fstk_AddIncludePath(char *s)
strcpy(IncludePaths[NextIncPath++], s); strcpy(IncludePaths[NextIncPath++], s);
} }
void FILE *
fstk_FindFile(char *s) fstk_FindFile(char *fname)
{ {
char t[_MAX_PATH + 1]; char path[PATH_MAX];
SLONG i = -1; int i;
FILE *f;
strcpy(t, s); if ((f = fopen(fname, "rb")) != NULL || errno != ENOENT) {
return f;
}
while (i < NextIncPath) { for (i = 0; i < NextIncPath; ++i) {
FILE *f; if (strlcpy(path, IncludePaths[i], sizeof path) >=
sizeof path) {
if ((f = fopen(t, "rb")) != NULL) { continue;
fclose(f);
strcpy(s, t);
return;
} }
i += 1; if (strlcat(path, fname, sizeof path) >= sizeof path) {
if (i < NextIncPath) { continue;
strcpy(t, IncludePaths[i]); }
strcat(t, s);
if ((f = fopen(path, "rb")) != NULL || errno != ENOENT) {
return f;
} }
} }
errno = ENOENT;
return NULL;
} }
/* /*
* RGBAsm - FSTACK.C (FileStack routines) * RGBAsm - FSTACK.C (FileStack routines)
@@ -225,33 +239,32 @@ fstk_FindFile(char *s)
* *
*/ */
ULONG void
fstk_RunInclude(char *tzFileName) fstk_RunInclude(char *tzFileName)
{ {
FILE *f; FILE *f;
//printf("INCLUDE: %s\n", s); f = fstk_FindFile(tzFileName);
fstk_FindFile(tzFileName); if (f == NULL) {
//printf("INCLUDING: %s\n", tzFileName); fprintf(stderr, "Unable to open included file '%s': ",
tzFileName);
perror(NULL);
exit(1);
}
if ((f = fopen(tzFileName, "r")) != NULL) { pushcontext();
pushcontext(); nLineNo = 1;
nLineNo = 1; nCurrentStatus = STAT_isInclude;
nCurrentStatus = STAT_isInclude; strcpy(tzCurrentFileName, tzFileName);
strcpy(tzCurrentFileName, tzFileName); pCurrentFile = f;
pCurrentFile = f; CurrentFlexHandle = yy_create_buffer(pCurrentFile);
CurrentFlexHandle = yy_create_buffer(pCurrentFile); yy_switch_to_buffer(CurrentFlexHandle);
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'); yyunput('\n');
nLineNo -= 1; nLineNo -= 1;
return (1);
} else
return (0);
} }
/* /*
* RGBAsm - FSTACK.C (FileStack routines) * RGBAsm - FSTACK.C (FileStack routines)
@@ -360,7 +373,7 @@ fstk_RunRept(ULONG count)
* *
*/ */
ULONG void
fstk_Init(char *s) fstk_Init(char *s)
{ {
char tzFileName[_MAX_PATH + 1]; char tzFileName[_MAX_PATH + 1];
@@ -368,17 +381,19 @@ fstk_Init(char *s)
sym_AddString("__FILE__", s); sym_AddString("__FILE__", s);
strcpy(tzFileName, s); strcpy(tzFileName, s);
fstk_FindFile(tzFileName);
pFileStack = NULL; pFileStack = NULL;
if ((pCurrentFile = fopen(tzFileName, "r")) != NULL) { pCurrentFile = fopen(tzFileName, "rb");
nMacroCount = 0; if (pCurrentFile == NULL) {
nCurrentStatus = STAT_isInclude; fprintf(stderr, "Unable to open file '%s': ",
strcpy(tzCurrentFileName, tzFileName); tzFileName);
CurrentFlexHandle = yy_create_buffer(pCurrentFile); perror(NULL);
yy_switch_to_buffer(CurrentFlexHandle); exit(1);
nLineNo = 1; }
return (1);
} else nMacroCount = 0;
return (0); nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName);
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);
nLineNo = 1;
} }

View File

@@ -348,7 +348,6 @@ main(int argc, char *argv[])
DefaultOptions = CurrentOptions; DefaultOptions = CurrentOptions;
/* tzMainfile=argv[argn++]; argc-=1; */
tzMainfile = argv[argc - 1]; tzMainfile = argv[argc - 1];
setuplex(); setuplex();
@@ -366,75 +365,71 @@ main(int argc, char *argv[])
nPass = 1; nPass = 1;
nErrors = 0; nErrors = 0;
sym_PrepPass1(); sym_PrepPass1();
if (fstk_Init(tzMainfile)) { fstk_Init(tzMainfile);
if (CurrentOptions.verbose) { if (CurrentOptions.verbose) {
printf("Pass 1...\n"); printf("Pass 1...\n");
} }
yy_set_state(LEX_STATE_NORMAL); yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions); opt_SetCurrentOptions(&DefaultOptions);
if (yyparse() == 0 && nErrors == 0) { if (yyparse() == 0 && nErrors == 0) {
if (nIFDepth == 0) { if (nIFDepth == 0) {
nTotalLines = 0; nTotalLines = 0;
nLineNo = 1; nLineNo = 1;
nIFDepth = 0; nIFDepth = 0;
nPC = 0; nPC = 0;
nPass = 2; nPass = 2;
nErrors = 0; nErrors = 0;
sym_PrepPass2(); sym_PrepPass2();
out_PrepPass2(); out_PrepPass2();
fstk_Init(tzMainfile); fstk_Init(tzMainfile);
yy_set_state(LEX_STATE_NORMAL); yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions); opt_SetCurrentOptions(&DefaultOptions);
if (CurrentOptions.verbose) {
printf("Pass 2...\n");
}
if (yyparse() == 0 && nErrors == 0) {
double timespent;
nEndClock = clock();
timespent =
((double) (nEndClock - nStartClock))
/ (double) CLOCKS_PER_SEC;
if (CurrentOptions.verbose) { if (CurrentOptions.verbose) {
printf("Pass 2...\n");
}
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 {
printf printf
("Assembly aborted in pass 2 (%ld errors)!\n", ("Success! %ld lines in %d.%02d seconds ",
nErrors); nTotalLines, (int) timespent,
//sym_PrintSymbolTable(); ((int) (timespent * 100.0)) % 100);
exit(5); if (timespent == 0)
printf
("(INFINITY lines/minute)\n");
else
printf("(%d lines/minute)\n",
(int) (60 / timespent *
nTotalLines));
} }
out_WriteObject();
} else { } else {
fprintf(stderr, printf
"Unterminated IF construct (%ld levels)!\n", ("Assembly aborted in pass 2 (%ld errors)!\n",
nIFDepth); nErrors);
exit(1); //sym_PrintSymbolTable();
exit(5);
} }
} else { } else {
fprintf(stderr, fprintf(stderr,
"Assembly aborted in pass 1 (%ld errors)!\n", "Unterminated IF construct (%ld levels)!\n",
nErrors); nIFDepth);
exit(1); exit(1);
} }
} else { } else {
printf("File '%s' not found\n", tzMainfile); fprintf(stderr,
exit(5); "Assembly aborted in pass 1 (%ld errors)!\n",
nErrors);
exit(1);
} }
return (0); return 0;
} }

View File

@@ -907,30 +907,33 @@ out_BinaryFile(char *s)
{ {
FILE *f; 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); fseek(f, 0, SEEK_END);
fsize = ftell(f); fsize = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
checkcodesection(fsize); checkcodesection(fsize);
if (nPass == 2) { if (nPass == 2) {
SLONG dest = nPC; SLONG dest = nPC;
SLONG todo = fsize; SLONG todo = fsize;
while (todo--) while (todo--)
pCurrentSection->tData[dest++] = fgetc(f); pCurrentSection->tData[dest++] = fgetc(f);
} }
pCurrentSection->nPC += fsize; pCurrentSection->nPC += fsize;
nPC += fsize; nPC += fsize;
pPCSymbol->nValue += fsize; pPCSymbol->nValue += fsize;
fclose(f); fclose(f);
} else
fatalerror("Could not open file '%s': %s", s, strerror(errno));
} }
void void
@@ -944,36 +947,39 @@ out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
if (length < 0) if (length < 0)
fatalerror("Number of bytes to read must be greater than zero"); 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); fseek(f, 0, SEEK_END);
fsize = ftell(f); fsize = ftell(f);
if (start_pos >= fsize) if (start_pos >= fsize)
fatalerror("Specified start position is greater than length of file"); fatalerror("Specified start position is greater than length of file");
if ((start_pos + length) > fsize) if ((start_pos + length) > fsize)
fatalerror("Specified range in INCBIN is out of bounds"); 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) { if (nPass == 2) {
SLONG dest = nPC; SLONG dest = nPC;
SLONG todo = length; SLONG todo = length;
while (todo--) while (todo--)
pCurrentSection->tData[dest++] = fgetc(f); pCurrentSection->tData[dest++] = fgetc(f);
} }
pCurrentSection->nPC += length; pCurrentSection->nPC += length;
nPC += length; nPC += length;
pPCSymbol->nValue += length; pPCSymbol->nValue += length;
fclose(f); fclose(f);
} else
fatalerror("Could not open file '%s': %s", s, strerror(errno));
} }

View File

@@ -265,10 +265,7 @@ set : T_LABEL T_POP_SET const
include : T_POP_INCLUDE string include : T_POP_INCLUDE string
{ {
if( !fstk_RunInclude($2) ) fstk_RunInclude($2);
{
yyerror("Could not open file '%s' : %s\n", $2, strerror(errno));
}
} }
; ;

55
src/extern/strlcat.c vendored Normal file
View File

@@ -0,0 +1,55 @@
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 */
}

51
src/extern/strlcpy.c vendored Normal file
View File

@@ -0,0 +1,51 @@
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 */
}