diff -ruN a/main/main.c b/main/main.c --- a/main/main.c 2026-10-22 19:39:17.000000000 +0300 +++ b/main/main.c 2026-10-22 20:44:12.699275643 +0300 @@ -518,6 +518,7 @@ PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) @@ -1671,6 +1672,10 @@ PG(com_initialized) = 0; } #endif + + /* CVE-2026-109618: may be accessed before php_request_startup() of the next request */ + memset(PG(http_globals), 0, sizeof(PG(http_globals))); + PG(modules_activated) = 0; } /* }}} */ diff -ruN a/main/rfc1867.c b/main/rfc1867.c --- a/main/rfc1867.c 2026-10-22 19:39:17.000000000 +0300 +++ b/main/rfc1867.c 2026-10-22 20:44:12.699275643 +0300 @@ -459,6 +459,14 @@ return 0; } +static zend_bool php_mime_should_save_hdr(const char *name) +{ + return !strcasecmp(name, "Content-Disposition") + || !strcasecmp(name, "Content-Type"); +} + +static char *php_mime_get_hdr_value(zend_llist header, char *key); + /* parse headers */ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC) { @@ -496,10 +504,16 @@ } *value = '\0'; - do { value++; } while(isspace(*value)); - key = estrdup(line); - smart_str_appends(&buf_value, value); + /* CVE-2026-109618: keep only headers we use, and ignore duplicates */ + if (!php_mime_should_save_hdr(line) + || php_mime_get_hdr_value(*header, line)) { + key = NULL; + } else { + key = estrdup(line); + do { value++; } while (isspace((unsigned char)*value)); + smart_str_appends(&buf_value, value); + } } else if (buf_value.c) { /* If no ':' on the line, add to previous line */ smart_str_appends(&buf_value, line); } else { @@ -782,12 +796,20 @@ void *event_extra_data = NULL; int llen = 0; int upload_cnt = INI_INT("max_file_uploads"); + int body_parts_cnt = INI_INT("max_multipart_body_parts"); + int body_parts_limit; if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) { sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size)); return; } + /* CVE-2026-109618: default limit of multipart body parts */ + if (body_parts_cnt < 0) { + body_parts_cnt = PG(max_input_vars) + upload_cnt; + } + body_parts_limit = body_parts_cnt; + /* Get the boundary */ boundary = strstr(content_type_dup, "boundary"); if (!boundary) { @@ -878,6 +900,11 @@ char *pair = NULL; int end = 0; + if (--body_parts_cnt < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit); + goto fileupload_done; + } + while (isspace(*cd)) { ++cd; } diff -ruN a/main/SAPI.c b/main/SAPI.c --- a/main/SAPI.c 2026-10-22 19:39:17.000000000 +0300 +++ b/main/SAPI.c 2026-10-22 20:44:12.699275643 +0300 @@ -427,18 +427,23 @@ } if (SG(request_info).auth_user) { efree(SG(request_info).auth_user); + SG(request_info).auth_user = NULL; } if (SG(request_info).auth_password) { efree(SG(request_info).auth_password); + SG(request_info).auth_password = NULL; } if (SG(request_info).auth_digest) { efree(SG(request_info).auth_digest); + SG(request_info).auth_digest = NULL; } if (SG(request_info).content_type_dup) { efree(SG(request_info).content_type_dup); + SG(request_info).content_type_dup = NULL; } if (SG(request_info).current_user) { efree(SG(request_info).current_user); + SG(request_info).current_user = NULL; } if (sapi_module.deactivate) { sapi_module.deactivate(TSRMLS_C); diff -ruN a/Zend/zend_alloc.c b/Zend/zend_alloc.c --- a/Zend/zend_alloc.c 2026-10-22 19:39:17.000000000 +0300 +++ b/Zend/zend_alloc.c 2026-10-22 20:44:12.699275643 +0300 @@ -91,7 +91,7 @@ #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID) kill(getpid(), SIGSEGV); #endif - exit(1); + _exit(1); } /*******************/ @@ -1660,6 +1660,40 @@ } } +ZEND_API void zend_mm_safe_error_ex(const char *format, ...) +{ + const char *error_filename; + uint error_lineno; + char buf[1024]; + va_list args; + TSRMLS_FETCH(); + + if (zend_is_compiling(TSRMLS_C)) { + error_filename = zend_get_compiled_filename(TSRMLS_C); + error_lineno = zend_get_compiled_lineno(TSRMLS_C); + } else if (EG(in_execution)) { + error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL; + error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0; + } else { + error_filename = NULL; + error_lineno = 0; + } + if (!error_filename) { + error_filename = "Unknown"; + } + + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + + fprintf(stderr, "\nFatal error: %s in %s on line %d\n", buf, error_filename, error_lineno); +/* See http://support.microsoft.com/kb/190351 */ +#ifdef PHP_WIN32 + fflush(stderr); +#endif + _exit(1); +} + static void zend_mm_safe_error(zend_mm_heap *heap, const char *format, size_t limit, @@ -1669,59 +1703,14 @@ #endif size_t size) { - if (heap->reserve) { - _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); - heap->reserve = NULL; - } - if (heap->overflow == 0) { - char *error_filename; - uint error_lineno; - TSRMLS_FETCH(); - if (zend_is_compiling(TSRMLS_C)) { - error_filename = zend_get_compiled_filename(TSRMLS_C); - error_lineno = zend_get_compiled_lineno(TSRMLS_C); - } else if (EG(in_execution)) { - error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL; - error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0; - } else { - error_filename = NULL; - error_lineno = 0; - } - if (!error_filename) { - error_filename = "Unknown"; - } - heap->overflow = 1; - zend_try { - zend_error_noreturn(E_ERROR, - format, - limit, -#if ZEND_DEBUG - filename, - lineno, -#endif - size); - } zend_catch { - if (heap->overflow == 2) { - fprintf(stderr, "\nFatal error: "); - fprintf(stderr, - format, - limit, + (void) heap; + zend_mm_safe_error_ex(format, + limit, #if ZEND_DEBUG - filename, - lineno, + filename, + lineno, #endif - size); - fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno); - } -/* See http://support.microsoft.com/kb/190351 */ -#ifdef PHP_WIN32 - fflush(stderr); -#endif - } zend_end_try(); - } else { - heap->overflow = 2; - } - zend_bailout(); + size); } static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size) @@ -2383,7 +2372,7 @@ "rm"(offset)); if (UNEXPECTED(overflow)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); return 0; } return res; @@ -2403,7 +2392,7 @@ "rm"(offset)); if (UNEXPECTED(overflow)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); return 0; } return res; @@ -2416,7 +2405,7 @@ zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset; if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); return 0; } return (size_t) res; @@ -2431,7 +2420,7 @@ double _delta = (double)res - _d; if (UNEXPECTED((_d + _delta ) != _d)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + zend_mm_safe_error_ex("Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); return 0; } return res; diff -ruN a/Zend/zend_alloc.h b/Zend/zend_alloc.h --- a/Zend/zend_alloc.h 2026-10-22 19:39:17.000000000 +0300 +++ b/Zend/zend_alloc.h 2026-10-22 20:44:12.699275643 +0300 @@ -159,6 +159,15 @@ ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC); ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC); +/* CVE-2026-109618: report a fatal allocation error and terminate the process at once, + * without zend_bailout(): request memory may be in an inconsistent state + * (CVE-2026-109618). */ +ZEND_API void zend_mm_safe_error_ex(const char *format, ...) +#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) + __attribute__ ((noreturn)) +#endif + ; + END_EXTERN_C() /* Macroses for zend_fast_cache.h compatibility */ diff -ruN a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c --- a/Zend/zend_execute_API.c 2026-10-22 19:39:17.000000000 +0300 +++ b/Zend/zend_execute_API.c 2026-10-22 20:44:12.699275643 +0300 @@ -303,6 +303,10 @@ zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC); + /* CVE-2026-109618: may be used by zend_error() before init_executor() */ + EG(error_handling) = EH_NORMAL; + EG(exception) = NULL; + /* Destroy all op arrays */ if (EG(full_tables_cleanup)) { zend_hash_apply(EG(function_table), (apply_func_t) clean_non_persistent_function_full TSRMLS_CC); diff -ruN a/Zend/zend_llist.c b/Zend/zend_llist.c --- a/Zend/zend_llist.c 2026-10-22 19:39:17.000000000 +0300 +++ b/Zend/zend_llist.c 2026-10-22 20:44:12.699275643 +0300 @@ -117,6 +117,8 @@ current = next; } + l->head = NULL; + l->tail = NULL; l->count = 0; } diff -ruN a/Zend/zend_operators.c b/Zend/zend_operators.c --- a/Zend/zend_operators.c 2026-10-22 19:39:17.000000000 +0300 +++ b/Zend/zend_operators.c 2026-10-22 20:44:12.699275643 +0300 @@ -1252,7 +1252,7 @@ if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) { efree(Z_STRVAL_P(result)); ZVAL_EMPTY_STRING(result); - zend_error(E_ERROR, "String size overflow"); + zend_mm_safe_error_ex("String size overflow"); } Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1); @@ -1261,6 +1261,10 @@ Z_STRVAL_P(result)[res_len]=0; Z_STRLEN_P(result) = res_len; } else { + /* CVE-2026-109618: the sum must fit in int, including the trailing NUL */ + if (UNEXPECTED(Z_STRLEN_P(op1) < 0 || Z_STRLEN_P(op2) < 0 || Z_STRLEN_P(op1) > INT_MAX - 1 - Z_STRLEN_P(op2))) { + zend_mm_safe_error_ex("String size overflow"); + } Z_STRLEN_P(result) = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); Z_STRVAL_P(result) = (char *) emalloc(Z_STRLEN_P(result) + 1); memcpy(Z_STRVAL_P(result), Z_STRVAL_P(op1), Z_STRLEN_P(op1)); diff -ruN a/Zend/zend_strtod.c b/Zend/zend_strtod.c --- a/Zend/zend_strtod.c 2026-10-22 19:39:17.000000000 +0300 +++ b/Zend/zend_strtod.c 2026-10-22 20:44:12.699275643 +0300 @@ -473,7 +473,7 @@ Bigint *rv; if (k > Kmax) { - zend_error(E_ERROR, "Balloc() allocation exceeds list boundary"); + zend_mm_safe_error_ex("Balloc() allocation exceeds list boundary"); } _THREAD_PRIVATE_MUTEX_LOCK(dtoa_mutex); @@ -484,7 +484,7 @@ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long)); if (!rv) { _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa_mutex); - zend_error(E_ERROR, "Balloc() failed to allocate memory"); + zend_mm_safe_error_ex("Balloc() failed to allocate memory"); } rv->k = k; rv->maxwds = x;