Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

A Reference-Counting Bug in the Linux Kernel io_uring Subsystem - CVE-2021-20226- 463

Lucas Leong - ZDIPosted 4 Years Ago
  • The Linux kernel introduced a new subsystem for batching I/O operation system calls within the kernel. This is where the vulnerability is at.
  • When passing around pointers all around the kernel, it is important to know where these pointers are being used at. Otherwise, an object may be freed that is still being used somewhere. In order to keep track of this, a strategy known as reference counting is used. This keeps track of the always of pointers referencing this object. When the object gets to zero, it is okay to free the pointer.
  • In the IORING_OP_CLOSE operation, the system call passes a files_struct to the kernel thread. However, the pointer does not increment the reference count! This creates a discrepancy between the amount of expected places using this pointer and the actual amount. This creates a use after free (UAF) vulnerability.
  • In order to exploit this, a complicated series of thread manipulation must be done because there is a small window in which this is actually exploitable. The general idea is to make a call to location that handles files_struct to get a reference. Then, concurrently, get the IORING_OP_CLOSE to quickly run and free the object. Now, the other location has a UAF on the object.
  • In terms of actual exploitation, the author found a good candidate for each of a read and write primitive with map_lookup_elem and map_update_elem respectively. This functionality can be used to free the file object, insert our user controlled data with pointers into this location then the copy_to_user() function is called, allowing for an arbitrary read primitive.
  • For the arbitrary write primitive, a similar flow can be used but with the map_update_elem function with the data being written coming from userland. This exploit method is restricted to a one-core env because of the code being hit though.
  • An additional interesting point in this exploit is about making the race window easy to hit. By setting up recvmsg in the kernel to block on a specific operation, the race window becomes more consistent to win.
  • Overall, reference counting is difficult to do! A single mistake on not adding a reference can lead to complete compromise. The discoverer of the bug made a post that goes into the exploitation.