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: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ 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; negative occurrence values are now rejected).
(Weilin Du)

- Sockets:
. Added the TCP_USER_TIMEOUT constant for Linux to set the maximum time in
Expand Down
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,11 @@ PHP 8.6 UPGRADE NOTES
- mysqli
. Added new constant MYSQLI_OPT_COMPRESS.

- Soap:
. WSDL/XML Schema parsing now rejects out-of-range integer values for
occurrence constraints and integer restriction facets. Negative minOccurs
and maxOccurs values are rejected as well.

========================================
10. New Global Constants
========================================
Expand Down
35 changes: 32 additions & 3 deletions ext/soap/php_schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,35 @@ 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, bool allow_negative)
{
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 || (type == IS_LONG && ZEND_LONG_EXCEEDS_INT(lval))) {
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
}

if (type == IS_LONG) {
if (!allow_negative && lval < 0) {
soap_error1(E_ERROR, "Parsing Schema: %s value is out of range", name);
}
return (int) lval;
}

errno = 0;
lval = ZEND_STRTOL(str, NULL, 10);
if ((errno == ERANGE && (lval > 0 || lval < 0))
|| ZEND_LONG_EXCEEDS_INT(lval)
|| (!allow_negative && lval < 0)) {
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 +883,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, true);

return TRUE;
}
Expand Down Expand Up @@ -1016,7 +1045,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", false);
} else {
model->min_occurs = 1;
}
Expand All @@ -1026,7 +1055,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", false);
}
} else {
model->max_occurs = 1;
Expand Down
128 changes: 128 additions & 0 deletions ext/soap/tests/bugs/gh22167.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
--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"),
"negative minOccurs" => occurrence_schema("minOccurs", "-1"),
"negative maxOccurs" => occurrence_schema("maxOccurs", "-1"),
"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",
"negative out-of-range numeric-string" => "-2147483649",
"decimal numeric-string" => "2147483648.0",
"exponent numeric-string" => "2147483648e0",
Comment thread
LamentXU123 marked this conversation as resolved.
];

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
negative minOccurs: SOAP-ERROR: Parsing Schema: minOccurs value is out of range
negative 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
negative out-of-range numeric-string: 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