Skip to content

Commit f8756a7

Browse files
nielsdosremicollet
authored andcommitted
Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape
(cherry picked from commit f9ecf90070a11dad09ca7671a712f81cc2a7d52f) (cherry picked from commit 9f367d8) (cherry picked from commit 50e9e72) (cherry picked from commit 9822bfa)
1 parent 1178705 commit f8756a7

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

ext/ldap/ldap.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
#include "ext/standard/php_string.h"
5656
#include "ext/standard/info.h"
57+
#include "Zend/zend_exceptions.h"
5758

5859
#ifdef HAVE_LDAP_SASL_H
5960
#include <sasl.h>
@@ -3005,13 +3006,23 @@ static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value,
30053006
zend_string *ret;
30063007

30073008
for (i = 0; i < valuelen; i++) {
3008-
len += (map[(unsigned char) value[i]]) ? 3 : 1;
3009+
size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
3010+
if (len > ZSTR_MAX_LEN - addend) {
3011+
return NULL;
3012+
}
3013+
len += addend;
30093014
}
30103015
/* Per RFC 4514, a leading and trailing space must be escaped */
30113016
if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
3017+
if (len > ZSTR_MAX_LEN - 2) {
3018+
return NULL;
3019+
}
30123020
len += 2;
30133021
}
30143022
if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
3023+
if (len > ZSTR_MAX_LEN - 2) {
3024+
return NULL;
3025+
}
30153026
len += 2;
30163027
}
30173028

@@ -3078,7 +3089,13 @@ PHP_FUNCTION(ldap_escape)
30783089
php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
30793090
}
30803091

3081-
RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
3092+
zend_string *result = php_ldap_do_escape(map, value, valuelen, flags);
3093+
if (UNEXPECTED(!result)) {
3094+
zend_throw_exception(NULL, "Argument #1 ($value) is too long", 0);
3095+
return;
3096+
}
3097+
3098+
RETURN_NEW_STR(result);
30823099
}
30833100

30843101
#ifdef STR_TRANSLATION
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
3+
--EXTENSIONS--
4+
ldap
5+
--INI--
6+
memory_limit=-1
7+
--SKIPIF--
8+
<?php
9+
if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
10+
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
11+
?>
12+
--FILE--
13+
<?php
14+
try {
15+
ldap_escape(' '.str_repeat("#", 1431655758), "", LDAP_ESCAPE_DN);
16+
} catch (Exception $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
20+
try {
21+
ldap_escape(str_repeat("#", 1431655758).' ', "", LDAP_ESCAPE_DN);
22+
} catch (Exception $e) {
23+
echo $e->getMessage(), "\n";
24+
}
25+
?>
26+
--EXPECT--
27+
ldap_escape(): Argument #1 ($value) is too long
28+
ldap_escape(): Argument #1 ($value) is too long
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
3+
--EXTENSIONS--
4+
ldap
5+
--INI--
6+
memory_limit=-1
7+
--SKIPIF--
8+
<?php
9+
if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
10+
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
11+
?>
12+
--FILE--
13+
<?php
14+
try {
15+
ldap_escape(str_repeat("*", 1431655759), "", LDAP_ESCAPE_FILTER);
16+
} catch (Exception $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
20+
// would allocate a string of length 2
21+
try {
22+
ldap_escape(str_repeat("*", 1431655766), "", LDAP_ESCAPE_FILTER);
23+
} catch (Exception $e) {
24+
echo $e->getMessage(), "\n";
25+
}
26+
?>
27+
--EXPECT--
28+
ldap_escape(): Argument #1 ($value) is too long
29+
ldap_escape(): Argument #1 ($value) is too long

0 commit comments

Comments
 (0)