Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#15584 closed defect (fixed)

Linking libtorsocks with libtcmalloc results in SIGSEGV

Reported by: post-factum Owned by: dgoulet
Priority: Medium Milestone:
Component: Core Tor/Torsocks Version:
Severity: Keywords: sigsegv libtcmalloc libtorsocks torsocks ld_preload
Cc: Actual Points:
Parent ID: Points:
Reviewer: Sponsor:


Any application that is linked against libtcmalloc gets SISEGV if it's being run with libtorsocks preloaded. However, it depends on preloading order.

If libtorsocks is preloaded first, app segfaults:

[~]$ LD_PRELOAD="/usr/lib64/torsocks/ /usr/lib64/" uname -a
[1]    7817 segmentation fault (core dumped)  LD_PRELOAD= uname -a

If, instead, libtcmalloc is preloaded first, everything is OK:

[~]$ LD_PRELOAD="/usr/lib64/ /usr/lib64/torsocks/" uname -a
Linux spock 3.19.0-pf3 #1 SMP PREEMPT Tue Mar 24 17:14:04 EET 2015 x86_64 GNU/Linux

The problem is that if an app in question is linked against libtcmalloc, torifying it via "torify" or "torsocks" wrapper always leads to segfault because libtorsocks is loaded before libtcmalloc.

Attempt made to debug any app leads to non-informative backtrace:

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff725e40c in ?? () from /usr/lib/
#2  0x00007ffff725ed3f in ?? () from /usr/lib/
#3  0x00007ffff725ef49 in NumCPUs() () from /usr/lib/
#4  0x00007ffff723b439 in ?? () from /usr/lib/
#5  0x00007ffff7dea1fa in call_init.part () from /lib64/
#6  0x00007ffff7dea30b in _dl_init () from /lib64/
#7  0x00007ffff7ddbdba in _dl_start_user () from /lib64/
#8  0x0000000000000003 in ?? ()
#9  0x00007fffffffe47a in ?? ()
#10 0x00007fffffffe4aa in ?? ()
#11 0x00007fffffffe4af in ?? ()
#12 0x0000000000000000 in ?? ()

I use torsocks v2.0.0 and libtcmalloc v2.4.

So my questions are:

  1. should this be libtorsocks or libtcmalloc issue?
  2. how should I get more info on this bug?
  3. what should be done to fix the issue?

Child Tickets

Attachments (1)

0001-Use-direct-syscalls-in-routines-called-from-static-c.patch (7.7 KB) - added by yawning 5 years ago.

Download all attachments as: .zip

Change History (6)

comment:1 Changed 5 years ago by post-factum

Here is a link to opened issue from gperftools bug tracker:

comment:2 Changed 5 years ago by yawning

This is where it crashes:

tsocks_close (fd=3) at ../../../src/lib/close.c:56
56		return tsocks_libc_close(fd);
(gdb) p tsocks_libc_close
$6 = (int (*)(int)) 0x0

And this is what the rest of the stack trace looks like:

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff79863a5 in ReadIntFromFile (
    file=file@entry=0x7ffff79942c8 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", value=value@entry=0x7fffffffe0a4) at ../src/base/
#2  0x00007ffff7986c4f in InitializeSystemInfo () at ../src/base/
#3  0x00007ffff7986e49 in NumCPUs () at ../src/base/
#4  0x00007ffff79693f9 in SpinLock_InitHelper (this=<optimized out>)
    at ../src/base/
#5  __static_initialization_and_destruction_0 (__initialize_p=1, 
    __priority=65535) at ../src/base/
#6 () at ../src/base/
#7  0x00007ffff7dea1fa in call_init.part () from /lib64/
#8  0x00007ffff7dea30b in _dl_init () from /lib64/
#9  0x00007ffff7ddbdba in _dl_start_user () from /lib64/
#10 0x0000000000000001 in ?? ()
#11 0x00007fffffffe8c1 in ?? ()
#12 0x0000000000000000 in ?? ()

That pointer is set via init_libc_symbols() called from tsocks_init(), which has the GCC constructor attribute. Per the GCC documentation:

The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects (see C++ Attributes).

What is happening is that tcmalloc does file I/O with libc calls that torsocks usually hijacks when initializing a static namespace scope object (before libtorsocks is initialized), and SIGSEGVs.

How to fix this:

  • Option 1: Fixing ReadIntFromFile() and VDSOSupport::Init() appear to make this work on a Linux system, but other platforms probably require additional changes. See attached patch.
  • Option 2: The torsocks code could probably be changed to use pthread_once instead of relying on the ctor to initialize (or something similar), but I'm not sure if dgoulet has the time for that.

Attempting to force the tsocks initialization routine to be called before tcmalloc's static constructors by setting the priority to something really low didn't appear to work.

I'm not sure which option is better, and it's not really a bug in either codebase.

comment:3 Changed 5 years ago by yawning

Status: newneeds_review

And this is the torsocks fix. Since C++ is a thing, and torsocks should support people doing various silly and not so silly things in their constructors, this is probably better than patching libtcmalloc.

I ended up implementing my own pthread_once() analog since I didn't feel that changing libtorsocks to always link against a real pthread implementation on Linux was all that great. Changing the code to use pthread_once() is easy if people happen to disagree with me.

comment:4 Changed 5 years ago by dgoulet

Resolution: fixed
Status: needs_reviewclosed

Minor syntax fix and use of tsocks_mutex_t. The rest was perfect!

Merged! Thanks

comment:5 Changed 5 years ago by post-factum

Thanks :).

Note: See TracTickets for help on using tickets.