- Fixed SQL injection via E'...' backslash breakout CVE-2026-17543 - Fixed GHSA-vc5h-9ppw-p5f3 Crash via recursive symlinks CVE-2026-7260 Resolves: RHEL-223940
103 lines
3.1 KiB
Diff
103 lines
3.1 KiB
Diff
From 8.2.33, without binary diffs
|
|
|
|
|
|
From 92458605f7f88697973e1183b46296d4c9bf9c46 Mon Sep 17 00:00:00 2001
|
|
From: Jakub Zelenka <bukka@php.net>
|
|
Date: Sun, 3 May 2026 19:26:31 +0200
|
|
Subject: [PATCH 3/5] Fix GHSA-vc5h-9ppw-p5f3: phar circular symlink crash
|
|
|
|
Prevents infinite recursion in phar_get_link_source.
|
|
|
|
(cherry picked from commit 2e0fa0a44441d74bf8cc4e1ce1c8af9cd4209f52)
|
|
(cherry picked from commit c84ffef248fddba29bde47847bd4cd06761e0aab)
|
|
---
|
|
.../tests/tar/files/circular_symlinks.tar | Bin 0 -> 10240 bytes
|
|
.../tar/files/circular_symlinks_long.tar | Bin 0 -> 215040 bytes
|
|
.../tests/tar/files/circular_symlinks_rho.tar | Bin 0 -> 10240 bytes
|
|
.../ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt | 27 ++++++++++
|
|
ext/phar/util.c | 51 ++++++++++++++----
|
|
5 files changed, 67 insertions(+), 11 deletions(-)
|
|
create mode 100644 ext/phar/tests/tar/files/circular_symlinks.tar
|
|
create mode 100644 ext/phar/tests/tar/files/circular_symlinks_long.tar
|
|
create mode 100644 ext/phar/tests/tar/files/circular_symlinks_rho.tar
|
|
create mode 100644 ext/phar/tests/tar/ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt
|
|
|
|
diff --git a/ext/phar/util.c b/ext/phar/util.c
|
|
index 59362bbc72..d49ea9bfc5 100644
|
|
--- a/ext/phar/util.c
|
|
+++ b/ext/phar/util.c
|
|
@@ -57,30 +57,59 @@ static char *phar_get_link_location(phar_entry_info *entry) /* {{{ */
|
|
}
|
|
/* }}} */
|
|
|
|
-phar_entry_info *phar_get_link_source(phar_entry_info *entry) /* {{{ */
|
|
+static phar_entry_info *phar_follow_one_link(phar_entry_info *entry)
|
|
{
|
|
phar_entry_info *link_entry;
|
|
char *link;
|
|
|
|
- if (!entry->link) {
|
|
- return entry;
|
|
- }
|
|
-
|
|
link = phar_get_link_location(entry);
|
|
if (NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), entry->link, strlen(entry->link))) ||
|
|
NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), link, strlen(link)))) {
|
|
if (link != entry->link) {
|
|
efree(link);
|
|
}
|
|
- return phar_get_link_source(link_entry);
|
|
- } else {
|
|
- if (link != entry->link) {
|
|
- efree(link);
|
|
+ return link_entry;
|
|
+ }
|
|
+
|
|
+ if (link != entry->link) {
|
|
+ efree(link);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+phar_entry_info *phar_get_link_source(phar_entry_info *entry)
|
|
+{
|
|
+ phar_entry_info *slow, *fast;
|
|
+
|
|
+ if (!entry->link) {
|
|
+ return entry;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Use Floyd's cycle detection algorithm to follow the symlink chain without unbounded
|
|
+ * recursion. Each entry has at most one outgoing link, so if a cycle exists the fast pointer
|
|
+ * will eventually meet the slow one. Otherwise the fast pointer reaches the end first.
|
|
+ */
|
|
+ slow = fast = entry;
|
|
+ while (1) {
|
|
+ fast = phar_follow_one_link(fast);
|
|
+ if (!fast || !fast->link) {
|
|
+ return fast;
|
|
+ }
|
|
+ fast = phar_follow_one_link(fast);
|
|
+ if (!fast || !fast->link) {
|
|
+ return fast;
|
|
+ }
|
|
+
|
|
+ /* no need to check slow as it's always behind */
|
|
+ slow = phar_follow_one_link(slow);
|
|
+
|
|
+ if (slow == fast) {
|
|
+ /* circular symlink chain */
|
|
+ return NULL;
|
|
}
|
|
- return NULL;
|
|
}
|
|
}
|
|
-/* }}} */
|
|
|
|
/* retrieve a phar_entry_info's current file pointer for reading contents */
|
|
php_stream *phar_get_efp(phar_entry_info *entry, int follow_links) /* {{{ */
|
|
--
|
|
2.55.0
|
|
|