Skip to content

Commit 97a00cc

Browse files
committed
Fix GH-22167: reject out-of-range SOAP schema integers
1 parent 625f0a7 commit 97a00cc

3 files changed

Lines changed: 151 additions & 3 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ PHP NEWS
176176
represented as a string anymore but a int. (David Carlier)
177177
. Fixed bug GH-21421 (SoapClient typemap property breaks engine assumptions).
178178
(ndossche)
179+
. Fixed bug GH-22167 (Out-of-range XML Schema integer values were silently
180+
accepted during WSDL parsing). (Weilin Du)
179181

180182
- Sockets:
181183
. Added the TCP_USER_TIMEOUT constant for Linux to set the maximum time in

ext/soap/php_schema.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,30 @@ static bool node_is_equal_xsd(xmlNodePtr node, const char *name)
5353
return node_is_equal_ex_one_of(node, name, ns);
5454
}
5555

56+
static int schema_parse_int(const xmlChar *value, const char *name)
57+
{
58+
const char *str = (const char *) value;
59+
zend_long lval = 0;
60+
int oflow_info = 0;
61+
uint8_t type = is_numeric_string_ex(str, strlen(str), &lval, NULL, true, &oflow_info, NULL);
62+
63+
if (oflow_info > 0 || (type == IS_LONG && ZEND_LONG_INT_OVFL(lval))) {
64+
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
65+
}
66+
67+
if (type == IS_LONG) {
68+
return (int) lval;
69+
}
70+
71+
errno = 0;
72+
lval = ZEND_STRTOL(str, NULL, 10);
73+
if ((errno == ERANGE && lval > 0) || ZEND_LONG_INT_OVFL(lval)) {
74+
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
75+
}
76+
77+
return (int) lval;
78+
}
79+
5680
static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *ns, const xmlChar *type)
5781
{
5882
smart_str nscat = {0};
@@ -854,7 +878,7 @@ static int schema_restriction_var_int(xmlNodePtr val, sdlRestrictionIntPtr *valp
854878
soap_error0(E_ERROR, "Parsing Schema: missing restriction value");
855879
}
856880

857-
(*valptr)->value = atoi((char*)value->children->content);
881+
(*valptr)->value = schema_parse_int(value->children->content, (const char *) val->name);
858882

859883
return TRUE;
860884
}
@@ -1016,7 +1040,7 @@ void schema_min_max(xmlNodePtr node, sdlContentModelPtr model)
10161040
xmlAttrPtr attr = get_attribute(node->properties, "minOccurs");
10171041

10181042
if (attr) {
1019-
model->min_occurs = atoi((char*)attr->children->content);
1043+
model->min_occurs = schema_parse_int(attr->children->content, "minOccurs");
10201044
} else {
10211045
model->min_occurs = 1;
10221046
}
@@ -1026,7 +1050,7 @@ void schema_min_max(xmlNodePtr node, sdlContentModelPtr model)
10261050
if (!strncmp((char*)attr->children->content, "unbounded", sizeof("unbounded"))) {
10271051
model->max_occurs = -1;
10281052
} else {
1029-
model->max_occurs = atoi((char*)attr->children->content);
1053+
model->max_occurs = schema_parse_int(attr->children->content, "maxOccurs");
10301054
}
10311055
} else {
10321056
model->max_occurs = 1;

ext/soap/tests/bugs/gh22167.phpt

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
--TEST--
2+
GH-22167 (Out-of-range XML Schema integer values in SOAP WSDL)
3+
--EXTENSIONS--
4+
soap
5+
--INI--
6+
soap.wsdl_cache_enabled=0
7+
--FILE--
8+
<?php
9+
function wsdl_with_schema(string $schema): string {
10+
return <<<XML
11+
<?xml version="1.0"?>
12+
<definitions
13+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
14+
xmlns:tns="http://test-uri/"
15+
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
16+
xmlns="http://schemas.xmlsoap.org/wsdl/"
17+
targetNamespace="http://test-uri/">
18+
<types>
19+
<xsd:schema targetNamespace="http://test-uri/">
20+
$schema
21+
</xsd:schema>
22+
</types>
23+
<message name="m"><part name="p" type="tns:T"/></message>
24+
<portType name="p"><operation name="op"><input message="tns:m"/></operation></portType>
25+
<binding name="b" type="tns:p">
26+
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
27+
<operation name="op">
28+
<soap:operation soapAction="#op"/>
29+
<input>
30+
<soap:body use="encoded"
31+
namespace="http://test-uri/"
32+
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
33+
</input>
34+
</operation>
35+
</binding>
36+
<service name="s"><port name="p" binding="tns:b"><soap:address location="test://"/></port></service>
37+
</definitions>
38+
XML;
39+
}
40+
41+
function occurrence_schema(string $attribute, string $value = "2147483648"): string {
42+
return <<<XML
43+
<xsd:complexType name="T">
44+
<xsd:sequence>
45+
<xsd:element name="x" type="xsd:string" $attribute="$value"/>
46+
</xsd:sequence>
47+
</xsd:complexType>
48+
XML;
49+
}
50+
51+
function restriction_schema(string $facet, string $value = "2147483648"): string {
52+
return <<<XML
53+
<xsd:simpleType name="T">
54+
<xsd:restriction base="xsd:int">
55+
<xsd:$facet value="$value"/>
56+
</xsd:restriction>
57+
</xsd:simpleType>
58+
XML;
59+
}
60+
61+
$cases = [
62+
"minOccurs" => occurrence_schema("minOccurs"),
63+
"maxOccurs" => occurrence_schema("maxOccurs"),
64+
"minExclusive" => restriction_schema("minExclusive"),
65+
"minInclusive" => restriction_schema("minInclusive"),
66+
"maxExclusive" => restriction_schema("maxExclusive"),
67+
"maxInclusive" => restriction_schema("maxInclusive"),
68+
"totalDigits" => restriction_schema("totalDigits"),
69+
"fractionDigits" => restriction_schema("fractionDigits"),
70+
"length" => restriction_schema("length"),
71+
"minLength" => restriction_schema("minLength"),
72+
"maxLength" => restriction_schema("maxLength"),
73+
];
74+
75+
$numeric_string_cases = [
76+
"leading whitespace numeric-string" => " 2147483648",
77+
"leading plus numeric-string" => "+2147483648",
78+
"leading zero numeric-string" => "00000000002147483648",
79+
"leading numeric-string with trailing data" => "2147483648abc",
80+
"decimal numeric-string" => "2147483648.0",
81+
"exponent numeric-string" => "2147483648e0",
82+
];
83+
84+
foreach ($numeric_string_cases as $name => $value) {
85+
$cases[$name] = occurrence_schema("maxOccurs", $value);
86+
}
87+
88+
$cases["fractional numeric-string within int range"] = occurrence_schema("maxOccurs", "3.141");
89+
90+
foreach ($cases as $name => $schema) {
91+
$file = tempnam(sys_get_temp_dir(), "wsdl");
92+
file_put_contents($file, wsdl_with_schema($schema));
93+
94+
try {
95+
new SoapClient($file, ["cache_wsdl" => WSDL_CACHE_NONE]);
96+
echo "$name: parsed\n";
97+
} catch (SoapFault $e) {
98+
echo "$name: {$e->getMessage()}\n";
99+
} finally {
100+
unlink($file);
101+
}
102+
}
103+
?>
104+
--EXPECT--
105+
minOccurs: SOAP-ERROR: Parsing Schema: minOccurs value is out of range
106+
maxOccurs: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
107+
minExclusive: SOAP-ERROR: Parsing Schema: minExclusive value is out of range
108+
minInclusive: SOAP-ERROR: Parsing Schema: minInclusive value is out of range
109+
maxExclusive: SOAP-ERROR: Parsing Schema: maxExclusive value is out of range
110+
maxInclusive: SOAP-ERROR: Parsing Schema: maxInclusive value is out of range
111+
totalDigits: SOAP-ERROR: Parsing Schema: totalDigits value is out of range
112+
fractionDigits: SOAP-ERROR: Parsing Schema: fractionDigits value is out of range
113+
length: SOAP-ERROR: Parsing Schema: length value is out of range
114+
minLength: SOAP-ERROR: Parsing Schema: minLength value is out of range
115+
maxLength: SOAP-ERROR: Parsing Schema: maxLength value is out of range
116+
leading whitespace numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
117+
leading plus numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
118+
leading zero numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
119+
leading numeric-string with trailing data: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
120+
decimal numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
121+
exponent numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
122+
fractional numeric-string within int range: parsed

0 commit comments

Comments
 (0)