Binding Integrity
Binding Integrity Project
Motivation
One of the reasons that browsers are easier to compromise than other kinds of client software is that they provide scripting capabilities to a potential attacker. As such, many of the exploits we’ve seen begin with a JavaScript program obtaining and manipulating a freed block of C++ memory. Although the Chrome sandboxing architecture provides excellent protection in this situation, we’d like to prevent JavaScript from getting freed blocks of memory in the first place, so as to make the full exploitation of Chrome even harder than it already is.
Approach
At the time a C++ object is created, we know the corresponding V8 type with which it will be later wrapped for use by V8. We devise an unguessable (by the attacker) representation for each type and put it into the C++ object when it is constructed. We similarly zero out this information at destruction time.
At the time of a method callback into the C++ object, V8 happens to know the type that is expected to be associated with it. It can then determine what type representation should have been set into the block of memory at creation time, and check that it is still valid. Free blocks will have zeros (or will have been clobbered by heap freelists), and will fail the check. Mis-typed blocks will have different values, and will fail the check. Blocks crafted by the attacker won’t have valid values because the type information representation is unguessable, and will fail the check. At this point the renderer can shoot itself, rather than proceeding into C++ with corrupted memory.
But these method invocation calls are very hot code paths, and we don’t want to introduce the overhead of another test and branch here.
As it turns out, the V8 wrapper objects contain reference pointers back to the blocks of C++ memory, and these do a good job of keeping the memory alive. Once wrapped, a block is unlikely to be freed. Hence, most of the cases involve wrapping a block that is already free, and we get nearly the full benefit by doing the check at wrapper creation time only, where performance is not important.
Implementation
It is important that we do not bloat the size of the objects in order to hold this type representation.
Many (but not all) objects wrapped by V8 inherit somewhere from a class called ScriptWrappable, which is a single pointer wide. It holds a pointer to the C++ object’s wrapper when it is wrapped, or NULL otherwise. We can re-use the slot that holds the the wrapper pointer (which would otherwise be NULL for an unwrapped object) to hold the type information, because we only need the type information for unwrapped objects. Masking in a 1 in the bottom bit (otherwise unused due to aligned pointers) allows us to distinguish between the two cases.
Hence, for objects that are to be checked in this manner, they must inherit somewhere from the ScriptWrappable class (which need not be a common base class).
This implies that all objects that inherit from ScriptWrappable and have their own .idl files will have to call
ScriptWrappable::init(this);
as part of their constructors. Passing “this” is necessary to select between N overloaded versions of ScriptWrappable::init() based upon the type of the object.
The implementations of the N overloaded versions of ScriptWrappable::init() are automatically generated by the .idl compiler (CodeGeneratorV8.pm at present) from the .idl files. The .idl files need not specify which objects are scriptwrappable, as the compiler can deduce this from type inheritance via partially specialized template tricks.
The unguessable nature of the type representation is achieved by relying on ASLR to randomize the address of a per-type instance of an existing V8 data structure called WrapperTypeInfo. The address of the WrapperTypeInfo structure for a given type thus already provides what is required here.
Note that ScriptWrappable was originally invented to provide a performance improvement. One additional benefit of this change is that making more objects ScriptWrappable makes chrome faster.