curl · Report #3493602
Stack Buffer Overflow in mprintf.c formatting function (fallback path)
How it was found
Summary
A stack-based buffer overflow exists in mprintf.c within the out_double() function. This vulnerability affects builds where HAVE_SNPRINTF is undefined, forcing the use of the legacy sprintf function.
The logic responsible for calculating the maximum safe precision (maxprec) for floating-point formatting fails to correctly handle negative numbers. Specifically, it does not properly account for the number of digits required by the integer portion of negative values. As a result, the buffer size calculation is incorrect, allowing a subsequent sprintf call to write more data than the fixed-size stack buffer can hold.
Affected Component
- File:
lib/mprintf.c - Function:
out_double() - Vulnerable Condition:
HAVE_SNPRINTFis not defined at compile time
Technical Details
The function uses a local stack buffer (work) of size BUFFSIZE (326 bytes). To prevent overflow, the code attempts to estimate the number of digits required for the integer part of the floating-point value and reduce the allowable precision accordingly.
The relevant code is shown below (approx. line 675 in master):
while(val >= 10.0) {
val /= 10;
maxprec--;
}
For negative values (e.g., -1.0e100), the condition val >= 10.0 is false on entry, so the loop is skipped entirely. As a result, maxprec is not reduced, even though the integer portion of the formatted value will consume significant buffer space. The subsequent sprintf call writes the minus sign, the full integer portion, and the requested fractional precision, exceeding the 326-byte stack buffer.
Steps To Reproduce
-
Configure the Build
Compile
libcurlwithHAVE_SNPRINTFundefined to force the fallbacksprintfpath. One way to simulate this is by modifyinglib/mprintf.c:#if 0 /* Force fallback path for testing */ (snprintf)(work, BUFFSIZE, formatbuf, dnum); #else (sprintf)(work, formatbuf, dnum); /* Vulnerable path */ #endif -
Compile Reproduction Program
Compile the following C program against the modified
libcurlbuild:#include <stdio.h> #include <curl/curl.h> #include <string.h> int main(void) { // -1.0e100 requires ~102 characters for the integer part // Precision .300 requires 300 characters for the fractional part // Total output length ~402 characters // Stack buffer size in mprintf.c is 326 bytes double v = -1.0e100; char *output = curl_maprintf("%.300f", v); if (output) { printf("Output length: %lu bytes\n", (unsigned long)strlen(output)); curl_free(output); } return 0; } -
Run the Program
-
Observe
The output length exceeds the 326-byte buffer size. Depending on stack protections (stack canaries, ASLR), this results in a segmentation fault or stack smashing detection.
Suggested Fix
Correct the integer digit calculation to account for negative values by operating on the absolute value (or equivalent logic):
double absval = fabs(val);
while(absval >= 10.0) {
absval /= 10.0;
maxprec--;
}
Optionally, clamp maxprec to prevent underflow:
if(maxprec < 0)
maxprec = 0;
Impact
This vulnerability results in a classic stack-based buffer overflow.
- Availability: Denial of Service (application crash)
- Security Impact: In scenarios where the floating-point value and format string are influenced by attacker-controlled input, this issue could potentially be leveraged for further memory corruption, including control-flow manipulation.
- Scope: The vulnerable code path is part of the legacy fallback implementation and is not used in default modern curl builds. It primarily affects legacy Unix systems, embedded platforms, or custom builds where
snprintfis unavailable or explicitly disabled.