From 1d064531d608c49dab50a33444418a8939fefcdf Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 28 Jun 2025 11:20:27 +0200 Subject: [PATCH] Fix OSS-Fuzz #428053935 Registering the constant may happen under another name due to lowercasing. This will cause the lookup to the constant to fail. Instead of looking it up, just change the Zend API to return a pointer instead. --- UPGRADING.INTERNALS | 2 ++ .../constants/oss_fuzz_428053935.phpt | 19 +++++++++++++++++++ Zend/zend_builtin_functions.c | 2 +- Zend/zend_constants.c | 7 +++---- Zend/zend_constants.h | 2 +- Zend/zend_vm_def.h | 9 ++++----- Zend/zend_vm_execute.h | 9 ++++----- 7 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 Zend/tests/attributes/constants/oss_fuzz_428053935.phpt diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index acc9612b72e3..ae8a28ac23ac 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -45,6 +45,8 @@ PHP 8.5 INTERNALS UPGRADE NOTES properties. . ZEND_IS_XDIGIT() macro was removed because it was unused and its name did not match its actual behavior. + . zend_register_constant() now returns a pointer to the added constant + on success and NULL on failure instead of SUCCESS/FAILURE. ======================== 2. Build system changes diff --git a/Zend/tests/attributes/constants/oss_fuzz_428053935.phpt b/Zend/tests/attributes/constants/oss_fuzz_428053935.phpt new file mode 100644 index 000000000000..97747fd6194f --- /dev/null +++ b/Zend/tests/attributes/constants/oss_fuzz_428053935.phpt @@ -0,0 +1,19 @@ +--TEST-- +OSS-Fuzz #428053935 +--FILE-- +getAttributes()); +?> +--EXPECTF-- +array(1) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(8) "Foo\Attr" + } +} diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 48e5c7089729..fc3b0f57d85e 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -592,7 +592,7 @@ ZEND_FUNCTION(define) /* non persistent */ ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); c.name = zend_string_copy(name); - if (zend_register_constant(&c) == SUCCESS) { + if (zend_register_constant(&c) != NULL) { RETURN_TRUE; } else { RETURN_FALSE; diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index ffad8315ae40..db37b9cf7682 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -505,11 +505,11 @@ static void* zend_hash_add_constant(HashTable *ht, zend_string *key, zend_consta return ret; } -ZEND_API zend_result zend_register_constant(zend_constant *c) +ZEND_API zend_constant *zend_register_constant(zend_constant *c) { zend_string *lowercase_name = NULL; zend_string *name; - zend_result ret = SUCCESS; + zend_constant *ret = NULL; bool persistent = (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) != 0; #if 0 @@ -539,7 +539,7 @@ ZEND_API zend_result zend_register_constant(zend_constant *c) /* Check if the user is trying to define any special constant */ if (zend_string_equals_literal(name, "__COMPILER_HALT_OFFSET__") || (!persistent && zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name))) - || zend_hash_add_constant(EG(zend_constants), name, c) == NULL + || (ret = zend_hash_add_constant(EG(zend_constants), name, c)) == NULL ) { zend_error(E_WARNING, "Constant %s already defined", ZSTR_VAL(name)); zend_string_release(c->name); @@ -550,7 +550,6 @@ ZEND_API zend_result zend_register_constant(zend_constant *c) if (!persistent) { zval_ptr_dtor_nogc(&c->value); } - ret = FAILURE; } if (lowercase_name) { zend_string_release(lowercase_name); diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index 3912215d8077..69ea1d9021a8 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -97,7 +97,7 @@ ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zen ZEND_API void zend_register_double_constant(const char *name, size_t name_len, double dval, int flags, int module_number); ZEND_API void zend_register_string_constant(const char *name, size_t name_len, const char *strval, int flags, int module_number); ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, const char *strval, size_t strlen, int flags, int module_number); -ZEND_API zend_result zend_register_constant(zend_constant *c); +ZEND_API zend_constant *zend_register_constant(zend_constant *c); void zend_constant_add_attributes(zend_constant *c, HashTable *attributes); #ifdef ZTS void zend_copy_constants(HashTable *target, HashTable *source); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index be7bc8b37b7d..51aaf635b3b3 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8261,7 +8261,7 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); c.name = zend_string_copy(Z_STR_P(name)); - if (zend_register_constant(&c) == FAILURE) { + if (zend_register_constant(&c) == NULL) { } FREE_OP1(); @@ -8274,7 +8274,7 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST) USE_OPLINE zval *name; zval *val; - zend_constant c; + zend_constant c, *registered; SAVE_OPLINE(); name = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -8293,7 +8293,8 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST) ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); c.name = zend_string_copy(Z_STR_P(name)); - if (zend_register_constant(&c) == FAILURE) { + registered = zend_register_constant(&c); + if (registered == NULL) { FREE_OP1(); FREE_OP2(); /* two opcodes used, second one is the data with attributes */ @@ -8301,9 +8302,7 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST) } HashTable *attributes = Z_PTR_P(GET_OP_DATA_ZVAL_PTR(BP_VAR_R)); - zend_constant *registered = zend_get_constant_ptr(c.name); ZEND_ASSERT(attributes != NULL); - ZEND_ASSERT(registered != NULL); zend_constant_add_attributes(registered, attributes); FREE_OP1(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3a13f4244d36..f29c6b472614 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -8043,7 +8043,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); c.name = zend_string_copy(Z_STR_P(name)); - if (zend_register_constant(&c) == FAILURE) { + if (zend_register_constant(&c) == NULL) { } @@ -8055,7 +8055,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_ USE_OPLINE zval *name; zval *val; - zend_constant c; + zend_constant c, *registered; SAVE_OPLINE(); name = RT_CONSTANT(opline, opline->op1); @@ -8074,7 +8074,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_ ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); c.name = zend_string_copy(Z_STR_P(name)); - if (zend_register_constant(&c) == FAILURE) { + registered = zend_register_constant(&c); + if (registered == NULL) { /* two opcodes used, second one is the data with attributes */ @@ -8082,9 +8083,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_ } HashTable *attributes = Z_PTR_P(get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1)); - zend_constant *registered = zend_get_constant_ptr(c.name); ZEND_ASSERT(attributes != NULL); - ZEND_ASSERT(registered != NULL); zend_constant_add_attributes(registered, attributes);