Skip to content

Commit fba659a

Browse files
nielsdosbukka
authored andcommitted
Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape
1 parent d7fe408 commit fba659a

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
@@ -3701,13 +3701,23 @@ static zend_string* php_ldap_do_escape(const bool *map, const char *value, size_
37013701
zend_string *ret;
37023702

37033703
for (i = 0; i < valuelen; i++) {
3704-
len += (map[(unsigned char) value[i]]) ? 3 : 1;
3704+
size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
3705+
if (len > ZSTR_MAX_LEN - addend) {
3706+
return NULL;
3707+
}
3708+
len += addend;
37053709
}
37063710
/* Per RFC 4514, a leading and trailing space must be escaped */
37073711
if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
3712+
if (len > ZSTR_MAX_LEN - 2) {
3713+
return NULL;
3714+
}
37083715
len += 2;
37093716
}
37103717
if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
3718+
if (len > ZSTR_MAX_LEN - 2) {
3719+
return NULL;
3720+
}
37113721
len += 2;
37123722
}
37133723

@@ -3774,7 +3784,13 @@ PHP_FUNCTION(ldap_escape)
37743784
php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
37753785
}
37763786

3777-
RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
3787+
zend_string *result = php_ldap_do_escape(map, value, valuelen, flags);
3788+
if (UNEXPECTED(!result)) {
3789+
zend_argument_value_error(1, "is too long");
3790+
RETURN_THROWS();
3791+
}
3792+
3793+
RETURN_NEW_STR(result);
37783794
}
37793795

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