fix bug #71719 (Buffer overflow in HTTP url parsing functions)
authorMichael Wallner <mike@php.net>
Wed, 9 Mar 2016 08:21:28 +0000 (09:21 +0100)
committerMichael Wallner <mike@php.net>
Wed, 9 Mar 2016 08:22:45 +0000 (09:22 +0100)
The parser's offset was not reset when we softfail in scheme
parsing and continue to parse a path.
Thanks to hlt99 at blinkenshell dot org for the report.

.gitattributes
src/php_http_url.c
tests/bug71719.phpt [new file with mode: 0644]
tests/data/bug71719.bin [new file with mode: 0644]

index b0aef47..7159932 100644 (file)
@@ -1,3 +1,4 @@
 package.xml            merge=touch
 php_http.h             merge=touch
 .travis.yml            merge=touch
+/tests/data/bug71719.bin       -diff -text
index 81b2d95..1215942 100644 (file)
@@ -1467,7 +1467,7 @@ static const char *parse_scheme(struct parse_state *state)
                case '7': case '8': case '9':
                case '+': case '-': case '.':
                        if (state->ptr == tmp) {
-                               return tmp;
+                               goto softfail;
                        }
                        /* no break */
                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
@@ -1484,19 +1484,20 @@ static const char *parse_scheme(struct parse_state *state)
 
                default:
                        if (!(mb = parse_mb(state, PARSE_SCHEME, state->ptr, state->end, tmp, 1))) {
-                               /* soft fail; parse path next */
-                               return tmp;
+                               goto softfail;
                        }
                        state->ptr += mb - 1;
                }
        } while (++state->ptr != state->end);
 
+softfail:
+       state->offset = 0;
        return state->ptr = tmp;
 }
 
 php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags TSRMLS_DC)
 {
-       size_t maxlen = 3 * len;
+       size_t maxlen = 3 * len + 8 /* null bytes for all components */;
        struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen);
 
        state->end = str + len;
diff --git a/tests/bug71719.phpt b/tests/bug71719.phpt
new file mode 100644 (file)
index 0000000..f75bac9
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Buffer overflow in HTTP url parsing functions
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+
+echo "Test\n";
+try {
+       echo new http\Message(file_get_contents(__DIR__."/data/bug71719.bin"), false);
+} catch (Exception $e) {
+       echo $e;
+}
+?>
+
+===DONE===
+--EXPECTF--
+Test
+%r(exception ')?%rhttp\Exception\BadMessageException%r(' with message '|: )%rhttp\Message::__construct(): Could not parse HTTP protocol version 'HTTP/%s.0'%r'?%r in %sbug71719.php:5
+Stack trace:
+#0 %sbug71719.php(5): http\Message->__construct('\x80\xACTd 5 HTTP/1.1...', false)
+#1 {main}
+===DONE===
diff --git a/tests/data/bug71719.bin b/tests/data/bug71719.bin
new file mode 100644 (file)
index 0000000..245db28
Binary files /dev/null and b/tests/data/bug71719.bin differ