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

Ilia Alshanetsky <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-07-16T22:14:33-04:00

Commit: https://github.com/php/php-src/commit/47355da494ba696b1bdb6d10448a225e742bd316
Raw diff: https://github.com/php/php-src/commit/47355da494ba696b1bdb6d10448a225e742bd316.diff

Merge branch 'PHP-8.5'

* PHP-8.5:
  ext/standard: fix out-of-bounds access in the ftp:// directory stream

Changed paths:
  A  ext/standard/tests/streams/ftp_dirstream_oob.phpt
  M  ext/ftp/tests/server.inc
  M  ext/standard/ftp_fopen_wrapper.c
  M  ext/standard/tests/streams/opendir-002.phpt
  M  ext/standard/tests/streams/opendir-004.phpt


Diff:

diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc
index 251536ff8202..2c7a3a8a5643 100644
--- a/ext/ftp/tests/server.inc
+++ b/ext/ftp/tests/server.inc
@@ -290,7 +290,7 @@ if ($pid) {
             }
 
             if (empty($m[1]) || $m[1] !== 'emptydir') {
-                fputs($fs, "file1\r\nfile1\r\nfile\nb0rk\r\n");
+                fputs($fs, $nlst_data ?? "file1\r\nfile1\r\nfile\nb0rk\r\n");
             }
 
             fputs($s, "226 Closing data Connection.\r\n");
diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c
index dfe905a8c220..2597269bad41 100644
--- a/ext/standard/ftp_fopen_wrapper.c
+++ b/ext/standard/ftp_fopen_wrapper.c
@@ -638,9 +638,9 @@ static ssize_t php_ftp_dirstream_read(php_stream *stream, char *buf, size_t coun
 
 	basename = php_basename(ent->d_name, tmp_len, NULL, 0);
 
-	tmp_len = MIN(sizeof(ent->d_name), ZSTR_LEN(basename) - 1);
+	tmp_len = MIN(sizeof(ent->d_name) - 1, ZSTR_LEN(basename));
 	memcpy(ent->d_name, ZSTR_VAL(basename), tmp_len);
-	ent->d_name[tmp_len - 1] = '\0';
+	ent->d_name[tmp_len] = '\0';
 	zend_string_release_ex(basename, 0);
 	ent->d_type = DT_UNKNOWN;
 
diff --git a/ext/standard/tests/streams/ftp_dirstream_oob.phpt b/ext/standard/tests/streams/ftp_dirstream_oob.phpt
new file mode 100644
index 000000000000..9e184f3c8ac6
--- /dev/null
+++ b/ext/standard/tests/streams/ftp_dirstream_oob.phpt
@@ -0,0 +1,33 @@
+--TEST--
+opendir() with 'ftp://' stream must not go out of bounds on an empty or slash-only listing line
+--SKIPIF--
+<?php
+if (array_search('ftp',stream_get_wrappers()) === FALSE) die("skip ftp wrapper not available.");
+if (!function_exists('pcntl_fork')) die("skip pcntl_fork() not available.");
+?>
+--FILE--
+<?php
+
+/* An empty line makes php_basename() return "\n" and a slash-only final line
+ * makes it return "", the two lengths the buffer math underflowed on. */
+$nlst_data = "file1\r\n\nb0rk\r\n/";
+
+require __DIR__ . "/../../../ftp/tests/server.inc";
+
+$path="ftp://localhost:" . $port."/";
+
+$ds=opendir($path);
+var_dump($ds);
+
+while (($fn=readdir($ds)) !== false) {
+      var_dump($fn);
+}
+
+closedir($ds);
+?>
+--EXPECTF--
+resource(%d) of type (stream)
+string(5) "file1"
+string(0) ""
+string(4) "b0rk"
+string(0) ""
diff --git a/ext/standard/tests/streams/opendir-002.phpt b/ext/standard/tests/streams/opendir-002.phpt
index 4978c8affa3d..0a5712564e2e 100644
--- a/ext/standard/tests/streams/opendir-002.phpt
+++ b/ext/standard/tests/streams/opendir-002.phpt
@@ -25,5 +25,5 @@ closedir($ds);
 resource(%d) of type (stream)
 string(5) "file1"
 string(5) "file1"
-string(3) "fil"
+string(4) "file"
 string(4) "b0rk"
diff --git a/ext/standard/tests/streams/opendir-004.phpt b/ext/standard/tests/streams/opendir-004.phpt
index 9ccb86b4f4b4..3f076e0d8386 100644
--- a/ext/standard/tests/streams/opendir-004.phpt
+++ b/ext/standard/tests/streams/opendir-004.phpt
@@ -27,5 +27,5 @@ while ($fn=readdir($ds)) {
 resource(%d) of type (stream)
 string(5) "file1"
 string(5) "file1"
-string(3) "fil"
+string(4) "file"
 string(4) "b0rk"
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.