Skip to content

tool_cb_prg: signed integer overflow in overflow check #22316

Description

@xmoezzz

I did this

I built the current curl master branch (87704c4) with Clang UBSan and ran curl with --progress-bar, a one-byte upload, and a server response containing Content-Length: 9223372036854775807.

Server:

from http.server import BaseHTTPRequestHandler, HTTPServer
import time

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        self.rfile.read(int(self.headers.get("Content-Length", "0")))
        self.send_response(200)
        self.send_header("Content-Length", "9223372036854775807")
        self.end_headers()
        time.sleep(3)

    def log_message(self, *args):
        pass

HTTPServer(("127.0.0.1", 18080), Handler).handle_request()

Build:

cmake -S . -B build-ubsan -G Ninja \
  -DCMAKE_BUILD_TYPE=Debug \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_C_FLAGS="-O1 -g -fsanitize=undefined -fno-sanitize-recover=undefined -fno-omit-frame-pointer" \
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=undefined"

cmake --build build-ubsan --target curl

Command:

UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
./src/curl --http1.1 --progress-bar --max-time 1 \
  --data-binary x http://127.0.0.1:18080/ -o /dev/null

UBSan reports:

runtime error: signed integer overflow: 9223372036854775807 + 1 cannot be represented in type 'curl_off_t' (aka 'long')
    #0 0x000100b6a698 in tool_progress_cb tool_cb_prg.c
    #1 0x000100e10814 in pgrs_update progress.c:706
    #2 0x000100e10d78 in Curl_pgrsCheck progress.c:718
    #3 0x000100e31440 in Curl_sendrecv transfer.c:380
    #4 0x000100e05488 in multi_runsingle multi.c:2837
    #5 0x000100e01f30 in multi_perform multi.c:2914
    #6 0x000100dbefec in curl_easy_perform easy.c:820
    #7 0x000100b7800c in run_all_transfers tool_operate.c:2341
    #8 0x000100b77d0c in operate tool_operate.c:2505
    #9 0x000100b77534 in main tool_main.c:189
    #10 0x000184983dfc in start+0x1b4c (dyld:arm64+0xbdfc)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /omitted/curl-master/src/tool_cb_prg.c:143:59
[1]    39438 abort      UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./build-ubsan/src/curl    1

The overflow occurs in the overflow check itself:

else if((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal))

Here, dltotal is CURL_OFF_T_MAX from the response Content-Length, and ultotal is 1.

I expected the following

The progress-bar size calculation should avoid signed overflow.

curl/libcurl version

curl master branch (87704c4)

operating system

macOS arm64
ProductName: macOS
ProductVersion: 26.5.2
BuildVersion: 25F84

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions