--- ext/standard/array.c 2004-12-23 17:40:03.000000000 +0100 +++ ext/standard/array.c 2005-10-31 23:26:23.000000000 +0100 @@ -22,7 +22,7 @@ */ -/* $Id: array.c,v 1.199.2.42 2004/12/23 16:40:03 tony2001 Exp $ */ +/* $Id: array.c,v 1.199.2.44.2.9 2005/10/03 14:05:07 iliaa Exp $ */ #include "php.h" #include "php_ini.h" @@ -631,7 +640,7 @@ s = *((Bucket **) b); if (f->nKeyLength) { - Z_STRVAL(key1) = estrndup(f->arKey, f->nKeyLength); + Z_STRVAL(key1) = estrndup(f->arKey, f->nKeyLength-1); Z_STRLEN(key1) = f->nKeyLength-1; Z_TYPE(key1) = IS_STRING; } else { @@ -639,7 +648,7 @@ Z_TYPE(key1) = IS_LONG; } if (s->nKeyLength) { - Z_STRVAL(key2) = estrndup(s->arKey, s->nKeyLength); + Z_STRVAL(key2) = estrndup(s->arKey, s->nKeyLength-1); Z_STRLEN(key2) = s->nKeyLength-1; Z_TYPE(key2) = IS_STRING; } else { @@ -1243,6 +1252,10 @@ /* break omitted intentionally */ case EXTR_OVERWRITE: + /* GLOBALS protection */ + if (var_exists && !strcmp(var_name, "GLOBALS")) { + break; + } smart_str_appendl(&final_name, var_name, var_name_len); break; @@ -1291,14 +1304,18 @@ zval **orig_var; if (zend_hash_find(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) &orig_var) == SUCCESS) { - zval_ptr_dtor(orig_var); - SEPARATE_ZVAL_TO_MAKE_IS_REF(entry); zval_add_ref(entry); + zval_ptr_dtor(orig_var); + *orig_var = *entry; } else { - (*entry)->is_ref = 1; + if ((*var_array)->refcount > 1) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(entry); + } else { + (*entry)->is_ref = 1; + } zval_add_ref(entry); zend_hash_update(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) entry, sizeof(zval *), NULL); } @@ -1818,8 +1835,8 @@ hashtable and replace it with new one */ new_hash = php_splice(Z_ARRVAL_P(stack), 0, 0, &args[1], argc-1, NULL); zend_hash_destroy(Z_ARRVAL_P(stack)); - efree(Z_ARRVAL_P(stack)); - Z_ARRVAL_P(stack) = new_hash; + *Z_ARRVAL_P(stack) = *new_hash; + FREE_HASHTABLE(new_hash); /* Clean up and return the number of elements in the stack */ efree(args); @@ -1896,8 +1913,8 @@ /* Replace input array's hashtable with the new one */ zend_hash_destroy(Z_ARRVAL_P(array)); - efree(Z_ARRVAL_P(array)); - Z_ARRVAL_P(array) = new_hash; + *Z_ARRVAL_P(array) = *new_hash; + FREE_HASHTABLE(new_hash); /* Clean up */ if (argc == 4) @@ -2384,8 +2401,8 @@ /* Copy the result hash into return value */ zend_hash_destroy(Z_ARRVAL_P(return_value)); - efree(Z_ARRVAL_P(return_value)); - Z_ARRVAL_P(return_value) = new_hash; + *Z_ARRVAL_P(return_value) = *new_hash; + FREE_HASHTABLE(new_hash); /* Clean up */ efree(pads); @@ -2483,7 +2500,7 @@ zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(entry), NULL); break; case HASH_KEY_IS_STRING: - new_key=estrndup(string_key,str_key_len); + new_key=estrndup(string_key,str_key_len - 1); if (change_to_upper) php_strtoupper(new_key, str_key_len - 1); else @@ -2609,6 +2626,15 @@ /* copy the argument array */ *return_value = **args[0]; zval_copy_ctor(return_value); + if (return_value->value.ht == &EG(symbol_table)) { + HashTable *ht; + zval *tmp; + + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(ht, return_value->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + return_value->value.ht = ht; + } /* go through the lists and look for common values */ while (*ptrs[0]) { @@ -2759,6 +2785,15 @@ /* copy the argument array */ *return_value = **args[0]; zval_copy_ctor(return_value); + if (return_value->value.ht == &EG(symbol_table)) { + HashTable *ht; + zval *tmp; + + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(ht, return_value->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + return_value->value.ht = ht; + } /* go through the lists and look for values of ptr[0] that are not in the others */ @@ -3229,8 +3264,11 @@ efree(callback_name); if (ZEND_NUM_ARGS() > 2) { - convert_to_long_ex(initial); - result = *initial; + ALLOC_ZVAL(result); + *result = **initial; + zval_copy_ctor(result); + convert_to_long(result); + INIT_PZVAL(result); } else { MAKE_STD_ZVAL(result); ZVAL_NULL(result); @@ -3246,6 +3284,7 @@ if (result) { *return_value = *result; zval_copy_ctor(return_value); + zval_ptr_dtor(&result); } return; } @@ -3282,6 +3321,7 @@ PHP_FUNCTION(array_filter) { zval **input, **callback = NULL; + zval *array, *func = NULL; zval **operand; zval **args[1]; zval *retval = NULL; @@ -3300,9 +3340,13 @@ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array"); return; } + if (callback) { + func = *callback; + } + array = *input; if (ZEND_NUM_ARGS() > 1) { - if (!zend_is_callable(*callback, 0, &callback_name)) { + if (!zend_is_callable(func, 0, &callback_name)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument, '%s', should be a valid callback", callback_name); efree(callback_name); return; @@ -3311,16 +3355,16 @@ } array_init(return_value); - if (zend_hash_num_elements(Z_ARRVAL_PP(input)) == 0) + if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) return; - for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos); - zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&operand, &pos) == SUCCESS; - zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) { + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); + zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&operand, &pos) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)) { - if (callback) { + if (func) { args[0] = operand; - if (call_user_function_ex(EG(function_table), NULL, *callback, &retval, 1, args, 0, NULL TSRMLS_CC) == SUCCESS && retval) { + if (call_user_function_ex(EG(function_table), NULL, func, &retval, 1, args, 0, NULL TSRMLS_CC) == SUCCESS && retval) { if (!zend_is_true(retval)) { zval_ptr_dtor(&retval); continue; @@ -3334,7 +3378,7 @@ continue; zval_add_ref(operand); - switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(input), &string_key, &string_key_len, &num_key, 0, &pos)) { + switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos)) { case HASH_KEY_IS_STRING: zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, operand, sizeof(zval *), NULL); @@ -3401,6 +3445,7 @@ efree(array_pos); return; } + SEPARATE_ZVAL_IF_NOT_REF(pargs[i]); args[i] = *pargs[i]; array_len[i] = zend_hash_num_elements(Z_ARRVAL_PP(pargs[i])); if (array_len[i] > maxlen) { --- ext/standard/basic_functions.c 2005-01-18 12:01:20.000000000 +0100 +++ ext/standard/basic_functions.c 2005-10-31 23:29:26.000000000 +0100 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: basic_functions.c,v 1.543.2.47 2005/01/18 11:01:20 sniper Exp $ */ +/* $Id: basic_functions.c,v 1.543.2.51.2.3 2005/09/29 16:31:48 iliaa Exp $ */ #include "php.h" #include "php_streams.h" @@ -42,18 +42,7 @@ #include #include -#ifndef NETWARE #include -#else -/*#include "netware/env.h"*/ /* Temporary */ -#ifdef NEW_LIBC /* Same headers hold good for Winsock and Berkeley sockets */ -#include -/*#include */ -#include -#else -#include -#endif -#endif #if HAVE_ARPA_INET_H # include @@ -813,8 +802,8 @@ PHP_FE(prev, first_arg_force_ref) PHP_FE(next, first_arg_force_ref) PHP_FE(reset, first_arg_force_ref) - PHP_FE(current, first_arg_force_ref) - PHP_FE(key, first_arg_force_ref) + PHP_FE(current, NULL) + PHP_FE(key, NULL) PHP_FE(min, NULL) PHP_FE(max, NULL) PHP_FE(in_array, NULL) @@ -944,6 +933,13 @@ static void php_putenv_destructor(putenv_entry *pe) { if (pe->previous_value) { +#if _MSC_VER + /* VS.Net has a bug in putenv() when setting a variable that + * is already set; if the SetEnvironmentVariable() API call + * fails, the Crt will double free() a string. + * We try to avoid this by setting our own value first */ + SetEnvironmentVariable(pe->key, "bugbug"); +#endif putenv(pe->previous_value); } else { # if HAVE_UNSETENV @@ -1232,11 +1228,10 @@ } STR_FREE(BG(locale_string)); - if (FG(stream_wrappers)) { - zend_hash_destroy(FG(stream_wrappers)); - efree(FG(stream_wrappers)); - FG(stream_wrappers) = NULL; - } + /* + FG(stream_wrappers) are destroyed + during php_request_shutdown() + */ PHP_RSHUTDOWN(fsock) (SHUTDOWN_FUNC_ARGS_PASSTHRU); PHP_RSHUTDOWN(filestat) (SHUTDOWN_FUNC_ARGS_PASSTHRU); @@ -1430,6 +1425,14 @@ } } +#if _MSC_VER + /* VS.Net has a bug in putenv() when setting a variable that + * is already set; if the SetEnvironmentVariable() API call + * fails, the Crt will double free() a string. + * We try to avoid this by setting our own value first */ + SetEnvironmentVariable(pe.key, "bugbug"); +#endif + if (putenv(pe.putenv_string) == 0) { /* success */ zend_hash_add(&BG(putenv_ht), pe.key, pe.key_len+1, (void **) &pe, sizeof(putenv_entry), NULL); #ifdef HAVE_TZSET @@ -2089,17 +2092,21 @@ static int user_shutdown_function_call(php_shutdown_function_entry *shutdown_function_entry TSRMLS_DC) { zval retval; + char *function_name = NULL; - if (call_user_function( EG(function_table), NULL, - shutdown_function_entry->arguments[0], - &retval, - shutdown_function_entry->arg_count - 1, - shutdown_function_entry->arguments + 1 - TSRMLS_CC ) == SUCCESS ) { + if (!zend_is_callable(shutdown_function_entry->arguments[0], 0, &function_name)) { + php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", function_name); + } else if (call_user_function(EG(function_table), NULL, + shutdown_function_entry->arguments[0], + &retval, + shutdown_function_entry->arg_count - 1, + shutdown_function_entry->arguments + 1 + TSRMLS_CC ) == SUCCESS) + { zval_dtor(&retval); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call %s() - function does not exist", Z_STRVAL_P(shutdown_function_entry->arguments[0])); + } + if (function_name) { + efree(function_name); } return 0; } @@ -2192,6 +2199,7 @@ PHP_FUNCTION(register_shutdown_function) { php_shutdown_function_entry shutdown_function_entry; + char *function_name = NULL; int i; shutdown_function_entry.arg_count = ZEND_NUM_ARGS(); @@ -2200,26 +2208,31 @@ WRONG_PARAM_COUNT; } - shutdown_function_entry.arguments = (pval **) safe_emalloc(sizeof(pval *), shutdown_function_entry.arg_count, 0); + shutdown_function_entry.arguments = (zval **) safe_emalloc(sizeof(zval *), shutdown_function_entry.arg_count, 0); if (zend_get_parameters_array(ht, shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { RETURN_FALSE; } - /* Prevent entering of anything but arrays/strings */ - if (Z_TYPE_P(shutdown_function_entry.arguments[0]) != IS_ARRAY) { - convert_to_string(shutdown_function_entry.arguments[0]); - } - - if (!BG(user_shutdown_function_names)) { - ALLOC_HASHTABLE(BG(user_shutdown_function_names)); - zend_hash_init(BG(user_shutdown_function_names), 0, NULL, (void (*)(void *)) user_shutdown_function_dtor, 0); - } + /* Prevent entering of anything but valid callback (syntax check only!) */ + if (!zend_is_callable(shutdown_function_entry.arguments[0], 1, &function_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid shutdown callback '%s' passed", function_name); + efree(shutdown_function_entry.arguments); + RETVAL_FALSE; + } else { + if (!BG(user_shutdown_function_names)) { + ALLOC_HASHTABLE(BG(user_shutdown_function_names)); + zend_hash_init(BG(user_shutdown_function_names), 0, NULL, (void (*)(void *)) user_shutdown_function_dtor, 0); + } - for (i = 0; i < shutdown_function_entry.arg_count; i++) { - shutdown_function_entry.arguments[i]->refcount++; + for (i = 0; i < shutdown_function_entry.arg_count; i++) { + shutdown_function_entry.arguments[i]->refcount++; + } + zend_hash_next_index_insert(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry), NULL); + } + if (function_name) { + efree(function_name); } - zend_hash_next_index_insert(BG(user_shutdown_function_names), &shutdown_function_entry, sizeof(php_shutdown_function_entry), NULL); } /* }}} */ @@ -3014,11 +3027,25 @@ prefix = va_arg(args, char *); prefix_len = va_arg(args, uint); - new_key_len = prefix_len + hash_key->nKeyLength; - new_key = (char *) emalloc(new_key_len); + if (!prefix_len) { + if (!hash_key->nKeyLength) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric key detected - possible security hazard."); + return 0; + } else if (!strcmp(hash_key->arKey, "GLOBALS")) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted GLOBALS variable overwrite."); + return 0; + } + } + + if (hash_key->nKeyLength) { + new_key_len = prefix_len + hash_key->nKeyLength; + new_key = (char *) emalloc(new_key_len); - memcpy(new_key, prefix, prefix_len); - memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + } else { + new_key_len = spprintf(&new_key, 0, "%s%ld", prefix, hash_key->h); + } zend_hash_del(&EG(symbol_table), new_key, new_key_len); ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); --- ext/standard/string.c 2005-01-20 18:57:41.000000000 +0100 +++ ext/standard/string.c 2005-10-31 23:34:37.000000000 +0100 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: string.c,v 1.333.2.48 2005/01/20 17:57:41 iliaa Exp $ */ +/* $Id: string.c,v 1.333.2.52.2.1 2005/09/28 22:34:04 iliaa Exp $ */ /* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */ @@ -1317,8 +1317,6 @@ if (!Z_STRLEN_PP(needle)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter."); efree(haystack_orig); - zval_ptr_dtor(haystack); - zval_ptr_dtor(needle); RETURN_FALSE; } @@ -1339,8 +1337,6 @@ RETVAL_FALSE; } - zval_ptr_dtor(haystack); - zval_ptr_dtor(needle); efree(haystack_orig); } /* }}} */ @@ -1576,7 +1572,13 @@ } if (chunklen > Z_STRLEN_PP(p_str)) { - RETURN_STRINGL(Z_STRVAL_PP(p_str), Z_STRLEN_PP(p_str), 1); + /* to maintain BC, we must return original string + ending */ + result_len = endlen + Z_STRLEN_PP(p_str); + result = emalloc(result_len + 1); + memcpy(result, Z_STRVAL_PP(p_str), Z_STRLEN_PP(p_str)); + memcpy(result + Z_STRLEN_PP(p_str), end, endlen); + result[result_len] = '\0'; + RETURN_STRINGL(result, result_len, 0); } if (!Z_STRLEN_PP(p_str)) { @@ -3169,7 +3179,6 @@ zval *sarg; char *res = NULL; int argCount; - int old_rg; argCount = ARG_COUNT(ht); if (argCount < 1 || argCount > 2 || zend_get_parameters_ex(argCount, &arg, &arrayArg) == FAILURE) { @@ -3182,19 +3191,18 @@ res = estrndup(Z_STRVAL_P(sarg), Z_STRLEN_P(sarg)); } - old_rg = PG(register_globals); if (argCount == 1) { - PG(register_globals) = 1; - sapi_module.treat_data(PARSE_STRING, res, NULL TSRMLS_CC); + zval tmp; + Z_ARRVAL(tmp) = EG(active_symbol_table); + + sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC); } else { - PG(register_globals) = 0; /* Clear out the array that was passed in. */ zval_dtor(*arrayArg); array_init(*arrayArg); sapi_module.treat_data(PARSE_STRING, res, *arrayArg TSRMLS_CC); } - PG(register_globals) = old_rg; } /* }}} */ --- main/php_variables.c 2004-10-18 17:08:46.000000000 +0200 +++ main/php_variables.c 2005-10-31 23:39:38.000000000 +0100 @@ -16,7 +16,7 @@ | Zeev Suraski | +----------------------------------------------------------------------+ */ -/* $Id: php_variables.c,v 1.45.2.8 2004/10/18 15:08:46 tony2001 Exp $ */ +/* $Id: php_variables.c,v 1.45.2.13.2.4 2005/10/02 11:33:27 rrichards Exp $ */ #include #include "php.h" @@ -73,6 +73,10 @@ symtable1 = Z_ARRVAL_P(track_vars_array); } else if (PG(register_globals)) { symtable1 = EG(active_symbol_table); + /* GLOBALS hijack attempt, reject parameter */ + if (!strncmp("GLOBALS", var, sizeof("GLOBALS")) || !strncmp("GLOBALS", var, sizeof("GLOBALS[")-1)) { + return; + } } if (!symtable1) { /* Nothing to do */ @@ -99,6 +103,13 @@ zval_dtor(val); return; } + + /* GLOBALS hijack attempt, reject parameter */ + if (symtable1 == EG(active_symbol_table) && !strcmp("GLOBALS", var)) { + zval_dtor(val); + return; + } + /* ensure that we don't have spaces or dots in the variable name (not binary safe) */ for (p=var; *p; p++) { switch(*p) { @@ -182,11 +193,25 @@ if (!index) { zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } else { + zval **tmp; + if (PG(magic_quotes_gpc) && (index!=var)) { char *escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC); + + if (PG(http_globals)[TRACK_VARS_COOKIE] && symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) && + zend_hash_find(symtable1, escaped_index, index_len+1, (void **) &tmp) != FAILURE) { + efree(escaped_index); + break; + } + zend_hash_update(symtable1, escaped_index, index_len+1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); efree(escaped_index); } else { + if (PG(http_globals)[TRACK_VARS_COOKIE] && symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) && + zend_hash_find(symtable1, index, index_len+1, (void **) &tmp) != FAILURE) { + break; + } + zend_hash_update(symtable1, index, index_len+1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } }