]> granicus.if.org Git - php/commitdiff
Don't resolve special class names
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 22 Feb 2021 09:09:28 +0000 (10:09 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 22 Feb 2021 09:11:14 +0000 (10:11 +0100)
Adjust zend_resolve_class_name() to not resolve special class names.
This avoids the need to only call this function after a preliminary
check for non-default fetch types. Doing so is somewhat fragile
when dynamic class names are involved.

Fixes oss-fuzz #31139.

Zend/tests/invalid_const_class_name.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/Zend/tests/invalid_const_class_name.phpt b/Zend/tests/invalid_const_class_name.phpt
new file mode 100644 (file)
index 0000000..bedd74e
--- /dev/null
@@ -0,0 +1,8 @@
+--TEST--
+Invalid constant class name in nested class constant access
+--FILE--
+<?php
+[]::X::X;
+?>
+--EXPECTF--
+Fatal error: Illegal class name in %s on line %d
index 15bc64783d9b37035be6a029491ade778d49d0a1..5ecaa399bd73ffa9589e3deda78acbbd5748fef2 100644 (file)
@@ -941,22 +941,35 @@ zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /* {{{ */
 {
        char *compound;
 
+       if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
+               if (type == ZEND_NAME_FQ) {
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "'\\%s' is an invalid class name", ZSTR_VAL(name));
+               }
+               if (type == ZEND_NAME_RELATIVE) {
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "'namespace\\%s' is an invalid class name", ZSTR_VAL(name));
+               }
+               ZEND_ASSERT(type == ZEND_NAME_NOT_FQ);
+               return zend_string_copy(name);
+       }
+
        if (type == ZEND_NAME_RELATIVE) {
                return zend_prefix_with_ns(name);
        }
 
-       if (type == ZEND_NAME_FQ || ZSTR_VAL(name)[0] == '\\') {
-               /* Remove \ prefix (only relevant if this is a string rather than a label) */
+       if (type == ZEND_NAME_FQ) {
                if (ZSTR_VAL(name)[0] == '\\') {
+                       /* Remove \ prefix (only relevant if this is a string rather than a label) */
                        name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
-               } else {
-                       zend_string_addref(name);
-               }
-               /* Ensure that \self, \parent and \static are not used */
-               if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "'\\%s' is an invalid class name", ZSTR_VAL(name));
+                       if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
+                               zend_error_noreturn(E_COMPILE_ERROR,
+                                       "'\\%s' is an invalid class name", ZSTR_VAL(name));
+                       }
+                       return name;
                }
-               return name;
+
+               return zend_string_copy(name);
        }
 
        if (FC(imports)) {
@@ -10078,20 +10091,7 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
                                return;
                        }
 
-                       switch (zend_get_class_fetch_type(zend_ast_get_str(class_ast))) {
-                               case ZEND_FETCH_CLASS_SELF:
-                                       if (!zend_is_scope_known()) {
-                                               return;
-                                       }
-                                       resolved_name = zend_string_copy(CG(active_class_entry)->name);
-                                       break;
-                               case ZEND_FETCH_CLASS_DEFAULT:
-                                       resolved_name = zend_resolve_class_name_ast(class_ast);
-                                       break;
-                               default:
-                                       return;
-                       }
-
+                       resolved_name = zend_resolve_class_name_ast(class_ast);
                        if (!zend_try_ct_eval_class_const(&result, resolved_name, zend_ast_get_str(name_ast))) {
                                zend_string_release_ex(resolved_name, 0);
                                return;