Skip to content

Commit fa41ee9

Browse files
committed
Fix GH-22167: reject out-of-range SOAP schema integers
1 parent 673cb6d commit fa41ee9

3 files changed

Lines changed: 154 additions & 3 deletions

File tree

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ PHP NEWS
1515
IntlCalendar::equals(), ::before(), ::after(), and ::isEquivalentTo().
1616
(Weilin Du)
1717

18+
- SOAP:
19+
. Fixed bug GH-22167 (Out-of-range XML Schema integer values were silently
20+
accepted during WSDL parsing). (Weilin Du)
21+
1822
- Zlib:
1923
. Fixed memory leak if deflate initialization fails and there is a dict.
2024
(ndossche)

ext/soap/php_schema.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,31 @@ static int schema_restriction_var_char(xmlNodePtr val, sdlRestrictionCharPtr *va
4343

4444
static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type);
4545

46+
static int schema_parse_int(const xmlChar *value, const char *name)
47+
{
48+
const char *str = (const char *) value;
49+
zend_long lval = 0;
50+
int oflow_info = 0;
51+
uint8_t type = is_numeric_string_ex(str, strlen(str), &lval, NULL, true, &oflow_info, NULL);
52+
53+
if (oflow_info > 0 || (type == IS_LONG && ZEND_LONG_INT_OVFL(lval))) {
54+
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
55+
}
56+
57+
if (type == IS_LONG) {
58+
return (int) lval;
59+
}
60+
61+
/* Keep atoi()-style parsing for values like "3.141". */
62+
errno = 0;
63+
lval = ZEND_STRTOL(str, NULL, 10);
64+
if ((errno == ERANGE && lval > 0) || ZEND_LONG_INT_OVFL(lval)) {
65+
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
66+
}
67+
68+
return (int) lval;
69+
}
70+
4671
static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *ns, const xmlChar *type)
4772
{
4873
smart_str nscat = {0};
@@ -844,7 +869,7 @@ static int schema_restriction_var_int(xmlNodePtr val, sdlRestrictionIntPtr *valp
844869
soap_error0(E_ERROR, "Parsing Schema: missing restriction value");
845870
}
846871

847-
(*valptr)->value = atoi((char*)value->children->content);
872+
(*valptr)->value = schema_parse_int(value->children->content, (const char *) val->name);
848873

849874
return TRUE;
850875
}
@@ -1006,7 +1031,7 @@ void schema_min_max(xmlNodePtr node, sdlContentModelPtr model)
10061031
xmlAttrPtr attr = get_attribute(node->properties, "minOccurs");
10071032

10081033
if (attr) {
1009-
model->min_occurs = atoi((char*)attr->children->content);
1034+
model->min_occurs = schema_parse_int(attr->children->content, "minOccurs");
10101035
} else {
10111036
model->min_occurs = 1;
10121037
}
@@ -1016,7 +1041,7 @@ void schema_min_max(xmlNodePtr node, sdlContentModelPtr model)
10161041
if (!strncmp((char*)attr->children->content, "unbounded", sizeof("unbounded"))) {
10171042
model->max_occurs = -1;
10181043
} else {
1019-
model->max_occurs = atoi((char*)attr->children->content);
1044+
model->max_occurs = schema_parse_int(attr->children->content, "maxOccurs");
10201045
}
10211046
} else {
10221047
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)