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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ PHP NEWS
represented as a string anymore but a int. (David Carlier)
. Fixed bug GH-21421 (SoapClient typemap property breaks engine assumptions).
(ndossche)
. Fixed bug GH-22167 (Out-of-range XML Schema integer values were silently
accepted during WSDL parsing). (Weilin Du)

- Sockets:
. Added the TCP_USER_TIMEOUT constant for Linux to set the maximum time in
Expand Down
30 changes: 27 additions & 3 deletions ext/soap/php_schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@ static bool node_is_equal_xsd(xmlNodePtr node, const char *name)
return node_is_equal_ex_one_of(node, name, ns);
}

static int schema_parse_int(const xmlChar *value, const char *name)
{
const char *str = (const char *) value;
zend_long lval = 0;
int oflow_info = 0;
uint8_t type = is_numeric_string_ex(str, strlen(str), &lval, NULL, true, &oflow_info, NULL);

if (oflow_info > 0 || (type == IS_LONG && ZEND_LONG_INT_OVFL(lval))) {
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
}

if (type == IS_LONG) {
return (int) lval;
}

errno = 0;
lval = ZEND_STRTOL(str, NULL, 10);
if ((errno == ERANGE && lval > 0) || ZEND_LONG_INT_OVFL(lval)) {
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
}

return (int) lval;
}

static encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlChar *ns, const xmlChar *type)
{
smart_str nscat = {0};
Expand Down Expand Up @@ -854,7 +878,7 @@ static int schema_restriction_var_int(xmlNodePtr val, sdlRestrictionIntPtr *valp
soap_error0(E_ERROR, "Parsing Schema: missing restriction value");
}

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

return TRUE;
}
Expand Down Expand Up @@ -1016,7 +1040,7 @@ void schema_min_max(xmlNodePtr node, sdlContentModelPtr model)
xmlAttrPtr attr = get_attribute(node->properties, "minOccurs");

if (attr) {
model->min_occurs = atoi((char*)attr->children->content);
model->min_occurs = schema_parse_int(attr->children->content, "minOccurs");
} else {
model->min_occurs = 1;
}
Expand All @@ -1026,7 +1050,7 @@ void schema_min_max(xmlNodePtr node, sdlContentModelPtr model)
if (!strncmp((char*)attr->children->content, "unbounded", sizeof("unbounded"))) {
model->max_occurs = -1;
} else {
model->max_occurs = atoi((char*)attr->children->content);
model->max_occurs = schema_parse_int(attr->children->content, "maxOccurs");
}
} else {
model->max_occurs = 1;
Expand Down
122 changes: 122 additions & 0 deletions ext/soap/tests/bugs/gh22167.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
--TEST--
GH-22167 (Out-of-range XML Schema integer values in SOAP WSDL)
--EXTENSIONS--
soap
--INI--
soap.wsdl_cache_enabled=0
--FILE--
<?php
function wsdl_with_schema(string $schema): string {
return <<<XML
<?xml version="1.0"?>
<definitions
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://test-uri/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://test-uri/">
<types>
<xsd:schema targetNamespace="http://test-uri/">
$schema
</xsd:schema>
</types>
<message name="m"><part name="p" type="tns:T"/></message>
<portType name="p"><operation name="op"><input message="tns:m"/></operation></portType>
<binding name="b" type="tns:p">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="op">
<soap:operation soapAction="#op"/>
<input>
<soap:body use="encoded"
namespace="http://test-uri/"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
</operation>
</binding>
<service name="s"><port name="p" binding="tns:b"><soap:address location="test://"/></port></service>
</definitions>
XML;
}

function occurrence_schema(string $attribute, string $value = "2147483648"): string {
return <<<XML
<xsd:complexType name="T">
<xsd:sequence>
<xsd:element name="x" type="xsd:string" $attribute="$value"/>
</xsd:sequence>
</xsd:complexType>
XML;
}

function restriction_schema(string $facet, string $value = "2147483648"): string {
return <<<XML
<xsd:simpleType name="T">
<xsd:restriction base="xsd:int">
<xsd:$facet value="$value"/>
</xsd:restriction>
</xsd:simpleType>
XML;
}

$cases = [
"minOccurs" => occurrence_schema("minOccurs"),
"maxOccurs" => occurrence_schema("maxOccurs"),
"minExclusive" => restriction_schema("minExclusive"),
"minInclusive" => restriction_schema("minInclusive"),
"maxExclusive" => restriction_schema("maxExclusive"),
"maxInclusive" => restriction_schema("maxInclusive"),
"totalDigits" => restriction_schema("totalDigits"),
"fractionDigits" => restriction_schema("fractionDigits"),
"length" => restriction_schema("length"),
"minLength" => restriction_schema("minLength"),
"maxLength" => restriction_schema("maxLength"),
];

$numeric_string_cases = [
"leading whitespace numeric-string" => " 2147483648",
"leading plus numeric-string" => "+2147483648",
"leading zero numeric-string" => "00000000002147483648",
"leading numeric-string with trailing data" => "2147483648abc",
"decimal numeric-string" => "2147483648.0",
"exponent numeric-string" => "2147483648e0",
];

foreach ($numeric_string_cases as $name => $value) {
$cases[$name] = occurrence_schema("maxOccurs", $value);
}

$cases["fractional numeric-string within int range"] = occurrence_schema("maxOccurs", "3.141");

foreach ($cases as $name => $schema) {
$file = tempnam(sys_get_temp_dir(), "wsdl");
file_put_contents($file, wsdl_with_schema($schema));

try {
new SoapClient($file, ["cache_wsdl" => WSDL_CACHE_NONE]);
echo "$name: parsed\n";
} catch (SoapFault $e) {
echo "$name: {$e->getMessage()}\n";
} finally {
unlink($file);
}
}
?>
--EXPECT--
minOccurs: SOAP-ERROR: Parsing Schema: minOccurs value is out of range
maxOccurs: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
minExclusive: SOAP-ERROR: Parsing Schema: minExclusive value is out of range
minInclusive: SOAP-ERROR: Parsing Schema: minInclusive value is out of range
maxExclusive: SOAP-ERROR: Parsing Schema: maxExclusive value is out of range
maxInclusive: SOAP-ERROR: Parsing Schema: maxInclusive value is out of range
totalDigits: SOAP-ERROR: Parsing Schema: totalDigits value is out of range
fractionDigits: SOAP-ERROR: Parsing Schema: fractionDigits value is out of range
length: SOAP-ERROR: Parsing Schema: length value is out of range
minLength: SOAP-ERROR: Parsing Schema: minLength value is out of range
maxLength: SOAP-ERROR: Parsing Schema: maxLength value is out of range
leading whitespace numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
leading plus numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
leading zero numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
leading numeric-string with trailing data: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
decimal numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
exponent numeric-string: SOAP-ERROR: Parsing Schema: maxOccurs value is out of range
fractional numeric-string within int range: parsed
Loading