8000 if CURLOPT_OPENSOCKETFUNCTION callback sets CURLOPT_ERRORBUFFER string, string will be overwritten · Issue #17100 · curl/curl · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

if CURLOPT_OPENSOCKETFUNCTION callback sets CURLOPT_ERRORBUFFER string, string will be overwritten #17100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MaxEliaserAWS opened this issue Apr 19, 2025 · 4 comments
Labels
libcurl API not-a-curl-bug This is not a bug in curl

Comments

@MaxEliaserAWS
Copy link

I did this

  • Set the CURLOPT_ERRORBUFFER option to a char array
  • Implement a CURLOPT_OPENSOCKETFUNCTION callback
  • Callback should put some kind of string in the CURLOPT_ERRORBUFFER buffer and then return CURL_SOCKET_BAD

I expected the following

The CURLOPT_ERRORBUFFER buffer should contain the string set by the CURLOPT_OPENSOCKETFUNCTION after curl_easy_perform has returned

curl/libcurl version

I have bisected this to commit 71b7e01 (lib: connect/h2/h3 refactor)

I believe this commit was released in CURL 7.88.x. I skimmed the changelog at https://curl.se/changes.html#7_88_0 and I could not find anything to suggest that this change was intentional. I also compared the docs using curl-7_87_0...curl-7_88_0 and git diff curl-7_87_0...curl-7_88_0 -- docs/libcurl/ and I also could not find anything there to suggest this change was intentional. Perhaps I missed something though.

operating system

I have demonstrated this issue on AmazonLinux 2023 using the packaged libcurl. I have also demonstrated the issue on AmazonLinux 2 and Ubuntu 20.04 using my own compiled libcurl. All of this testing was done using various x86_64 machines.

@MaxEliaserAWS
Copy link
Author

I am tentatively classifying this issue as a regression in the LibCURL, introduced in the 7.88 release. I checked the known bugs list and open GitHub issues and did not find anything that looks like a match.

Urgency and expectations

I am not immediately blocked by this issue and I'm not demanding a fix right away or anything. I am able to work around it. If you elect not to prioritize this issue, that is fine-- I just need a ticket I can reference to explain why I am applying a workaround in our codebase, hence why I am filing this.

Regardless of your decision we remain grateful for your efforts on this crucial piece of Internet infrastructure.

To Reproduce

  • Set the CURLOPT_ERRORBUFFER option to a char array
  • Implement a CURLOPT_OPENSOCKETFUNCTION callback
  • Callback should put some kind of string in the CURLOPT_ERRORBUFFER buffer and then return CURL_SOCKET_BAD

Expected result

The CURLOPT_ERRORBUFFER buffer should contain the string set by the CURLOPT_OPENSOCKETFUNCTION after curl_easy_perform has returned

Actual result

The CURLOPT_ERRORBUFFER contains a generic error message

Operating system

I have demonstrated this issue on AmazonLinux 2023 using the packaged libcurl. I have also demonstrated the issue on AmazonLinux 2 and Ubuntu 20.04 using my own compiled libcurl. All of this testing was done using various x86_64 machines.

Bisect result

I have bisected this to commit 71b7e01 (lib: connect/h2/h3 refactor)

I believe this commit was released in CURL 7.88.x. I skimmed the changelog at https://curl.se/changes.html#7_88_0 and I could not find anything to suggest that this change was intentional. I also compared the docs using curl-7_87_0...curl-7_88_0 and git diff curl-7_87_0...curl-7_88_0 -- docs/libcurl/ and I also could not find anything there to suggest this change was intentional. Perhaps I missed something though.

Demo program

I have written a short, but complete C program to demonstrate the issue.

// Usage:
// gcc -o demonstrate_libcurl_problem demonstrate_libcurl_problem.c -lcurl

#include <stdio.h>
#include <curl/curl.h>
#include <string.h>

static curl_socket_t opensocket_callback(void *clientp,
                                       curlsocktype purpose,
                                       struct curl_sockaddr *address)
{
    char *errbuf = (char *)clientp;
    snprintf(errbuf, CURL_ERROR_SIZE, "My custom error message");
    return CURL_SOCKET_BAD;
}

int main(void)
{
    CURL *curl = curl_easy_init();
    char errbuf[CURL_ERROR_SIZE] = {0};
    
    curl_easy_setopt(curl, CURLOPT_URL, "http://example.org/");
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
    curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_callback);
    curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, errbuf);

    CURLcode res = curl_easy_perform(curl);
    printf("Error buffer: %s\n", errbuf);

    curl_easy_cleanup(curl);
    return 0;
}

Example good output:

~/src$ LD_LIBRARY_PATH=/tmp/curl/lib/.libs ./demonstrate_libcurl_problem
./demonstrate_libcurl_problem: /tmp/curl/lib/.libs/libcurl.so.4: no version information available (required by ./demonstrate_libcurl_problem)
Error buffer: My custom error message

Example bad output:

~/src$ LD_LIBRARY_PATH=/tmp/curl/lib/.libs ./demonstrate_libcurl_problem
./demonstrate_libcurl_problem: /tmp/curl/lib/.libs/libcurl.so.4: no version information available (required by ./demonstrate_libcurl_problem)
Error buffer: Failed to connect to example.org port 80 after 24 ms: Couldn't connect to server

Mild debugging

I have used gdb to show that the overwrite happens in Curl_failf as called by cf_he_connect.

~/src$ LD_LIBRARY_PATH=/tmp/curl/lib/.libs gdb ./demonstrate_libcurl_problem
[...]
(gdb) b 27
Breakpoint 1 at 0x15aa: file demonstrate_libcurl_problem.c, line 27.
(gdb) r
Starting program: /home/eliaserm/src/demonstrate_libcurl_problem
[...]
Breakpoint 1, main () at demonstrate_libcurl_problem.c:27
27          CURLcode res = curl_easy_perform(curl);
(gdb) p errbuf
$1 =   '\000' <repeats 255 times>
(gdb) p &errbuf[0]
$2 = 0x7fffffffda50 ""
(gdb) watch *(char*)0x7fffffffda50
Hardware watchpoint 2: *(char*)0x7fffffffda50
(gdb) c
Continuing.
[...]
Thread 1 "demonstrate_lib" hit Hardware watchpoint 2: *(char*)0x7fffffffda50

Old value = 0 '\000'
New value = 77 'M'
__memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:307
307     ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: No such file or directory.
(gdb) bt
#0  __memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:307
#1  0x00007ffff7dbf059 in __GI__IO_default_xsputn (n=<optimized out>, data=<optimized out>, f=<optimized out>) at genops.c:386
#2  __GI__IO_default_xsputn (f=0x7fffffffcf50, data=<optimized out>, n=23) at genops.c:370
#3  0x00007ffff7da3972 in __vfprintf_internal (s=s@entry=0x7fffffffcf50, format=format@entry=0x555555556004 "My custom error message", ap=ap@entry=0x7fffffffd0d0, mode_flags=mode_flags@entry=0) at ../libio/libioP.h:948
#4  0x00007ffff7db8f9a in __vsnprintf_internal (string=0x7fffffffda50 "My custom error ", maxlen=<optimized out>, format=0x555555556004 "My custom error message", args=args@entry=0x7fffffffd0d0, mode_flags=mode_flags@entry=0) at vsnprintf.c:114
#5  0x00007ffff7d8edf6 in __GI___snprintf (s=<optimized out>, maxlen=<optimized out>, format=<optimized out>) at snprintf.c:31
#6  0x000055555555538f in opensocket_callback (clientp=0x7fffffffda50, purpose=CURLSOCKTYPE_IPCXN, address=0x555555578388) at demonstrate_libcurl_problem.c:13
#7  0x00007ffff7f456b0 in Curl_socket_open () from /tmp/curl/lib/.libs/libcurl.so.4
#8  0x00007ffff7f4583d in cf_socket_open () from /tmp/curl/lib/.libs/libcurl.so.4
#9  0x00007ffff7f464b5 in cf_tcp_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#10 0x00007ffff7f48e64 in cf_he_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#11 0x00007ffff7f4988e in cf_setup_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#12 0x00007ffff7f47216 in Curl_conn_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#13 0x00007ffff7f74a99 in multi_runsingle () from /tmp/curl/lib/.libs/libcurl.so.4
#14 0x00007ffff7f75e66 in curl_multi_perform () from /tmp/curl/lib/.libs/libcurl.so.4
#15 0x00007ffff7f5267b in curl_easy_perform () from /tmp/curl/lib/.libs/libcurl.so.4
#16 0x00005555555555b9 in main () at demonstrate_libcurl_problem.c:27
(gdb) c
Continuing.
[...]
(more repetitions of opensocket_callback mutating the string have been removed from this transcript)
[...]
Thread 1 "demonstrate_lib" hit Hardware watchpoint 2: *(char*)0x7fffffffda50

Old value = 77 'M'
New value = 70 'F'
0x00007ffff7eb6e8e in __strcpy_avx2 () at ../sysdeps/x86_64/multiarch/strcpy-avx2.S:103
103     ../sysdeps/x86_64/multiarch/strcpy-avx2.S: No such file or directory.
(gdb) bt
#0  0x00007ffff7eb6e8e in __strcpy_avx2 () at ../sysdeps/x86_64/multiarch/strcpy-avx2.S:103
#1  0x00007ffff7f7cc20 in Curl_failf () from /tmp/curl/lib/.libs/libcurl.so.4
#2  0x00007ffff7f48d24 in cf_he_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#3  0x00007ffff7f4988e in cf_setup_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#4  0x00007ffff7f47216 in Curl_conn_connect () from /tmp/curl/lib/.libs/libcurl.so.4
#5  0x00007ffff7f74a99 in multi_runsingle () from /tmp/curl/lib/.libs/libcurl.so.4
#6  0x00007ffff7f75e66 in curl_multi_perform () from /tmp/curl/lib/.libs/libcurl.so.4
#7  0x00007ffff7f5267b in curl_easy_perform () from /tmp/curl/lib/.libs/libcurl.so.4
8000

#8  0x00005555555555b9 in main () at demonstrate_libcurl_problem.c:27
(gdb) finish
Run till exit from #0  0x00007ffff7eb6e8e in __strcpy_avx2 () at ../sysdeps/x86_64/multiarch/strcpy-avx2.S:103
0x00007ffff7f7cc20 in Curl_failf () from /tmp/curl/lib/.libs/libcurl.so.4
(gdb) p (char*)0x7fffffffda50
$3 = 0x7fffffffda50 "Failed to connect to example.org port 80 after 23797 ms: Couldn't connect to server"
(gdb)

@bagder
Copy link
Member
bagder commented Apr 19, 2025

The CURLOPT_ERRORBUFFER buffer should contain the string set by the CURLOPT_OPENSOCKETFUNCTION after curl_easy_perform has returned

I don't think libcurl gives any promises that allow the application to update the error buffer like this without the risk that the library overwrites it. The error buffer is intended to be used by libcurl itself.

I think you should use a separate buffer for your application's own needs.

@MaxEliaserAWS
Copy link
Author

Thank you for the explanation. I have put up a simple documentation patch (pr #17105) to add this information.

bagder pushed a commit that referenced this issue Apr 22, 2025
@bagder
Copy link
Member
bagder commented Apr 22, 2025

Docs update #17105 merged

@bagder bagder closed this as completed Apr 22, 2025
nbaws pushed a commit to nbaws/curl that referenced this issue Apr 26, 2025
nbaws pushed a commit to nbaws/curl that referenced this issue Apr 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libcurl API not-a-curl-bug This is not a bug in curl
Development

No branches or pull requests

2 participants
0