[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

Ilia Alshanetsky <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-08-27T08:31:46-04:00

Commit: https://github.com/php/php-src/commit/9d5a6159e9d26746e09b7f8f546f128ad1d63032
Raw diff: https://github.com/php/php-src/commit/9d5a6159e9d26746e09b7f8f546f128ad1d63032.diff

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  [http] Fix out-of-bounds read on empty Location header

Changed paths:
  A  ext/standard/tests/http/http_empty_location_redirect.phpt
  M  NEWS
  M  ext/standard/http_fopen_wrapper.c


Diff:

diff --git a/NEWS b/NEWS
index 466321cf1029..074990dc4d57 100644
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,10 @@ PHP                                                                        NEWS
   . Fixed the interactive shell not waiting for the pager process to exit.
     (Weilin Du)
 
+- Standard:
+  . Fixed an out-of-bounds read when following a redirect response with an
+    empty Location header. (iliaal)
+
 - Zip:
   . Fixed bug GH-17787 (ZipArchive stream stops reading early when the archive
     is freed while the stream is still open). (Eyüp Can Akman)
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index 22700cf904f1..6cd3ce031e44 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -1053,7 +1053,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
 
 			char *new_path = NULL;
 
-			if (strlen(header_info.location) < 8 ||
+			if (header_info.location_len < 8 ||
 					(strncasecmp(header_info.location, "http://", sizeof("http://")-1) &&
 							strncasecmp(header_info.location, "https://", sizeof("https://")-1) &&
 							strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) &&
@@ -1061,7 +1061,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
 			{
 				char *loc_path = NULL;
 				if (*header_info.location != '/') {
-					if (*(header_info.location+1) != '\0' && resource->path) {
+					if (header_info.location_len > 0 && resource->path) {
 						char *s = strrchr(ZSTR_VAL(resource->path), '/');
 						if (!s) {
 							s = ZSTR_VAL(resource->path);
diff --git a/ext/standard/tests/http/http_empty_location_redirect.phpt b/ext/standard/tests/http/http_empty_location_redirect.phpt
new file mode 100644
index 000000000000..a7f99bf1e249
--- /dev/null
+++ b/ext/standard/tests/http/http_empty_location_redirect.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Empty Location header must not over-read when building the redirect target
+--FILE--
+<?php
+$serverCode = <<<'CODE'
+$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
+phpt_notify_server_start($server);
+
+for ($n = 0; $n < 4; $n++) {
+    $conn = stream_socket_accept($server, 10);
+    if (!$conn) {
+        break;
+    }
+    $req = fgets($conn);
+    while (trim(fgets($conn)) !== '') {}
+    $uri = explode(' ', $req)[1];
+    if ($n < 3) {
+        fwrite($conn, "HTTP/1.1 302 Found\r\nLocation:\r\nContent-Length: 0\r\n\r\n");
+    } else {
+        $body = "uri=$uri";
+        fwrite($conn, "HTTP/1.1 200 OK\r\nContent-Length: " . strlen($body) . "\r\n\r\n$body");
+    }
+    fclose($conn);
+}
+CODE;
+
+$clientCode = <<<'CODE'
+$ctx = stream_context_create(['http' => ['follow_location' => 1]]);
+echo @file_get_contents("http://{{ ADDR }}/a/b", false, $ctx), "\n";
+CODE;
+
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+?>
+--EXPECT--
+uri=/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.