Skip to content

Free of Interior Heap Pointer in varfunc() #21898

Description

@hahahkim

I did this

When varfunc() in src/var.c processes a chained variable-expansion that places trim after any function that can emit leading whitespace, the trim handler advances the working pointer c past the leading whitespace characters in-place.

A shared cleanup block that follows every function iteration then calls curlx_free(c) on that shifted, interior pointer instead of on the original allocation base.

c is updated here:

curl/src/var.c

Lines 94 to 112 in 7c34365

if(FUNCMATCH(f, FUNC_TRIM, FUNC_TRIM_LEN)) {
size_t len = clen;
f += FUNC_TRIM_LEN;
if(clen) {
/* skip leading white space, including CRLF */
while(ISSPACE(*c)) {
c++;
len--;
}
while(len && ISSPACE(c[len - 1]))
len--;
}
/* put it in the output */
curlx_dyn_reset(out);
if(curlx_dyn_addn(out, c, len)) {
err = PARAM_NO_MEM;
break;
}
}

and freed here:

curl/src/var.c

Lines 188 to 189 in 7c34365

if(alloc)
curlx_free(c);

This bug can easily trigger ASAN using 64dec and trim as belows.
64dec causes the buffer allocation, and whitespaces in the decoded data triggers trim to update c

$ ./curl --variable VAR=IA== --expand-url 'http://localhost:9999/{{VAR:64dec:trim}}'

=================================================================
==3844293==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x503000020111 in thread T0
    #0 0x77b04e6fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x77b04e3752f7 in curl_dbg_free /home/eunsookim/repo/curl/curl-latest/lib/memdebug.c:385
    #2 0x5f4a82aef203 in varfunc /home/eunsookim/repo/curl/curl-latest/src/var.c:189
    #3 0x5f4a82aefbbb in varexpand /home/eunsookim/repo/curl/curl-latest/src/var.c:298
    #4 0x5f4a82abeb00 in getparameter /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3022
    #5 0x5f4a82abf6be in parse_args /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3154
    #6 0x5f4a82ad4826 in operate /home/eunsookim/repo/curl/curl-latest/src/tool_operate.c:2421
    #7 0x5f4a82ac55c5 in main /home/eunsookim/repo/curl/curl-latest/src/tool_main.c:189
    #8 0x77b04d82a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
    #9 0x77b04d82a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
    #10 0x5f4a82a8f5e4 in _start (/home/eunsookim/repo/curl/curl-latest/bld-asan/src/curl+0xad5e4) (BuildId: 4f63030c99f8e089db65531fce2cdee9bef8685b)

0x503000020111 is located 1 bytes inside of 18-byte region [0x503000020110,0x503000020122)
allocated by thread T0 here:
    #0 0x77b04e6fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x77b04e374dce in curl_dbg_malloc /home/eunsookim/repo/curl/curl-latest/lib/memdebug.c:224
    #2 0x5f4a82af604a in curlx_memdup0 /home/eunsookim/repo/curl/curl-latest/lib/curlx/strdup.c:87
    #3 0x5f4a82aef23d in varfunc /home/eunsookim/repo/curl/curl-latest/src/var.c:192
    #4 0x5f4a82aefbbb in varexpand /home/eunsookim/repo/curl/curl-latest/src/var.c:298
    #5 0x5f4a82abeb00 in getparameter /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3022
    #6 0x5f4a82abf6be in parse_args /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3154
    #7 0x5f4a82ad4826 in operate /home/eunsookim/repo/curl/curl-latest/src/tool_operate.c:2421
    #8 0x5f4a82ac55c5 in main /home/eunsookim/repo/curl/curl-latest/src/tool_main.c:189
    #9 0x77b04d82a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
    #10 0x77b04d82a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
    #11 0x5f4a82a8f5e4 in _start (/home/eunsookim/repo/curl/curl-latest/bld-asan/src/curl+0xad5e4) (BuildId: 4f63030c99f8e089db65531fce2cdee9bef8685b)

SUMMARY: AddressSanitizer: bad-free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52 in free
==3844293==ABORTING

As it can be only triggered in local with specific options and is hard to exploit, I'm reporting this as a bug rather than a security issue.

I expected the following

curlx_free should free the original base of the allocated buffer c.

curl/libcurl version

curl 8.21.0-DEV (Linux)

operating system

Linux 6.6.87.2

The initial discovery was made by AI (MDASH).
The analysis, exploitation, and this report have been reviewed and verified by human experts.

Reporting on behalf of Autonomous Code Security (ACS) team at Microsoft.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions