From 06ef76a51d5b1f6a67c03332933e8e716e718d1d Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 27 Nov 2020 15:39:45 +0100 Subject: [PATCH 1/2] Fix #76813: Access_violation_near_NULL_on_source_operand If no valid token has been recognized, we return `T_UNEXPECTED` instead of proceeding with an invalid scanner state. We also fix the only superficially related issue regarding empty input followed by `T_SEPARATOR` and command, which caused another segfault. --- sapi/phpdbg/phpdbg_lexer.l | 5 ++++- sapi/phpdbg/phpdbg_parser.y | 8 ++++++-- sapi/phpdbg/tests/bug76813.phpt | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 sapi/phpdbg/tests/bug76813.phpt diff --git a/sapi/phpdbg/phpdbg_lexer.l b/sapi/phpdbg/phpdbg_lexer.l index 422cda4f2c07..120e407c2bfa 100644 --- a/sapi/phpdbg/phpdbg_lexer.l +++ b/sapi/phpdbg/phpdbg_lexer.l @@ -84,7 +84,10 @@ ADDR [0][x][a-fA-F0-9]+ OPCODE (ZEND_|zend_)([A-Za-z])+ INPUT ("\\"[#"']|["]("\\\\"|"\\"["]|[^\n\000"])+["]|[']("\\"[']|"\\\\"|[^\n\000'])+[']|[^\n\000#"'])+ - := yyleng = (size_t) YYCURSOR - (size_t) yytext; + { + if (YYCURSOR == NULL) return T_UNEXPECTED; + yyleng = (size_t) YYCURSOR - (size_t) yytext; +} <*>[\n\000] { return 0; diff --git a/sapi/phpdbg/phpdbg_parser.y b/sapi/phpdbg/phpdbg_parser.y index 3031ce5a8077..4c4a339c0ab9 100644 --- a/sapi/phpdbg/phpdbg_parser.y +++ b/sapi/phpdbg/phpdbg_parser.y @@ -63,11 +63,15 @@ typedef void* yyscan_t; %% /* Rules */ input - : command { $$ = $1; } - | input T_SEPARATOR command { phpdbg_stack_separate($1.top); $$ = $3; } + : non_empty_input { $$ = $1; } | /* empty */ ; +non_empty_input + : command { $$ = $1; } + | non_empty_input T_SEPARATOR command { phpdbg_stack_separate($1.top); $$ = $3; } + ; + command : parameters { $$.top = PHPDBG_G(parser_stack)->top; } | full_expression { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); $$.top = PHPDBG_G(parser_stack)->top; } diff --git a/sapi/phpdbg/tests/bug76813.phpt b/sapi/phpdbg/tests/bug76813.phpt new file mode 100644 index 000000000000..61e5e3fea63d --- /dev/null +++ b/sapi/phpdbg/tests/bug76813.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #76813 (Access_violation_near_NULL_on_source_operand) +--PHPDBG-- +"#!==)===\377\377\276\242=" +#!==)===\377\377\276\242= +--EXPECT-- +prompt> [Parse Error: syntax error, unexpected input, expecting $end] +prompt> [Parse Error: syntax error, unexpected # (pound sign), expecting $end] +prompt> [Parse Error: syntax error, unexpected # (pound sign), expecting $end] +prompt> From c6e857b11e8aa6a81b956defc18709e32efecaeb Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sat, 28 Nov 2020 13:47:37 +0100 Subject: [PATCH 2/2] Cleaner solution We avoid `YYCURSOR` becoming `NULL` by initializing `YYMARKER`, and add a default rule for `` where we catch unexpected input. --- sapi/phpdbg/phpdbg_lexer.l | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sapi/phpdbg/phpdbg_lexer.l b/sapi/phpdbg/phpdbg_lexer.l index 120e407c2bfa..e57702ba0b16 100644 --- a/sapi/phpdbg/phpdbg_lexer.l +++ b/sapi/phpdbg/phpdbg_lexer.l @@ -33,7 +33,7 @@ void phpdbg_init_lexer (phpdbg_param_t *stack, char *input) { YYSETCONDITION(INITIAL); - LEX(text) = YYCURSOR = (unsigned char *) input; + LEX(text) = YYCURSOR = YYMARKER = (unsigned char *) input; LEX(len) = strlen(input); } @@ -84,10 +84,7 @@ ADDR [0][x][a-fA-F0-9]+ OPCODE (ZEND_|zend_)([A-Za-z])+ INPUT ("\\"[#"']|["]("\\\\"|"\\"["]|[^\n\000"])+["]|[']("\\"[']|"\\\\"|[^\n\000'])+[']|[^\n\000#"'])+ - { - if (YYCURSOR == NULL) return T_UNEXPECTED; - yyleng = (size_t) YYCURSOR - (size_t) yytext; -} + := yyleng = (size_t) YYCURSOR - (size_t) yytext; <*>[\n\000] { return 0; @@ -168,6 +165,10 @@ INPUT ("\\"[#"']|["]("\\\\"|"\\"["]|[^\n\000"])+["]|[']("\\"[']|"\\\\"|[^\ return T_ID; } +* { + return T_UNEXPECTED; +} + {INPUT} { phpdbg_init_param(yylval, STR_PARAM); yylval->str = estrdup(yytext);