On Wed, Apr 25 2018, Joel Sing <[email protected]> wrote:
> On Wednesday 25 April 2018 15:29:32 Joel Sing wrote:
>> On Tuesday 24 April 2018 12:07:10 Philip Guenther wrote:
>> > On Tue, 24 Apr 2018, Jeremie Courreges-Anglas wrote:
>> > ...
>> >
>> > > We took a quick look yesterday, the crash happens in dtors, the cause of
>> > > the crash looks like a use after free. I'm not a BIO_* hacker, here's
>> > > a stack trace on amd64, curl rebuilt with DEBUG=-g:
>> > >
>> > > Program received signal SIGBUS, Bus error.
>> > > p 0x000005738701c2d7 in BIO_write (b=0x5735f58b080, in=0x573e9a05400,
>> > > inl=24) at /usr/src/lib/libcrypto/bio/bio_lib.c:289 289 if
>> > > ((b->method == NULL) || (b->method->bwrite == NULL)) { (gdb) p *b
>> > > $1 = {method = 0xdfdfdfdfdfdfdfdf, callback = 0xdfdfdfdfdfdfdfdf, cb_arg
>> > > =
>> > > 0xdfdfdfdfdfdfdfdf <error: Cannot access memory at address
>> > > 0xdfdfdfdfdfdfdfdf>, init = -538976289, shutdown = -538976289, flags =
>> > > -538976289,>
>> > >
>> > > retry_reason = -538976289, num = -538976289, ptr = 0xdfdfdfdfdfdfdfdf,
>> > > next_bio = 0xdfdfdfdfdfdfdfdf, prev_bio = 0xdfdfdfdfdfdfdfdf,
>> > > references = -538976289, num_read = 16131858542891098079, num_write =
>> > > 16131858542891098079, ex_data = {sk = 0xdfdfdfdfdfdfdfdf}}>
>> > >
>> > > (gdb) bt
>> > > #0 0x000005738701c2d7 in BIO_write (b=0x5735f58b080, in=0x573e9a05400,
>> > > inl=24) at /usr/src/lib/libcrypto/bio/bio_lib.c:289 #1
>> > > 0x00000573bd3467ab in __sflush (fp=0x573bd5b9410 <usual>) at
>> > > /usr/src/lib/libc/stdio/fflush.c:80 #2 0x00000573bd34aa5f in _fwalk
>> > > (function=0x573bd346740 <__sflush>) at
>> > > /usr/src/lib/libc/stdio/fwalk.c:50
>> > > #3 0x00000573bd2ffd8c in _libc___cxa_finalize (dso=0x0) at
>> > > /usr/src/lib/libc/stdlib/atexit.c:177 #4 0x00000573bd2ea9f1 in
>> > > _libc_exit (status=0) at /usr/src/lib/libc/stdlib/exit.c:54 #5
>> > > 0x00000570ee100b0d in _start ()
>> > > (gdb)
>> >
>> > So these BIOs are used with funopen()? I smells like the BIO is being
>> > closed directly instead of being closed with fclose(), with the result
>> > that stdio still has a reference to it and you get the flush later trying
>> > to access the freed BIO.
>>
>> This is a bug in torsocks - torsocks is just a shell script that preloads
>> libtorsocks.so, which hijacks a bunch of libc symbols. Their implementation
>> for fclose() is broken and does not work properly with things that have been
>> funopen()'d - in short, they call fileno() and check that the resulting fd
>> > 0 and if it is not they return without calling the libc fclose(). This
>> leaves a dangling fp, which the dtors later try to flush. The fix is
>> probably to unconditionally call the libc fclose() regardless of what the
>> fd is. FWIW in this case the corresponding funopen is from libcrypto's
>> BIO_vprintf().
>
> This appears to resolve the issue:
Hah, I just cooked a very similar diff (see below). Yours looks fine
too, ok jca@
> Index: Makefile
> ===================================================================
> RCS file: /cvs/ports/net/torsocks/Makefile,v
> retrieving revision 1.11
> diff -u -p -u -p -r1.11 Makefile
> --- Makefile 29 Jan 2018 21:44:30 -0000 1.11
> +++ Makefile 25 Apr 2018 09:03:23 -0000
> @@ -3,6 +3,7 @@
> COMMENT = socks proxy for use with tor
>
> DISTNAME = torsocks-2.2.0
> +REVSION = 0
>
> GH_PROJECT = torsocks
> GH_ACCOUNT = dgoulet
> Index: patches/patch-src_lib_fclose_c
> ===================================================================
> RCS file: patches/patch-src_lib_fclose_c
> diff -N patches/patch-src_lib_fclose_c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ patches/patch-src_lib_fclose_c 25 Apr 2018 09:03:23 -0000
> @@ -0,0 +1,21 @@
> +$OpenBSD$
> +
> +Unbreak funopen usage with libtorsocks - always call the libc fclose
> +function, even when fd < 0.
> +
> +Index: src/lib/fclose.c
> +--- src/lib/fclose.c.orig
> ++++ src/lib/fclose.c
> +@@ -64,11 +64,9 @@ LIBC_FCLOSE_RET_TYPE tsocks_fclose(LIBC_FCLOSE_SIG)
> + connection_put_ref(conn);
> + }
> +
> ++error:
> + /* Return the original libc fclose. */
> + return tsocks_libc_fclose(fp);
> +-
> +-error:
> +- return -1;
> + }
> +
> + /*
>
Index: Makefile
===================================================================
RCS file: /d/cvs/ports/net/torsocks/Makefile,v
retrieving revision 1.11
diff -u -p -r1.11 Makefile
--- Makefile 29 Jan 2018 21:44:30 -0000 1.11
+++ Makefile 25 Apr 2018 10:13:13 -0000
@@ -3,6 +3,7 @@
COMMENT = socks proxy for use with tor
DISTNAME = torsocks-2.2.0
+REVISION = 0
GH_PROJECT = torsocks
GH_ACCOUNT = dgoulet
Index: patches/patch-src_lib_fclose_c
===================================================================
RCS file: patches/patch-src_lib_fclose_c
diff -N patches/patch-src_lib_fclose_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_lib_fclose_c 25 Apr 2018 10:16:18 -0000
@@ -0,0 +1,27 @@
+$OpenBSD$
+
+In case fp is "special" - eg it is managed by LibreSSL through
+funopen(3) - we may not have a valid fd but we still want to call
+fclose(3) on it.
+
+Index: src/lib/fclose.c
+--- src/lib/fclose.c.orig
++++ src/lib/fclose.c
+@@ -38,8 +38,7 @@ LIBC_FCLOSE_RET_TYPE tsocks_fclose(LIBC_FCLOSE_SIG)
+
+ fd = fileno(fp);
+ if (fd < 0) {
+- /* errno is set to EBADF here by fileno(). */
+- goto error;
++ goto nofd;
+ }
+
+ DBG("[fclose] Close caught for fd %d", fd);
+@@ -64,6 +63,7 @@ LIBC_FCLOSE_RET_TYPE tsocks_fclose(LIBC_FCLOSE_SIG)
+ connection_put_ref(conn);
+ }
+
++nofd:
+ /* Return the original libc fclose. */
+ return tsocks_libc_fclose(fp);
+
--
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE