cURL库mprintf.c中栈缓冲区溢出漏洞深度分析

本文详细分析了在cURL库的mprintf.c格式化函数中发现的栈缓冲区溢出漏洞。该漏洞源于旧版回退代码中浮点数负值处理不当,可能导致拒绝服务甚至代码执行风险。

Stack Buffer Overflow in cURL mprintf.c Formatting Function (Fallback Path) - Report #3493602

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_SNPRINTF is 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):

1
2
3
4
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

1. Configure the Build

Compile libcurl with HAVE_SNPRINTF undefined to force the fallback sprintf path. One way to simulate this is by modifying lib/mprintf.c:

1
2
3
4
5
#if 0 /* Force fallback path for testing */
  (snprintf)(work, BUFFSIZE, formatbuf, dnum);
#else
  (sprintf)(work, formatbuf, dnum); /* Vulnerable path */
#endif

2. Compile Reproduction Program

Compile the following C program against the modified libcurl build:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#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;
}

3. Run the Program

4. 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):

1
2
3
4
5
6
double absval = fabs(val);

while(absval >= 10.0) {
  absval /= 10.0;
  maxprec--;
}

Optionally, clamp maxprec to prevent underflow:

1
2
if(maxprec < 0)
  maxprec = 0;

Impact

This vulnerability results in a classic stack-based buffer overflow.

  • Availability: Denial of Service (application crash)

  • 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 snprintf is unavailable or explicitly disabled.

Discussion Timeline

bagder (curl staff) posted a comment. Updated 4 days ago @han_ank please mention a platform where this happens with unaltered source code

jimfuller2024 (curl staff) posted a comment. 3 days ago which platforms … maybe really old linuxes (I remember some older bsd variants, of course System V!) … maybe some embedded systems (TinyOS or FreeRTOS) … there is virtually no ‘surface area’ here which might indicate we can deprecate this all together.

jimfuller2024 (curl staff) posted a comment. 3 days ago forgot to mention - but I am not even certain TinyOS can build curl … maybe someone has done it with FreeRTOS

bagder (curl staff) posted a comment. 3 days ago There were some systems in the 90s that lacked snprintf. Even really old Windows back in those days I believe might had lacked it. In the last twenty or so years even embedded systems have been made with proper libc implementations that offer snprintf. I have not been able to find anything done in the last decades that do not offer snprintf. snprintf() is mandated by the C99 standard, which as the name suggests, came around 1999. libc implementations intended to work with C99 then need to offer the function. As we cannot find any system that is not a legacy end of life one, we cannot consider this a valid vulnerability - but a bug. To completely avoid this discussion from happening again, we remove the sprintf() fallback from the code: https://github.com/curl/curl/pull/20218

ankitsingh015 posted a comment. 3 days ago

bagder (curl staff) closed the report and changed the status to Informative. 3 days ago Thanks for your report. Closed as informative as it identifies a problem (now fixed).

bagder (curl staff) requested to disclose this report. 3 days ago Per project policy for transparency, we want all reports disclosed and made public.

ankitsingh015 agreed to disclose this report. 3 days ago This report has been disclosed. 3 days ago

Report Details

  • Reported on: January 7, 2026, 10:12pm UTC
  • Reported by: ankitsingh015
  • Reported to: curl
  • Report Id: #3493602
  • Status: Informative
  • Severity: High (7 ~ 8.9)
  • Disclosed: January 8, 2026, 9:36am UTC
  • Weakness: Classic Buffer Overflow
  • CVE ID: None
  • Bounty: None
  • Account details: None
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计