generation universal rooting exploit • Hunting new bugs • Reviewing public patch on upstream • CVE-2015-1805 • Introduced in 2006 • Fixed in kernel 3.18 • No patch for 3.10 or earlier • Most of Android devices ship with 3.10 by that time
iov_fault_in_pages_write • Time of use: pipe_iov_copy_to_user • Check & use what? • Vmmap page status • Valid during check => atomic == 1 • Invalid during use => REDO • Valid during REDO => overrun J • Race the page table as the “data” • Unconventional data racing
4k … chars=4096, total_len=4112, atomic 0 32 8 … 0 8 4k … chars=4064, total_len=4112, copied=32 0 0 8 … 0 8 4k … chars=0, total_len=48, copied=4096 0 0 0*508 8*2 0 8 4k … chars=4096, total_len=48, atomic 0 0 0*508 0*2 0 0 4072 … Check Use (copy #1) REDO Next page chars=4096, total_len=4112, atomic 0 32 8 8*509 0 8 4k … munmap mmap n Thread A n Thread B • Each block represent 1 or more iovec • Only length matters here Calc total_len chars = buf->len Probe each iovec for writing atomic = 1 atomic = 0 For each iov (determined by chars) is atomic? copy_to_user copy_to_user_atomic total_len -= chars Remaining buf? N Y Y N Y pipe_read error? atomic? N ERROR Y (set atomic = 0) Process base and len REDO Y N
ops->map(pipe, buf, atomic); error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); • Create a thread to do mmap and munmap repeatedly • The window is small, but the exploit can be repeated over and over until it win. • ops->map is “kmap”
to a kernel virtual addres • The cost of high memory handling can be quite high. • Be used when kernel cannot keep all of the available physical memory mapped at all times • In the arch arm, kernel can only map less than 1GB of physical memory. • In the arch arm64, kmap will simply covert the page struct address onto a pointer to the page contents rather than juggling mappings out. Code: https://github.com/idl3r/testcode/blob/master/test2.c
Each cache hold slabs of objects of the same size • common kmalloc cache: • kmalloc-64,kmalloc-128…kmalloc-4096,kmalloc-8192 • Structure specific cache: • UNIX, UDP, task_struct … • Mergeable slab caches, e.g. PING & UNIX • Objects on a slab are contiguous • Meta-data is overloaded with ‘struct page’ • Except ‘free_list’ which is at the head of object, pointed to next free object • A slab may have allocated and deallocated object
this cache is not allocated frequently • Much easier than spraying kmalloc-512 J • Allocate a page with malformed iovecs, hope that is just after the page of good iovecs. Good iovecs allocated by readv Sprayed object Overrun Sprayed object
overwrite kernel stack (CVE-2014-3153) • Used to spray any size and content of object in kmalloc caches persistently (used lots of times in my unpublished exploits) • Used again in CVE-2015-1805 • In this case • Temporarily allocate malformed iovecs in kmalloc-8192 • iovec[] = {0,0},{kernel_addr,8},{user_addr,0x1000}… • Call sendmmsg repeatedly
kernel_addr isn’t a valid user address • Sprayed objects may be freed, which means the first 8 bytes of page may be overwritten as a free_list pointed to next freed object. • Free_list is a pointer to free object or null • Note that the length of first iovec is null! • pipe_iov_copy_to_user just ignore the first iovec and go on 0 0 kernel_addr 8 User_addr 0x1000 User_addr … Free_list 0 kernel_addr 8 User_addr 0x1000 User_addr …
since 5.1 ROMs • After PingPong root • Knox Active Protection is enabled before kernel boot • In boot loader • Based on Knox Warranty Void bit status • CONFIG_TIMA_RKP (TIMA Real time kernel protection) • ONLY unlocked device can have KAP disabled
S5 and later devices) • Page table protection • “Protects” key kernel objects • current->cred • current->real_cred • Page table entries (section and page) • Can’t write directly on those objects, needs to call hyper-visor • Can be extended to other kernel objects
Almost all ops table entries takes un-controllable pointer as input • May corrupt the object to control the pointer, but takes risk • Hard to find decent gadget controlling X0 and ends with an BR • Not BLR since we need to keep LR intact calling into a function • There is a good entry but only takes 32-bit input: • And it returns an int as well… 1517 struct file_operations { 1518 struct module *owner; ... 1538 int (*check_flags)(int); ... 1546 };
Replaces override_creds in case of Knox • Intended for temporary credential override • Takes a pointer to pointer instead! • And no check of this pointer’s origin!!
be released in the not too distant future • Code-named Valkyrie • AFAIK, this is: • *************** • *************** • *************** • ***************