]> granicus.if.org Git - php/commitdiff
Fix UAF in is_callable() and allocated trampoline
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 30 Jan 2020 10:01:13 +0000 (11:01 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 30 Jan 2020 10:04:59 +0000 (11:04 +0100)
By nulling out the function_handler, so it will not get used
below. Reuse the existing helper for this purpose.

Zend/tests/is_callable_trampoline_uaf.phpt [new file with mode: 0644]
Zend/zend_API.c

diff --git a/Zend/tests/is_callable_trampoline_uaf.phpt b/Zend/tests/is_callable_trampoline_uaf.phpt
new file mode 100644 (file)
index 0000000..2410864
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+is_callable() with trampoline should not caused UAF
+--FILE--
+<?php
+
+class B {}
+class A extends B {
+    public function bar($func) {
+        var_dump(is_callable(array('parent', 'foo')));
+    }
+
+    public function __call($func, $args) {
+    }
+}
+
+class X {
+    public static function __callStatic($func, $args) {
+    }
+}
+
+$a = new A();
+// Extra X::foo() wrapper to force use of allocated trampoline.
+X::foo($a->bar('foo'));
+
+?>
+--EXPECT--
+bool(false)
index 4511368bea7a0b14191f5e0fd44241e54c2b2c98..b7af44a32a5738b7231e292d4305579b9eb8027f 100644 (file)
@@ -3154,13 +3154,7 @@ get_function_via_handler:
                                        if (strict_class &&
                                            (!fcc->function_handler->common.scope ||
                                             !instanceof_function(ce_org, fcc->function_handler->common.scope))) {
-                                               if (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
-                                                       if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION &&
-                                                               fcc->function_handler->common.function_name) {
-                                                               zend_string_release_ex(fcc->function_handler->common.function_name, 0);
-                                                       }
-                                                       zend_free_trampoline(fcc->function_handler);
-                                               }
+                                               zend_release_fcall_info_cache(fcc);
                                        } else {
                                                retval = 1;
                                                call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;