Thursday, May 28, 2009

Time-stamp counter disabling oddities in the Linux kernel

The time-stamp counter (TSC) is part of the performance monitoring facilities provided on Intel processors. It's stored in a 64-bits MSR. Except for 64-bit wraparound (and of course reset), the TSC is guaranteed to be monotonically increasing by Intel, but not necessarily at a constant rate.
Historically, the TSC increased with every internal processor clock cycle, but now the rate is usually constant (even if the processor changes frequency) and usually equals the maximum processor frequency.

There are multiple ways of reading the value of the TSC MSR, a popular one is the RDTSC instruction. This instruction will load the value into EDX:EAX and is not privileged unless the Time-Stamp Disable (TSD) bit is set in CR4. Most operating systems will not set CR4.TSD on any thread, so programmers are free to use RDTSC in their Ring3 code.

The problem is that the TSC has been used as a tool in the past to mount side channel attacks. Two examples are "Cache Attacks and Countermeasures: the Case of AES" by Osvik, Shamir and Tromer and "Cache missing for fun and profit" by Colin Percival. (Less importantly, it has also been used to create exploits against race conditions in the Linux kernel such as this one)

In an attempt to kill RDTSC as a tool to conduct various mischiefs, Andrea Arcangeli, author of the SECCOMP prctl (that allows a thread to enter a sandboxed "computing mode" where only read, write, exit and sigreturn syscalls are allowed) tried to disable RDTSC by setting CR4.TSD in any thread that runs under seccomp (in 2.6.12).

That's where the oddities begin: I was recently surprised to see that a process I ran under seccomp had actually access to rdtsc. A quick look at the source code of my kernel revealed this:

#ifdef TIF_NOTSC
disable_TSC();
#endif

Note that TIF_NOTSC is not a config option! So I took a look at both thread_info_64.h and thread_info_32.h to discover that in the 64 bits version, TIF_NOTSC was not defined. As a consequence, on a 32 bits kernel, seccomp will disable the TSC in seccomp threads but will not on a 64 bits kernel (even for 32 bits processes). Chris Evans blogged previously about how a seemingly simple security technology such as seccomp could still have bugs. "Here's another one" I thought.

While tracking this bug, I found out that it wasn't a bug but a conscious decision by Andi Kleen to not disable TSC, but only on x86_64 (patch applied in 2.6.14) for performance reasons. I consider this a really odd decision: seccomp behaving differently on 64 bits and 32 bits kernels is a non sense! If you consider TSC disabling a security feature, it has to behave consistently or you should just remove it altogether. Here is a thread, started in November 2005 by Andrea Arcangeli who also regretted the lack of consistency.

But then, in Linux 2.6.23, this feature became impact-free, performance-wise. So at that point, I really consider not having it on x86_64 kernels a bug, not only a strange decision. As I mentioned previously, the bug is due to TIF_NOTSC not being defined for 64 bits kernels.
I wondered if this bug would still be there in recent Linux kernels despite the ongoing i386 and x86_64 merge. It wasn't in 2.6.27 where thread_info_64.h and thread_info_32.h have been merged into one thread_info.h file. But in fact, it was already corrected in 2.6.26 at the same time as a new feature, prctl(PR_SET_TSC), was introduced.

PR_SET_TSC lets you control the CR4.TSD flag for your thread: you can make your thread SIGSEGV on rdtsc. And this feature is another big oddity for me: if you consider rdtsc harmful, it would make sense to let a process drop the privilege to use RDTSC, but the weird thing here is that they don't forbid you to call prctl(PR_SET_TSC) again to clear the TSD flag and restore your privilege to use rdtsc! So I can't imagine what this is for, the only use case I can see would be in a ptrace sandbox.

Another use case would have been SECCOMP of course. By removing the automatic TSC disabling from seccomp, a thread could use PR_SET_TSC prior to using PR_SETCOMP if it wanted to disable rdtsc, thus making this behavior configurable. Since a thread under seccomp cannot call prctl(), the thread wouldn't have been able to re-enable it. But the problem would have been that existing code relying on SECCOMP might be expecting to drop TSC access without having to use PR_SET_TSC. But wait! This feature had never worked in the first place, it was the perfect time to change the behavior and finally fix this bug. Another oddity!

I should also discuss the whole idea of forbidding access to the useful rdtsc instruction in the first place. Could an attacker emulate this with a thread on another processor incrementing a counter manually anyway? Are the RTC, HPET or the gtod_data counter in the vsyscall page useable? How realistic are those side channel attacks in the first place? If they are, when could it become the easiest attack you can perform on a system ? That will be for another post.

Tuesday, May 19, 2009

Write once, own everyone, Java deserialization issues

EDIT3: This vulnerability has been nominated for a Pwnie Award for "best client-side bug"!
EDIT 2: On June 15th 2009, Apple has updated Java on MacOS X with a version that fixes this issue.
EDIT 1: this has been featured on
Slashdot, Ars Technica, ZDNet, OSnews and many others. The focus was on the fact that this is still not fixed on MacOS X. However, keep in mind that you may still be at risk if you use another operating system (Windows, Linux), especially with an outdated version of Java, which is very common. You should disable Java applets in your browser if you can, or at least consider using NoScript.

It is time to talk about my favorite client-side vulnerability ever. Surprisingly (if you know me), this is a Java vulnerability, or rather a class of Java vulnerabilities that allows to completely bypass the Java sandbox and execute arbitrary code remotely in Java enabled web browsers.
This was found by Sami Koivu. He reported the first instance of it (CVE-2008-5353) to Sun on August 1st 2008 and this instance has been fixed by Sun on December 3rd 2008. These vulnerabilities are both technically interesting and have a lot of impact.

Since they share core classes, OpenJDK, GIJ, icedtea and Sun's JRE were all vulnerable at some point. And unfortunately, this vulnerability is still not fixed everywhere yet.

I've been wanting to talk about this for a while. I was holding off, while Apple was working to patch this vulnerability. Unfortunately, it is still not patched in their latest security update from just a few days ago. I believe that since this vulnerability has already been public for almost 6 months, making MacOS X users aware that Java needs to be disabled in their browser is the good thing to do.

As a side note, Sami Koivu and I paired at latest Pwn2own (his vulnerability, my exploit) and owned both Firefox and Safari on MacOS X on day one (Java is there and enabled by default on MacOS X). Unfortunately it fell out of the challenge criterions because the vulnerability had already been reported to Sun and I had already pinged Apple in January about it.

So let's talk about the first reported instance of this class of vulnerabilities, the Calendar deserialization vulnerability.

For legacy reasons, the deserialization of the sun.util.calendar.ZoneInfo object in a java.util.Calendar has to be fine tuned, so the readObject() method in the Calendar class will handle it. However, an applet cannot access sun.util.calendar.ZoneInfo because it is inside "sun" and anything in "sun" has to be trusted for the Java Applet security model to hold.
For this reason the code responsible for the ZoneInfo deserialization has to run with privileges. The code in java.util is trusted and can get more privileges by using a doPrivileged block:
   try{
ZoneInfo zi = (ZoneInfo) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return input.readObject();
}
});
if (zi != null) {
zone = zi;
}
} catch (Exception e) {}

So what does this buy us ? We can craft an input and deserialize objects from it. By deserializing a Calendar, we can get a ZoneInfo object deserialized in a privileged context. Wait! How do they check this is a ZoneInfo object? They let Java's type checking do this for them. So if we carefully craft our input, we can get an arbitrary object deserialized but it'll not get affected to zi unless it's a valid ZoneInfo.

To exploit this, let's find a class that we would be forbidden to instantiate in an Applet because it would allow us to escape from the Java sandbox. The RuntimePermission class is a great source of inspiration. A ClassLoader seems to be exactly what we are looking for! Let's make our own ClassLoader sub-class and override the readObject() method. This method will be called during deserialization. In this method we can affect ourselves (this) to a static variable so that our shiny new ClassLoader doesn't get garbage collected and so that we can use it later.

With our own ClassLoader we can define classes with our own ProtectionDomain (with arbitrary privileges). That's it!

There is more work to do. The overall exploit can be quite complex (mine is over 500 lines but you can make a simpler version) but you get the basic idea.
Also there is the problem of manually crafting the malicious serialized file. In a first version I did this manually by re-implementing the Serialization protocol. Later I found a nice trick: by overriding replaceObject(), you can let Java do all the work for you.

I've mentioned that this was a class of vulnerabilities: the reason is that with this design, every time Java code deserializes an attacker-controlled input in a privileged context, it's a security vulnerability. Sun fixed the Calendar vulnerability (see this patch) by creating a new accessClassInPackage.sun.util.calendar privilege and restricting the doPrivileged block to this, so they didn't fix the whole class of them (more on this in a later post).

That's it for the technical part.

Now why do I think this client-side arbitrary remote code execution vulnerability is more interesting that most others?

First, according to Adobe and Sun, Java is available in 80% to 90% of all web browser, which makes it a nice target.

Secondly, for various reasons, Java is usually poorly updated:
  • The Sun Java update mechanism isn't tied to the operating system update system on the Windows platform. Personal users and companies don't update it often, some of them do have processes in place to deal with Microsoft's patch Tuesdays but don't for other software updates.
  • Many companies are using web applications or Java software that rely on a specific Java version. It may be tedious to update Java because it would break many things. This may be the reason why Apple's Java updates are so infrequent.
  • Some Linux distributions don't support Sun's JRE (proprietary software) despite making it available. When I asked Ubuntu to fix this vulnerability, they fixed OpenJDK quickly but told me the Sun JRE was not supported (despite being available by default on the latest LTS Ubuntu release).
Third, and this is the important point: most other client-side vulnerabilities that can lead to arbitrary code execution, including other Java vulnerabilities are memory corruption vulnerabilities in a component written in native code. Exploiting those reliably can be hard. Especially if you have to deal with multiple operating system versions or with PaX-like protections such as DEP and ASLR.
This one is a pure Java vulnerability. This means you can write a 100% reliable exploit in pure Java. This exploit will work on all the platforms, all the architectures and all the browsers! Mine has been tested on Firefox, IE6, IE7, IE8, Safari and on MacOS X, Windows, Linux and OpenBSD and should work anywhere.

This is close to the holy grail of client-side vulnerabilities.

So MacOS X users, please disable Java in your web browser.
Others: make sure you have updated Java and still disable it in your web browser: it's a huge attack surface and it suffers from many other security vulnerabilities.
Moreover, even without taking into consideration Java vulnerabilities themselves, since the Java plugin allocates all memory as RWX and doesn't opt-in for randomization, a Java applet can be used to bypass ASLR and non executability (DEP on Windows) in browser exploits.

You can also get some information about this vulnerability on Sami Koivu's blog, here and here and a time line for some of the bugs he reported to Sun here.