curl · Report #3575245
Integer Overflow in curl_multi_get_handles() Leading to Heap Buffer Overflow
How it was found
Integer Overflow in curl_multi_get_handles() Leading to Heap Buffer Overflow
Summary
The curl_multi_get_handles() function in lib/multi.c contains an integer overflow vulnerability when the number of easy handles in a multi handle approaches UINT_MAX (4,294,967,295). When count == UINT_MAX, the expression count + 1 overflows to 0, causing malloc(0) to return a non-NULL pointer. Subsequent write operations a[i++] = data then write beyond the allocated buffer, resulting in a heap buffer overflow. While exploitation requires extreme resource consumption (~32TB memory for ~4.3 billion handles), this represents a memory safety violation that should be addressed.
PoC Concept:
// lib/multi.c:3728-3729
unsigned int count = Curl_uint32_tbl_count(&multi->xfers);
CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1)); // OVERFLOW when count == UINT_MAX
// When count == 0xFFFFFFFF: count + 1 = 0, malloc(0) returns non-NULL
// Subsequent a[i++] = data writes to undersized buffer
Affected Version
curl version: 8.18.0 (API curl_multi_get_handles() introduced in this version)
Platform: All platforms (64-bit systems theoretically exploitable, 32-bit systems not exploitable due to address space limits)
curl 8.18.0 (x86_64-pc-linux-gnu) libcurl/8.18.0 OpenSSL/3.0.0 zlib/1.2.13
Release-Date: 2026-01-07
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTP3 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets zstd
Steps to Reproduce
Method 1: Code Analysis (Recommended)
- Examine the vulnerable code in
lib/multi.c:3724-3745:
CURL **curl_multi_get_handles(CURLM *m)
{
struct Curl_multi *multi = m;
void *entry;
unsigned int count = Curl_uint32_tbl_count(&multi->xfers);
CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1)); // VULNERABLE
if(a) {
unsigned int i = 0;
uint32_t mid;
if(Curl_uint32_tbl_first(&multi->xfers, &mid, &entry)) {
do {
struct Curl_easy *data = entry;
DEBUGASSERT(i < count);
if(!data->state.internal)
a[i++] = data; // Write to potentially undersized buffer
} while(Curl_uint32_tbl_next(&multi->xfers, mid, &mid, &entry));
}
a[i] = NULL;
}
return a;
}
- Observe that when
count == 0xFFFFFFFF(UINT_MAX):count + 1overflows to0malloc(sizeof(void*) * 0)=malloc(0)returns non-NULL- Subsequent writes cause heap buffer overflow
Method 2: Simulation PoC
Run the attached Python PoC to see the overflow demonstration:
# Simulate integer overflow
count = 0xFFFFFFFF # UINT_MAX
overflow_result = (count + 1) & 0xFFFFFFFF # Result: 0
# Memory allocation would be:
element_size = 8 # sizeof(void*) on 64-bit
alloc_size = element_size * overflow_result # = 0 bytes
# malloc(0) returns non-NULL pointer
# Subsequent writes overflow the buffer
Method 3: Stress Test (Theoretical)
The following code demonstrates the attack path (not practical due to memory requirements):
#include <curl/curl.h>
#include <limits.h>
int main() {
CURLM *multi = curl_multi_init();
// Would need ~4.3 billion iterations
// Requiring ~32TB of memory
for(unsigned long i = 0; i < UINT_MAX; i++) {
CURL *easy = curl_easy_init();
curl_easy_setopt(easy, CURLOPT_URL, "http://example.com");
curl_multi_add_handle(multi, easy);
}
// This triggers the overflow
CURL **handles = curl_multi_get_handles(multi);
// handles points to undersized buffer
// Writing to handles[0] causes heap overflow
return 0;
}
Impact
Security Impact
-
Heap Buffer Overflow: When triggered, this vulnerability causes a write to memory beyond the allocated buffer boundary. This can lead to:
- Memory corruption
- Denial of Service (crash)
- Potential arbitrary code execution (though exploitation is extremely difficult)
-
Memory Safety Violation: This represents a fundamental violation of memory safety principles in a widely-used library.
Practical Exploitability
| Factor | Assessment |
|---|---|
| Memory Required | ~32TB (each handle ~8KB × 4.3 billion handles) |
| Time Required | ~50 days at 1,000 handles/sec |
| 32-bit Systems | Not exploitable (4GB address space limit) |
| 64-bit Systems | Theoretically exploitable but impractical |
| Real-world Impact | LOW - Extreme resource requirements make practical exploitation nearly impossible |
Why This Still Matters
- Code Quality: This is a clear violation of secure coding practices (CWE-190: Integer Overflow)
- Future Risk: As memory becomes cheaper, the exploitability threshold may become more achievable
- Similar Patterns: This vulnerability pattern might exist in other parts of the codebase
- Defensive Programming: Adding the overflow check is a simple one-line fix that improves code robustness
Recommended Fix
unsigned int count = Curl_uint32_tbl_count(&multi->xfers);
/* Prevent integer overflow */
if(count == UINT_MAX) {
return NULL;
}
CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1));
Attachments
curl_multi_overflow_poc.py- Python simulation demonstrating the overflow conceptcurl_multi_overflow_poc.c- C PoC (requires libcurl)
Credit: Sun Tao Date: 2026-02-26
Impact
Summary:
The curl_multi_get_handles() function in lib/multi.c contains an integer overflow vulnerability when the number of easy handles in a multi handle approaches UINT_MAX (4,294,967,295). When count == UINT_MAX, the expression count + 1 overflows to 0, causing malloc(0) to return a non-NULL pointer. Subsequent write operations a[i++] = data then write beyond the allocated buffer, resulting in a heap buffer overflow. While exploitation requires extreme resource consumption (~32TB memory for ~4.3 billion handles), this represents a memory safety violation that should be addressed.