From ef2c459941b5ffae501e5311f5ac2041aadbe461 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 13 Nov 2024 01:41:40 +0100 Subject: [PATCH] Use-after-free for ??= due to incorrect live-range calculation Fixes GHSA-rwp7-7vc6-8477 --- NEWS | 2 ++ Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt | 26 +++++++++++++++++++++++++ Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt | 24 +++++++++++++++++++++++ Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt | 22 +++++++++++++++++++++ Zend/zend_opcode.c | 8 ++++++++ 5 files changed, 82 insertions(+) create mode 100644 Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt create mode 100644 Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt create mode 100644 Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt diff --git a/NEWS b/NEWS index 07effa01580..aeffd4ece47 100644 --- a/NEWS +++ b/NEWS @@ -31,6 +31,8 @@ PHP NEWS `__callStatic` is allowed). (timwolla) . Fixed bug GH-17797 (zend_test_compile_string crash on invalid script path). (David Carlier) + . Fixed GHSA-rwp7-7vc6-8477 (Reference counting in php_request_shutdown + causes Use-After-Free). (CVE-2024-11235) (ilutov) - DOM: . Fixed bug GH-17847 (xinclude destroys live node). (nielsdos) diff --git a/Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt b/Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt new file mode 100644 index 00000000000..d0e9ddcba41 --- /dev/null +++ b/Zend/tests/ghsa-rwp7-7vc6-8477_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +GHSA-rwp7-7vc6-8477: Use-after-free for ??= due to incorrect live-range calculation +--FILE-- +foo()->baz ??= 1; +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Hello diff --git a/Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt b/Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt new file mode 100644 index 00000000000..4115d9eae26 --- /dev/null +++ b/Zend/tests/ghsa-rwp7-7vc6-8477_002.phpt @@ -0,0 +1,24 @@ +--TEST-- +GHSA-rwp7-7vc6-8477: Use-after-free for ??= due to incorrect live-range calculation +--FILE-- +foo()->prop ??= 'foo'; +} catch (Error $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Cannot assign string to property Foo::$prop of type int diff --git a/Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt b/Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt new file mode 100644 index 00000000000..f2808afbf84 --- /dev/null +++ b/Zend/tests/ghsa-rwp7-7vc6-8477_003.phpt @@ -0,0 +1,22 @@ +--TEST-- +GHSA-rwp7-7vc6-8477: Use-after-free for ??= due to incorrect live-range calculation +--FILE-- +prop ??= 'foo'; +} catch (Error $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Cannot assign string to property Foo::$prop of type int diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 55bf81376d9..06f411a1d36 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -922,6 +922,14 @@ static void zend_calc_live_ranges( opnum--; opline--; + /* SEPARATE always redeclares its op1. For the purposes of live-ranges, + * its declaration is irrelevant. Don't terminate the current live-range + * to avoid breaking special handling of COPY_TMP. */ + if (opline->opcode == ZEND_SEPARATE) { + ZEND_ASSERT(opline->op1.var == opline->result.var); + continue; + } + if ((opline->result_type & (IS_TMP_VAR|IS_VAR)) && !is_fake_def(opline)) { uint32_t var_num = EX_VAR_TO_NUM(opline->result.var) - var_offset; /* Defs without uses can occur for two reasons: Either because the result is