Skip to content

Commit 6338a94

Browse files
eddyz87Alexei Starovoitov
authored andcommitted
selftests/bpf: Tests for uninitialized stack reads
Three testcases to make sure that stack reads from uninitialized locations are accepted by verifier when executed in privileged mode: - read from a fixed offset; - read from a variable offset; - passing a pointer to stack to a helper converts STACK_INVALID to STACK_MISC. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/r/20230219200427.606541-3-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 6715df8 commit 6338a94

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <test_progs.h>
4+
#include "uninit_stack.skel.h"
5+
6+
void test_uninit_stack(void)
7+
{
8+
RUN_TESTS(uninit_stack);
9+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
#include "bpf_misc.h"
6+
7+
/* Read an uninitialized value from stack at a fixed offset */
8+
SEC("socket")
9+
__naked int read_uninit_stack_fixed_off(void *ctx)
10+
{
11+
asm volatile (" \
12+
r0 = 0; \
13+
/* force stack depth to be 128 */ \
14+
*(u64*)(r10 - 128) = r1; \
15+
r1 = *(u8 *)(r10 - 8 ); \
16+
r0 += r1; \
17+
r1 = *(u8 *)(r10 - 11); \
18+
r1 = *(u8 *)(r10 - 13); \
19+
r1 = *(u8 *)(r10 - 15); \
20+
r1 = *(u16*)(r10 - 16); \
21+
r1 = *(u32*)(r10 - 32); \
22+
r1 = *(u64*)(r10 - 64); \
23+
/* read from a spill of a wrong size, it is a separate \
24+
* branch in check_stack_read_fixed_off() \
25+
*/ \
26+
*(u32*)(r10 - 72) = r1; \
27+
r1 = *(u64*)(r10 - 72); \
28+
r0 = 0; \
29+
exit; \
30+
"
31+
::: __clobber_all);
32+
}
33+
34+
/* Read an uninitialized value from stack at a variable offset */
35+
SEC("socket")
36+
__naked int read_uninit_stack_var_off(void *ctx)
37+
{
38+
asm volatile (" \
39+
call %[bpf_get_prandom_u32]; \
40+
/* force stack depth to be 64 */ \
41+
*(u64*)(r10 - 64) = r0; \
42+
r0 = -r0; \
43+
/* give r0 a range [-31, -1] */ \
44+
if r0 s<= -32 goto exit_%=; \
45+
if r0 s>= 0 goto exit_%=; \
46+
/* access stack using r0 */ \
47+
r1 = r10; \
48+
r1 += r0; \
49+
r2 = *(u8*)(r1 + 0); \
50+
exit_%=: r0 = 0; \
51+
exit; \
52+
"
53+
:
54+
: __imm(bpf_get_prandom_u32)
55+
: __clobber_all);
56+
}
57+
58+
static __noinline void dummy(void) {}
59+
60+
/* Pass a pointer to uninitialized stack memory to a helper.
61+
* Passed memory block should be marked as STACK_MISC after helper call.
62+
*/
63+
SEC("socket")
64+
__log_level(7) __msg("fp-104=mmmmmmmm")
65+
__naked int helper_uninit_to_misc(void *ctx)
66+
{
67+
asm volatile (" \
68+
/* force stack depth to be 128 */ \
69+
*(u64*)(r10 - 128) = r1; \
70+
r1 = r10; \
71+
r1 += -128; \
72+
r2 = 32; \
73+
call %[bpf_trace_printk]; \
74+
/* Call to dummy() forces print_verifier_state(..., true), \
75+
* thus showing the stack state, matched by __msg(). \
76+
*/ \
77+
call %[dummy]; \
78+
r0 = 0; \
79+
exit; \
80+
"
81+
:
82+
: __imm(bpf_trace_printk),
83+
__imm(dummy)
84+
: __clobber_all);
85+
}
86+
87+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)