Skip to content

Commit 74f5943

Browse files
committed
Merge tag 'php-8.1.27' into was-8.1.x
Tag for php-8.1.27
2 parents 7da0ff2 + 7f5048c commit 74f5943

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1204
-116
lines changed

NEWS

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,64 @@
11
PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3+
21 Dec 2023, PHP 8.1.27
4+
5+
- Core:
6+
. Fixed oss-fuzz #54325 (Use-after-free of name in var-var with malicious
7+
error handler). (ilutov)
8+
. Fixed oss-fuzz #64209 (In-place modification of filename in
9+
php_message_handler_for_zend). (ilutov)
10+
. Fixed bug GH-12758 / GH-12768 (Invalid opline in OOM handlers within
11+
ZEND_FUNC_GET_ARGS and ZEND_BIND_STATIC). (Florian Engelhardt)
12+
13+
- DOM:
14+
. Fixed bug GH-12616 (DOM: Removing XMLNS namespace node results in invalid
15+
default: prefix). (nielsdos)
16+
17+
- FPM:
18+
. Fixed bug GH-12705 (Segmentation fault in fpm_status_export_to_zval).
19+
(Patrick Prasse)
20+
21+
- Intl:
22+
. Fixed bug GH-12635 (Test bug69398.phpt fails with ICU 74.1). (nielsdos)
23+
24+
- LibXML:
25+
. Fixed bug GH-12702 (libxml2 2.12.0 issue building from src). (nono303)
26+
27+
- MySQLnd:
28+
. Avoid using uninitialised struct. (mikhainin)
29+
30+
- OpenSSL:
31+
. Fixed bug #50713 (openssl_pkcs7_verify() may ignore untrusted CAs).
32+
(Jakub Zelenka)
33+
34+
- PCRE:
35+
. Fixed bug GH-12628 (The gh11374 test fails on Alpinelinux). (nielsdos)
36+
37+
- PGSQL:
38+
. Fixed bug GH-12763 wrong argument type for pg_untrace. (degtyarov)
39+
40+
- PHPDBG:
41+
. Fixed bug GH-12675 (MEMORY_LEAK in phpdbg_prompt.c). (nielsdos)
42+
43+
- SQLite3:
44+
. Fixed bug GH-12633 (sqlite3_defensive.phpt fails with sqlite 3.44.0).
45+
(SakiTakamachi)
46+
47+
- Standard:
48+
. Fix memory leak in syslog device handling. (danog)
49+
. Fixed bug GH-12621 (browscap segmentation fault when configured in the
50+
vhost). (nielsdos)
51+
. Fixed bug GH-12655 (proc_open() does not take into account references
52+
in the descriptor array). (nielsdos)
53+
54+
- Streams:
55+
. Fixed bug #79945 (Stream wrappers in imagecreatefrompng causes segfault).
56+
(Jakub Zelenka)
57+
58+
- Zip:
59+
. Fixed bug GH-12661 (Inconsistency in ZipArchive::addGlob remove_path Option
60+
Behavior). (Remi)
61+
362
23 Nov 2023, PHP 8.1.26
463

564
- Core:

Zend/tests/oss_fuzz_54325.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
oss-fuzz #54325: Fix use-after-free of name in var-var with malicious error handler
3+
--FILE--
4+
<?php
5+
set_error_handler(function ($errno, $errstr) {
6+
var_dump($errstr);
7+
global $x;
8+
$x = new stdClass;
9+
});
10+
11+
// Needs to be non-interned string
12+
$x = strrev('foo');
13+
$$x++;
14+
var_dump($x);
15+
?>
16+
--EXPECT--
17+
string(23) "Undefined variable $oof"
18+
object(stdClass)#2 (0) {
19+
}

Zend/tests/oss_fuzz_64209.phpt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
oss-fuzz #64209: Fix in-place modification of filename in php_message_handler_for_zend
3+
--FILE--
4+
<?php
5+
require '://@';
6+
?>
7+
--EXPECTF--
8+
Warning: require(://@): Failed to open stream: No such file or directory in %s on line %d
9+
10+
Fatal error: Uncaught Error: Failed opening required '://@' (include_path='%s') in %s:%d
11+
Stack trace:
12+
#0 {main}
13+
thrown in %s on line %d

Zend/zend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#ifndef ZEND_H
2121
#define ZEND_H
2222

23-
#define ZEND_VERSION "4.1.26"
23+
#define ZEND_VERSION "4.1.27"
2424

2525
#define ZEND_ENGINE_3
2626

Zend/zend_vm_def.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1748,13 +1748,20 @@ ZEND_VM_C_LABEL(fetch_this):
17481748
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
17491749
retval = &EG(uninitialized_zval);
17501750
} else {
1751+
if (OP1_TYPE == IS_CV) {
1752+
/* Keep name alive in case an error handler tries to free it. */
1753+
zend_string_addref(name);
1754+
}
17511755
zend_error(E_WARNING, "Undefined %svariable $%s",
17521756
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
17531757
if (type == BP_VAR_RW && !EG(exception)) {
17541758
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
17551759
} else {
17561760
retval = &EG(uninitialized_zval);
17571761
}
1762+
if (OP1_TYPE == IS_CV) {
1763+
zend_string_release(name);
1764+
}
17581765
}
17591766
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
17601767
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
@@ -8781,6 +8788,8 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
87818788

87828789
variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
87838790

8791+
SAVE_OPLINE();
8792+
87848793
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
87858794
if (!ht) {
87868795
ht = zend_array_dup(EX(func)->op_array.static_variables);
@@ -8790,7 +8799,6 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
87908799

87918800
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
87928801

8793-
SAVE_OPLINE();
87948802
if (opline->extended_value & ZEND_BIND_REF) {
87958803
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
87968804
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
@@ -9243,6 +9251,7 @@ ZEND_VM_HANDLER(172, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED)
92439251
}
92449252

92459253
if (result_size) {
9254+
SAVE_OPLINE();
92469255
uint32_t first_extra_arg = EX(func)->op_array.num_args;
92479256

92489257
ht = zend_new_array(result_size);

Zend/zend_vm_execute.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9755,13 +9755,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad
97559755
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
97569756
retval = &EG(uninitialized_zval);
97579757
} else {
9758+
if (IS_CONST == IS_CV) {
9759+
/* Keep name alive in case an error handler tries to free it. */
9760+
zend_string_addref(name);
9761+
}
97589762
zend_error(E_WARNING, "Undefined %svariable $%s",
97599763
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
97609764
if (type == BP_VAR_RW && !EG(exception)) {
97619765
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
97629766
} else {
97639767
retval = &EG(uninitialized_zval);
97649768
}
9769+
if (IS_CONST == IS_CV) {
9770+
zend_string_release(name);
9771+
}
97659772
}
97669773
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
97679774
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
@@ -10693,6 +10700,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSE
1069310700
}
1069410701

1069510702
if (result_size) {
10703+
SAVE_OPLINE();
1069610704
uint32_t first_extra_arg = EX(func)->op_array.num_args;
1069710705

1069810706
ht = zend_new_array(result_size);
@@ -17560,13 +17568,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad
1756017568
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
1756117569
retval = &EG(uninitialized_zval);
1756217570
} else {
17571+
if ((IS_TMP_VAR|IS_VAR) == IS_CV) {
17572+
/* Keep name alive in case an error handler tries to free it. */
17573+
zend_string_addref(name);
17574+
}
1756317575
zend_error(E_WARNING, "Undefined %svariable $%s",
1756417576
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
1756517577
if (type == BP_VAR_RW && !EG(exception)) {
1756617578
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
1756717579
} else {
1756817580
retval = &EG(uninitialized_zval);
1756917581
}
17582+
if ((IS_TMP_VAR|IS_VAR) == IS_CV) {
17583+
zend_string_release(name);
17584+
}
1757017585
}
1757117586
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
1757217587
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
@@ -36050,6 +36065,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUS
3605036065
}
3605136066

3605236067
if (result_size) {
36068+
SAVE_OPLINE();
3605336069
uint32_t first_extra_arg = EX(func)->op_array.num_args;
3605436070

3605536071
ht = zend_new_array(result_size);
@@ -47008,13 +47024,20 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_ad
4700847024
} else if (type == BP_VAR_IS || type == BP_VAR_UNSET) {
4700947025
retval = &EG(uninitialized_zval);
4701047026
} else {
47027+
if (IS_CV == IS_CV) {
47028+
/* Keep name alive in case an error handler tries to free it. */
47029+
zend_string_addref(name);
47030+
}
4701147031
zend_error(E_WARNING, "Undefined %svariable $%s",
4701247032
(opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name));
4701347033
if (type == BP_VAR_RW && !EG(exception)) {
4701447034
retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval));
4701547035
} else {
4701647036
retval = &EG(uninitialized_zval);
4701747037
}
47038+
if (IS_CV == IS_CV) {
47039+
zend_string_release(name);
47040+
}
4701847041
}
4701947042
/* GLOBAL or $$name variable may be an INDIRECT pointer to CV */
4702047043
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
@@ -48450,6 +48473,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN
4845048473

4845148474
variable_ptr = EX_VAR(opline->op1.var);
4845248475

48476+
SAVE_OPLINE();
48477+
4845348478
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
4845448479
if (!ht) {
4845548480
ht = zend_array_dup(EX(func)->op_array.static_variables);
@@ -48459,7 +48484,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN
4845948484

4846048485
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
4846148486

48462-
SAVE_OPLINE();
4846348487
if (opline->extended_value & ZEND_BIND_REF) {
4846448488
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
4846548489
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {

configure.ac

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
1717
dnl ----------------------------------------------------------------------------
1818

1919
AC_PREREQ([2.68])
20-
AC_INIT([PHP],[8.1.26],[https://github.com/php/php-src/issues],[php],[https://www.php.net])
20+
AC_INIT([PHP],[8.1.27],[https://github.com/php/php-src/issues],[php],[https://www.php.net])
2121
AC_CONFIG_SRCDIR([main/php_version.h])
2222
AC_CONFIG_AUX_DIR([build])
2323
AC_PRESERVE_HELP_ORDER
@@ -1536,6 +1536,23 @@ if test "$PHP_UNDEFINED_SANITIZER" = "yes"; then
15361536
AX_CHECK_COMPILE_FLAG([-fsanitize=undefined], [
15371537
CFLAGS="$CFLAGS -fsanitize=undefined"
15381538
CXXFLAGS="$CXXFLAGS -fsanitize=undefined"
1539+
1540+
dnl Clang 17 adds stricter function pointer compatibility checks where pointer args cannot be
1541+
dnl cast to void*. In that case, set -fno-sanitize=function.
1542+
OLD_CFLAGS="$CFLAGS"
1543+
CFLAGS="$CFLAGS -fno-sanitize-recover=undefined"
1544+
AC_RUN_IFELSE([AC_LANG_SOURCE([[
1545+
void foo(char *string) {}
1546+
int main(void) {
1547+
void (*f)(void *) = (void (*)(void *))foo;
1548+
f("foo");
1549+
}
1550+
]])],,[ubsan_needs_no_function=yes],)
1551+
CFLAGS="$OLD_CFLAGS"
1552+
if test "$ubsan_needs_no_function" = yes; then
1553+
CFLAGS="$CFLAGS -fno-sanitize=function"
1554+
CXXFLAGS="$CFLAGS -fno-sanitize=function"
1555+
fi
15391556
], [AC_MSG_ERROR([UndefinedBehaviorSanitizer is not available])])
15401557
fi
15411558

ext/dom/document.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
2424
#include "php_dom.h"
2525
#include <libxml/SAX.h>
26+
#include <libxml/xmlsave.h>
2627
#ifdef LIBXML_SCHEMAS_ENABLED
2728
#include <libxml/relaxng.h>
2829
#include <libxml/xmlschemas.h>

ext/dom/element.c

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,83 @@ PHP_METHOD(DOMElement, setAttributeNS)
724724
}
725725
/* }}} end dom_element_set_attribute_ns */
726726

727+
static void dom_remove_eliminated_ns_single_element(xmlNodePtr node, xmlNsPtr eliminatedNs)
728+
{
729+
ZEND_ASSERT(node->type == XML_ELEMENT_NODE);
730+
if (node->ns == eliminatedNs) {
731+
node->ns = NULL;
732+
}
733+
734+
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
735+
if (attr->ns == eliminatedNs) {
736+
attr->ns = NULL;
737+
}
738+
}
739+
}
740+
741+
static void dom_remove_eliminated_ns(xmlNodePtr node, xmlNsPtr eliminatedNs)
742+
{
743+
dom_remove_eliminated_ns_single_element(node, eliminatedNs);
744+
745+
xmlNodePtr base = node;
746+
node = node->children;
747+
while (node != NULL) {
748+
ZEND_ASSERT(node != base);
749+
750+
if (node->type == XML_ELEMENT_NODE) {
751+
dom_remove_eliminated_ns_single_element(node, eliminatedNs);
752+
753+
if (node->children) {
754+
node = node->children;
755+
continue;
756+
}
757+
}
758+
759+
if (node->next) {
760+
node = node->next;
761+
} else {
762+
/* Go upwards, until we find a parent node with a next sibling, or until we hit the base. */
763+
do {
764+
node = node->parent;
765+
if (node == base) {
766+
return;
767+
}
768+
} while (node->next == NULL);
769+
node = node->next;
770+
}
771+
}
772+
}
773+
774+
static void dom_eliminate_ns(xmlNodePtr nodep, xmlNsPtr nsptr)
775+
{
776+
if (nsptr->href != NULL) {
777+
xmlFree((char *) nsptr->href);
778+
nsptr->href = NULL;
779+
}
780+
if (nsptr->prefix != NULL) {
781+
xmlFree((char *) nsptr->prefix);
782+
nsptr->prefix = NULL;
783+
}
784+
785+
/* Remove it from the list and move it to the old ns list */
786+
xmlNsPtr current_ns = nodep->nsDef;
787+
if (current_ns == nsptr) {
788+
nodep->nsDef = nsptr->next;
789+
} else {
790+
do {
791+
if (current_ns->next == nsptr) {
792+
current_ns->next = nsptr->next;
793+
break;
794+
}
795+
current_ns = current_ns->next;
796+
} while (current_ns != NULL);
797+
}
798+
nsptr->next = NULL;
799+
dom_set_old_ns(nodep->doc, nsptr);
800+
801+
dom_remove_eliminated_ns(nodep, nsptr);
802+
}
803+
727804
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElRemAtNS
728805
Since: DOM Level 2
729806
*/
@@ -754,14 +831,7 @@ PHP_METHOD(DOMElement, removeAttributeNS)
754831
nsptr = dom_get_nsdecl(nodep, (xmlChar *)name);
755832
if (nsptr != NULL) {
756833
if (xmlStrEqual((xmlChar *)uri, nsptr->href)) {
757-
if (nsptr->href != NULL) {
758-
xmlFree((char *) nsptr->href);
759-
nsptr->href = NULL;
760-
}
761-
if (nsptr->prefix != NULL) {
762-
xmlFree((char *) nsptr->prefix);
763-
nsptr->prefix = NULL;
764-
}
834+
dom_eliminate_ns(nodep, nsptr);
765835
} else {
766836
RETURN_NULL();
767837
}

0 commit comments

Comments
 (0)