Add assertion check for potential UAF trigger

It actually currently triggers if an INCLUDE directive is given at EOF,
but #742 will fix that.
This commit is contained in:
ISSOtm
2021-02-19 16:52:35 +01:00
parent 6ef3ee1391
commit cd072d5e6a
2 changed files with 18 additions and 6 deletions

View File

@@ -24,7 +24,7 @@
#define MAXINCPATHS 128 #define MAXINCPATHS 128
#ifdef LEXER_DEBUG #ifdef LEXER_DEBUG
#define dbgPrint(...) fprintf(stderr, "[lexer] " __VA_ARGS__) #define dbgPrint(...) fprintf(stderr, "[fstack] " __VA_ARGS__)
#else #else
#define dbgPrint(...) #define dbgPrint(...)
#endif #endif
@@ -270,6 +270,7 @@ bool yywrap(void)
struct Context *context = contextStack; struct Context *context = contextStack;
contextStack = contextStack->parent; contextStack = contextStack->parent;
assert(contextDepth != 0); // This is never supposed to underflow
contextDepth--; contextDepth--;
lexer_DeleteState(context->lexerState); lexer_DeleteState(context->lexerState);

View File

@@ -479,6 +479,19 @@ void lexer_RestartRept(uint32_t lineNo)
void lexer_DeleteState(struct LexerState *state) void lexer_DeleteState(struct LexerState *state)
{ {
// A big chunk of the lexer state soundness is the file stack ("fstack").
// Each context in the fstack has its own *unique* lexer state; thus, we always guarantee
// that lexer states lifetimes are always properly managed, since they're handled solely
// by the fstack... with *one* exception.
// Assume a context is pushed on top of the fstack, and the corresponding lexer state gets
// scheduled at EOF; `lexerStateAtEOL` thus becomes a (weak) ref to that lexer state...
// It has been possible, due to a bug, that the corresponding fstack context gets popped
// before EOL, deleting the associated state... but it would still be switched to at EOL.
// This assertion checks that this doesn't happen again.
// It could be argued that deleting a state that's scheduled for EOF could simply clear
// `lexerStateEOL`, but there's currently no situation in which this should happen.
assert(state != lexerStateEOL);
if (!state->isMmapped) if (!state->isMmapped)
close(state->fd); close(state->fd);
else if (state->isFile && !state->isReferenced) else if (state->isFile && !state->isReferenced)
@@ -2329,13 +2342,13 @@ restart:
[LEXER_RAW] = yylex_RAW, [LEXER_RAW] = yylex_RAW,
[LEXER_SKIP_TO_ELIF] = yylex_SKIP_TO_ELIF, [LEXER_SKIP_TO_ELIF] = yylex_SKIP_TO_ELIF,
[LEXER_SKIP_TO_ENDC] = yylex_SKIP_TO_ENDC, [LEXER_SKIP_TO_ENDC] = yylex_SKIP_TO_ENDC,
[LEXER_SKIP_TO_ENDR] = yylex_SKIP_TO_ENDR [LEXER_SKIP_TO_ENDR] = yylex_SKIP_TO_ENDR,
}; };
int token = lexerModeFuncs[lexerState->mode](); int token = lexerModeFuncs[lexerState->mode]();
if (token == T_EOF) { if (token == T_EOF) {
/* Try to switch to new buffer; if it succeeds, scan again */ /* Try to switch to new buffer; if it succeeds, scan again */
dbgPrint("Reached EOF!\n"); dbgPrint("Reached EOB!\n");
/* Captures end at their buffer's boundary no matter what */ /* Captures end at their buffer's boundary no matter what */
if (!lexerState->capturing) { if (!lexerState->capturing) {
if (!yywrap()) if (!yywrap())
@@ -2345,9 +2358,7 @@ restart:
} }
} }
lexerState->atLineStart = false; lexerState->atLineStart = token == T_NEWLINE;
if (token == T_NEWLINE)
lexerState->atLineStart = true;
return token; return token;
} }