Memory corruption and use-after-free
Many system components are written in the unsafe C/C++ languages that are prone to memory corruption vulnerabilities. Over more than 20 years, attackers have been abusing these vulnerabilities to compromise and subvert the system. Of course there have been much of defense side research efforts to stop these issues, but it is not quite close to be perfect --- many of them take too radical approaches so it involves either the changes of the underlying running system or is not quite suitable for real-world applications.
Today, use-after-free is generally known as one of the most difficult
vulnerability type. Many modern C/C++ applications are developed under
object-oriented or event-driven designs, which in turn separates out the memory
resource use
and free
patterns. Due to this separation, developers cannot
easily understand whether a certain memory pointer may point to a valid memory
object or not, and a use-after-free vulnerability is introduced if they
misunderstand. From the perspective of static analysis, use-after-free is a
still challenging problem with a similar reason --- separated use and free
routines require a precise points-to analysis with a complete inter-procedural
analysis.
DangNull: Nullifying dangling pointers
Use-after-free example
class Div: Element;
class Body: Element;
class Document {
Element* child;
};
// (a) memory allocations
Document *doc = new Document();
Body *body = new Body();
Div *div = new Div();
// (b) using memory: propagating pointers
doc->child = body;
body->child = div;
// (c) memory free: doc->child is now dangled
delete body;
// (d) use-after-free: dereference the dangled pointer
if (doc->child)
doc->child->getAlign();
Above code snippet shows a contrived example having use-after-free issues. A
pointer doc->child
points to the invalid memory region after body
is
deleted. Thus, doc->child
is a dangling pointer, and use-after-free occurs
once the pointer doc->child
is dereferenced.
Use-after-free could have been prevented if all the pointers pointing to the
object to be freed are properly nullified (e.g., nullifying doc->child
once
body
is deleted). However, such nullification is not straightforward for
developers because doc->child
is essentially a back-pointer to body
and a
list of back-pointers are known when the object is freed.
Nullifying dangling pointers
Motivated by this hardness for developers, we developed DangNull
that
automatically nullifies all potential dangling pointers and thus prevents
use-after-free. By instrumenting additional code and maintaining extra
metadata, it can trace object relationships via pointers and nullifies the
pointers once it is dangled. For example, the above vulnerable code will be
transformed into the code like below.
doc->child = body;
+ trace(&doc->child, body);
body->child = div;
+ trace(&body->child, div);
// delete operator is intercepted,
// and all back-pointers including doc->child are nulified.
delete body;
// doc->child is NULL, so use-after-free is prevented.
if (doc->child)
doc->child->getAlign();
While intercepting all allocations and deallocations, it also instruments an
extra runtime function call, trace()
, to keep track of object relationships
via pointers. One interesting property of DangNull
is in reusing null-pointer
checks in the program. Because the automatic nullification of dangling pointers
are actually the runtime semantics that developers intended and had to
implement, DangNull
fills up the missing semantic hole and keeps the program
alive even after the use-after-free attempts. We have implemented this idea
using LLVM
compiler infrastructures, and instrumented the Chromium browser
(please refer the paper [1] for details).
Demo
The following video clip shows the demo on Chromium hardened with DangNull. We
tested using a use-after-free exploit, CVE-2013-2909
, and it shows how
DangNull stops the exploit --- it stops the exploit attempts by triggering a
segmentation fault due to null-dereference (we do a little bit more extra jobs to
safely contain this exception, which we call safe-null dereference). When the
nullification value is NULL, the Chromium browser can correctly render the
exploit page as if the vulnerability is patched.
[1] Preventing Use-after-free with Dangling Pointers Nullification. Byoungyoung Lee, Chengyu Song, Yeongjin Jang, Tielei Wang, Taesoo Kim, Long Lu, Wenke Lee. Published in NDSS 2015. [PDF]