Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ext/soap/php_encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -2073,7 +2073,8 @@ static int calc_dimension_12(const char* str)
}
str++;
}
return i;
/* arraySize without dimension => one-dimension of unspecified size */
return i > 0 ? i : 1;
}

static void soap_array_position_add_digit(int *position, int digit)
Expand Down
151 changes: 151 additions & 0 deletions ext/soap/tests/gh22887.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
--TEST--
GH-22887 (heap out-of-bounds read while decoding an array with an empty arraySize)
--EXTENSIONS--
soap
--FILE--
<?php
class TestSoapClient extends SoapClient {
public string $response = '';
public string $request = '';

public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string {
$this->request = $request;
return $this->response;
}
}

function soap_response(int $version, string $attributes): string {
$envelope = $version === SOAP_1_2
? 'http://www.w3.org/2003/05/soap-envelope'
: 'http://schemas.xmlsoap.org/soap/envelope/';
$encoding = $version === SOAP_1_2
? 'http://www.w3.org/2003/05/soap-encoding'
: 'http://schemas.xmlsoap.org/soap/encoding/';

return <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="$envelope"
xmlns:SOAP-ENC="$encoding"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns1="http://example.org/">
<SOAP-ENV:Body>
<ns1:testResponse SOAP-ENV:encodingStyle="$encoding">
<return $attributes>
<item xsi:type="xsd:string">first</item>
<item xsi:type="xsd:string">second</item>
</return>
</ns1:testResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
}

/* Decoding: an arraySize holding no dimension at all must not be trusted as a
* zero-dimensional array. */
foreach ([SOAP_1_1 => '1.1', SOAP_1_2 => '1.2'] as $version => $label) {
foreach ([
'SOAP-ENC:arraySize=""',
'SOAP-ENC:arraySize=" "',
'SOAP-ENC:arraySize="abc"',
'SOAP-ENC:itemType="xsd:string" SOAP-ENC:arraySize=""',
'SOAP-ENC:arraySize="2"',
] as $attributes) {
$client = new TestSoapClient(null, [
'location' => 'test://',
'uri' => 'http://example.org/',
'soap_version' => $version,
]);
$client->response = soap_response($version, $attributes);

echo "SOAP $label, $attributes:", PHP_EOL;
var_dump($client->test());
}
}

/* Encoding: same thing for an arraySize coming from a WSDL. */
$client = new TestSoapClient(__DIR__ . '/gh22887.wsdl', [
'cache_wsdl' => WSDL_CACHE_NONE,
'soap_version' => SOAP_1_2,
]);
$client->test(['first', 'second']);

$request = new DOMDocument();
$request->loadXML($client->request);
$value = $request->getElementsByTagName('value')->item(0);
echo 'arraySize: ', var_export($value->getAttribute('enc:arraySize'), true), PHP_EOL;
echo 'items: ', $value->getElementsByTagName('item')->length, PHP_EOL;
?>
--EXPECT--
SOAP 1.1, SOAP-ENC:arraySize="":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.1, SOAP-ENC:arraySize=" ":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.1, SOAP-ENC:arraySize="abc":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.1, SOAP-ENC:itemType="xsd:string" SOAP-ENC:arraySize="":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.1, SOAP-ENC:arraySize="2":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.2, SOAP-ENC:arraySize="":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.2, SOAP-ENC:arraySize=" ":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.2, SOAP-ENC:arraySize="abc":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.2, SOAP-ENC:itemType="xsd:string" SOAP-ENC:arraySize="":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
SOAP 1.2, SOAP-ENC:arraySize="2":
array(2) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
}
arraySize: '2'
items: 2
49 changes: 49 additions & 0 deletions ext/soap/tests/gh22887.wsdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" name="gh22887" targetNamespace="urn:gh22887"
xmlns:tns="urn:gh22887"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-enc="http://www.w3.org/2003/05/soap-encoding">
<types>
<xsd:schema targetNamespace="urn:gh22887">
<xsd:complexType name="ArrayOfString">
<xsd:complexContent>
<xsd:restriction base="soap-enc:Array">
<xsd:attribute ref="soap-enc:itemType" wsdl:itemType="xsd:string"/>
<xsd:attribute ref="soap-enc:arraySize" wsdl:arraySize=""/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
</types>
<message name="testRequest">
<part name="value" type="tns:ArrayOfString"/>
</message>
<message name="testResponse">
<part name="return" type="xsd:string"/>
</message>
<portType name="testPortType">
<operation name="test">
<input message="tns:testRequest"/>
<output message="tns:testResponse"/>
</operation>
</portType>
<binding name="testBinding" type="tns:testPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="test">
<soap:operation soapAction="urn:gh22887#test"/>
<input>
<soap:body use="encoded" namespace="urn:gh22887" encodingStyle="http://www.w3.org/2003/05/soap-encoding"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:gh22887" encodingStyle="http://www.w3.org/2003/05/soap-encoding"/>
</output>
</operation>
</binding>
<service name="testService">
<port name="testPort" binding="tns:testBinding">
<soap:address location="test://"/>
</port>
</service>
</definitions>
Loading