The vulnerability exists in the esp6 crypto module. When receiving a buffer, there is an allocation that is 8 pages wide. The input, from the user, is written recurisively to this page without restriction on the size. Buffer overflow!
The overflow is quite a powerful primitive. Upon initial analysis, they noticed that the final several bytes (tail bytes) were not controllable. This was the only restriction though. The weird thing is that the overflow is at the page level instead of the heap allocator level. Page-level fengshui is a little weird!
The page allocator (buddy allocator) manages physical pages in the Linux kernel. This is what manages the SLUB, SLAB and other heap allocators in the kernel. The allocator maintains free pages in a data structure called free_area; this is just an array of elements that keeps track of the sizes of pages. Order-1, Order-2 - all pages to the power of 2.
If there there are no freed pages in the list, then it borrows them from a higher order. To shape the heap properly for the OOB write, they forced the complete usage of a single order. Then, when a higher order is used we KNOW the data will be continuous. To mitigate the noise from a kernel daemon, they found a weird pattern that worked 90ish percent of the time.
To get an arbitrary read primitive, the object user_key_payload was used. This field had a length value, making it perfect for an out of bounds read primitive. The tail corruption constraint worked with this object as well. This object had a hard cap on the amount that could be created. As a result, the feng shui had to be very calculated.
Once they have the OOB read, they decide to leak out data from the struct msg_msg. Since this has pointers, it is nice for breaking KASLR. Additionally, they use this leak to corrupt the msg_msg->next pointer and the length value of this structure to get a more powerful OOB read.
Once we have the leak, then we can ues our corruption to overwrite arbitrary data. Again, msg_msg is the object of choice. This is done by forcing a pause on a copy from userland to kernel then overwriting msg_msg->next with our overflow. Once the copy into our structure happens, we can write the data to arbitrary memory.
With the aribrary write, the authors overwrite the PATH of mobprobe, which is used to load userspace kernel modules. Their driver simply adds the setuid bit to bash to become root. Easy!
The bug is fairly simple. But, they had to learn all about the page level allocator and find unique objects to make this work because of the constraints in play. Overall, a great write up with awesome diagrams. It's sad this was found prior to their pwn2own entry.