Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Allow reads from uninit stack

This commits updates the following functions to allow reads from
uninitialized stack locations when env->allow_uninit_stack option is
enabled:
- check_stack_read_fixed_off()
- check_stack_range_initialized(), called from:
- check_stack_read_var_off()
- check_helper_mem_access()

Such change allows to relax logic in stacksafe() to treat STACK_MISC
and STACK_INVALID in a same way and make the following stack slot
configurations equivalent:

| Cached state | Current state |
| stack slot | stack slot |
|------------------+------------------|
| STACK_INVALID or | STACK_INVALID or |
| STACK_MISC | STACK_SPILL or |
| | STACK_MISC or |
| | STACK_ZERO or |
| | STACK_DYNPTR |

This leads to significant verification speed gains (see below).

The idea was suggested by Andrii Nakryiko [1] and initial patch was
created by Alexei Starovoitov [2].

Currently the env->allow_uninit_stack is allowed for programs loaded
by users with CAP_PERFMON or CAP_SYS_ADMIN capabilities.

A number of test cases from verifier/*.c were expecting uninitialized
stack access to be an error. These test cases were updated to execute
in unprivileged mode (thus preserving the tests).

The test progs/test_global_func10.c expected "invalid indirect read
from stack" error message because of the access to uninitialized
memory region. This error is no longer possible in privileged mode.
The test is updated to provoke an error "invalid indirect access to
stack" because of access to invalid stack address (such error is not
verified by progs/test_global_func*.c series of tests).

The following tests had to be removed because these can't be made
unprivileged:
- verifier/sock.c:
- "sk_storage_get(map, skb->sk, &stack_value, 1): partially init
stack_value"
BPF_PROG_TYPE_SCHED_CLS programs are not executed in unprivileged mode.
- verifier/var_off.c:
- "indirect variable-offset stack access, max_off+size > max_initialized"
- "indirect variable-offset stack access, uninitialized"
These tests verify that access to uninitialized stack values is
detected when stack offset is not a constant. However, variable
stack access is prohibited in unprivileged mode, thus these tests
are no longer valid.

* * *

Here is veristat log comparing this patch with current master on a
set of selftest binaries listed in tools/testing/selftests/bpf/veristat.cfg
and cilium BPF binaries (see [3]):

$ ./veristat -e file,prog,states -C -f 'states_pct<-30' master.log current.log
File Program States (A) States (B) States (DIFF)
-------------------------- -------------------------- ---------- ---------- ----------------
bpf_host.o tail_handle_ipv6_from_host 349 244 -105 (-30.09%)
bpf_host.o tail_handle_nat_fwd_ipv4 1320 895 -425 (-32.20%)
bpf_lxc.o tail_handle_nat_fwd_ipv4 1320 895 -425 (-32.20%)
bpf_sock.o cil_sock4_connect 70 48 -22 (-31.43%)
bpf_sock.o cil_sock4_sendmsg 68 46 -22 (-32.35%)
bpf_xdp.o tail_handle_nat_fwd_ipv4 1554 803 -751 (-48.33%)
bpf_xdp.o tail_lb_ipv4 6457 2473 -3984 (-61.70%)
bpf_xdp.o tail_lb_ipv6 7249 3908 -3341 (-46.09%)
pyperf600_bpf_loop.bpf.o on_event 287 145 -142 (-49.48%)
strobemeta.bpf.o on_event 15915 4772 -11143 (-70.02%)
strobemeta_nounroll2.bpf.o on_event 17087 3820 -13267 (-77.64%)
xdp_synproxy_kern.bpf.o syncookie_tc 21271 6635 -14636 (-68.81%)
xdp_synproxy_kern.bpf.o syncookie_xdp 23122 6024 -17098 (-73.95%)
-------------------------- -------------------------- ---------- ---------- ----------------

Note: I limited selection by states_pct<-30%.

Inspection of differences in pyperf600_bpf_loop behavior shows that
the following patch for the test removes almost all differences:

- a/tools/testing/selftests/bpf/progs/pyperf.h
+ b/tools/testing/selftests/bpf/progs/pyperf.h
@ -266,8 +266,8 @ int __on_event(struct bpf_raw_tracepoint_args *ctx)
}

if (event->pthread_match || !pidData->use_tls) {
- void* frame_ptr;
- FrameData frame;
+ void* frame_ptr = 0;
+ FrameData frame = {};
Symbol sym = {};
int cur_cpu = bpf_get_smp_processor_id();

W/o this patch the difference comes from the following pattern
(for different variables):

static bool get_frame_data(... FrameData *frame ...)
{
...
bpf_probe_read_user(&frame->f_code, ...);
if (!frame->f_code)
return false;
...
bpf_probe_read_user(&frame->co_name, ...);
if (frame->co_name)
...;
}

int __on_event(struct bpf_raw_tracepoint_args *ctx)
{
FrameData frame;
...
get_frame_data(... &frame ...) // indirectly via a bpf_loop & callback
...
}

SEC("raw_tracepoint/kfree_skb")
int on_event(struct bpf_raw_tracepoint_args* ctx)
{
...
ret |= __on_event(ctx);
ret |= __on_event(ctx);
...
}

With regards to value `frame->co_name` the following is important:
- Because of the conditional `if (!frame->f_code)` each call to
__on_event() produces two states, one with `frame->co_name` marked
as STACK_MISC, another with it as is (and marked STACK_INVALID on a
first call).
- The call to bpf_probe_read_user() does not mark stack slots
corresponding to `&frame->co_name` as REG_LIVE_WRITTEN but it marks
these slots as BPF_MISC, this happens because of the following loop
in the check_helper_call():

for (i = 0; i < meta.access_size; i++) {
err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B,
BPF_WRITE, -1, false);
if (err)
return err;
}

Note the size of the write, it is a one byte write for each byte
touched by a helper. The BPF_B write does not lead to write marks
for the target stack slot.
- Which means that w/o this patch when second __on_event() call is
verified `if (frame->co_name)` will propagate read marks first to a
stack slot with STACK_MISC marks and second to a stack slot with
STACK_INVALID marks and these states would be considered different.

[1] https://lore.kernel.org/bpf/CAEf4BzY3e+ZuC6HUa8dCiUovQRg2SzEk7M-dSkqNZyn=xEmnPA@mail.gmail.com/
[2] https://lore.kernel.org/bpf/CAADnVQKs2i1iuZ5SUGuJtxWVfGYR9kDgYKhq3rNV+kBLQCu7rA@mail.gmail.com/
[3] git@github.com:anakryiko/cilium.git

Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Co-developed-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20230219200427.606541-2-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
6715df8d 5b7c4cab

+108 -136
+10 -1
kernel/bpf/verifier.c
··· 3826 3826 continue; 3827 3827 if (type == STACK_MISC) 3828 3828 continue; 3829 + if (type == STACK_INVALID && env->allow_uninit_stack) 3830 + continue; 3829 3831 verbose(env, "invalid read from stack off %d+%d size %d\n", 3830 3832 off, i, size); 3831 3833 return -EACCES; ··· 3864 3862 if (type == STACK_MISC) 3865 3863 continue; 3866 3864 if (type == STACK_ZERO) 3865 + continue; 3866 + if (type == STACK_INVALID && env->allow_uninit_stack) 3867 3867 continue; 3868 3868 verbose(env, "invalid read from stack off %d+%d size %d\n", 3869 3869 off, i, size); ··· 5758 5754 stype = &state->stack[spi].slot_type[slot % BPF_REG_SIZE]; 5759 5755 if (*stype == STACK_MISC) 5760 5756 goto mark; 5761 - if (*stype == STACK_ZERO) { 5757 + if ((*stype == STACK_ZERO) || 5758 + (*stype == STACK_INVALID && env->allow_uninit_stack)) { 5762 5759 if (clobber) { 5763 5760 /* helper can write anything into the stack */ 5764 5761 *stype = STACK_MISC; ··· 13939 13934 } 13940 13935 13941 13936 if (old->stack[spi].slot_type[i % BPF_REG_SIZE] == STACK_INVALID) 13937 + continue; 13938 + 13939 + if (env->allow_uninit_stack && 13940 + old->stack[spi].slot_type[i % BPF_REG_SIZE] == STACK_MISC) 13942 13941 continue; 13943 13942 13944 13943 /* explored stack has more populated slots than current stack
+4 -4
tools/testing/selftests/bpf/progs/test_global_func10.c
··· 5 5 #include "bpf_misc.h" 6 6 7 7 struct Small { 8 - int x; 8 + long x; 9 9 }; 10 10 11 11 struct Big { 12 - int x; 13 - int y; 12 + long x; 13 + long y; 14 14 }; 15 15 16 16 __noinline int foo(const struct Big *big) ··· 22 22 } 23 23 24 24 SEC("cgroup_skb/ingress") 25 - __failure __msg("invalid indirect read from stack") 25 + __failure __msg("invalid indirect access to stack") 26 26 int global_func10(struct __sk_buff *skb) 27 27 { 28 28 const struct Small small = {.x = skb->len };
+8 -5
tools/testing/selftests/bpf/verifier/calls.c
··· 2221 2221 * that fp-8 stack slot was unused in the fall-through 2222 2222 * branch and will accept the program incorrectly 2223 2223 */ 2224 - BPF_JMP_IMM(BPF_JGT, BPF_REG_1, 2, 2), 2224 + BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32), 2225 + BPF_JMP_IMM(BPF_JGT, BPF_REG_0, 2, 2), 2225 2226 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 2226 2227 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 2227 2228 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 2228 2229 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 2229 2230 BPF_LD_MAP_FD(BPF_REG_1, 0), 2230 2231 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 2232 + BPF_MOV64_IMM(BPF_REG_0, 0), 2231 2233 BPF_EXIT_INSN(), 2232 2234 }, 2233 - .fixup_map_hash_48b = { 6 }, 2234 - .errstr = "invalid indirect read from stack R2 off -8+0 size 8", 2235 - .result = REJECT, 2236 - .prog_type = BPF_PROG_TYPE_XDP, 2235 + .fixup_map_hash_48b = { 7 }, 2236 + .errstr_unpriv = "invalid indirect read from stack R2 off -8+0 size 8", 2237 + .result_unpriv = REJECT, 2238 + /* in privileged mode reads from uninitialized stack locations are permitted */ 2239 + .result = ACCEPT, 2237 2240 }, 2238 2241 { 2239 2242 "calls: ctx read at start of subprog",
+69 -35
tools/testing/selftests/bpf/verifier/helper_access_var_len.c
··· 29 29 { 30 30 "helper access to variable memory: stack, bitwise AND, zero included", 31 31 .insns = { 32 - BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), 33 - BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), 34 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), 35 - BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), 36 - BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), 37 - BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 64), 38 - BPF_MOV64_IMM(BPF_REG_3, 0), 39 - BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel), 32 + /* set max stack size */ 33 + BPF_ST_MEM(BPF_DW, BPF_REG_10, -128, 0), 34 + /* set r3 to a random value */ 35 + BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32), 36 + BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), 37 + /* use bitwise AND to limit r3 range to [0, 64] */ 38 + BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 64), 39 + BPF_LD_MAP_FD(BPF_REG_1, 0), 40 + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 41 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -64), 42 + BPF_MOV64_IMM(BPF_REG_4, 0), 43 + /* Call bpf_ringbuf_output(), it is one of a few helper functions with 44 + * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode. 45 + * For unpriv this should signal an error, because memory at &fp[-64] is 46 + * not initialized. 47 + */ 48 + BPF_EMIT_CALL(BPF_FUNC_ringbuf_output), 40 49 BPF_EXIT_INSN(), 41 50 }, 42 - .errstr = "invalid indirect read from stack R1 off -64+0 size 64", 43 - .result = REJECT, 44 - .prog_type = BPF_PROG_TYPE_TRACEPOINT, 51 + .fixup_map_ringbuf = { 4 }, 52 + .errstr_unpriv = "invalid indirect read from stack R2 off -64+0 size 64", 53 + .result_unpriv = REJECT, 54 + /* in privileged mode reads from uninitialized stack locations are permitted */ 55 + .result = ACCEPT, 45 56 }, 46 57 { 47 58 "helper access to variable memory: stack, bitwise AND + JMP, wrong max", ··· 194 183 { 195 184 "helper access to variable memory: stack, JMP, no min check", 196 185 .insns = { 197 - BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), 198 - BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), 199 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), 200 - BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), 201 - BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), 202 - BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 64, 3), 203 - BPF_MOV64_IMM(BPF_REG_3, 0), 204 - BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel), 186 + /* set max stack size */ 187 + BPF_ST_MEM(BPF_DW, BPF_REG_10, -128, 0), 188 + /* set r3 to a random value */ 189 + BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32), 190 + BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), 191 + /* use JMP to limit r3 range to [0, 64] */ 192 + BPF_JMP_IMM(BPF_JGT, BPF_REG_3, 64, 6), 193 + BPF_LD_MAP_FD(BPF_REG_1, 0), 194 + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 195 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -64), 196 + BPF_MOV64_IMM(BPF_REG_4, 0), 197 + /* Call bpf_ringbuf_output(), it is one of a few helper functions with 198 + * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode. 199 + * For unpriv this should signal an error, because memory at &fp[-64] is 200 + * not initialized. 201 + */ 202 + BPF_EMIT_CALL(BPF_FUNC_ringbuf_output), 205 203 BPF_MOV64_IMM(BPF_REG_0, 0), 206 204 BPF_EXIT_INSN(), 207 205 }, 208 - .errstr = "invalid indirect read from stack R1 off -64+0 size 64", 209 - .result = REJECT, 210 - .prog_type = BPF_PROG_TYPE_TRACEPOINT, 206 + .fixup_map_ringbuf = { 4 }, 207 + .errstr_unpriv = "invalid indirect read from stack R2 off -64+0 size 64", 208 + .result_unpriv = REJECT, 209 + /* in privileged mode reads from uninitialized stack locations are permitted */ 210 + .result = ACCEPT, 211 211 }, 212 212 { 213 213 "helper access to variable memory: stack, JMP (signed), no min check", ··· 586 564 { 587 565 "helper access to variable memory: 8 bytes leak", 588 566 .insns = { 589 - BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), 590 - BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), 591 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), 567 + /* set max stack size */ 568 + BPF_ST_MEM(BPF_DW, BPF_REG_10, -128, 0), 569 + /* set r3 to a random value */ 570 + BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32), 571 + BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), 572 + BPF_LD_MAP_FD(BPF_REG_1, 0), 573 + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 574 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -64), 592 575 BPF_MOV64_IMM(BPF_REG_0, 0), 593 576 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -64), 594 577 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -56), 595 578 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -48), 596 579 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -40), 580 + /* Note: fp[-32] left uninitialized */ 597 581 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -24), 598 582 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -16), 599 583 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), 600 - BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), 601 - BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), 602 - BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 63), 603 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), 604 - BPF_MOV64_IMM(BPF_REG_3, 0), 605 - BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel), 606 - BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16), 584 + /* Limit r3 range to [1, 64] */ 585 + BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 63), 586 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 1), 587 + BPF_MOV64_IMM(BPF_REG_4, 0), 588 + /* Call bpf_ringbuf_output(), it is one of a few helper functions with 589 + * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode. 590 + * For unpriv this should signal an error, because memory region [1, 64] 591 + * at &fp[-64] is not fully initialized. 592 + */ 593 + BPF_EMIT_CALL(BPF_FUNC_ringbuf_output), 594 + BPF_MOV64_IMM(BPF_REG_0, 0), 607 595 BPF_EXIT_INSN(), 608 596 }, 609 - .errstr = "invalid indirect read from stack R1 off -64+32 size 64", 610 - .result = REJECT, 611 - .prog_type = BPF_PROG_TYPE_TRACEPOINT, 597 + .fixup_map_ringbuf = { 3 }, 598 + .errstr_unpriv = "invalid indirect read from stack R2 off -64+32 size 64", 599 + .result_unpriv = REJECT, 600 + /* in privileged mode reads from uninitialized stack locations are permitted */ 601 + .result = ACCEPT, 612 602 }, 613 603 { 614 604 "helper access to variable memory: 8 bytes no leak (init memory)",
+5 -4
tools/testing/selftests/bpf/verifier/int_ptr.c
··· 54 54 /* bpf_strtoul() */ 55 55 BPF_EMIT_CALL(BPF_FUNC_strtoul), 56 56 57 - BPF_MOV64_IMM(BPF_REG_0, 1), 57 + BPF_MOV64_IMM(BPF_REG_0, 0), 58 58 BPF_EXIT_INSN(), 59 59 }, 60 - .result = REJECT, 61 - .prog_type = BPF_PROG_TYPE_CGROUP_SYSCTL, 62 - .errstr = "invalid indirect read from stack R4 off -16+4 size 8", 60 + .result_unpriv = REJECT, 61 + .errstr_unpriv = "invalid indirect read from stack R4 off -16+4 size 8", 62 + /* in privileged mode reads from uninitialized stack locations are permitted */ 63 + .result = ACCEPT, 63 64 }, 64 65 { 65 66 "ARG_PTR_TO_LONG misaligned",
+8 -5
tools/testing/selftests/bpf/verifier/search_pruning.c
··· 128 128 BPF_EXIT_INSN(), 129 129 }, 130 130 .fixup_map_hash_8b = { 3 }, 131 - .errstr = "invalid read from stack off -16+0 size 8", 132 - .result = REJECT, 133 - .prog_type = BPF_PROG_TYPE_TRACEPOINT, 131 + .errstr_unpriv = "invalid read from stack off -16+0 size 8", 132 + .result_unpriv = REJECT, 133 + /* in privileged mode reads from uninitialized stack locations are permitted */ 134 + .result = ACCEPT, 134 135 }, 135 136 { 136 137 "precision tracking for u32 spill/fill", ··· 259 258 BPF_EXIT_INSN(), 260 259 }, 261 260 .flags = BPF_F_TEST_STATE_FREQ, 262 - .errstr = "invalid read from stack off -8+1 size 8", 263 - .result = REJECT, 261 + .errstr_unpriv = "invalid read from stack off -8+1 size 8", 262 + .result_unpriv = REJECT, 263 + /* in privileged mode reads from uninitialized stack locations are permitted */ 264 + .result = ACCEPT, 264 265 },
-27
tools/testing/selftests/bpf/verifier/sock.c
··· 531 531 .result = ACCEPT, 532 532 }, 533 533 { 534 - "sk_storage_get(map, skb->sk, &stack_value, 1): partially init stack_value", 535 - .insns = { 536 - BPF_MOV64_IMM(BPF_REG_2, 0), 537 - BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8), 538 - BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, offsetof(struct __sk_buff, sk)), 539 - BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), 540 - BPF_MOV64_IMM(BPF_REG_0, 0), 541 - BPF_EXIT_INSN(), 542 - BPF_EMIT_CALL(BPF_FUNC_sk_fullsock), 543 - BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), 544 - BPF_MOV64_IMM(BPF_REG_0, 0), 545 - BPF_EXIT_INSN(), 546 - BPF_MOV64_IMM(BPF_REG_4, 1), 547 - BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), 548 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -8), 549 - BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), 550 - BPF_LD_MAP_FD(BPF_REG_1, 0), 551 - BPF_EMIT_CALL(BPF_FUNC_sk_storage_get), 552 - BPF_MOV64_IMM(BPF_REG_0, 0), 553 - BPF_EXIT_INSN(), 554 - }, 555 - .fixup_sk_storage_map = { 14 }, 556 - .prog_type = BPF_PROG_TYPE_SCHED_CLS, 557 - .result = REJECT, 558 - .errstr = "invalid indirect read from stack", 559 - }, 560 - { 561 534 "bpf_map_lookup_elem(smap, &key)", 562 535 .insns = { 563 536 BPF_ST_MEM(BPF_W, BPF_REG_10, -4, 0),
+4 -3
tools/testing/selftests/bpf/verifier/spill_fill.c
··· 171 171 BPF_MOV64_IMM(BPF_REG_0, 0), 172 172 BPF_EXIT_INSN(), 173 173 }, 174 - .result = REJECT, 175 - .errstr = "invalid read from stack off -4+0 size 4", 176 - .prog_type = BPF_PROG_TYPE_SCHED_CLS, 174 + .result_unpriv = REJECT, 175 + .errstr_unpriv = "invalid read from stack off -4+0 size 4", 176 + /* in privileged mode reads from uninitialized stack locations are permitted */ 177 + .result = ACCEPT, 177 178 }, 178 179 { 179 180 "Spill a u32 const scalar. Refill as u16. Offset to skb->data",
-52
tools/testing/selftests/bpf/verifier/var_off.c
··· 213 213 .prog_type = BPF_PROG_TYPE_LWT_IN, 214 214 }, 215 215 { 216 - "indirect variable-offset stack access, max_off+size > max_initialized", 217 - .insns = { 218 - /* Fill only the second from top 8 bytes of the stack. */ 219 - BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0), 220 - /* Get an unknown value. */ 221 - BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), 222 - /* Make it small and 4-byte aligned. */ 223 - BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), 224 - BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16), 225 - /* Add it to fp. We now have either fp-12 or fp-16, but we don't know 226 - * which. fp-12 size 8 is partially uninitialized stack. 227 - */ 228 - BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), 229 - /* Dereference it indirectly. */ 230 - BPF_LD_MAP_FD(BPF_REG_1, 0), 231 - BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), 232 - BPF_MOV64_IMM(BPF_REG_0, 0), 233 - BPF_EXIT_INSN(), 234 - }, 235 - .fixup_map_hash_8b = { 5 }, 236 - .errstr = "invalid indirect read from stack R2 var_off", 237 - .result = REJECT, 238 - .prog_type = BPF_PROG_TYPE_LWT_IN, 239 - }, 240 - { 241 216 "indirect variable-offset stack access, min_off < min_initialized", 242 217 .insns = { 243 218 /* Fill only the top 8 bytes of the stack. */ ··· 263 288 .result_unpriv = REJECT, 264 289 .result = ACCEPT, 265 290 .prog_type = BPF_PROG_TYPE_CGROUP_SKB, 266 - }, 267 - { 268 - "indirect variable-offset stack access, uninitialized", 269 - .insns = { 270 - BPF_MOV64_IMM(BPF_REG_2, 6), 271 - BPF_MOV64_IMM(BPF_REG_3, 28), 272 - /* Fill the top 16 bytes of the stack. */ 273 - BPF_ST_MEM(BPF_W, BPF_REG_10, -16, 0), 274 - BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 275 - /* Get an unknown value. */ 276 - BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, 0), 277 - /* Make it small and 4-byte aligned. */ 278 - BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 4), 279 - BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16), 280 - /* Add it to fp. We now have either fp-12 or fp-16, we don't know 281 - * which, but either way it points to initialized stack. 282 - */ 283 - BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10), 284 - BPF_MOV64_IMM(BPF_REG_5, 8), 285 - /* Dereference it indirectly. */ 286 - BPF_EMIT_CALL(BPF_FUNC_getsockopt), 287 - BPF_MOV64_IMM(BPF_REG_0, 0), 288 - BPF_EXIT_INSN(), 289 - }, 290 - .errstr = "invalid indirect read from stack R4 var_off", 291 - .result = REJECT, 292 - .prog_type = BPF_PROG_TYPE_SOCK_OPS, 293 291 }, 294 292 { 295 293 "indirect variable-offset stack access, ok",