Skip to content

Commit a2ee688

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: GHSA-wm6j-2649-pv75: [mbstring] Fix null pointer dereference in php_mb_check_encoding() via mb_ereg_search_init() GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint GHSA-hmxp-6pc4-f3vv: [soap] Fix broken Apache map value NULL check GHSA-m33r-qmcv-p97q: [soap] Fix use-after-free after header parsing failure with SOAP_PERSISTENCE_SESSION GHSA-85c2-q967-79q5: [soap] Fix stale SOAP_GLOBAL(ref_map) pointer with Apache Map
2 parents 6a27514 + 86bb29d commit a2ee688

9 files changed

Lines changed: 277 additions & 9 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GHSA-wm6j-2649-pv75: Null pointer dereference in php_mb_check_encoding() via mb_ereg_search_init()
3+
--CREDITS--
4+
vi3tL0u1s
5+
--EXTENSIONS--
6+
mbstring
7+
--SKIPIF--
8+
<?php
9+
if (!function_exists('mb_regex_encoding')) die('skip No mbregex support');
10+
?>
11+
--FILE--
12+
<?php
13+
// iso-8859-11 is supported by Oniguruma but not by mbfl
14+
mb_regex_encoding('iso-8859-11');
15+
mb_ereg_search_init('x');
16+
?>
17+
--EXPECTF--
18+
Fatal error: Uncaught ValueError: mb_regex_encoding(): Argument #1 ($encoding) must be a valid encoding, "iso-8859-11" given in %s:%d
19+
Stack trace:
20+
#0 %s(%d): mb_regex_encoding('iso-8859-11')
21+
#1 {main}
22+
thrown in %s on line %d

ext/mbstring/php_mbregex.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,13 @@ int php_mb_regex_set_mbctype(const char *encname)
409409
if (mbctype == ONIG_ENCODING_UNDEF) {
410410
return FAILURE;
411411
}
412+
const mbfl_encoding *mbfl_enc = mbfl_name2encoding(encname);
413+
if (mbfl_enc == NULL) {
414+
/* Encoding supported by Oniguruma but not by mbfl */
415+
return FAILURE;
416+
}
412417
MBREX(current_mbctype) = mbctype;
413-
MBREX(current_mbctype_mbfl_encoding) = mbfl_name2encoding(encname);
418+
MBREX(current_mbctype_mbfl_encoding) = mbfl_enc;
414419
return SUCCESS;
415420
}
416421
/* }}} */

ext/soap/php_encoding.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ static bool soap_check_xml_ref(zval *data, xmlNodePtr node)
374374
static void soap_add_xml_ref(zval *data, xmlNodePtr node)
375375
{
376376
if (SOAP_GLOBAL(ref_map)) {
377+
Z_TRY_ADDREF_P(data);
377378
zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data);
378379
}
379380
}
@@ -2796,7 +2797,7 @@ static zval *to_zval_map(zval *ret, encodeTypePtr type, xmlNodePtr data)
27962797
}
27972798

27982799
xmlValue = get_node(item->children, "value");
2799-
if (!xmlKey) {
2800+
if (!xmlValue) {
28002801
soap_error0(E_ERROR, "Encoding: Can't decode apache map, missing value");
28012802
}
28022803

@@ -3540,7 +3541,7 @@ void encode_reset_ns(void)
35403541
} else {
35413542
SOAP_GLOBAL(ref_map) = emalloc(sizeof(HashTable));
35423543
}
3543-
zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0);
3544+
zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, ZVAL_PTR_DTOR, 0);
35443545
}
35453546

35463547
void encode_finish(void)

ext/soap/soap.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,12 +1551,20 @@ PHP_METHOD(SoapServer, handle)
15511551
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
15521552
php_output_discard();
15531553
soap_server_fault_ex(function, &h->retval, h);
1554-
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1554+
if (service->type == SOAP_CLASS && soap_obj) {
1555+
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1556+
zval_ptr_dtor(soap_obj);
1557+
}
1558+
}
15551559
goto fail;
15561560
} else if (EG(exception)) {
15571561
php_output_discard();
15581562
_soap_server_exception(service, function, ZEND_THIS);
1559-
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1563+
if (service->type == SOAP_CLASS && soap_obj) {
1564+
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1565+
zval_ptr_dtor(soap_obj);
1566+
}
1567+
}
15601568
goto fail;
15611569
}
15621570
} else if (h->mustUnderstand) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
GHSA-85c2-q967-79q5: Stale SOAP_GLOBAL(ref_map) pointer with Apache Map
3+
--CREDITS--
4+
brettgervasoni
5+
--EXTENSIONS--
6+
soap
7+
--FILE--
8+
<?php
9+
10+
class Handler {
11+
public function test(...$args) {
12+
$GLOBALS['result'] = $args;
13+
}
14+
}
15+
16+
$envelope = <<<'XML'
17+
<?xml version="1.0" encoding="UTF-8"?>
18+
<soapenv:Envelope
19+
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
20+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
21+
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
22+
23+
<soapenv:Body>
24+
<test>
25+
<map xsi:type="apache:Map" xmlns:apache="http://xml.apache.org/xml-soap">
26+
<item>
27+
<key>foo</key>
28+
<value id="stale"><object>bar</object></value>
29+
</item>
30+
<item>
31+
<key>foo</key>
32+
<value>baz</value>
33+
</item>
34+
</map>
35+
<stale href="#stale"/>
36+
</test>
37+
</soapenv:Body>
38+
</soapenv:Envelope>
39+
XML;
40+
41+
$s = new SoapServer(null, ['uri' => 'urn:a']);
42+
$s->setClass(Handler::class);
43+
$s->handle($envelope);
44+
var_dump($result);
45+
46+
?>
47+
--EXPECTF--
48+
<?xml version="1.0" encoding="UTF-8"?>
49+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:testResponse><return xsi:nil="true"/></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
50+
array(2) {
51+
[0]=>
52+
array(1) {
53+
["foo"]=>
54+
string(3) "baz"
55+
}
56+
[1]=>
57+
object(stdClass)#%d (1) {
58+
["object"]=>
59+
string(3) "bar"
60+
}
61+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
GHSA-hmxp-6pc4-f3vv: Null pointer dereference on missing Apache map value
3+
--CREDITS--
4+
Ilia Alshanetsky (iliaal)
5+
--EXTENSIONS--
6+
soap
7+
--FILE--
8+
<?php
9+
10+
$request = <<<XML
11+
<?xml version="1.0" encoding="UTF-8"?>
12+
<soap:Envelope
13+
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
14+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
15+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
16+
xmlns:apache="http://xml.apache.org/xml-soap">
17+
18+
<soap:Body>
19+
<test>
20+
<map xsi:type="apache:Map">
21+
<item><key>hello</key></item>
22+
</map>
23+
</test>
24+
</soap:Body>
25+
</soap:Envelope>
26+
XML;
27+
28+
$server = new SoapServer(null, [
29+
'uri' => 'urn:test',
30+
'typemap' => [['type_name' => 'anything']],
31+
]);
32+
$server->addFunction('test');
33+
function test($m) { return null; }
34+
$server->handle($request);
35+
36+
?>
37+
--EXPECT--
38+
<?xml version="1.0" encoding="UTF-8"?>
39+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>SOAP-ERROR: Encoding: Can't decode apache map, missing value</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
GHSA-m33r-qmcv-p97q: Use-after-free after header parsing failure with SOAP_PERSISTENCE_SESSION
3+
--CREDITS--
4+
Ilia Alshanetsky (iliaal)
5+
--EXTENSIONS--
6+
soap
7+
session
8+
--FILE--
9+
<?php
10+
11+
class Handler {
12+
public function return() {
13+
return new SoapFault('Server', 'denied');
14+
}
15+
public function throw() {
16+
throw new SoapFault('Server', 'denied');
17+
}
18+
public function hello() {
19+
return 'ok';
20+
}
21+
}
22+
23+
session_start();
24+
25+
$srv = new SoapServer(null, ['uri' => 'urn:a']);
26+
$srv->setClass(Handler::class);
27+
$srv->setPersistence(SOAP_PERSISTENCE_SESSION);
28+
29+
$srv->handle(<<<XML
30+
<?xml version="1.0" encoding="UTF-8"?>
31+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="urn:a">
32+
<soap:Header>
33+
<a:return/>
34+
</soap:Header>
35+
<soap:Body>
36+
<a:hello/>
37+
</soap:Body>
38+
</soap:Envelope>
39+
XML);
40+
41+
$srv->handle(<<<XML
42+
<?xml version="1.0" encoding="UTF-8"?>
43+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="urn:a">
44+
<soap:Header>
45+
<a:throw/>
46+
</soap:Header>
47+
<soap:Body>
48+
<a:hello/>
49+
</soap:Body>
50+
</soap:Envelope>
51+
XML);
52+
53+
?>
54+
--EXPECT--
55+
<?xml version="1.0" encoding="UTF-8"?>
56+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
57+
<?xml version="1.0" encoding="UTF-8"?>
58+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

sapi/fpm/fpm/fpm_status.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ int fpm_status_handle_request(void) /* {{{ */
522522
if (full_syntax) {
523523
unsigned int i;
524524
int first;
525-
zend_string *tmp_query_string;
526-
char *query_string;
525+
zend_string *tmp_query_string, *tmp_request_uri_string;
526+
char *query_string, *request_uri_string;
527527
struct timeval duration, now;
528528
float cpu;
529529

@@ -548,13 +548,36 @@ int fpm_status_handle_request(void) /* {{{ */
548548
}
549549
}
550550

551+
request_uri_string = NULL;
552+
tmp_request_uri_string = NULL;
553+
if (proc->request_uri[0] != '\0') {
554+
if (encode_html) {
555+
tmp_request_uri_string = php_escape_html_entities_ex(
556+
(const unsigned char *) proc->request_uri,
557+
strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
558+
NULL, /* double_encode */ 1, /* quiet */ 0);
559+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
560+
} else if (encode_json) {
561+
tmp_request_uri_string = php_json_encode_string(proc->request_uri,
562+
strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE);
563+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
564+
/* remove quotes around the string */
565+
if (ZSTR_LEN(tmp_request_uri_string) >= 2) {
566+
request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0';
567+
++request_uri_string;
568+
}
569+
} else {
570+
request_uri_string = proc->request_uri;
571+
}
572+
}
573+
551574
query_string = NULL;
552575
tmp_query_string = NULL;
553576
if (proc->query_string[0] != '\0') {
554577
if (encode_html) {
555578
tmp_query_string = php_escape_html_entities_ex(
556579
(const unsigned char *) proc->query_string,
557-
strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
580+
strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
558581
NULL, /* double_encode */ 1, /* quiet */ 0);
559582
} else if (encode_json) {
560583
tmp_query_string = php_json_encode_string(proc->query_string,
@@ -593,7 +616,7 @@ int fpm_status_handle_request(void) /* {{{ */
593616
proc->requests,
594617
(unsigned long) (duration.tv_sec * 1000000UL + duration.tv_usec),
595618
proc->request_method[0] != '\0' ? proc->request_method : "-",
596-
proc->request_uri[0] != '\0' ? proc->request_uri : "-",
619+
request_uri_string ? request_uri_string : "-",
597620
query_string ? "?" : "",
598621
query_string ? query_string : "",
599622
proc->content_length,
@@ -604,6 +627,9 @@ int fpm_status_handle_request(void) /* {{{ */
604627
PUTS(buffer);
605628
efree(buffer);
606629

630+
if (tmp_request_uri_string) {
631+
zend_string_free(tmp_request_uri_string);
632+
}
607633
if (tmp_query_string) {
608634
zend_string_free(tmp_query_string);
609635
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
FPM: GHSA-7qg2-v9fj-4mwv - status xss
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
8+
require_once "tester.inc";
9+
10+
$cfg = <<<EOT
11+
[global]
12+
error_log = {{FILE:LOG}}
13+
[unconfined]
14+
listen = {{ADDR}}
15+
pm = static
16+
pm.max_children = 2
17+
pm.status_path = /status
18+
catch_workers_output = yes
19+
EOT;
20+
21+
$code = <<<EOT
22+
<?php
23+
usleep(200000);
24+
EOT;
25+
26+
$tester = new FPM\Tester($cfg, $code);
27+
$tester->start();
28+
$tester->expectLogStartNotices();
29+
$responses = $tester
30+
->multiRequest([
31+
['uri' => '/<script>alert(1)</script>', 'query' => '<script>alert(2)</script>'],
32+
['uri' => '/status', 'query' => 'full&html', 'delay' => 100000],
33+
]);
34+
var_dump(strpos($responses[1]->getBody(), '<script>'));
35+
$tester->terminate();
36+
$tester->expectLogTerminatingNotices();
37+
$tester->close();
38+
39+
?>
40+
Done
41+
--EXPECT--
42+
bool(false)
43+
Done
44+
--CLEAN--
45+
<?php
46+
require_once "tester.inc";
47+
FPM\Tester::clean();
48+
?>

0 commit comments

Comments
 (0)