summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/progs/uninit_stack.c
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2023-02-22 12:34:51 -0800
committerAlexei Starovoitov <ast@kernel.org>2023-02-22 12:34:51 -0800
commitbf9bec4cb3a401a14c24a7ef937d3c26aff9ad60 (patch)
treeeb8bd666efbe96ebae7a891d0b8661dcad7fbbcf /tools/testing/selftests/bpf/progs/uninit_stack.c
parent5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 (diff)
parent6338a94d5ab42a94e96ea36edc5f7df1fe73e68e (diff)
Merge branch 'bpf: Allow reads from uninit stack'
Eduard Zingerman says: ==================== This patch-set modifies BPF verifier to accept programs that read from uninitialized stack locations, but only if executed in privileged mode. This provides significant verification performance gains: 30% to 70% less processed states for big number of test programs. The reason for performance gains comes from treating STACK_MISC and STACK_INVALID as compatible, when cached state is compared to current state in verifier.c:stacksafe(). The change should not affect safety, because any value read from STACK_MISC location has full binary range (e.g. 0x00-0xff for byte-sized reads). Details and measurements are provided in the description for the patch #1. The change was suggested by Andrii Nakryiko, the initial patch was created by Alexei Starovoitov. The discussion could be found at [1]. Changes v1 -> v2 (v1 available at [2]): - Calls to helper functions now convert STACK_INVALID to STACK_MISC (suggested by Andrii); - The test case progs/test_global_func10.c is updated to expect new error message. Before recent commit [3] exact content of error messages was not verified for this test. - Replaced incorrect '//'-style comments in test case asm blocks by '/*...*/'-style comments in order to fix compilation issues; - Changed the tag from "Suggested-By" to "Co-developed-by" for Alexei on patch #1, please let me know if this is appropriate use of the tag. [1] https://lore.kernel.org/bpf/CAADnVQKs2i1iuZ5SUGuJtxWVfGYR9kDgYKhq3rNV+kBLQCu7rA@mail.gmail.com/ [2] https://lore.kernel.org/bpf/20230216183606.2483834-1-eddyz87@gmail.com/ [3] 95ebb376176c ("selftests/bpf: Convert test_global_funcs test to test_loader framework") ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/testing/selftests/bpf/progs/uninit_stack.c')
-rw-r--r--tools/testing/selftests/bpf/progs/uninit_stack.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/progs/uninit_stack.c b/tools/testing/selftests/bpf/progs/uninit_stack.c
new file mode 100644
index 000000000000..8a403470e557
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/uninit_stack.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+/* Read an uninitialized value from stack at a fixed offset */
+SEC("socket")
+__naked int read_uninit_stack_fixed_off(void *ctx)
+{
+ asm volatile (" \
+ r0 = 0; \
+ /* force stack depth to be 128 */ \
+ *(u64*)(r10 - 128) = r1; \
+ r1 = *(u8 *)(r10 - 8 ); \
+ r0 += r1; \
+ r1 = *(u8 *)(r10 - 11); \
+ r1 = *(u8 *)(r10 - 13); \
+ r1 = *(u8 *)(r10 - 15); \
+ r1 = *(u16*)(r10 - 16); \
+ r1 = *(u32*)(r10 - 32); \
+ r1 = *(u64*)(r10 - 64); \
+ /* read from a spill of a wrong size, it is a separate \
+ * branch in check_stack_read_fixed_off() \
+ */ \
+ *(u32*)(r10 - 72) = r1; \
+ r1 = *(u64*)(r10 - 72); \
+ r0 = 0; \
+ exit; \
+"
+ ::: __clobber_all);
+}
+
+/* Read an uninitialized value from stack at a variable offset */
+SEC("socket")
+__naked int read_uninit_stack_var_off(void *ctx)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ /* force stack depth to be 64 */ \
+ *(u64*)(r10 - 64) = r0; \
+ r0 = -r0; \
+ /* give r0 a range [-31, -1] */ \
+ if r0 s<= -32 goto exit_%=; \
+ if r0 s>= 0 goto exit_%=; \
+ /* access stack using r0 */ \
+ r1 = r10; \
+ r1 += r0; \
+ r2 = *(u8*)(r1 + 0); \
+exit_%=: r0 = 0; \
+ exit; \
+"
+ :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
+static __noinline void dummy(void) {}
+
+/* Pass a pointer to uninitialized stack memory to a helper.
+ * Passed memory block should be marked as STACK_MISC after helper call.
+ */
+SEC("socket")
+__log_level(7) __msg("fp-104=mmmmmmmm")
+__naked int helper_uninit_to_misc(void *ctx)
+{
+ asm volatile (" \
+ /* force stack depth to be 128 */ \
+ *(u64*)(r10 - 128) = r1; \
+ r1 = r10; \
+ r1 += -128; \
+ r2 = 32; \
+ call %[bpf_trace_printk]; \
+ /* Call to dummy() forces print_verifier_state(..., true), \
+ * thus showing the stack state, matched by __msg(). \
+ */ \
+ call %[dummy]; \
+ r0 = 0; \
+ exit; \
+"
+ :
+ : __imm(bpf_trace_printk),
+ __imm(dummy)
+ : __clobber_all);
+}
+
+char _license[] SEC("license") = "GPL";