Skip to content

Commit 5571765

Browse files
committed
Forbid use of <?= as a semi-reserved identifier
One of the weirdest pieces of PHP code I've ever seen. In terms of tokens, this gets internally translated to use x as y; echo as my_echo; On master it crashes because this "echo" does not have attached identifier metadata. Make sure it is added and then reject the use of "<?=" as an identifier inside zend_lex_tstring. Fixes oss-fuzz #23547.
1 parent 6fa126e commit 5571765

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
<?= cannot be used as an identifier
3+
--FILE--
4+
<?php
5+
trait T {
6+
public function x() {}
7+
}
8+
class C {
9+
use T {
10+
x as y?><?= as my_echo;
11+
}
12+
}
13+
?>
14+
--EXPECTF--
15+
Parse error: Cannot use "<?=" as an identifier in %s on line %d

Zend/zend_language_parser.y

+3-2
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ identifier:
296296
T_STRING { $$ = $1; }
297297
| semi_reserved {
298298
zval zv;
299-
zend_lex_tstring(&zv, $1);
299+
if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; }
300300
$$ = zend_ast_create_zval(&zv);
301301
}
302302
;
@@ -852,7 +852,8 @@ trait_alias:
852852
trait_method_reference T_AS T_STRING
853853
{ $$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, $3); }
854854
| trait_method_reference T_AS reserved_non_modifiers
855-
{ zval zv; zend_lex_tstring(&zv, $3);
855+
{ zval zv;
856+
if (zend_lex_tstring(&zv, $3) == FAILURE) { YYABORT; }
856857
$$ = zend_ast_create(ZEND_AST_TRAIT_ALIAS, $1, zend_ast_create_zval(&zv)); }
857858
| trait_method_reference T_AS member_modifier identifier
858859
{ $$ = zend_ast_create_ex(ZEND_AST_TRAIT_ALIAS, $3, $1, $4); }

Zend/zend_language_scanner.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state);
7878
ZEND_API int zend_prepare_string_for_scanning(zval *str, const char *filename);
7979
ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, const zend_encoding *old_encoding);
8080
ZEND_API int zend_multibyte_set_filter(const zend_encoding *onetime_encoding);
81-
ZEND_API void zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref);
81+
ZEND_API int zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref);
8282

8383
END_EXTERN_C()
8484

Zend/zend_language_scanner.l

+9-2
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,21 @@ ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle)
306306
}
307307
}
308308

309-
ZEND_API void zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref)
309+
ZEND_API int zend_lex_tstring(zval *zv, zend_lexer_ident_ref ident_ref)
310310
{
311311
char *ident = (char *) SCNG(yy_start) + ident_ref.offset;
312312
size_t length = ident_ref.len;
313+
if (length == sizeof("<?=")-1 && memcmp(ident, "<?=", sizeof("<?=")-1) == 0) {
314+
zend_throw_exception(zend_ce_parse_error, "Cannot use \"<?=\" as an identifier", 0);
315+
return FAILURE;
316+
}
317+
313318
if (SCNG(on_event)) {
314319
SCNG(on_event)(ON_FEEDBACK, T_STRING, 0, ident, length, SCNG(on_event_context));
315320
}
316321

317322
ZVAL_STRINGL(zv, ident, length);
323+
return SUCCESS;
318324
}
319325

320326
#define BOM_UTF32_BE "\x00\x00\xfe\xff"
@@ -2149,7 +2155,8 @@ string:
21492155
<INITIAL>"<?=" {
21502156
BEGIN(ST_IN_SCRIPTING);
21512157
if (PARSER_MODE()) {
2152-
RETURN_TOKEN(T_ECHO);
2158+
/* We'll reject this as an identifier in zend_lex_tstring. */
2159+
RETURN_TOKEN_WITH_IDENT(T_ECHO);
21532160
}
21542161
RETURN_TOKEN(T_OPEN_TAG_WITH_ECHO);
21552162
}

0 commit comments

Comments
 (0)