PHP :: Sec Bug #72533 :: locale_accept_from_http out-of-bounds access
| Sec Bug #72533 | locale_accept_from_http out-of-bounds access | ||||
|---|---|---|---|---|---|
| Submitted: | 2016-07-03 04:03 UTC | Modified: | 2016-07-25 15:19 UTC | ||
| From: | fernando at null-life dot com | Assigned: | stas (profile) | ||
| Status: | Closed | Package: | intl (PECL) | ||
| PHP Version: | 7.0.8 | OS: | * | ||
| Private report: | No | CVE-ID: | 2016-6294 | ||
[2016-07-03 04:03 UTC] fernando at null-life dot com
Description: ------------ Calling to uloc_acceptLanguageFromHTTP with parameter size "httpAcceptLanguage" equal or greater than ULOC_FULLNAME_CAPACITY + 1, the local variable "tmp" might leave unterminated. uloc_acceptLanguageFromHTTP doesn’t check status result after call to uloc_canonicalize. This might cause stack data leak. This bug is inside libicu but it can be mitigated from PHP checking the user input length (HTTP Accept-Language Header), similar to bug67397-patch https://bugs.php.net/patch-display.php?bug_id=67397&patch=bug67397-patch&revision=latest if (http_accept_len > ULOC_FULLNAME_CAPACITY) { //return an error or maybe truncate the input } Since locale_accept_from_http is supposed to accept external user input we believe this should be treated as a security issue. Source code https://github.com/php/php-src/blob/master/ext/intl/locale/locale_methods.c#L1585 PHP_FUNCTION(locale_accept_from_http) { UEnumeration *available; char *http_accept = NULL; size_t http_accept_len; UErrorCode status = 0; int len; char resultLocale[INTL_MAX_LOCALE_LEN+1]; UAcceptResult outResult; if(zend_parse_parameters( ZEND_NUM_ARGS(), "s", &http_accept, &http_accept_len) == FAILURE) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "locale_accept_from_http: unable to parse input parameters", 0 ); RETURN_FALSE; } available = ures_openAvailableLocales(NULL, &status); INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list"); len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, &outResult, http_accept, available, &status); uenum_close(available); INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to find acceptable locale"); if (len < 0 || outResult == ULOC_ACCEPT_FAILED) { RETURN_FALSE; } RETURN_STRINGL(resultLocale, len); } Test script: --------------- <?php $var1=str_repeat("a", 200); locale_accept_from_http($var1); Expected result: ---------------- No crash Actual result: -------------- LD_LIBRARY_PATH=/usr/local/icu-57-gcc-asan/lib USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 /ram/php-fuzz/phuzzer/php-70/sapi/cli/php -n -dextension=/ram/php-fuzz/phuzzer/php-70/modules/intl.so phuzzer2.php ================================================================= ==4186==ERROR: AddressSanitizer: stack-buffer-overflow on address 0xffa09b6e at pc 0xf72198a1 bp 0xffa097d8 sp 0xffa093ac READ of size 159 at 0xffa09b6e thread T0 #0 0xf72198a0 (/usr/lib/i386-linux-gnu/libasan.so.2+0x408a0) #1 0xf08d0089 in uloc_acceptLanguageFromHTTP /home/user/icu-release-57-1/source/common/uloc.cpp:2353 #2 0xf119a433 in zif_locale_accept_from_http /home/user/php/php-70-asan/ext/intl/locale/locale_methods.c:1604 #3 0x9a388ac in ZEND_DO_ICALL_SPEC_HANDLER /home/user/php/php-70-asan/Zend/zend_vm_execute.h:586 #4 0x980d06f in execute_ex /home/user/php/php-70-asan/Zend/zend_vm_execute.h:414 #5 0x9b287c5 in zend_execute /home/user/php/php-70-asan/Zend/zend_vm_execute.h:458 #6 0x95e4c3c in zend_execute_scripts /home/user/php/php-70-asan/Zend/zend.c:1427 #7 0x932d58b in php_execute_script /home/user/php/php-70-asan/main/main.c:2494 #8 0x9b31004 in do_cli /home/user/php/php-70-asan/sapi/cli/php_cli.c:974 #9 0x80a6e78 in main /home/user/php/php-70-asan/sapi/cli/php_cli.c:1344 #10 0xf6c70636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636) #11 0x80a755a (/ram/php-fuzz/phuzzer/php-70-asan/sapi/cli/php+0x80a755a) Address 0xffa09b6e is located in stack of thread T0 at offset 798 in frame #0 0xf08cf9f7 in uloc_acceptLanguageFromHTTP /home/user/icu-release-57-1/source/common/uloc.cpp:2290 This frame has 5 object(s): [32, 36) 'myEnd' [96, 456) 'smallBuffer' [512, 517) 'rep' [576, 606) 'buf' [640, 798) 'tmp' <== Memory access at offset 798 overflows this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 ??
Patches
Pull Requests
History
AllCommentsChangesGit/SVN commits
[2016-07-13 05:39 UTC] stas@php.net
-Assigned To: +Assigned To: stas
[2016-07-19 07:47 UTC] stas@php.net
-Status: Assigned +Status: Closed
[2016-07-25 15:19 UTC] remi@php.net
-CVE-ID: +CVE-ID: 2016-6294