php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #39751 putenv causes string copy of freed memory region, causing crash
Submitted: 2006-12-06 04:46 UTC Modified: 2006-12-10 01:51 UTC
From: KevinJohnHoffman at gmail dot com Assigned: edink (profile)
Status: Closed Package: Reproducible crash
PHP Version: 5.2.0 OS: Win32
Private report: No CVE-ID: None
 [2006-12-06 04:46 UTC] KevinJohnHoffman at gmail dot com
Description:
------------
If putenv deletes an environment variable (putenv("VAR="))
after it was set previously (putenv("VAR=xxx")) then pe->previous_entry (pe is the internal hash table entry for the environment variable) will point to a freed memory region.

This bug is triggered on windows because pe->previous_entry is set to point directly to the environment string (environ[...]) instead of a *copy* of the string. The MSVCRT library will free that string when an environment variable is deleted. Thus, pe->previous_entry can point to a free memory region when used later.

The patch is extremely simple... pe->previous_entry should point to a copy of the string from the environment.

putenv is used in the above pattern by the PEAR Date\TimeZone.php file in the inDaylightTime function. 

However, this bug affects any code that follows the above pattern. It can also be used as an attack vector to cause a denial of service attack on Apache/PHP servers running on windows.

This is probably the same bug as #36819. A patch will be submitted shortly.

Reproduce code:
---------------
putenv("VAR=something");
putenv("VAR=");
//The previous_value field of the hashtable entry (pe)
//for "VAR" now points to freed memory.
//Lot's of other code here that reuses this memory block
//(overwriting it with binary data) and then frees it
//will cause problems.

//Either the script exiting or doing putenv("VAR=something")
//will cause the deconstructor on the hash table entry
//to be called (php_putenv_destructor)

//The deconstructor will call putenv using pe->previous_value
//The MSVCRT putenv function will call strlen on the arg.
//If the freed memory at pe->previous_value now points to a
//data page that is no longer valid the program will crash.

Details will be submitted along with the patch. It's hard to write a script that executes once that will cause it to crash. 

Expected result:
----------------
The code should run without crashing and without accessing freed memory.

Actual result:
--------------
PHP or Apache crashes. This is usually a lot easier to reproduce if running in Apache via the handler and the page is executed several times.

minidumps are available upon request.

01f3df1c 1023baad MSVCR70D!strlen+0x30
01f3df50 00c5fcd1 MSVCR70D!putenv+0x3d
01f3e028 00a6863a php5ts_debug!php_putenv_destructor(struct putenv_entry * pe = 0x0311bf80)+0x51 [c:\dev\sdk\php5.2-dev\source\ext\standard\basic_functions.c @ 3835]
01f3e11c 00c60eef php5ts_debug!zend_hash_del_key_or_index(struct _hashtable * ht = 0x01d01fb4, char * arKey = 0x031033c0 "", unsigned int nKeyLength = 3, unsigned long h = 0xb8823d3, int flag = 0)+0x19a [c:\dev\sdk\php5.2-dev\source\zend\zend_hash.c @ 492]
01f3e27c 009d2198 php5ts_debug!zif_putenv(int ht = 1, struct _zval_struct * return_value = 0x03103af0, struct _zval_struct ** return_value_ptr = 0x00000000, struct _zval_struct * this_ptr = 0x00000000, int return_value_used = 0, void *** tsrm_ls = 0x01ca5890)+0x40f [c:\dev\sdk\php5.2-dev\source\ext\standard\basic_functions.c @ 4423]
01f3e40c 009dba2f php5ts_debug!zend_do_fcall_common_helper_SPEC(struct _zend_execute_data * execute_data = 0x01f3e5e0, void *** tsrm_ls = 0x01ca5890)+0x458 [c:\dev\sdk\php5.2-dev\source\zend\zend_vm_execute.h @ 200]
01f3e500 009d1a6d php5ts_debug!ZEND_DO_FCALL_SPEC_CONST_HANDLER(struct _zend_execute_data * execute_data = 0x01f3e5e0, void *** tsrm_ls = 0x01ca5890)+0xbf [c:\dev\sdk\php5.2-dev\source\zend\zend_vm_execute.h @ 1681]
...
01f3f7bc 0099db9f php5ts_debug!execute(struct _zend_op_array * op_array = 0x02cc4098, void *** tsrm_ls = 0x01ca5890)+0x2dd [c:\dev\sdk\php5.2-dev\source\zend\zend_vm_execute.h @ 92]
01f3f9a8 00aaf3f7 php5ts_debug!zend_execute_scripts(int type = 8, void *** tsrm_ls = 0x01ca5890, struct _zval_struct ** retval = 0x00000000, int file_count = 3, struct _zval_struct ** orig_retval_ptr_ptr = 0x00000000)+0x19f [c:\dev\sdk\php5.2-dev\source\zend\zend.c @ 1098]
01f3fc9c 007b6c10 php5ts_debug!php_execute_script(struct _zend_file_handle * primary_file = 0x01f3fddc, void *** tsrm_ls = 0x01ca5890)+0x367 [c:\dev\sdk\php5.2-dev\source\main\main.c @ 1781]
01f3fecc 6ff0263e php5apache2_2!php_handler(struct request_rec * r = 0x01204058)+0x610 [c:\dev\sdk\php5.2-dev\source\sapi\apache2handler\sapi_apache2.c @ 604]
01f3fee4 6ff02b1e libhttpd!ap_run_handler+0x4e
...

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-12-06 05:25 UTC] KevinJohnHoffman at gmail dot com
Patch has now been submitted to internals@lists.php.net.
 [2006-12-06 11:58 UTC] tony2001@php.net
Edin, could you please check this out?
 [2006-12-10 01:27 UTC] edink@php.net
Patch applied, thanks!
 [2006-12-10 01:50 UTC] KevinJohnHoffman at gmail dot com
This bug does not necessarily exist on other platforms because of their implementation of putenv may not manage the memory of the individual strings in the environment (only the memory for the array of environment strings).

For example:
http://src.opensolaris.org/source/xref/loficc/crypto/usr/src/lib/libbc/libc/gen/common/putenv.c

This implementation does not free the memory for the old value of the environment variable. Hence this bug would not affect the OpenSolaris platform. I have not investigated other platform's implementation of putenv, but my guess is that they are similiar to the OpenSolaris implementation.

Hence, that is why in my patch I used #ifdefs so that it would only use the new behavior in Windows.
 [2006-12-10 01:51 UTC] KevinJohnHoffman at gmail dot com
Thanks!
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC