Forward-Edge and Backward-Edge Control-Flow Integrity Performance in the Linux Kernel
Total Page:16
File Type:pdf, Size:1020Kb
Forward-Edge and Backward-Edge Control-Flow Integrity Performance in the Linux Kernel Christian Resell Thesis submitted for the degree of Master in Informatics: Programming and Networks 60 credits Department of Informatics Faculty of mathematics and natural sciences UNIVERSITY OF OSLO Spring 2020 Forward-Edge and Backward-Edge Control-Flow Integrity Performance in the Linux Kernel Christian Resell © 2020 Christian Resell Forward-Edge and Backward-Edge Control-Flow Integrity Performance in the Linux Kernel http://www.duo.uio.no/ Printed: Reprosentralen, University of Oslo Abstract This thesis will provide an overview of modern software defenses applied to the Linux kernel on the x86 64 and arm64 architectures. The main focus is the performance of forward-edge and backward-edge control-flow integrity. A requirement for control-flow integrity is to compile the Linux kernel with clang. Forward-edge control-flow integrity has an addition requirement of compiling the kernel with link-time optimization. Thus it is natural to also examine the effect of compiling the Linux kernel with clang, and what the performance impact of enabling link-time optimization is. The results gathered from the benchmarks show that link-time optimization provides a performance boost in almost every single macro benchmark. The re- sults also show that control-flow integrity comes at a cost. Kernels with control- flow integrity enabled perform worst in virtually all the benchmarks. Surpris- ingly, gcc performed better in the micro benchmarks, but performs slightly worse than clang on the macro benchmarks. 1 Acknowledgements First of all I would like to thank my supervisor, Knut Omang, for letting me choose my own topic for this thesis. His patience and great advice have been crucial for completing the thesis. Thanks to Aleksi Luukkonen for letting me use his hardware during the early stages of writing. This was very helpful for getting started. Thank you to Christoffer Buen for being a great rubber duck when I was stuck early in the research process. I would also like to thank my family for all the support they have given me through the years. Finally, I would like to thank my girlfriend, Marit Iren Rognli Tokle, for supporting me and putting up with me while I have been working on this thesis. June 15. 2020. Christian Resell 3 Contents 1 Introduction 1 1.1 Introduction . .1 1.2 Background and motivation . .1 1.3 Terms and definitions . .2 1.3.1 Vulnerability and exploit . .2 1.3.2 Kernel space and user space . .2 1.3.3 System calls . .2 1.3.4 Inlining . .2 1.4 Conventions . .3 1.5 Outline . .3 2 Linux kernel 4 2.1 Introduction . .4 2.2 History and distributions . .4 2.3 Android . .5 2.4 Android IPC — Binder . .6 2.5 Open source . .6 2.6 Architectures . .7 2.6.1 Calling conventions . .7 2.6.2 Prologues and epilogues . 12 3 Software vulnerabilities 14 3.1 Introduction . 14 3.2 Memory layout . 14 3.3 Memory corruption bugs . 17 3.4 Code-reuse attacks . 20 3.4.1 return-to-libc . 20 3.4.2 Return-oriented programming . 22 3.4.3 Jump-oriented programming . 23 3.4.4 Other attacks . 24 3.5 Memory corruption defenses . 24 3.5.1 Address space layout randomization . 24 3.5.2 Stack protection . 25 3.6 Other vulnerability classes . 26 3.6.1 Format string vulnerabilities . 26 3.6.2 Use-after-free vulnerabilities . 28 3.6.3 Type confusion . 28 3.6.4 Heap vulnerabilities in general . 28 5 3.6.5 Terminology . 28 4 Compilers and linkers 29 4.1 Introduction . 29 4.2 General information . 29 4.3 GNU Compiler Collection . 30 4.4 LLVM . 30 4.4.1 Vulnerability mitigations . 31 4.4.2 ASLR/PIE . 31 4.4.3 RELRO . 31 4.4.4 NX . 32 4.4.5 Fortify source . 32 4.4.6 Compiler mitigation summary . 34 4.4.7 Summary . 35 4.5 Link-time optimization . 35 4.5.1 Link-time optimization in LLVM . 35 4.6 Control-flow integrity . 36 4.6.1 Forward-edge control-flow integrity in clang . 36 4.6.2 Cross-DSO CFI . 43 4.6.3 Backward-edge control-flow integrity in clang . 45 4.7 Hardware alternatives . 47 4.7.1 CET . 47 4.7.2 PAC . 48 5 Linux kernel internals 49 5.1 Introduction . 49 5.2 Linux kernel versions . 49 5.3 Build system . 50 5.4 Linux kernel security . 51 5.4.1 KASLR . 51 5.4.2 SMEP/PXN . 51 5.4.3 SMAP/PAN . 51 5.4.4 STRICT KERNEL RWX ..................... 51 5.4.5 STRICT DEVMEM ........................ 51 5.4.6 HARDENED USERCOPY ..................... 52 5.4.7 Page Table Isolation . 52 6 Forward-edge and backward-edge control-flow integrity in the Linux kernel 54 6.1 Introduction . 54 6.2 Building the Linux kernel with clang . 54 6.2.1 Variable-length arrays . 54 6.2.2 Assembly goto . 55 6.3 LTO, CFI, and SCS in Linux . 55 6.3.1 Link-time optimization . 55 6.3.2 Control-flow integrity . 56 6.3.3 CFI failure . 57 6.4 ShadowCallStack . 60 6 7 Performance benchmarks 64 7.1 Introduction . 64 7.2 Motivation and previous work . 66 7.3 Binary size . 68 7.4 Compile time . 68 7.5 Kernel performance . 69 7.6 WireGuard . 69 8 Results 71 8.1 Introduction . 71 8.2 QEMU results . 71 8.3 Binary size . 72 8.4 Compilation time . 72 8.5 Micro benchmarks . 73 8.5.1 LMBench . 73 8.6 Macro benchmarks . 86 8.6.1 Redis . 86 8.6.2 ApacheBench . 87 8.6.3 WireGuard . 92 8.7 Android benchmarks . 96 8.8 Summary . 96 8.9 Future work . 97 A Scripts 99 A.1 Linux kernel installation script . 99 A.2 Linux kernel build script . 100 A.3 Android Linux kernel build script . 102 A.4 Docker . 103 A.5 Benchmarking script . 103 A.6 Python benchmarking scripts . 104 A.7 WireGuard benchmarking . 123 B Code 132 B.1 CFI failure fixes . 132 B.2 Inline limit patch . 133 7 List of Tables 2.1 Android versions . .6 2.2 binder domains . .6 2.3 x86 64 registers . .8 2.4 arm64 registers . .8 3.1 ELF sections . 15 4.1 LLVM sub-projects . 30 4.2 Compiler mitigation summary . 34 4.3 CFI schemes . 36 5.1 Longterm release kernels . 50 7.1 x86 64 kernel configurations . 64 7.2 arm64 kernel configurations . 65 7.3 Micro and macro benchmarks . 69 7.4 LMBench bandwidth benchmarks description . ..