CVE-2018-7584: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: In PHP through 5.6.33, 7.0.x before 7.0.28, 7.1.x through 7.1.14, and 7.2.x through 7.2.2, there is a stack-based buffer under-read while parsing an HTTP response in the php_stream_url_wrap_http_ex function in ext/standard/http_fopen_wrapper.c. This subsequently results in copying a large string.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 9.8
Published: 2018-03-01T19:29Z
Repository: https://github.com/php/php-src
Language: C
Files changed: ext/standard/http_fopen_wrapper.c, ext/standard/tests/http/bug75981.phpt
Commit date: 2018-02-26 22:25:51 -0800
Commit message: Fix bug #75981: prevent reading beyond buffer start

Diff: diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index ed6adc003988..78bd935a0e2b 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -735,13 +735,13 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
 						}
 						php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE,
 								tmp_line, response_code);
 				}
 			}
-			if (tmp_line[tmp_line_len - 1] == '\n') {
+			if (tmp_line_len >= 1 && tmp_line[tmp_line_len - 1] == '\n') {
 				--tmp_line_len;
-				if (tmp_line[tmp_line_len - 1] == '\r') {
+				if (tmp_line_len >= 1 &&tmp_line[tmp_line_len - 1] == '\r') {
 					--tmp_line_len;
 				}
 			}
 			MAKE_STD_ZVAL(http_response);
 			ZVAL_STRINGL(http_response, tmp_line, tmp_line_len, 1);
diff --git a/ext/standard/tests/http/bug75981.phpt b/ext/standard/tests/http/bug75981.phpt
new file mode 100644
index 000000000000..d415de66b900
--- /dev/null
+++ b/ext/standard/tests/http/bug75981.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #75981 (stack-buffer-overflow while parsing HTTP response)
+--INI--
+allow_url_fopen=1
+--SKIPIF--
+<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
+--FILE--
+<?php
+require 'server.inc';
+
+$options = [
+  'http' => [
+    'protocol_version' => '1.1',
+    'header' => 'Connection: Close'
+  ],
+];
+
+$ctx = stream_context_create($options);
+
+$responses = [
+	"data://text/plain,000000000100\xA\xA"
+];
+$pid = http_server('tcp://127.0.0.1:12342', $responses);
+
+echo @file_get_contents('http://127.0.0.1:12342/', false, $ctx);
+
+http_server_kill($pid);
+
+?>
+DONE
+--EXPECT--
+DONE

Vulnerable code: 			if (tmp_line[tmp_line_len - 1] == '\n') {
				if (tmp_line[tmp_line_len - 1] == '\r') {
Fixed code: 			if (tmp_line_len >= 1 && tmp_line[tmp_line_len - 1] == '\n') {
				if (tmp_line_len >= 1 &&tmp_line[tmp_line_len - 1] == '\r') {
--TEST--
Bug #75981 (stack-buffer-overflow while parsing HTTP response)
--INI--
allow_url_fopen=1
--SKIPIF--
<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
--FILE--
<?php
require 'server.inc';

$options = [
  'http' => [
    'protocol_version' => '1.1',
    'header' => 'Connection: Close'
  ],
];

$ctx = stream_context_create($options);

$responses = [
	"data://text/plain,000000000100\xA\xA"
];
$pid = http_server('tcp://127.0.0.1:12342', $responses);

echo @file_get_contents('http://127.0.0.1:12342/', false, $ctx);

http_server_kill($pid);

?>
DONE
--EXPECT--
DONE