summaryrefslogtreecommitdiffstats
path: root/php-cve-2024-8932.patch
blob: 44b863a8c417ba2126abc35b8739d3ded553be6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
From 9822bfae85607dffc13848d40a2340daf090f39b Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Thu, 26 Sep 2024 22:22:27 +0200
Subject: [PATCH 5/8] Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape

(cherry picked from commit f9ecf90070a11dad09ca7671a712f81cc2a7d52f)
(cherry picked from commit 9f367d847989b339c33369737daf573e30bab5f1)
(cherry picked from commit 50e9e72530a4805980384b8ea6672877af816145)
---
 ext/ldap/ldap.c                           | 21 ++++++++++++++--
 ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt | 28 ++++++++++++++++++++++
 ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt | 29 +++++++++++++++++++++++
 3 files changed, 76 insertions(+), 2 deletions(-)
 create mode 100644 ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
 create mode 100644 ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt

diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c
index d5a90b879e..748b0a6ff5 100644
--- a/ext/ldap/ldap.c
+++ b/ext/ldap/ldap.c
@@ -54,6 +54,7 @@
 
 #include "ext/standard/php_string.h"
 #include "ext/standard/info.h"
+#include "Zend/zend_exceptions.h"
 
 #ifdef HAVE_LDAP_SASL_H
 #include <sasl.h>
@@ -3868,13 +3869,23 @@ static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value,
 	zend_string *ret;
 
 	for (i = 0; i < valuelen; i++) {
-		len += (map[(unsigned char) value[i]]) ? 3 : 1;
+		size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
+		if (len > ZSTR_MAX_LEN - addend) {
+			return NULL;
+		}
+		len += addend;
 	}
 	/* Per RFC 4514, a leading and trailing space must be escaped */
 	if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
+		if (len > ZSTR_MAX_LEN - 2) {
+			return NULL;
+		}
 		len += 2;
 	}
 	if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
+		if (len > ZSTR_MAX_LEN - 2) {
+			return NULL;
+		}
 		len += 2;
 	}
 
@@ -3941,7 +3952,13 @@ PHP_FUNCTION(ldap_escape)
 		php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
 	}
 
-	RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
+	zend_string *result = php_ldap_do_escape(map, value, valuelen, flags);
+	if (UNEXPECTED(!result)) {
+		zend_throw_exception(NULL, "Argument #1 ($value) is too long", 0);
+		return;
+	}
+
+	RETURN_NEW_STR(result);
 }
 
 #ifdef STR_TRANSLATION
diff --git a/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt b/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
new file mode 100644
index 0000000000..734bbe91d4
--- /dev/null
+++ b/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
@@ -0,0 +1,28 @@
+--TEST--
+GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
+--EXTENSIONS--
+ldap
+--INI--
+memory_limit=-1
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
+if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
+?>
+--FILE--
+<?php
+try {
+    ldap_escape(' '.str_repeat("#", 1431655758), "", LDAP_ESCAPE_DN);
+} catch (Exception $e) {
+    echo $e->getMessage(), "\n";
+}
+
+try {
+    ldap_escape(str_repeat("#", 1431655758).' ', "", LDAP_ESCAPE_DN);
+} catch (Exception $e) {
+    echo $e->getMessage(), "\n";
+}
+?>
+--EXPECT--
+ldap_escape(): Argument #1 ($value) is too long
+ldap_escape(): Argument #1 ($value) is too long
diff --git a/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt b/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
new file mode 100644
index 0000000000..5c1b0fb661
--- /dev/null
+++ b/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
@@ -0,0 +1,29 @@
+--TEST--
+GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
+--EXTENSIONS--
+ldap
+--INI--
+memory_limit=-1
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
+if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
+?>
+--FILE--
+<?php
+try {
+    ldap_escape(str_repeat("*", 1431655759), "", LDAP_ESCAPE_FILTER);
+} catch (Exception $e) {
+    echo $e->getMessage(), "\n";
+}
+
+// would allocate a string of length 2
+try {
+    ldap_escape(str_repeat("*", 1431655766), "", LDAP_ESCAPE_FILTER);
+} catch (Exception $e) {
+    echo $e->getMessage(), "\n";
+}
+?>
+--EXPECT--
+ldap_escape(): Argument #1 ($value) is too long
+ldap_escape(): Argument #1 ($value) is too long
-- 
2.47.0