Skip to content

Commit 3e1e852

Browse files
committed
ext/soap: Fix SOAP array index integer overflow
1 parent 242fee9 commit 3e1e852

3 files changed

Lines changed: 85 additions & 3 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ PHP NEWS
147147
- Soap:
148148
. Soap::__setCookie() when cookie name is a digit is now not stored and
149149
represented as a string anymore but a int. (David Carlier)
150+
. Fixed integer overflow when decoding SOAP array indexes. (Weilin Du)
150151
. Fixed bug GH-21421 (SoapClient typemap property breaks engine assumptions).
151152
(ndossche)
152153

ext/soap/php_encoding.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
+----------------------------------------------------------------------+
1515
*/
1616

17+
#include <limits.h>
1718
#include <time.h>
1819

1920
#include "php_soap.h"
@@ -2048,6 +2049,15 @@ static int calc_dimension_12(const char* str)
20482049
return i;
20492050
}
20502051

2052+
static void soap_array_position_add_digit(int *position, int digit)
2053+
{
2054+
if (*position > (INT_MAX - digit) / 10) {
2055+
soap_error0(E_ERROR, "Encoding: array index out of range");
2056+
}
2057+
2058+
*position = (*position * 10) + digit;
2059+
}
2060+
20512061
static int* get_position_12(int dimension, const char* str)
20522062
{
20532063
int *pos;
@@ -2068,7 +2078,7 @@ static int* get_position_12(int dimension, const char* str)
20682078
i++;
20692079
flag = 1;
20702080
}
2071-
pos[i] = (pos[i]*10)+(*str-'0');
2081+
soap_array_position_add_digit(&pos[i], *str - '0');
20722082
} else if (*str == '*') {
20732083
soap_error0(E_ERROR, "Encoding: '*' may only be first arraySize value in list");
20742084
} else {
@@ -2098,7 +2108,7 @@ static void get_position_ex(int dimension, const char* str, int** pos)
20982108
memset(*pos,0,sizeof(int)*dimension);
20992109
while (*str != ']' && *str != '\0' && i < dimension) {
21002110
if (*str >= '0' && *str <= '9') {
2101-
(*pos)[i] = ((*pos)[i]*10)+(*str-'0');
2111+
soap_array_position_add_digit(&(*pos)[i], *str - '0');
21022112
} else if (*str == ',') {
21032113
i++;
21042114
}
@@ -2686,12 +2696,14 @@ static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data)
26862696
i = dimension;
26872697
while (i > 0) {
26882698
i--;
2699+
if (pos[i] == INT_MAX) {
2700+
soap_error0(E_ERROR, "Encoding: array index out of range");
2701+
}
26892702
pos[i]++;
26902703
if (pos[i] >= dims[i]) {
26912704
if (i > 0) {
26922705
pos[i] = 0;
26932706
} else {
2694-
/* TODO: Array index overflow */
26952707
}
26962708
} else {
26972709
break;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
--TEST--
2+
SOAP array index overflow is rejected
3+
--EXTENSIONS--
4+
soap
5+
--FILE--
6+
<?php
7+
class TestSoapClient extends SoapClient {
8+
public string $response;
9+
10+
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
11+
return $this->response;
12+
}
13+
}
14+
15+
function soap_response(string $attributes, string $itemAttributes = ''): string {
16+
return <<<XML
17+
<?xml version="1.0" encoding="UTF-8"?>
18+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
19+
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
20+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xmlns:ns1="http://example.org/"
23+
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
24+
<SOAP-ENV:Body>
25+
<ns1:testResponse>
26+
<return $attributes>
27+
<item xsi:type="xsd:string" $itemAttributes>value</item>
28+
</return>
29+
</ns1:testResponse>
30+
</SOAP-ENV:Body>
31+
</SOAP-ENV:Envelope>
32+
XML;
33+
}
34+
35+
function test_overflow(string $name, string $response): void {
36+
$client = new TestSoapClient(NULL, [
37+
'location' => 'test://',
38+
'uri' => 'http://example.org/',
39+
'exceptions' => true,
40+
]);
41+
$client->response = $response;
42+
43+
try {
44+
$client->test();
45+
echo "$name: no fault\n";
46+
} catch (SoapFault $e) {
47+
echo "$name: $e->faultstring\n";
48+
}
49+
}
50+
51+
test_overflow(
52+
'arrayType',
53+
soap_response('SOAP-ENC:arrayType="xsd:string[2147483648]" xsi:type="SOAP-ENC:Array"')
54+
);
55+
56+
test_overflow(
57+
'offset',
58+
soap_response('SOAP-ENC:arrayType="xsd:string[1]" SOAP-ENC:offset="[2147483648]" xsi:type="SOAP-ENC:Array"')
59+
);
60+
61+
test_overflow(
62+
'position',
63+
soap_response('SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array"', 'SOAP-ENC:position="[2147483647]"')
64+
);
65+
?>
66+
--EXPECT--
67+
arrayType: SOAP-ERROR: Encoding: array index out of range
68+
offset: SOAP-ERROR: Encoding: array index out of range
69+
position: SOAP-ERROR: Encoding: array index out of range

0 commit comments

Comments
 (0)