Skip to content

Commit f9ecf90

Browse files
nielsdosbukka
authored andcommitted
Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape
1 parent 426a6d4 commit f9ecf90

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

ext/ldap/ldap.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3885,13 +3885,23 @@ static zend_string* php_ldap_do_escape(const bool *map, const char *value, size_
38853885
zend_string *ret;
38863886

38873887
for (i = 0; i < valuelen; i++) {
3888-
len += (map[(unsigned char) value[i]]) ? 3 : 1;
3888+
size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
3889+
if (len > ZSTR_MAX_LEN - addend) {
3890+
return NULL;
3891+
}
3892+
len += addend;
38893893
}
38903894
/* Per RFC 4514, a leading and trailing space must be escaped */
38913895
if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
3896+
if (len > ZSTR_MAX_LEN - 2) {
3897+
return NULL;
3898+
}
38923899
len += 2;
38933900
}
38943901
if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
3902+
if (len > ZSTR_MAX_LEN - 2) {
3903+
return NULL;
3904+
}
38953905
len += 2;
38963906
}
38973907

@@ -3958,7 +3968,13 @@ PHP_FUNCTION(ldap_escape)
39583968
php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
39593969
}
39603970

3961-
RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
3971+
zend_string *result = php_ldap_do_escape(map, value, valuelen, flags);
3972+
if (UNEXPECTED(!result)) {
3973+
zend_argument_value_error(1, "is too long");
3974+
RETURN_THROWS();
3975+
}
3976+
3977+
RETURN_NEW_STR(result);
39623978
}
39633979

39643980
#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 (ValueError $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
20+
try {
21+
ldap_escape(str_repeat("#", 1431655758).' ', "", LDAP_ESCAPE_DN);
22+
} catch (ValueError $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 (ValueError $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 (ValueError $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)