Skip to content

Commit 1db9672

Browse files
committed
fix bailout logic
1 parent 0e7df66 commit 1db9672

3 files changed

Lines changed: 88 additions & 108 deletions

File tree

ext/soap/php_packet_soap.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@
1818

1919
#include "php_soap.h"
2020

21+
static void master_to_zval_with_doc_cleanup(zval *ret, encodePtr encode, xmlNodePtr data, xmlDocPtr doc)
22+
{
23+
bool bailout = false;
24+
25+
/* SoapClient can turn decode errors into a bailout before parse_packet_soap() frees the response doc. */
26+
zend_try {
27+
master_to_zval(ret, encode, data);
28+
} zend_catch {
29+
bailout = true;
30+
} zend_end_try();
31+
32+
if (bailout) {
33+
xmlFreeDoc(doc);
34+
zend_bailout();
35+
}
36+
}
37+
2138
/* SOAP client calls this function to parse response from SOAP server */
2239
bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval *return_value, zval *soap_headers)
2340
{
@@ -191,22 +208,22 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio
191208
tmp = get_node(fault->children, "faultstring");
192209
if (tmp != NULL && tmp->children != NULL) {
193210
zval zv;
194-
master_to_zval(&zv, get_conversion(IS_STRING), tmp);
211+
master_to_zval_with_doc_cleanup(&zv, get_conversion(IS_STRING), tmp, response);
195212
convert_to_string(&zv)
196213
faultstring = Z_STR(zv);
197214
}
198215

199216
tmp = get_node(fault->children, "faultactor");
200217
if (tmp != NULL && tmp->children != NULL) {
201218
zval zv;
202-
master_to_zval(&zv, get_conversion(IS_STRING), tmp);
219+
master_to_zval_with_doc_cleanup(&zv, get_conversion(IS_STRING), tmp, response);
203220
convert_to_string(&zv)
204221
faultactor = Z_STR(zv);
205222
}
206223

207224
tmp = get_node(fault->children, "detail");
208225
if (tmp != NULL) {
209-
master_to_zval(&details, NULL, tmp);
226+
master_to_zval_with_doc_cleanup(&details, NULL, tmp, response);
210227
}
211228
} else {
212229
tmp = get_node(fault->children, "Code");
@@ -223,15 +240,15 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio
223240
tmp = get_node(tmp->children,"Text");
224241
if (tmp != NULL && tmp->children != NULL) {
225242
zval zv;
226-
master_to_zval(&zv, get_conversion(IS_STRING), tmp);
243+
master_to_zval_with_doc_cleanup(&zv, get_conversion(IS_STRING), tmp, response);
227244
convert_to_string(&zv)
228245
faultstring = Z_STR(zv);
229246
}
230247
}
231248

232249
tmp = get_node(fault->children,"Detail");
233250
if (tmp != NULL) {
234-
master_to_zval(&details, NULL, tmp);
251+
master_to_zval_with_doc_cleanup(&details, NULL, tmp, response);
235252
}
236253
}
237254
add_soap_fault(this_ptr, faultcode, faultstring ? ZSTR_VAL(faultstring) : NULL, faultactor ? ZSTR_VAL(faultactor) : NULL, &details);
@@ -324,9 +341,9 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio
324341
} else {
325342
/* Decoding value of parameter */
326343
if (param != NULL) {
327-
master_to_zval(&tmp, param->encode, val);
344+
master_to_zval_with_doc_cleanup(&tmp, param->encode, val, response);
328345
} else {
329-
master_to_zval(&tmp, NULL, val);
346+
master_to_zval_with_doc_cleanup(&tmp, NULL, val, response);
330347
}
331348
}
332349
add_assoc_zval(return_value, param->paramName, &tmp);
@@ -347,7 +364,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio
347364
zval tmp;
348365
zval *arr;
349366

350-
master_to_zval(&tmp, NULL, val);
367+
master_to_zval_with_doc_cleanup(&tmp, NULL, val, response);
351368
if (val->name) {
352369
if ((arr = zend_hash_str_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name))) != NULL) {
353370
add_next_index_zval(arr, &tmp);
@@ -412,7 +429,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio
412429
}
413430
smart_str_free(&key);
414431
}
415-
master_to_zval(&val, enc, trav);
432+
master_to_zval_with_doc_cleanup(&val, enc, trav, response);
416433
add_assoc_zval(soap_headers, (char*)trav->name, &val);
417434
}
418435
trav = trav->next;

ext/soap/soap.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,9 +2408,19 @@ static void do_soap_call(zend_execute_data *execute_data,
24082408
request = NULL;
24092409

24102410
if (ret && Z_TYPE(response) == IS_STRING) {
2411+
bool parse_bailout = false;
2412+
24112413
encode_reset_ns();
2412-
ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers);
2414+
zend_try {
2415+
ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers);
2416+
} zend_catch {
2417+
parse_bailout = true;
2418+
} zend_end_try();
24132419
encode_finish();
2420+
if (parse_bailout) {
2421+
zval_ptr_dtor(&response);
2422+
zend_bailout();
2423+
}
24142424
}
24152425

24162426
zval_ptr_dtor(&response);
@@ -2452,9 +2462,19 @@ static void do_soap_call(zend_execute_data *execute_data,
24522462
request = NULL;
24532463

24542464
if (ret && Z_TYPE(response) == IS_STRING) {
2465+
bool parse_bailout = false;
2466+
24552467
encode_reset_ns();
2456-
ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, NULL, return_value, output_headers);
2468+
zend_try {
2469+
ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, NULL, return_value, output_headers);
2470+
} zend_catch {
2471+
parse_bailout = true;
2472+
} zend_end_try();
24572473
encode_finish();
2474+
if (parse_bailout) {
2475+
zval_ptr_dtor(&response);
2476+
zend_bailout();
2477+
}
24582478
}
24592479

24602480
zval_ptr_dtor(&response);

ext/soap/tests/soap_array_index_overflow.phpt

Lines changed: 40 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,14 @@ SOAP array index overflow is rejected
44
soap
55
--FILE--
66
<?php
7-
$serverCode = <<<'PHP'
8-
function test($arg) {}
9-
$server = new SoapServer(null, ['uri' => 'http://example.org/']);
10-
$server->addFunction('test');
11-
$server->handle(file_get_contents('php://stdin'));
12-
PHP;
137

14-
$phpArgs = [
15-
'-d',
16-
'display_startup_errors=0',
17-
'-d',
18-
'extension_dir=' . ini_get('extension_dir'),
19-
'-d',
20-
'extension=' . (substr(PHP_OS, 0, 3) === 'WIN' ? 'php_' : '') . 'soap.' . PHP_SHLIB_SUFFIX,
21-
'-r',
22-
$serverCode,
23-
];
24-
if (php_ini_loaded_file()) {
25-
array_splice($phpArgs, 0, 0, ['-c', php_ini_loaded_file()]);
8+
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
9+
return $this->response;
10+
}
2611
}
2712

28-
$arrayTypeRequest = <<<XML
13+
function soap_response(string $attributes, string $itemAttributes = ''): string {
14+
return <<<XML
2915
<?xml version="1.0" encoding="UTF-8"?>
3016
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
3117
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
@@ -34,91 +20,48 @@ $arrayTypeRequest = <<<XML
3420
xmlns:ns1="http://example.org/"
3521
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
3622
<SOAP-ENV:Body>
37-
<ns1:test>
38-
<arg SOAP-ENC:arrayType="xsd:string[2147483648]" xsi:type="SOAP-ENC:Array">
39-
<item xsi:type="xsd:string">value</item>
40-
</arg>
41-
</ns1:test>
23+
<ns1:testResponse>
24+
<return $attributes>
25+
<item xsi:type="xsd:string" $itemAttributes>value</item>
26+
</return>
27+
</ns1:testResponse>
4228
</SOAP-ENV:Body>
4329
</SOAP-ENV:Envelope>
4430
XML;
31+
}
4532

46-
echo "arrayType:\n";
47-
$process = proc_open([PHP_BINARY, ...$phpArgs], [
48-
0 => ['pipe', 'r'],
49-
1 => ['pipe', 'w'],
50-
], $pipes);
51-
fwrite($pipes[0], $arrayTypeRequest);
52-
fclose($pipes[0]);
53-
echo stream_get_contents($pipes[1]);
54-
fclose($pipes[1]);
55-
proc_close($process);
33+
function test_overflow(string $name, string $response): void {
34+
$client = new TestSoapClient(NULL, [
35+
'location' => 'test://',
36+
'uri' => 'http://example.org/',
37+
'exceptions' => true,
38+
]);
39+
$client->response = $response;
5640

57-
$offsetRequest = <<<XML
58-
<?xml version="1.0" encoding="UTF-8"?>
59-
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
60-
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
61-
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
62-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
63-
xmlns:ns1="http://example.org/"
64-
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
65-
<SOAP-ENV:Body>
66-
<ns1:test>
67-
<arg SOAP-ENC:arrayType="xsd:string[1]" SOAP-ENC:offset="[2147483648]" xsi:type="SOAP-ENC:Array">
68-
<item xsi:type="xsd:string">value</item>
69-
</arg>
70-
</ns1:test>
71-
</SOAP-ENV:Body>
72-
</SOAP-ENV:Envelope>
73-
XML;
41+
try {
42+
$client->test();
43+
echo "$name: no fault\n";
44+
} catch (SoapFault $e) {
45+
echo "$name: $e->faultstring\n";
46+
}
47+
}
7448

75-
echo "offset:\n";
76-
$process = proc_open([PHP_BINARY, ...$phpArgs], [
77-
0 => ['pipe', 'r'],
78-
1 => ['pipe', 'w'],
79-
], $pipes);
80-
fwrite($pipes[0], $offsetRequest);
81-
fclose($pipes[0]);
82-
echo stream_get_contents($pipes[1]);
83-
fclose($pipes[1]);
84-
proc_close($process);
49+
test_overflow(
50+
'arrayType',
51+
soap_response('SOAP-ENC:arrayType="xsd:string[2147483648]" xsi:type="SOAP-ENC:Array"')
52+
);
8553

86-
$positionRequest = <<<XML
87-
<?xml version="1.0" encoding="UTF-8"?>
88-
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
89-
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
90-
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
91-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
92-
xmlns:ns1="http://example.org/"
93-
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
94-
<SOAP-ENV:Body>
95-
<ns1:test>
96-
<arg SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
97-
<item xsi:type="xsd:string" SOAP-ENC:position="[2147483647]">value</item>
98-
</arg>
99-
</ns1:test>
100-
</SOAP-ENV:Body>
101-
</SOAP-ENV:Envelope>
102-
XML;
54+
test_overflow(
55+
'offset',
56+
soap_response('SOAP-ENC:arrayType="xsd:string[1]" SOAP-ENC:offset="[2147483648]" xsi:type="SOAP-ENC:Array"')
57+
);
10358

104-
echo "position:\n";
105-
$process = proc_open([PHP_BINARY, ...$phpArgs], [
106-
0 => ['pipe', 'r'],
107-
1 => ['pipe', 'w'],
108-
], $pipes);
109-
fwrite($pipes[0], $positionRequest);
110-
fclose($pipes[0]);
111-
echo stream_get_contents($pipes[1]);
112-
fclose($pipes[1]);
113-
proc_close($process);
59+
test_overflow(
60+
'position',
61+
soap_response('SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array"', 'SOAP-ENC:position="[2147483647]"')
62+
);
11463
?>
11564
--EXPECT--
116-
arrayType:
117-
<?xml version="1.0" encoding="UTF-8"?>
118-
<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: array index out of range</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
119-
offset:
120-
<?xml version="1.0" encoding="UTF-8"?>
121-
<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: array index out of range</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
122-
position:
123-
<?xml version="1.0" encoding="UTF-8"?>
124-
<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: array index out of range</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
65+
arrayType: SOAP-ERROR: Encoding: array index out of range
66+
offset: SOAP-ERROR: Encoding: array index out of range
67+
position: SOAP-ERROR: Encoding: array index out of range

0 commit comments

Comments
 (0)