Skip to content

Commit 86bb29d

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: 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 ccb9ec6 + 79a054e commit 86bb29d

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
@@ -366,6 +366,7 @@ static bool soap_check_xml_ref(zval *data, xmlNodePtr node)
366366
static void soap_add_xml_ref(zval *data, xmlNodePtr node)
367367
{
368368
if (SOAP_GLOBAL(ref_map)) {
369+
Z_TRY_ADDREF_P(data);
369370
zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data);
370371
}
371372
}
@@ -2782,7 +2783,7 @@ static zval *to_zval_map(zval *ret, encodeTypePtr type, xmlNodePtr data)
27822783
}
27832784

27842785
xmlValue = get_node(item->children, "value");
2785-
if (!xmlKey) {
2786+
if (!xmlValue) {
27862787
soap_error0(E_ERROR, "Encoding: Can't decode apache map, missing value");
27872788
}
27882789

@@ -3513,7 +3514,7 @@ void encode_reset_ns(void)
35133514
} else {
35143515
SOAP_GLOBAL(ref_map) = emalloc(sizeof(HashTable));
35153516
}
3516-
zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0);
3517+
zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, ZVAL_PTR_DTOR, 0);
35173518
}
35183519

35193520
void encode_finish(void)

ext/soap/soap.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,12 +1444,20 @@ PHP_METHOD(SoapServer, handle)
14441444
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
14451445
php_output_discard();
14461446
soap_server_fault_ex(function, &h->retval, h);
1447-
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1447+
if (service->type == SOAP_CLASS && soap_obj) {
1448+
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1449+
zval_ptr_dtor(soap_obj);
1450+
}
1451+
}
14481452
goto fail;
14491453
} else if (EG(exception)) {
14501454
php_output_discard();
14511455
_soap_server_exception(service, function, ZEND_THIS);
1452-
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1456+
if (service->type == SOAP_CLASS && soap_obj) {
1457+
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1458+
zval_ptr_dtor(soap_obj);
1459+
}
1460+
}
14531461
goto fail;
14541462
}
14551463
} 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
@@ -512,8 +512,8 @@ int fpm_status_handle_request(void) /* {{{ */
512512
if (full_syntax) {
513513
unsigned int i;
514514
int first;
515-
zend_string *tmp_query_string;
516-
char *query_string;
515+
zend_string *tmp_query_string, *tmp_request_uri_string;
516+
char *query_string, *request_uri_string;
517517
struct timeval duration, now;
518518
float cpu;
519519

@@ -538,13 +538,36 @@ int fpm_status_handle_request(void) /* {{{ */
538538
}
539539
}
540540

541+
request_uri_string = NULL;
542+
tmp_request_uri_string = NULL;
543+
if (proc->request_uri[0] != '\0') {
544+
if (encode_html) {
545+
tmp_request_uri_string = php_escape_html_entities_ex(
546+
(const unsigned char *) proc->request_uri,
547+
strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
548+
NULL, /* double_encode */ 1, /* quiet */ 0);
549+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
550+
} else if (encode_json) {
551+
tmp_request_uri_string = php_json_encode_string(proc->request_uri,
552+
strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE);
553+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
554+
/* remove quotes around the string */
555+
if (ZSTR_LEN(tmp_request_uri_string) >= 2) {
556+
request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0';
557+
++request_uri_string;
558+
}
559+
} else {
560+
request_uri_string = proc->request_uri;
561+
}
562+
}
563+
541564
query_string = NULL;
542565
tmp_query_string = NULL;
543566
if (proc->query_string[0] != '\0') {
544567
if (encode_html) {
545568
tmp_query_string = php_escape_html_entities_ex(
546569
(const unsigned char *) proc->query_string,
547-
strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
570+
strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
548571
NULL, /* double_encode */ 1, /* quiet */ 0);
549572
} else if (encode_json) {
550573
tmp_query_string = php_json_encode_string(proc->query_string,
@@ -583,7 +606,7 @@ int fpm_status_handle_request(void) /* {{{ */
583606
proc->requests,
584607
(unsigned long) (duration.tv_sec * 1000000UL + duration.tv_usec),
585608
proc->request_method[0] != '\0' ? proc->request_method : "-",
586-
proc->request_uri[0] != '\0' ? proc->request_uri : "-",
609+
request_uri_string ? request_uri_string : "-",
587610
query_string ? "?" : "",
588611
query_string ? query_string : "",
589612
proc->content_length,
@@ -594,6 +617,9 @@ int fpm_status_handle_request(void) /* {{{ */
594617
PUTS(buffer);
595618
efree(buffer);
596619

620+
if (tmp_request_uri_string) {
621+
zend_string_free(tmp_request_uri_string);
622+
}
597623
if (tmp_query_string) {
598624
zend_string_free(tmp_query_string);
599625
}
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)