Skip to content

Taking Kernel Hardening to the Next Level

Jinbum ParkHaehyun ChoSeolheui KimYeji KimBumhan KimTaesoo KimSungbae Yoo

Blue TeamBlack Hat Asia38 minAdvancedOpen on YouTube ↗

Details taking Kernel Hardening to the Next Level and evaluates key implications for security practitioners.

Summary

Overview: Jinho Jung from Samsung Research and Samsung Mobile Security presents advanced kernel hardening techniques addressing Control-Flow Integrity (CFI) and Use-After-Free (UAF) vulnerabilities in modern operating system kernels. Evaluating the precision and compatibility constraints of ARM Pointer Authentication (PAC) in C-based kernels like Linux, Jung introduces "K-L" (published at USENIX Security), which binds dynamic function pointers to invariant struct member names to achieve fine-grained CFI without compatibility failures. Additionally, Jung details a whole-kernel static binary validator to detect compiler-introduced signing oracles and introduces "B-Tag" (published at ASPLOS), a high-performance single-memory-access UAF defense mechanism.

Key Topics: - ARM Pointer Authentication Code (PAC) internals: pacia/autia instructions, QARMA block cipher, and context-dependent pointer signing - Precision vs. compatibility trade-offs in kernel CFI: type-based equivalence classes vs. storage address context failures during memcpy operations - "obj_bind" fine-grained CFI: binding function pointers to invariant struct member name fields and static verification of compiler passes - Scalable kernel Use-After-Free (UAF) mitigation: optimizing access validation via "B-Tag" base-identifier slot math and Top-Byte-Ignore (TBI)

Technical Details: ARM Pointer Authentication (PAC) utilizes hardware instructions (pacia, autia) and the QARMA cipher to sign pointers using a 64-bit address, secret key, and context modifier, storing the PAC in unused upper pointer bits. In standard type-based CFI (like PARTS), contexts are static hashes of function prototypes, creating broad equivalence classes where hundreds of indirect branches share identical contexts. While Apple's iOS kernel CFI achieves higher precision for C++ vtables by combining static function hashes with dynamic storage addresses, applying storage addresses to C kernels (like Linux) causes fatal compatibility failures: when structs containing signed function pointers are duplicated via memcpy(), the storage address changes while the context embedded in the PAC does not, causing kernel panics upon dereference.

To solve this, Jung proposed obj_bind. Instead of volatile storage addresses, obj_bind binds function pointers to invariant struct fields—such as constant name string pointers initialized at object creation. Because memcpy() copies both the function pointer and its adjacent invariant context field simultaneously, subsequent authentication succeeds without pointer resigning. Evaluated across 87 core Linux kernel structs, obj_bind eliminated 100% of broad equivalence classes with only 3–7% performance overhead. Furthermore, Jung discovered that LLVM compiler optimization passes introduce subtle vulnerabilities into PA-enabled kernels, creating Time-of-Check to Time-of-Use (TOCTOU) stack-spill races and signing oracles where attacker-controlled registers reach signing instructions. Jung developed a whole-kernel static binary validator enforcing four compiler safety principles to audit binaries.

For kernel Use-After-Free defenses, traditional access validation requires allocating random IDs in pointer bits and validating them against an external table, incurring three additional memory lookups per dereference via multi-level tables. Jung's B-Tag design stores the object ID directly in the object header and divides unused pointer bits into an 8-bit Base Identifier (BI) and an 8-bit random security tag. Assuming 4KB maximum object regions and 64-byte alignment, the kernel calculates the exact object header address from any interior pointer in a single memory access using bitmasking and slot offsets, reducing UAF mitigation overhead to ~20% (or 1–2% overhead when using ARM Top-Byte-Ignore [TBI] for start-pointer-only checks).

Key Takeaways: Hardware-assisted CFI cannot rely solely on static function prototypes; adopting invariant struct members as dynamic PAC contexts (obj_bind) delivers fine-grained protection without breaking kernel memory operations like memcpy. Kernel compiler pipelines must be verified with binary-level static analysis to ensure compiler optimizations do not emit PAC signing oracles or register-spill TOCTOU vulnerabilities. Kernel UAF mitigations must balance physical memory limits and pointer arithmetic; combining bit-split base identifiers with alignment-based slot math allows single-lookup access validation without multi-level page table traversals.

(AI summary — Gemini Flash)

Related talks