Skip to content

Commit 0ad928e

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) (cherry picked from commit f8756a7) (cherry picked from commit c8a7aed)
1 parent 8dab7d0 commit 0ad928e

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

ext/ldap/ldap.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060

6161
#include "ext/standard/php_string.h"
6262
#include "ext/standard/info.h"
63+
#include "Zend/zend_exceptions.h"
6364

6465
#ifdef HAVE_LDAP_SASL_H
6566
#include <sasl.h>
@@ -2728,7 +2729,11 @@ static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value,
27282729
zend_string *ret;
27292730

27302731
for (i = 0; i < valuelen; i++) {
2731-
len += (map[(unsigned char) value[i]]) ? 3 : 1;
2732+
size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
2733+
if (len > ZSTR_MAX_LEN - addend) {
2734+
return NULL;
2735+
}
2736+
len += addend;
27322737
}
27332738

27342739
ret = zend_string_alloc(len, 0);
@@ -2794,7 +2799,13 @@ PHP_FUNCTION(ldap_escape)
27942799
php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
27952800
}
27962801

2797-
RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen));
2802+
zend_string *result = php_ldap_do_escape(map, value, valuelen);
2803+
if (UNEXPECTED(!result)) {
2804+
zend_throw_exception(NULL, "Argument #1 ($value) is too long", 0);
2805+
return;
2806+
}
2807+
2808+
RETURN_NEW_STR(result);
27982809
}
27992810

28002811
#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)