Preventative Patching Produces Pwn2Own Participant’s PanicOctober 31, 2018 | Jasiel Spelman
One of the things that adds anxiety to every entry for Pwn2Own is the duplicate checking process. Even if a contestant successfully demonstrates an exploit, it doesn’t count as a win if the vulnerability is already known by us or the vendor. This can be incredibly stressful for researchers as there’s no way to know if someone else has already submitted the vulnerability. As we begin preparing for Pwn2Own Tokyo, I thought I’d share a bug collision that affected me earlier this year.
new Uint32Array can end up being handled by the
NewTypedArray opcode while
Math.abs(x) can end up being handled by the
Just to be explicit about it, side effects are considered to be anything that may occur outside of the operation itself. As an example, the
ArithAbs opcode is expected to take an argument and return the absolute value of that argument, just as
Math.abs does. As such, it is not expected to be an effectful operation, meaning there should be no allocations of Arrays as a result of executing an
ArithAbs opcode. Effectful operations are denoted in a couple of different ways. In
DFGAbstractInterpreterInlines.h, they are denoted with a call to
clobberWorld, whereas in
DFGClobberize.h, they are denoted with calls to
write(Heap). We can gloss over what happens during those calls and focus on the fact that they clobber known states such that the JIT engine knows not to make any assumptions after the opcode has executed.
While I was en route to OPCDE Dubai in April of this year, I was reading through the DFG byte code parser and happened across this rather large comment within the
The case where
blah is a non-buffer object piqued my curiosity, so I quickly looked at
DFGClobberize.h to see if the
NewTypedArray opcode was properly treated as being effectful.
Here's what I saw in
This is standard and pretty much what I expected. If the argument to the
TypedArray constructor is
UntypedUse, then a call to
However, things were far more interesting when I looked at
As a comparison, here's how
Math.abs, handled by the
ArithAbs opcode, is handled within
See the difference? With the
ArithAbs operation, if the argument to
Math.abs is not an integer or a double, then clobberize will mark the operation as effectful. The
NewTypedArray operation was assumed to not be marked as effectful by DFGClobberize but was marked as effectful by the abstract interpreter. Since the operation isn’t properly modeled, we could get the JIT engine to confuse the type of an Array such that it lets us read out pointer values as floating point values or write floating point values that can later get interpreted as pointers. In the end, this type confusion could lead to code execution if crafted fake objects break the assumptions made by the JIT engine.
An observant reader will notice that I haven't provided any CVE or ZDI identifier for this vulnerability, which is due to the collisions I briefly mentioned at the beginning of this post. Six days after I found this bug, git commit
36dd2d2b40c5640412f39efcb6fd081a56016a5d was introduced in an attempt to catch issues with clobberize and the abstract interpreter disagreeing with each other. As part of this commit, the following was added to
Oddly enough, two days after this commit, one of our researchers found and submitted the same vulnerability.
Bug collisions are a part of research, especially when many are looking in similar areas. With Pwn2Own Tokyo right around the corner, here’s hoping that everyone participating has a chain that survives any patches issued before the contest.