curl / Mailing Lists / curl-library / Single Mail

curl-library

SIGSEGV after curl_easy_cleanup in libuv app.

From: Vitaliy T <vitaliy.tokarev_at_gmail.com>
Date: Thu, 6 Apr 2017 23:41:58 +0300

Hello,

I have wrote a program which uses libuv and libcurl. In general, it is
a multi-threaded program, based on the (libuv) worker pool concept.
Each worker does its job and later may send the result to the main
thread (loop).

The error occurs when all workers are completed their job. You have to
wait a bit before SIGSEGV would occur. I am not sure if I am doing
something wrong:
1. Is it safe to call curl_easy_* functions from threads?
2. Is it my mistake because of I coded libuv incorrectly?
3. Do I need to apply some special patches to libcurl in my case?

Here is the output from gdb under Alpine Linux (see details below):

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x4f76bae4 in dprintf_Pass1 (format=0xfffc6c7a <error: Cannot
access memory at address 0xfffc6c7a>, vto=0x4f4aa884,
endpos=0x4f4aa684,
    arglist=0x4f4ab6a8 "\314\071\177O⨅O\215\003") at mprintf.c:247
247 while(*fmt) {
[Current thread is 1 (LWP 8917)]
(gdb) bt
#0 0x4f76bae4 in dprintf_Pass1 (format=0xfffc6c7a <error: Cannot
access memory at address 0xfffc6c7a>, vto=0x4f4aa884,
endpos=0x4f4aa684,
    arglist=0x4f4ab6a8 "\314\071\177O⨅O\215\003") at mprintf.c:247
#1 0x4f76bf05 in dprintf_formatf (data=0x4f4ab640, stream=0x4f76d195
<addbyter>, format=0xfffc6c7a <error: Cannot access memory at address
0xfffc6c7a>,
    ap_save=0x4f4ab6a8 "\314\071\177O⨅O\215\003") at mprintf.c:596
#2 0x4f76d24c in curl_mvsnprintf (buffer=0x0, maxlength=16384,
format=0xfffc6c7a <error: Cannot access memory at address 0xfffc6c7a>,
    ap_save=0x4f4ab6a8 "\314\071\177O⨅O\215\003") at mprintf.c:1016
#3 0x4f754271 in Curl_failf (data=0x4f4ab754, fmt=0xfffc6c7a <error:
Cannot access memory at address 0xfffc6c7a>) at sendf.c:248
#4 0x4f744f17 in Curl_resolv_timeout (conn=0x39fb4,
hostname=0x4f824354 "\274\002", port=1330296892, entry=0x0,
timeoutms=0) at hostip.c:622
#5 0x4f587ab1 in ERR_remove_thread_state () from /lib/libcrypto.so.1.0.0
#6 0x4f86512e in __libc_sigaction (sig=13, sa=0x4f4aba8c, old=0x0) at
src/signal/sigaction.c:44
#7 0x4f77e746 in sigpipe_restore (ig=0x3b8) at sigpipe.h:68
#8 0x4f8458b1 in alloc_fwd (c=0x4f4abd48) at src/malloc/malloc.c:232
#9 0x4f8458b1 in alloc_fwd (c=0x9040) at src/malloc/malloc.c:232
#10 0x4f845aaf in free (p=0x4f864e8b <__restore>) at src/malloc/malloc.c:470
#11 0x04000000 in ?? ()
#12 0x4f864e8b in getitimer (which=<optimized out>, old=0x196f9a34) at
src/signal/getitimer.c:6
#13 0x00000000 in ?? ()

Investigation shows that the error caused by passing an invalid
address to the snprintf() function in the "lib/sendf.c" file:

      242 void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
      243 {
      244 va_list ap;
      245 size_t len;
      246 va_start(ap, fmt);
      247
      248 vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
      249
      250 if(data->set.errorbuffer && !data->state.errorbuf) {
      251 snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s",
data->state.buffer);
[...]

Here, data->set.errorbuffer has the invalid address because of struct
Curl_easy *data has been freed by curl_easy_cleanup() before. The
later call by sigpipe_restore() will use the invalid *data handler.

I have attached an archive with the example, strace(1) and gdb(1) outputs.

Tested on next virtual machines:

OS: Alpine Linux (x86, 32-bit) 3.5
uname: Linux alpine 4.4.52-0-grsec #1-Alpine SMP Tue Feb 28 10:15:44
GMT 2017 i686 GNU/Linux
libcurl version:

1. libcurl-7.52.1-r2 (distributive package)
curl 7.52.1 (i586-alpine-linux-musl) libcurl/7.54.0-DEV OpenSSL/1.0.2k
zlib/1.2.8 libssh2/1.6.0
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s
rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: Debug TrackMemory IPv6 Largefile NTLM NTLM_WB SSL libz
TLS-SRP UnixSockets HTTPS-proxy

2. curl 7.54.0-DEV (git/master)
curl 7.54.0-DEV (i686-pc-linux-gnu) libcurl/7.54.0-DEV OpenSSL/1.0.2k
zlib/1.2.8 libssh2/1.6.0
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s
rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: Debug TrackMemory IPv6 Largefile NTLM NTLM_WB SSL libz
TLS-SRP UnixSockets HTTPS-proxy

libuv version: libuv-1.9.1-r0 and libuv 1.11.1-dev (git/master)
musl version: musl-1.1.15-r6 (distributive package)
gcc version: 6.2.1 20160822 (Alpine 6.2.1) (distributive package)

Result: SIGSEGV

================================

OS: Kali Linux 2016.2 (amd64)
uname: Linux kali 4.9.0-kali2-amd64 #1 SMP Debian 4.9.13-1kali1
(2017-03-01) x86_64 GNU/Linux
libcurl version:

1. 7.52.1-3 (distributive package)
curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2k
zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0
nghttp2/1.18.1 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps
pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM
NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

2. 7.54.0-DEV (git/master)
curl 7.54.0-DEV (x86_64-pc-linux-gnu) libcurl/7.54.0-DEV
OpenSSL/1.1.0e zlib/1.2.8
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s
rtsp smb smbs smtp smtps telnet tftp
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP UnixSockets HTTPS-proxy

libuv version: 1.9.1-3 (distributive package)
glibc version: 2.24-9 (distributive package)
gcc version: 6.3.0 20170205 (Debian 6.3.0-6)

Results:
1. OK under libcurl 7.52.1-3 (distributive package). But I've noticed
that strace(1) does not show any sigaction calls.
2. SIGSEGV under libcurl 7.54.0-DEV (there are sigaction calls)

================================

OS: CentOS 7 (amd64)
uname: Linux localhost.localdomain 3.10.0-514.el7.x86_64 #1 SMP Tue
Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
libcurl version:

1. 7.29.0 35.el7.centos
curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.21 Basic
ECC zlib/1.2.7 libidn/1.28 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps
pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL
libz unix-sockets

2. 7.54.0-DEV (git/master)
curl 7.54.0-DEV (x86_64-unknown-linux-gnu) libcurl/7.54.0-DEV
OpenSSL/1.0.1e zlib/1.2.7
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s
rtsp smb smbs smtp smtps telnet tftp
Features: Debug TrackMemory IPv6 Largefile NTLM NTLM_WB SSL libz
UnixSockets HTTPS-proxy

libuv version: 1.11.1-dev (git/master)
glibc version: 2.17 157.el7_3.1
gcc version: 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)

Results:
1. OK under libcurl 7.29.0 (again, strace(1) does not show any sigaction calls).
2. SIGSEGV under libcurl 7.54.0-DEV

================================

Also, I have built libcurl 7.54.0-DEV with patches from Debian, but I
have still got segfaults.
Thanks!

-- 
With Best Regards,
Vitaliy V. Tokarev


-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette: https://curl.haxx.se/mail/etiquette.html

Received on 2017-04-06