From 50e9e72530a4805980384b8ea6672877af816145 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 4/7] Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape (cherry picked from commit f9ecf90070a11dad09ca7671a712f81cc2a7d52f) (cherry picked from commit 9f367d847989b339c33369737daf573e30bab5f1) --- 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 72a39bd93df..75adf1b5df2 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -49,6 +49,7 @@ #include "ext/standard/php_string.h" #include "ext/standard/info.h" +#include "Zend/zend_exceptions.h" #ifdef HAVE_LDAP_SASL #include @@ -3836,13 +3837,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; } @@ -3909,7 +3920,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 00000000000..734bbe91d42 --- /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-- + +--FILE-- +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 00000000000..5c1b0fb6611 --- /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-- + +--FILE-- +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