diff --git a/ext/standard/tests/general_functions/bug81645_1.phpt b/ext/standard/tests/general_functions/bug81645_1.phpt new file mode 100644 index 0000000000000..60629f372b159 --- /dev/null +++ b/ext/standard/tests/general_functions/bug81645_1.phpt @@ -0,0 +1,8 @@ +--TEST-- +Bug #81645 (header() allows arbitrary status codes) leading zero +--FILE-- + +--EXPECTF-- +Warning: Cannot set HTTP status line - status code is malformed in %s on line %d diff --git a/ext/standard/tests/general_functions/bug81645_2.phpt b/ext/standard/tests/general_functions/bug81645_2.phpt new file mode 100644 index 0000000000000..a9e9128443812 --- /dev/null +++ b/ext/standard/tests/general_functions/bug81645_2.phpt @@ -0,0 +1,8 @@ +--TEST-- +Bug #81645 (header() allows arbitrary status codes) 2 digit code +--FILE-- + +--EXPECTF-- +Warning: Cannot set HTTP status line - status code is malformed in %s on line %d diff --git a/ext/standard/tests/general_functions/bug81645_3.phpt b/ext/standard/tests/general_functions/bug81645_3.phpt new file mode 100644 index 0000000000000..d34af4afed4ab --- /dev/null +++ b/ext/standard/tests/general_functions/bug81645_3.phpt @@ -0,0 +1,8 @@ +--TEST-- +Bug #81645 (header() allows arbitrary status codes) longer than 3 digit +--FILE-- + +--EXPECTF-- +Warning: Cannot set HTTP status line - status code is malformed in %s on line %d diff --git a/ext/standard/tests/general_functions/bug81645_4.phpt b/ext/standard/tests/general_functions/bug81645_4.phpt new file mode 100644 index 0000000000000..b506dc146b1f5 --- /dev/null +++ b/ext/standard/tests/general_functions/bug81645_4.phpt @@ -0,0 +1,8 @@ +--TEST-- +Bug #81645 (header() allows arbitrary status codes) integer overflow +--FILE-- + +--EXPECTF-- +Warning: Cannot set HTTP status line - status code is malformed in %s on line %d diff --git a/main/SAPI.c b/main/SAPI.c index d1bd3134b6dee..e11361dddb56c 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -549,17 +549,26 @@ SAPI_API void sapi_initialize_empty_request(void) static int sapi_extract_response_code(const char *header_line) { - int code = 200; + zend_ulong code = 200; const char *ptr; for (ptr = header_line; *ptr; ptr++) { if (*ptr == ' ' && *(ptr + 1) != ' ') { - code = atoi(ptr + 1); + const char *code_begin = ptr + 1; + char *code_end; + + code = ZEND_STRTOUL(code_begin, &code_end, 10); + + /* rfc7230 3.1.2 status-code = 3DIGIT */ + if (code < 100 || code > 599 || (code_end - code_begin) != 3) { + return -1; + } + break; } } - return code; + return (int)code; } @@ -747,7 +756,14 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) if (header_line_len>=5 && !strncasecmp(header_line, "HTTP/", 5)) { /* filter out the response code */ - sapi_update_response_code(sapi_extract_response_code(header_line)); + int status_code = sapi_extract_response_code(header_line); + if (status_code < 0) { + sapi_module.sapi_error(E_WARNING, "Cannot set HTTP status line - " + "status code is malformed"); + efree(header_line); + return FAILURE; + } + sapi_update_response_code(status_code); /* sapi_update_response_code doesn't free the status line if the code didn't change */ if (SG(sapi_headers).http_status_line) { efree(SG(sapi_headers).http_status_line);