Fix Heap buffer overflow in array_merge() CVE-2025-14178 Fix Information Leak of Memory in getimagesize CVE-2025-14177 Resolves: RHEL-141193
104 lines
3.1 KiB
Diff
104 lines
3.1 KiB
Diff
From ed665eb1903737d2b52b27368b155f6208604ed9 Mon Sep 17 00:00:00 2001
|
|
From: Niels Dossche <7771979+ndossche@users.noreply.github.com>
|
|
Date: Tue, 25 Nov 2025 23:11:38 +0100
|
|
Subject: [PATCH 1/5] Fix GH-20584: Information Leak of Memory
|
|
|
|
The string added had uninitialized memory due to
|
|
php_read_stream_all_chunks() not moving the buffer position, resulting
|
|
in the same data always being overwritten instead of new data being
|
|
added to the end of the buffer.
|
|
|
|
This is backport as there is a security impact as described in
|
|
GHSA-3237-qqm7-mfv7 .
|
|
|
|
(cherry picked from commit c5f28c7cf0a052f48e47877c7aa5c5bcc54f1cfc)
|
|
---
|
|
ext/standard/image.c | 17 +++++++++++-
|
|
ext/standard/tests/image/gh20584.phpt | 39 +++++++++++++++++++++++++++
|
|
2 files changed, 55 insertions(+), 1 deletion(-)
|
|
create mode 100644 ext/standard/tests/image/gh20584.phpt
|
|
|
|
diff --git a/ext/standard/image.c b/ext/standard/image.c
|
|
index 419522c6a2e..69f18d100f5 100644
|
|
--- a/ext/standard/image.c
|
|
+++ b/ext/standard/image.c
|
|
@@ -424,6 +424,21 @@ static int php_skip_variable(php_stream * stream)
|
|
}
|
|
/* }}} */
|
|
|
|
+static size_t php_read_stream_all_chunks(php_stream *stream, char *buffer, size_t length)
|
|
+{
|
|
+ size_t read_total = 0;
|
|
+ do {
|
|
+ ssize_t read_now = php_stream_read(stream, buffer, length - read_total);
|
|
+ read_total += read_now;
|
|
+ if (read_now < stream->chunk_size && read_total != length) {
|
|
+ return 0;
|
|
+ }
|
|
+ buffer += read_now;
|
|
+ } while (read_total < length);
|
|
+
|
|
+ return read_total;
|
|
+}
|
|
+
|
|
/* {{{ php_read_APP */
|
|
static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
|
|
{
|
|
@@ -440,7 +455,7 @@ static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
|
|
|
|
buffer = emalloc(length);
|
|
|
|
- if (php_stream_read(stream, buffer, (size_t) length) != length) {
|
|
+ if (php_read_stream_all_chunks(stream, buffer, length) != length) {
|
|
efree(buffer);
|
|
return 0;
|
|
}
|
|
diff --git a/ext/standard/tests/image/gh20584.phpt b/ext/standard/tests/image/gh20584.phpt
|
|
new file mode 100644
|
|
index 00000000000..d117f218202
|
|
--- /dev/null
|
|
+++ b/ext/standard/tests/image/gh20584.phpt
|
|
@@ -0,0 +1,39 @@
|
|
+--TEST--
|
|
+GH-20584 (Information Leak of Memory)
|
|
+--CREDITS--
|
|
+Nikita Sveshnikov (Positive Technologies)
|
|
+--FILE--
|
|
+<?php
|
|
+// Minimal PoC: corruption/uninitialized memory leak when reading APP1 via php://filter
|
|
+$file = __DIR__ . '/gh20584.jpg';
|
|
+
|
|
+// Make APP1 large enough so it is read in multiple chunks
|
|
+$chunk = 8192;
|
|
+$tail = 123;
|
|
+$payload = str_repeat('A', $chunk) . str_repeat('B', $chunk) . str_repeat('Z',
|
|
+$tail);
|
|
+$app1Len = 2 + strlen($payload);
|
|
+
|
|
+// Minimal JPEG: SOI + APP1 + SOF0(1x1) + EOI
|
|
+$sof = "\xFF\xC0" . pack('n', 11) . "\x08" . pack('n',1) . pack('n',1) .
|
|
+"\x01\x11\x00";
|
|
+$jpeg = "\xFF\xD8" . "\xFF\xE1" . pack('n', $app1Len) . $payload . $sof .
|
|
+"\xFF\xD9";
|
|
+file_put_contents($file, $jpeg);
|
|
+
|
|
+// Read through a filter to enforce multiple reads
|
|
+$src = 'php://filter/read=string.rot13|string.rot13/resource=' . $file;
|
|
+$info = null;
|
|
+@getimagesize($src, $info);
|
|
+$exp = $payload;
|
|
+$ret = $info['APP1'];
|
|
+
|
|
+var_dump($ret === $exp);
|
|
+
|
|
+?>
|
|
+--CLEAN--
|
|
+<?php
|
|
+@unlink(__DIR__ . '/gh20584.jpg');
|
|
+?>
|
|
+--EXPECT--
|
|
+bool(true)
|
|
--
|
|
2.52.0
|
|
|