[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-bugs] #21010 [Applications/Tor Browser Sandbox]: Disable RDTSC/RDTSCP to limit side-channel attacks
#21010: Disable RDTSC/RDTSCP to limit side-channel attacks
--------------------------------------------------+---------------------
Reporter: cypherpunks | Owner: yawning
Type: enhancement | Status: new
Priority: Medium | Milestone:
Component: Applications/Tor Browser Sandbox | Version:
Severity: Normal | Keywords:
Actual Points: | Parent ID:
Points: | Reviewer:
Sponsor: |
--------------------------------------------------+---------------------
//TL;DR If you don't use vDSO, you can disable the TSC instructions
without causing segfaults.//
Side-channel attacks like FLUSH+FLUSH, FLUSH+RELOAD, PRIME+PROBE, and
EVICT+TIME can be used for covert information exfiltration, cross-process
and cross-VM keylogging, breaking poor crypto implementations (especially
JS-based crypto), and massively enhancing rowhammer attacks by enumerating
the physical row layout and physical memory layout, improving a generic
attack of 2 flips in 10 minutes to 30 flips per second on some hardware.
These attacks all require a high-precision timestamp counter instruction
to function, and don't involve making syscalls, so seccomp does not defend
against them. They have the same keylogging effects which grsecurity's
`/dev/ptmx` anti-side channel technique was designed to protect against,
so it bad news.
This is even worse for Tor Browser users, as in addition to limited
keylogging abilities, it allows for extensive cross-process (the user
doesn't need to be using the keyboard or mouse in the compromise Firefox
process) biometric fingerprinting via keystroke dynamics in a way that's
not practical using JavaScript's `performance.now()` or whatever it does.
That function has a resolution in the hundreds of nanoseconds even with
JIT enabled (and I hope your sandboxed browser will disable JIT), compared
to `RDTSC` which tends to be sub-nanosecond, making it fast enough to be
cross-process, and cross-VM (everything but cross-NUMA node). On the
bright side, x86 CPUs allow making this instruction available to ring 0
only via `CR4.TSD` (the timestamp disable bit in the 4th control
register), and the Linux kernel exposes an interface to allow userland to
toggle this on a per-process basis using `prctl()`.
Example usage, in C:
{{{
#include <sys/prctl.h>
#include <stdlib.h>
#include <stdio.h>
/* disable the TSC */
if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV, 0, 0, 0) == -1)
exit(1);
/* enable the TSC */
if (prctl(PR_SET_TSC, PR_SET_ENABLE, 0, 0, 0) == -1)
exit(1);
/* check the TSC state */
int tsc;
if (prctl(PR_GET_TSC, &tsc, 0, 0, 0) == -1)
exit(1);
printf("The TSC is %s for this process\n", tsc ? "enabled" : "disabled");
}}}
With this in mind, it should be important to consider disabling the TSC in
Tor Browser using the sandbox, and using seccomp to prevent it from re-
enabling it with `prctl()`. However, as a lot of people who have tried
this have seen, many glibc processes instantly segfault when this is done.
The reason this happens is that a few syscalls, namely `getcpu()`,
`gettimeofday()`, `time()`, and `clock_gettime()` use the `RDTSC`
instruction because, on x86, they are not a syscall, but a vDSO, meaning
the syscalls take place entirely in userspace (though a small dynamically
updating read-only bit of memory, called the VVAR, is created by the
kernel for the vDSO to poll), without requiring a context switch at all,
in order to improve performance. Unfortunately, some of those calls with
some arguments end up using `RDTSC` in userspace, triggering a `SIGSEGV`.
See `vdso(7)` for more information on how this works, and how glibc is
involved. The solution is to wrap `gettimeofday()`, `clock_gettime()`
(either entirely, or just some of its arguments), and `time()`, and force
them to use their true syscall equivalents. If they go through their glibc
functions, they'll use the vDSO mapping, and occur in userspace.
This fix should be very simple, as long as Firefox does not manually use a
TSC instruction in asm in its code by itself (in which case you'd have to
patch around that). If it doesn't do that, then all you'd have to do is
wrap a few functions like so:
{{{
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
return syscall(SYS_gettimeofday, tv, tz);
}
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
return syscall(SYS_clock_gettime, clk_id, tp);
}
time_t time(time_t *tloc)
{
return syscall(SYS_time, tloc);
}
}}}
If Firefox tries to call any of these syscalls from glibc, hooking it
using `LD_PRELOAD` or so with these functions should prevent it from
deferring to userspace execution as a vDSO, and instead use a true
syscall.
On a slight tangent, given that this would disable so many of the vDSOs
that exist, in the long-term it might be a good idea to look into a way to
completely disable all access to the vDSO and VVAR, if it's possible to do
that on a per-process basis (it also seems that modern x86_64 kernels
cannot have it disabled globally by adding `vdso=0` to the kernel boot
parameters either. Despite what the documentation says, the code says
otherwise). vDSOs have been abused in combination with other exploit
primitives for sandbox escapes and privesc. For example CVE-2016-5195
could escape sandboxes by overwriting the vDSO and waiting for a process
outside the sandbox to call it. Other vulnerabilities that lead to turning
read-only pages writable would lead to that issue as well, even if mapping
sensitive files like `/etc/passwd` or `/bin/su` isn't possible due to a
strict sandbox. I'm not entirely sure if simply preventing vDSO and VVAR
from being loaded is sufficient, but if so, then disabling it entirely
would be an even better solution (and glibc will gracefully fall back to
using native syscalls if it detects this). But in the meantime, hooking
the glibc functions and using `syscall()` to call the native syscalls
works fine for the purpose of safely disabling `RDTSC` and `RDTSCP`.
Oh, and another note. vDSO calls bypass seccomp (and strace) by nature, so
if you disable vDSO, you'll suddenly see a couple syscalls that previously
didn't seem to exist, so unless you have whitelisted things like `time()`
and `gettimeofday()`, you may see new violations that you didn't see
before.
As for anyone still using emulated, or god forbid, native vsyscalls who
haven't moved onto vDSO, screw them. A sandbox won't do much to protect
them anyway until they upgrade to a modern kernel.
Information about vDSO:
http://blog.tinola.com/?e=5
https://www.linuxjournal.com/content/creating-vdso-colonels-other-chicken
https://0xax.gitbooks.io/linux-insides/content/SysCall/syscall-3.html
http://man7.org/linux/man-pages/man7/vdso.7.html
http://lxr.free-electrons.com/source/arch/x86/entry/vdso/
Information about side-channel attacks:
https://www.tau.ac.il/~tromer/papers/cache-joc-20090619.pdf (EVICT+TIME
and PRIME+PROBE)
https://eprint.iacr.org/2013/448.pdf (FLUSH+RELOAD)
https://gruss.cc/files/flushflush.pdf (FLUSH+FLUSH)
Information about keystroke dynamics:
https://www.cs.cmu.edu/~keystroke/KillourhyMaxion09.pdf
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3835878/
https://people.eecs.berkeley.edu/~daw/papers/ssh-use01.pdf
Information about the TSC and disabling it:
https://en.wikipedia.org/wiki/Control_register#CR4
http://x86.renejeschke.de/html/file_module_x86_id_278.html
http://man7.org/linux/man-pages/man2/prctl.2.html
--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/21010>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online
_______________________________________________
tor-bugs mailing list
tor-bugs@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-bugs