Flexible and Concise Spectre Mitigations for BPF
EuroDW’23 Submission by Luis Gerhorst, Henriette Hofmeier, and Timo Hönig
Abstract:
High performance IO demands low-overhead communication between user- and kernel space. This demand can no longer be fulfilled by traditional system calls, which involve frequent transitions between user and kernel context. Linux’s extended Berkeley Packet Filter (BPF) avoid user-/kernel transitions by just-in-time compiling user bytecode and executing it in kernel-mode with near-native speed. To still isolate BPF programs from the kernel, they are statically analyzed for memory- and type-safety which imposes some restrictions but allows for good expressiveness and high performance. However, to mitigate the Spectre vulnerabilities disclosed in 2018, BPF’s expressiveness and performance had to be severely limited for unprivileged users to prevent speculative side-channel attacks. This forces users to resort to unsafe alternatives such as privileged BPF programs, which can not be consistently mitigated.
We empirically show that there is potential to improve the performance and expressiveness of unprivileged BPF without sacrificing safety. For this, we present preliminary microbenchmarks and show that a significant portion of real-world programs can not be successfully mitigated by the current implementation. To solve this, we propose to make the mitigations configurable at run-time in order to allow for flexible and concise Spectre mitigations.
1. Introduction
Operating systems rely on system calls to allow the controlled communication of isolated processes with the kernel and other processes. Every system call includes a processor mode switch from the unprivileged user mode to the privileged kernel mode. Although processor mode switches are the essential isolation mechanism to guarantee the system’s integrity, they induce direct and indirect performance costs as they invalidate parts of the processor state. In recent years, high-performance networks and storage hardware has made the user/kernel transition overhead the bottleneck for IO-heavy applications. To make matters worse, security vulnerabilities in modern processors (e.g., Meltdown) have prompted kernel mitigations that further increase the transition overhead.
Linux’s extended Berkeley Packet Filter (BPF) allow unprivileged user processes to load safety-checked bytecode into the kernel. The code is just-in-time compiled and executes at near-native speed. Invoking BPF programs in the kernel and calling kernel functions from within BPF is much faster than the respective switch to/from user context [4].
2. Related Work
To isolate the BPF programs from the kernel, the bytecode is statically verified
for memory- and type-safety in the v6.1 Linux kernel. Traditionally, only BPF
program paths that could actually execute architecturally were considered during
this static analysis. In response to the Spectre vulnerabilities disclosed in
2018
[1, 2, 8, 9, 11],
kernel developers have extended the BPF verifier to prevent side-channel leaks
from speculatively-executed BPF program paths. This includes (a) inserting
instructions to make speculation safe (e.g., index masking), (b) inserting
instructions to prevent speculation (e.g., x86 lfence
), or (c) statically
analyzing the behavior on speculative code paths to ensure they are safe. In
summary, these mitigations limit the performance and expressiveness of
unprivileged BPF programs in order make them safe1 even in the face of the Spectre attacks.
3. Preliminary Results
Our first contribution is a throughout analysis of current Linux BPF Sprectre mitigations. We empirically show that there is potential to improve the performance and expressiveness of unprivileged BPF without sacrificing safety [3, 6, 10, 12]. Regarding performance, this includes preliminary microbenchmarks of the Linux v6.1 BPF Spectre mitigations. Regarding expressiveness, we have collected BPF programs from multiple popular open-source projects and have found that a significant portion of these programs do not load with Spectre mitigations enabled. Finally, regarding safety, we rely on formal models as proposed by [3] and clearly state our attacker model and the assumptions about the hardware.
4. Work to be Done
Depending on the system’s context (guarantees from the hardware vendor and attack model), there are multiple feasible security policies to be implemented by the verifier. The current BPF verifier hard-codes on such policy for unprivileged programs and applies no consistent mitigation-policy to privileged programs.
We consider two approaches to solve this. First, the in-kernel verifier can be extended to apply mitigations more concisely, thereby improving performance and expressiveness. However, the verifier is already very complex which frequently leads to implementation bugs [5]. Second, as an alternative, the security policy implemented by the BPF verifier can be made configurable at runtime without increasing its complexity, for example, by integrating instructions to inhibit speculation into the BPF bytecode instruction set [7]. This would allow unprivileged programs to be concisely mitigated at load-time by a user space service. Further, this enables programmers and compilers to implement efficient mitigations for privileged programs manually at implementation-time, or automatically compile-time.
References:
Footnotes:
Not considering programming errors.