[tor-bugs] #21010 [Applications/Tor Browser Sandbox]: Disable RDTSC/RDTSCP to limit side-channel attacks

Tor Bug Tracker & Wiki blackhole at torproject.org
Sat Dec 17 14:49:08 UTC 2016


#21010: Disable RDTSC/RDTSCP to limit side-channel attacks
----------------------------------------------+-------------------------
 Reporter:  cypherpunks                       |          Owner:  yawning
     Type:  enhancement                       |         Status:  new
 Priority:  High                              |      Milestone:
Component:  Applications/Tor Browser Sandbox  |        Version:
 Severity:  Normal                            |     Resolution:
 Keywords:                                    |  Actual Points:
Parent ID:                                    |         Points:
 Reviewer:                                    |        Sponsor:
----------------------------------------------+-------------------------

Comment (by cypherpunks):

 I wrote a stub to test Firefox with TSC instructions disabled, but it
 segfaulted (though it solves the issue for the majority of programs). I
 disassembled all the libraries and searched for mentions of `RDTSC`, and
 this is what I found:

 {{{
 $ cd /usr/local/lib64/tor-browser
 $ lddtree -l firefox *.so | sort -u | while read -r so; do (echo -n "$so:
 "; objdump -M intel -D "$so" | grep -c rdtsc) | sed '/: 0$/d'; done
 /lib64/ld-linux-x86-64.so.2: 17
 /lib64/libc.so.6: 2
 /lib64/libpthread.so.0: 2
 /lib64/libresolv.so.2: 1
 ./libfreebl3.so: 1
 ./libxul.so: 21
 /usr/lib64/libfreetype.so.6: 1
 /usr/lib64/libgdk-x11-2.0.so.0: 3
 /usr/lib64/libgtk-x11-2.0.so.0: 2
 /usr/lib64/libX11.so.6: 1
 }}}

 `libxul.so` has the most instances, in symbols related to JS objects.
 Given how huge it is, I wouldn't be surprised if Firefox never actually
 hits those code paths. We'll cross that bridge when we get to it.

 The occurrence in `libresolve.so.2` is near the beginning of
 `__res_nmkquery`. I don't think it'll be an issue, considering Tor Browser
 doesn't do domain resolution directly but uses the SOCKS5/SOCKS4a protocol
 and lets Tor take care of it. From `res_nmkquery(3)`:

 {{{
 The res_nmkquery() and res_mkquery() functions construct a query mes-
 sage in buf of length buflen for the domain name dname. The query type
 op is usually QUERY, but can be any of the types defined in
 <arpa/nameser.h>. newrr is currently unused.
 }}}

 One occurrence in `libc.so.6` is in `tempnam`, and the other in `__fork`.

 The instances in all the others not mentioned here are false positives
 (e.g. from `.rodata` or in strings).

 The pthread library however calls it twice. Once at the very beginning of
 `start_thread`, and again at the very beginning of
 `__pthread_clock_gettime`:

 {{{
 $ objdump -M intel -D /lib64/libpthread.so.0 | grep -B7 rdtsc
 0000000000007480 <start_thread>:
     7480:       53                      push   rbx
     7481:       48 81 ec b0 10 00 00    sub    rsp,0x10b0
     7488:       48 83 0c 24 00          or     QWORD PTR [rsp],0x0
     748d:       48 81 c4 20 10 00 00    add    rsp,0x1020
     7494:       48 89 fb                mov    rbx,rdi
     7497:       48 89 7c 24 08          mov    QWORD PTR [rsp+0x8],rdi
     749c:       0f 31                   rdtsc
 --
 000000000000e950 <__pthread_clock_gettime>:
     e950:       55                      push   rbp
     e951:       53                      push   rbx
     e952:       48 81 ec 38 10 00 00    sub    rsp,0x1038
     e959:       48 83 0c 24 00          or     QWORD PTR [rsp],0x0
     e95e:       48 81 c4 20 10 00 00    add    rsp,0x1020
     e965:       48 89 d3                mov    rbx,rdx
     e968:       0f 31                   rdtsc
 }}}

 Reading through the glibc source, in `nptl/pthread_create.c`, it uses the
 macro `HP_TIMING_NOW`, defined in `ntpl/perf.c` to use `RDTSC` to save the
 time that the thread was started, if `HP_TIMING_AVAIL` is defined.

 The second symbol is in `nptl/pthread_clock_gettime.c`, and is called
 immediately after the function begins.

 It seems this culprit is `__fork` from glibc, since making the stub fork
 before returning to the real main function triggers a segfault. In the the
 glibc source, in `sysdeps/nptl/fork.c`, `HP_TIMING_NOW` is used, also if
 the macro `HP_TIMING_AVAIL` is defined. My guess is these are the
 functions that'll need to be hooked in order to make this work with
 threaded/forking programs like Firefox.

 Relevant chunks (for glibc-2.22):

 `ntpl/perf.c:705`
 {{{
 #ifdef i386
 #define HP_TIMING_NOW(Var)      __asm__ __volatile__ ("rdtsc" : "=A"
 (Var))
 #elif defined __x86_64__
 # define HP_TIMING_NOW(Var) \
   ({ unsigned int _hi, _lo; \
      asm volatile ("rdtsc" : "=a" (_lo), "=d" (_hi)); \
      (Var) = ((unsigned long long int) _hi << 32) | _lo; })
 #elif defined __ia64__
 #define HP_TIMING_NOW(Var)      __asm__ __volatile__ ("mov %0=ar.itc" :
 "=r" (Var) : : "memory")
 #else
 #error "HP_TIMING_NOW missing"
 #endif
 }}}

 `sysdeps/nptl/fork.c:145`
 {{{
 #if HP_TIMING_AVAIL
       /* The CPU clock of the thread and process have to be set to zero.
 */
       hp_timing_t now;
       HP_TIMING_NOW (now);
       THREAD_SETMEM (self, cpuclock_offset, now);
       GL(dl_cpuclock_offset) = now;
 #endif
 }}}

 `nptl/pthread_create.c:258`
 {{{
 #if HP_TIMING_AVAIL
   /* Remember the time when the thread was started.  */
   hp_timing_t now;
   HP_TIMING_NOW (now);
   THREAD_SETMEM (pd, cpuclock_offset, now);
 #endif
 }}}

 `ntpl/pthread_clock_gettime.c:30`
 {{{
   hp_timing_t tsc;

   /* Get the current counter.  */
   HP_TIMING_NOW (tsc);
 }}}

--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/21010#comment:4>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online


More information about the tor-bugs mailing list