From 526631ee339033ec3e1eeceaf774be5ad3067ff9 Mon Sep 17 00:00:00 2001 From: lazerg Date: Sat, 7 Nov 2026 14:50:12 +0500 Subject: [PATCH] Fix GH-25263: Use-after-free of __call trampoline when cloning CurlHandle --- ext/curl/interface.c | 21 +++++++++++++++++---- ext/curl/tests/gh25263.phpt | 28 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 ext/curl/tests/gh25263.phpt diff --git a/ext/curl/interface.c b/ext/curl/interface.c index b8c6ce7dde3e..316d1c1f0b56 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1284,10 +1284,23 @@ PHP_FUNCTION(curl_init) } /* }}} */ +static void php_curl_fcc_dup(zend_fcall_info_cache *dest, const zend_fcall_info_cache *src) +{ + zend_fcc_dup(dest, src); + /* Each FCC owns its trampoline copy, so the duplicate needs its own */ + if (UNEXPECTED(dest->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_function *copy = emalloc(sizeof(zend_function)); + + memcpy(copy, src->function_handler, sizeof(zend_function)); + zend_string_addref(copy->common.function_name); + dest->function_handler = copy; + } +} + static void php_curl_copy_fcc_with_option(php_curl *ch, CURLoption option, zend_fcall_info_cache *target_fcc, zend_fcall_info_cache *source_fcc) { if (ZEND_FCC_INITIALIZED(*source_fcc)) { - zend_fcc_dup(target_fcc, source_fcc); + php_curl_fcc_dup(target_fcc, source_fcc); } /* The callback data (i.e. pointer to the curl handle) stays even if a user callback @@ -1323,13 +1336,13 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source) ch->handlers.read->res = source->handlers.read->res; if (ZEND_FCC_INITIALIZED(source->handlers.read->fcc)) { - zend_fcc_dup(&ch->handlers.read->fcc, &source->handlers.read->fcc); + php_curl_fcc_dup(&ch->handlers.read->fcc, &source->handlers.read->fcc); } if (ZEND_FCC_INITIALIZED(source->handlers.write->fcc)) { - zend_fcc_dup(&ch->handlers.write->fcc, &source->handlers.write->fcc); + php_curl_fcc_dup(&ch->handlers.write->fcc, &source->handlers.write->fcc); } if (ZEND_FCC_INITIALIZED(source->handlers.write_header->fcc)) { - zend_fcc_dup(&ch->handlers.write_header->fcc, &source->handlers.write_header->fcc); + php_curl_fcc_dup(&ch->handlers.write_header->fcc, &source->handlers.write_header->fcc); } curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str); diff --git a/ext/curl/tests/gh25263.phpt b/ext/curl/tests/gh25263.phpt new file mode 100644 index 000000000000..663a0fa79fcb --- /dev/null +++ b/ext/curl/tests/gh25263.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-25263 (Use-after-free of __call trampoline when cloning CurlHandle) +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +trampoline +Done