diff --git a/.github/workflows/verify-bundled-files.yml b/.github/workflows/verify-bundled-files.yml index 6cce1a14cf7f3..291cd6adaa3da 100644 --- a/.github/workflows/verify-bundled-files.yml +++ b/.github/workflows/verify-bundled-files.yml @@ -16,6 +16,7 @@ permissions: jobs: VERIFY_BUNDLED_FILES: + if: github.repository == 'php/php-src' || github.event_name == 'workflow_dispatch' name: Verify Bundled Files runs-on: ubuntu-24.04 steps: diff --git a/UPGRADING b/UPGRADING index 8a1c61b9192cc..b1db9893de628 100644 --- a/UPGRADING +++ b/UPGRADING @@ -23,6 +23,10 @@ PHP 8.6 UPGRADE NOTES . Invalid values now throw in Phar::mungServer() instead of being silently ignored. +- Session: + . A ValueError is not thrown if $name is a string containing null bytes in + session_module_name(). + - Standard: . Invalid mode values now throw in array_filter() instead of being silently defaulted to 0. diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 27414f52b3754..1d8734d9fb076 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -97,6 +97,14 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Dropped session_options parameter from all methods in mysqlnd_auth. The same information is present in conn->options and should be used instead. +- ext/session: + . php_session_flush() now returns a bool rather than a zend_result. + . Removed session_adapt_url(). + . PS_OPEN_ARGS is now defined as + `void **mod_data, zend_string *save_path, zend_string *session_name` + rather than + `void **mod_data, const char *save_path, const char *session_name` + - ext/standard: . _php_error_log() now has a formal return type of zend_result. . _php_error_log() now accepts zend_string* values instead of char*. diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index 7f97caa1fdab4..5a0af26303913 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -176,7 +176,9 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array && zend_optimizer_update_op1_const(op_array, opline, &c)) { VAR_SOURCE(op1) = NULL; if (opline->opcode != ZEND_JMP_NULL - && !zend_bitset_in(used_ext, VAR_NUM(src->result.var))) { + && !zend_bitset_in(used_ext, VAR_NUM(src->result.var)) + /* FETCH_W with ZEND_FETCH_GLOBAL_LOCK does not free op1, which will be used again. */ + && !(opline->opcode == ZEND_FETCH_W && (opline->extended_value & ZEND_FETCH_GLOBAL_LOCK))) { literal_dtor(&ZEND_OP1_LITERAL(src)); MAKE_NOP(src); } diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h index 200bedd88cacf..716e3ba4b5715 100644 --- a/Zend/zend_multiply.h +++ b/Zend/zend_multiply.h @@ -342,7 +342,6 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t if (UNEXPECTED(overflow)) { zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; } return ret; } @@ -355,7 +354,6 @@ static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, si if (UNEXPECTED(overflow)) { zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset); - return 0; } return ret; } diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c index 09a357d189ed4..b9f8ca4524a05 100644 --- a/ext/opcache/shared_alloc_shm.c +++ b/ext/opcache/shared_alloc_shm.c @@ -42,7 +42,6 @@ # define MIN(x, y) ((x) > (y)? (y) : (x)) #endif -#define SEG_ALLOC_SIZE_MAX 32*1024*1024 #define SEG_ALLOC_SIZE_MIN 2*1024*1024 typedef struct { @@ -53,36 +52,38 @@ typedef struct { static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, const char **error_in) { int i; - size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size; + size_t allocate_size = 0, remaining_bytes, seg_allocate_size; int first_segment_id = -1; key_t first_segment_key = -1; struct shmid_ds sds; int shmget_flags; zend_shared_segment_shm *shared_segments; - seg_allocate_size = SEG_ALLOC_SIZE_MAX; - /* determine segment size we _really_ need: - * no more than to include requested_size - */ - while (requested_size * 2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) { - seg_allocate_size >>= 1; - } - shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; - /* try allocating this much, if not - try shrinking */ - while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { - allocate_size = MIN(requested_size, seg_allocate_size); - first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags); - if (first_segment_id != -1) { - break; + /* Try contiguous allocation first. */ + seg_allocate_size = requested_size; + first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); + if (UNEXPECTED(first_segment_id == -1)) { + /* Search for biggest n^2 < requested_size. */ + seg_allocate_size = SEG_ALLOC_SIZE_MIN; + while (seg_allocate_size < requested_size / 2) { + seg_allocate_size *= 2; } - seg_allocate_size >>= 1; /* shrink the allocated block */ - } - if (first_segment_id == -1) { - *error_in = "shmget"; - return ALLOC_FAILURE; + /* try allocating this much, if not - try shrinking */ + while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { + first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); + if (first_segment_id != -1) { + break; + } + seg_allocate_size >>= 1; /* shrink the allocated block */ + } + + if (first_segment_id == -1) { + *error_in = "shmget"; + return ALLOC_FAILURE; + } } *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1; diff --git a/ext/opcache/tests/oss-fuzz-481014628.phpt b/ext/opcache/tests/oss-fuzz-481014628.phpt new file mode 100644 index 0000000000000..8aa6cf3fe1fdb --- /dev/null +++ b/ext/opcache/tests/oss-fuzz-481014628.phpt @@ -0,0 +1,27 @@ +--TEST-- +OSS-Fuzz #481014628: Borked FETCH_W+ZEND_FETCH_GLOBAL_LOCK optimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + +--EXPECT-- +NULL +int(42) diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index 869bb1052c6df..87bcb7e3690fc 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -369,19 +369,22 @@ PS_OPEN_FUNC(files) int argc = 0; size_t dirdepth = 0; int filemode = 0600; + const char *used_save_path; - if (*save_path == '\0') { + if (ZSTR_LEN(save_path) == 0) { /* if save path is an empty string, determine the temporary dir */ - save_path = php_get_temporary_directory(); + used_save_path = php_get_temporary_directory(); - if (php_check_open_basedir(save_path)) { + if (php_check_open_basedir(used_save_path)) { return FAILURE; } + } else { + used_save_path = ZSTR_VAL(save_path); } /* split up input parameter */ - last = save_path; - p = strchr(save_path, ';'); + last = used_save_path; + p = strchr(used_save_path, ';'); while (p) { argv[argc++] = last; last = ++p; @@ -407,14 +410,14 @@ PS_OPEN_FUNC(files) return FAILURE; } } - save_path = argv[argc - 1]; + used_save_path = argv[argc - 1]; data = ecalloc(1, sizeof(*data)); data->fd = -1; data->dirdepth = dirdepth; data->filemode = filemode; - data->basedir = zend_string_init(save_path, strlen(save_path), /* persistent */ false); + data->basedir = zend_string_init(used_save_path, strlen(used_save_path), /* persistent */ false); if (PS_GET_MOD_DATA()) { ps_close_files(mod_data); diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index 5783ca625a4a6..90b91926a62c3 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -83,12 +83,11 @@ PS_OPEN_FUNC(user) { zval args[2]; zval retval; - zend_result ret = FAILURE; ZEND_ASSERT(!Z_ISUNDEF(PSF(open))); - ZVAL_STRING(&args[0], (char*)save_path); - ZVAL_STRING(&args[1], (char*)session_name); + ZVAL_STR(&args[0], zend_string_dup(save_path, false)); + ZVAL_STR(&args[1], zend_string_dup(session_name, false)); zend_try { ps_call_handler(&PSF(open), 2, args, &retval); @@ -102,7 +101,7 @@ PS_OPEN_FUNC(user) PS(mod_user_implemented) = true; - ret = verify_bool_return_type_userland_calls(&retval); + zend_result ret = verify_bool_return_type_userland_calls(&retval); zval_ptr_dtor(&retval); return ret; } diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c index 1735423e902c4..618cc6bd67965 100644 --- a/ext/session/mod_user_class.c +++ b/ext/session/mod_user_class.c @@ -36,11 +36,10 @@ PHP_METHOD(SessionHandler, open) { - char *save_path = NULL, *session_name = NULL; - size_t save_path_len, session_name_len; + zend_string *save_path, *session_name; zend_result ret; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &save_path, &save_path_len, &session_name, &session_name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &save_path, &session_name) == FAILURE) { RETURN_THROWS(); } diff --git a/ext/session/php_session.h b/ext/session/php_session.h index 9bf97cca02bf3..8c857d29a5fc0 100644 --- a/ext/session/php_session.h +++ b/ext/session/php_session.h @@ -26,7 +26,7 @@ #define PHP_SESSION_VERSION PHP_VERSION /* save handler macros */ -#define PS_OPEN_ARGS void **mod_data, const char *save_path, const char *session_name +#define PS_OPEN_ARGS void **mod_data, zend_string *save_path, zend_string *session_name #define PS_CLOSE_ARGS void **mod_data #define PS_READ_ARGS void **mod_data, zend_string *key, zend_string **val, zend_long maxlifetime #define PS_WRITE_ARGS void **mod_data, zend_string *key, zend_string *val, zend_long maxlifetime @@ -174,7 +174,6 @@ typedef struct _php_ps_globals { zval ps_validate_sid; zval ps_update_timestamp; } mod_user_names; - zend_string *mod_user_class_name; bool mod_user_implemented; bool mod_user_is_open; bool auto_start; @@ -249,8 +248,6 @@ PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS); PHPAPI zend_result php_session_validate_sid(PS_VALIDATE_SID_ARGS); PHPAPI zend_result php_session_update_timestamp(PS_UPDATE_TIMESTAMP_ARGS); -PHPAPI void session_adapt_url(const char *url, size_t url_len, char **new_url, size_t *new_len); - PHPAPI zend_result php_session_destroy(void); PHPAPI void php_add_session_var(zend_string *name); PHPAPI zval *php_set_session_var(zend_string *name, zval *state_val, php_unserialize_data_t *var_hash); @@ -264,7 +261,7 @@ PHPAPI zend_result php_session_register_serializer(const char *name, zend_result (*decode)(PS_SERIALIZER_DECODE_ARGS)); PHPAPI zend_result php_session_start(void); -PHPAPI zend_result php_session_flush(bool write); +PHPAPI bool php_session_flush(bool write); PHPAPI php_session_status php_get_session_status(void); PHPAPI const ps_module *_php_find_ps_module(const char *name); diff --git a/ext/session/session.c b/ext/session/session.c index 7578a038eadd0..d9a4e2b5a4d2b 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -101,7 +101,7 @@ zend_class_entry *php_session_update_timestamp_iface_entry; #define APPLY_TRANS_SID (PS(use_trans_sid) && !PS(use_only_cookies)) static zend_result php_session_send_cookie(void); -static zend_result php_session_abort(void); +static bool php_session_abort(void); static void proposed_session_id_to_session_id(const zval *proposed_session_id); /* Initialized in MINIT, readonly otherwise. */ @@ -177,11 +177,6 @@ static void php_rshutdown_session_globals(void) PS(session_vars) = NULL; } - if (PS(mod_user_class_name)) { - zend_string_release(PS(mod_user_class_name)); - PS(mod_user_class_name) = NULL; - } - php_session_cleanup_filename(); /* User save handlers may end up directly here by misuse, bugs in user script, etc. */ @@ -310,23 +305,17 @@ static zend_result php_session_decode(const zend_string *data) static const char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-"; -static void bin_to_readable(unsigned char *in, size_t inlen, char *out, size_t outlen, char nbits) +static void bin_to_readable(const unsigned char *in, size_t inlen, char *out, size_t outlen, char nbits) { - unsigned char *p, *q; - unsigned short w; - int mask; - int have; - - p = (unsigned char *)in; - q = (unsigned char *)in + inlen; - - w = 0; - have = 0; - mask = (1 << nbits) - 1; + const unsigned char *p = in; + const unsigned char *end_p = in + inlen; + unsigned short w = 0; + int have = 0; + const int mask = (1 << nbits) - 1; while (outlen--) { if (have < nbits) { - if (p < q) { + if (p < end_p) { w |= *p++ << have; have += 8; } else { @@ -429,7 +418,7 @@ static zend_result php_session_initialize(void) } /* Open session handler first */ - if (PS(mod)->s_open(&PS(mod_data), ZSTR_VAL(PS(save_path)), ZSTR_VAL(PS(session_name))) == FAILURE + if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE /* || PS(mod_data) == NULL */ /* FIXME: open must set valid PS(mod_data) with success */ ) { php_session_abort(); @@ -516,9 +505,7 @@ static void php_session_save_current_state(bool write) if (write) { IF_SESSION_VARS() { - zend_string *handler_class_name = PS(mod_user_class_name); - const char *handler_function_name = "write"; - + zval *handler_function = &PS(mod_user_names).ps_write; if (PS(mod_data) || PS(mod_user_implemented)) { zend_string *val; @@ -530,7 +517,7 @@ static void php_session_save_current_state(bool write) && zend_string_equals(val, PS(session_vars)) ) { ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); - handler_function_name = handler_class_name != NULL ? "updateTimestamp" : "update_timestamp"; + handler_function = &PS(mod_user_names).ps_update_timestamp; } else { ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); } @@ -547,14 +534,12 @@ static void php_session_save_current_state(bool write) "is correct (%s)", PS(mod)->s_name, ZSTR_VAL(PS(save_path))); - } else if (handler_class_name != NULL) { - php_error_docref(NULL, E_WARNING, "Failed to write session data using user " - "defined save handler. (session.save_path: %s, handler: %s::%s)", ZSTR_VAL(PS(save_path)), - ZSTR_VAL(handler_class_name), handler_function_name); } else { + zend_string *callable_name = zend_get_callable_name(handler_function); php_error_docref(NULL, E_WARNING, "Failed to write session data using user " "defined save handler. (session.save_path: %s, handler: %s)", ZSTR_VAL(PS(save_path)), - handler_function_name); + ZSTR_VAL(callable_name)); + zend_string_release_ex(callable_name, false); } } } @@ -1004,15 +989,12 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) PS_SERIALIZER_DECODE_FUNC(php_binary) { - const char *p; const char *endptr = val + vallen; - zend_string *name; php_unserialize_data_t var_hash; - zval *current, rv; PHP_VAR_UNSERIALIZE_INIT(var_hash); - for (p = val; p < endptr; ) { + for (const char *p = val; p < endptr; ) { size_t namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF); if (namelen > PS_BIN_MAX || (p + namelen) >= endptr) { @@ -1020,11 +1002,12 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) return FAILURE; } - name = zend_string_init(p + 1, namelen, false); + zend_string *name = zend_string_init(p + 1, namelen, false); p += namelen + 1; - current = var_tmp_var(&var_hash); + zval *current = var_tmp_var(&var_hash); if (php_var_unserialize(current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash)) { + zval rv; ZVAL_PTR(&rv, current); php_set_session_var(name, &rv, &var_hash); } else { @@ -1203,12 +1186,12 @@ typedef struct { #define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1); #define MAX_STR 512 -static const char *month_names[] = { +static const char *const month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -static const char *week_days[] = { +static const char *const week_days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; @@ -1309,8 +1292,6 @@ static const php_session_cache_limiter_t php_session_cache_limiters[] = { static int php_session_cache_limiter(void) { - const php_session_cache_limiter_t *lim; - if (ZSTR_LEN(PS(cache_limiter)) == 0) { return 0; } @@ -1322,7 +1303,7 @@ static int php_session_cache_limiter(void) return -2; } - for (lim = php_session_cache_limiters; lim->name; lim++) { + for (const php_session_cache_limiter_t *lim = php_session_cache_limiters; lim->name; lim++) { if (!strcasecmp(lim->name, ZSTR_VAL(PS(cache_limiter)))) { lim->func(); return 0; @@ -1455,9 +1436,8 @@ PHPAPI const ps_module *_php_find_ps_module(const char *name) PHPAPI const ps_serializer *_php_find_ps_serializer(const char *name) { const ps_serializer *found_serializer = NULL; - const ps_serializer *current_serializer; - for (current_serializer = ps_serializers; current_serializer->name; current_serializer++) { + for (const ps_serializer *current_serializer = ps_serializers; current_serializer->name; current_serializer++) { if (!strcasecmp(name, current_serializer->name)) { found_serializer = current_serializer; break; @@ -1652,16 +1632,14 @@ PHPAPI zend_result php_session_reset_id(void) PHPAPI zend_result php_session_start(void) { - const char *value; - switch (PS(session_status)) { case php_session_active: php_session_session_already_started_error(E_NOTICE, "Ignoring session_start() because a session has already been started"); return FAILURE; break; - case php_session_disabled: - value = zend_ini_string(ZEND_STRL("session.save_handler"), false); + case php_session_disabled: { + const char *value = zend_ini_string(ZEND_STRL("session.save_handler"), false); if (!PS(mod) && value) { PS(mod) = _php_find_ps_module(value); if (!PS(mod)) { @@ -1679,6 +1657,7 @@ PHPAPI zend_result php_session_start(void) } PS(session_status) = php_session_none; ZEND_FALLTHROUGH; + } case php_session_none: default: @@ -1691,7 +1670,7 @@ PHPAPI zend_result php_session_start(void) * Cookies are preferred, because initially cookie and get * variables will be available. * URL/POST session ID may be used when use_only_cookies=Off. - * session.use_strice_mode=On prevents session adoption. + * session.use_strict_mode=On prevents session adoption. * Session based file upload progress uses non-cookie ID. */ @@ -1729,14 +1708,14 @@ PHPAPI zend_result php_session_start(void) return SUCCESS; } -PHPAPI zend_result php_session_flush(bool write) +PHPAPI bool php_session_flush(bool write) { if (PS(session_status) == php_session_active) { php_session_save_current_state(write); PS(session_status) = php_session_none; - return SUCCESS; + return true; } - return FAILURE; + return false; } PHPAPI php_session_status php_get_session_status(void) @@ -1744,36 +1723,21 @@ PHPAPI php_session_status php_get_session_status(void) return PS(session_status); } -static zend_result php_session_abort(void) +static bool php_session_abort(void) { if (PS(session_status) == php_session_active) { if (PS(mod_data) || PS(mod_user_implemented)) { PS(mod)->s_close(&PS(mod_data)); } PS(session_status) = php_session_none; - return SUCCESS; + return true; } - return FAILURE; + return false; } -static zend_result php_session_reset(void) +static bool php_session_reset(void) { - if (PS(session_status) == php_session_active - && php_session_initialize() == SUCCESS) { - return SUCCESS; - } - return FAILURE; -} - - -/* This API is not used by any PHP modules including session currently. - session_adapt_url() may be used to set Session ID to target url without - starting "URL-Rewriter" output handler. */ -PHPAPI void session_adapt_url(const char *url, size_t url_len, char **new_url, size_t *new_len) -{ - if (APPLY_TRANS_SID && (PS(session_status) == php_session_active)) { - *new_url = php_url_scanner_adapt_single_url(url, url_len, ZSTR_VAL(PS(session_name)), ZSTR_VAL(PS(id)), new_len, true); - } + return PS(session_status) == php_session_active && php_session_initialize() == SUCCESS; } /* ******************************** @@ -1817,9 +1781,6 @@ PHP_FUNCTION(session_set_cookie_params) } if (options_ht) { - zend_string *key; - zval *value; - if (path) { zend_argument_value_error(2, "must be null when argument #1 ($lifetime_or_options) is an array"); RETURN_THROWS(); @@ -1839,7 +1800,7 @@ PHP_FUNCTION(session_set_cookie_params) zend_argument_value_error(5, "must be null when argument #1 ($lifetime_or_options) is an array"); RETURN_THROWS(); } - ZEND_HASH_FOREACH_STR_KEY_VAL(options_ht, key, value) { + ZEND_HASH_FOREACH_STR_KEY_VAL(options_ht, zend_string *key, zval *value) { if (key) { ZVAL_DEREF(value); if (zend_string_equals_literal_ci(key, "lifetime")) { @@ -1916,7 +1877,7 @@ PHP_FUNCTION(session_set_cookie_params) } if (!secure_null) { ini_name = ZSTR_INIT_LITERAL("session.cookie_secure", false); - result = zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + result = zend_alter_ini_entry(ini_name, secure ? ZSTR_CHAR('1') : ZSTR_CHAR('0'), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, false); if (result == FAILURE) { RETVAL_FALSE; @@ -1925,7 +1886,7 @@ PHP_FUNCTION(session_set_cookie_params) } if (!partitioned_null) { ini_name = ZSTR_INIT_LITERAL("session.cookie_partitioned", false); - result = zend_alter_ini_entry_chars(ini_name, partitioned ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + result = zend_alter_ini_entry(ini_name, partitioned ? ZSTR_CHAR('1') : ZSTR_CHAR('0'), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, false); if (result == FAILURE) { RETVAL_FALSE; @@ -1934,7 +1895,7 @@ PHP_FUNCTION(session_set_cookie_params) } if (!httponly_null) { ini_name = ZSTR_INIT_LITERAL("session.cookie_httponly", false); - result = zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + result = zend_alter_ini_entry(ini_name, httponly ? ZSTR_CHAR('1') : ZSTR_CHAR('0'), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, false); if (result == FAILURE) { RETVAL_FALSE; @@ -2005,9 +1966,8 @@ PHP_FUNCTION(session_name) PHP_FUNCTION(session_module_name) { zend_string *name = NULL; - zend_string *ini_name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!", &name) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|P!", &name) == FAILURE) { RETURN_THROWS(); } @@ -2024,7 +1984,7 @@ PHP_FUNCTION(session_module_name) if (name) { if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_USER))) { - zend_argument_value_error(1, "cannot be \"user\""); + zend_argument_value_error(1, "must not be \"user\""); RETURN_THROWS(); } if (!_php_find_ps_module(ZSTR_VAL(name))) { @@ -2038,7 +1998,7 @@ PHP_FUNCTION(session_module_name) } PS(mod_data) = NULL; - ini_name = ZSTR_INIT_LITERAL("session.save_handler", false); + zend_string *ini_name = ZSTR_INIT_LITERAL("session.save_handler", false); zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, false); } @@ -2115,11 +2075,6 @@ PHP_FUNCTION(session_set_save_handler) RETURN_FALSE; } - if (PS(mod_user_class_name)) { - zend_string_release(PS(mod_user_class_name)); - } - PS(mod_user_class_name) = zend_string_copy(Z_OBJCE_P(obj)->name); - /* Define mandatory handlers */ SESSION_SET_USER_HANDLER_OO_MANDATORY(ps_open, "open"); SESSION_SET_USER_HANDLER_OO_MANDATORY(ps_close, "close"); @@ -2154,7 +2109,8 @@ PHP_FUNCTION(session_set_save_handler) /* Validate ID handler */ SESSION_SET_USER_HANDLER_OO(ps_validate_sid, zend_string_copy(validate_sid_name)); /* Update Timestamp handler */ - SESSION_SET_USER_HANDLER_OO(ps_update_timestamp, zend_string_copy(update_timestamp_name)); + /* We need to provide a new string with the correct casing so that error messages work */ + SESSION_SET_USER_HANDLER_OO(ps_update_timestamp, ZSTR_INIT_LITERAL("updateTimestamp", false)); } else { /* For BC reasons we accept methods even if the class does not implement the interface */ if (zend_hash_find_ptr(object_methods, validate_sid_name)) { @@ -2163,7 +2119,8 @@ PHP_FUNCTION(session_set_save_handler) } if (zend_hash_find_ptr(object_methods, update_timestamp_name)) { /* For BC reasons we accept methods even if the class does not implement the interface */ - SESSION_SET_USER_HANDLER_OO(ps_update_timestamp, zend_string_copy(update_timestamp_name)); + /* We need to provide a new string with the correct casing so that error messages work */ + SESSION_SET_USER_HANDLER_OO(ps_update_timestamp, ZSTR_INIT_LITERAL("updateTimestamp", false)); } } zend_string_release_ex(validate_sid_name, false); @@ -2240,12 +2197,6 @@ PHP_FUNCTION(session_set_save_handler) RETURN_FALSE; } - /* If a custom session handler is already set, release relevant info */ - if (PS(mod_user_class_name)) { - zend_string_release(PS(mod_user_class_name)); - PS(mod_user_class_name) = NULL; - } - /* remove shutdown function */ remove_user_shutdown_function("session_shutdown", strlen("session_shutdown")); @@ -2381,7 +2332,7 @@ PHP_FUNCTION(session_regenerate_id) zend_string_release_ex(PS(id), false); PS(id) = NULL; - if (PS(mod)->s_open(&PS(mod_data), ZSTR_VAL(PS(save_path)), ZSTR_VAL(PS(session_name))) == FAILURE) { + if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE) { PS(session_status) = php_session_none; if (!EG(exception)) { zend_throw_error(NULL, "Failed to open session: %s (path: %s)", PS(mod)->s_name, ZSTR_VAL(PS(save_path))); @@ -2495,7 +2446,6 @@ PHP_FUNCTION(session_create_id) PHP_FUNCTION(session_cache_limiter) { zend_string *limiter = NULL; - zend_string *ini_name; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!", &limiter) == FAILURE) { RETURN_THROWS(); @@ -2514,7 +2464,7 @@ PHP_FUNCTION(session_cache_limiter) RETVAL_STRINGL(ZSTR_VAL(PS(cache_limiter)), ZSTR_LEN(PS(cache_limiter))); if (limiter) { - ini_name = ZSTR_INIT_LITERAL("session.cache_limiter", false); + zend_string *ini_name = ZSTR_INIT_LITERAL("session.cache_limiter", false); zend_alter_ini_entry(ini_name, limiter, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, false); } @@ -2585,7 +2535,7 @@ PHP_FUNCTION(session_decode) RETURN_BOOL(php_session_decode(str) == SUCCESS); } -static zend_result php_session_start_set_ini(zend_string *varname, zend_string *new_value) { +static zend_result php_session_start_set_ini(const zend_string *varname, zend_string *new_value) { zend_result ret; smart_str buf ={0}; smart_str_appends(&buf, "session"); @@ -2600,8 +2550,6 @@ static zend_result php_session_start_set_ini(zend_string *varname, zend_string * PHP_FUNCTION(session_start) { zval *options = NULL; - zval *value; - zend_string *str_idx; bool read_and_close = false; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a", &options) == FAILURE) { @@ -2625,7 +2573,7 @@ PHP_FUNCTION(session_start) /* set options */ if (options) { - ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), str_idx, value) { + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), zend_string *str_idx, zval *value) { if (UNEXPECTED(!str_idx)) { zend_argument_value_error(1, "must be of type array with keys as string"); RETURN_THROWS(); @@ -2742,11 +2690,7 @@ PHP_FUNCTION(session_write_close) RETURN_THROWS(); } - if (PS(session_status) != php_session_active) { - RETURN_FALSE; - } - php_session_flush(true); - RETURN_TRUE; + RETURN_BOOL(php_session_flush(true)); } /* Abort session and end session. Session data will not be written */ @@ -2756,11 +2700,7 @@ PHP_FUNCTION(session_abort) RETURN_THROWS(); } - if (PS(session_status) != php_session_active) { - RETURN_FALSE; - } - php_session_abort(); - RETURN_TRUE; + RETURN_BOOL(php_session_abort()); } /* Reset session data from saved session data */ @@ -2770,11 +2710,7 @@ PHP_FUNCTION(session_reset) RETURN_THROWS(); } - if (PS(session_status) != php_session_active) { - RETURN_FALSE; - } - php_session_reset(); - RETURN_TRUE; + RETURN_BOOL(php_session_reset()); } PHP_FUNCTION(session_status) @@ -2906,7 +2842,6 @@ static PHP_GINIT_FUNCTION(ps) ps_globals->session_status = php_session_none; ps_globals->default_mod = NULL; ps_globals->mod_user_implemented = false; - ps_globals->mod_user_class_name = NULL; ps_globals->mod_user_is_open = false; ps_globals->session_vars = NULL; ps_globals->set_handler = false; @@ -3043,14 +2978,12 @@ static PHP_MINFO_FUNCTION(session) static bool early_find_sid_in(zval *dest, int where) { - zval *potential_session_id; - if (Z_ISUNDEF(PG(http_globals)[where])) { return false; } - if ((potential_session_id = zend_hash_find(Z_ARRVAL(PG(http_globals)[where]), PS(session_name))) - && Z_TYPE_P(potential_session_id) == IS_STRING) { + zval *potential_session_id = zend_hash_find(Z_ARRVAL(PG(http_globals)[where]), PS(session_name)); + if (potential_session_id && Z_TYPE_P(potential_session_id) == IS_STRING) { zval_ptr_dtor(dest); ZVAL_COPY_DEREF(dest, potential_session_id); return true; @@ -3078,15 +3011,15 @@ static void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *pro static bool php_check_cancel_upload(const php_session_rfc1867_progress *progress) { - zval *progress_ary, *cancel_upload; - - if ((progress_ary = zend_symtable_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), progress->key.s)) == NULL) { + const zval *progress_ary = zend_symtable_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), progress->key.s); + if (progress_ary == NULL) { return false; } if (Z_TYPE_P(progress_ary) != IS_ARRAY) { return false; } - if ((cancel_upload = zend_hash_str_find(Z_ARRVAL_P(progress_ary), ZEND_STRL("cancel_upload"))) == NULL) { + const zval *cancel_upload = zend_hash_str_find(Z_ARRVAL_P(progress_ary), ZEND_STRL("cancel_upload")); + if (cancel_upload == NULL) { return false; } return Z_TYPE_P(cancel_upload) == IS_TRUE; diff --git a/ext/session/tests/bug73100.phpt b/ext/session/tests/bug73100.phpt index 21e698a14aba8..fc9984428726f 100644 --- a/ext/session/tests/bug73100.phpt +++ b/ext/session/tests/bug73100.phpt @@ -24,5 +24,5 @@ bool(true) Warning: session_module_name(): Session save handler module cannot be changed when a session is active (started from %s on line %d) in %s on line %d bool(true) -session_module_name(): Argument #1 ($module) cannot be "user" +session_module_name(): Argument #1 ($module) must not be "user" ===DONE=== diff --git a/ext/session/tests/session_module_name_errors.phpt b/ext/session/tests/session_module_name_errors.phpt new file mode 100644 index 0000000000000..f00171e6584ab --- /dev/null +++ b/ext/session/tests/session_module_name_errors.phpt @@ -0,0 +1,22 @@ +--TEST-- +session_module_name(): errors +--EXTENSIONS-- +session +--FILE-- +getMessage(), PHP_EOL; +} +try { + var_dump(session_module_name("fi\0le")); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +ValueError: session_module_name(): Argument #1 ($module) must not be "user" +ValueError: session_module_name(): Argument #1 ($module) must not contain any null bytes diff --git a/ext/session/tests/user_session_module/gh7787.phpt b/ext/session/tests/user_session_module/gh7787.phpt index 85ce7bd887cb6..ee62e8f049635 100644 --- a/ext/session/tests/user_session_module/gh7787.phpt +++ b/ext/session/tests/user_session_module/gh7787.phpt @@ -84,6 +84,6 @@ Warning: session_write_close(): Failed to write session data using user defined Deprecated: session_set_save_handler(): Providing individual callbacks instead of an object implementing SessionHandlerInterface is deprecated in %s on line %d -Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: %S, handler: write) in %s on line %d +Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: %S, handler: {closure:%s:57}) in %s on line %d -Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: %S, handler: update_timestamp) in %s on line %d +Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: %S, handler: {closure:%s:62}) in %s on line %d