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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bpf-fix-unsound-scalar-forking-for-bpf_or'

Daniel Wade says:

====================
bpf: Fix unsound scalar forking for BPF_OR

maybe_fork_scalars() unconditionally sets the pushed path dst register
to 0 for both BPF_AND and BPF_OR. For AND this is correct (0 & K == 0),
but for OR it is wrong (0 | K == K, not 0). This causes the verifier to
track an incorrect value on the pushed path, leading to a verifier/runtime
divergence that allows out-of-bounds map value access.

v4: Use block comment style for multi-line comments in selftests (Amery Hung)
Add Reviewed-by/Acked-by tags
v3: Use single-line comment style in selftests (Alexei Starovoitov)
v2: Use push_stack(env, env->insn_idx, ...) to re-execute the insn
on the pushed path (Eduard Zingerman)
====================

Link: https://patch.msgid.link/20260314021521.128361-1-danjwade95@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+95 -1
+1 -1
kernel/bpf/verifier.c
··· 15999 15999 else 16000 16000 return 0; 16001 16001 16002 - branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); 16002 + branch = push_stack(env, env->insn_idx, env->insn_idx, false); 16003 16003 if (IS_ERR(branch)) 16004 16004 return PTR_ERR(branch); 16005 16005
+94
tools/testing/selftests/bpf/progs/verifier_bounds.c
··· 2037 2037 : __clobber_all); 2038 2038 } 2039 2039 2040 + SEC("socket") 2041 + __description("maybe_fork_scalars: OR with constant rejects OOB") 2042 + __failure __msg("invalid access to map value") 2043 + __naked void or_scalar_fork_rejects_oob(void) 2044 + { 2045 + asm volatile (" \ 2046 + r1 = 0; \ 2047 + *(u64*)(r10 - 8) = r1; \ 2048 + r2 = r10; \ 2049 + r2 += -8; \ 2050 + r1 = %[map_hash_8b] ll; \ 2051 + call %[bpf_map_lookup_elem]; \ 2052 + if r0 == 0 goto l0_%=; \ 2053 + r9 = r0; \ 2054 + r6 = *(u64*)(r9 + 0); \ 2055 + r6 s>>= 63; \ 2056 + r6 |= 8; \ 2057 + /* r6 is -1 (current) or 8 (pushed) */ \ 2058 + if r6 s< 0 goto l0_%=; \ 2059 + /* pushed path: r6 = 8, OOB for value_size=8 */ \ 2060 + r9 += r6; \ 2061 + r0 = *(u8*)(r9 + 0); \ 2062 + l0_%=: r0 = 0; \ 2063 + exit; \ 2064 + " : 2065 + : __imm(bpf_map_lookup_elem), 2066 + __imm_addr(map_hash_8b) 2067 + : __clobber_all); 2068 + } 2069 + 2070 + SEC("socket") 2071 + __description("maybe_fork_scalars: AND with constant still works") 2072 + __success __retval(0) 2073 + __naked void and_scalar_fork_still_works(void) 2074 + { 2075 + asm volatile (" \ 2076 + r1 = 0; \ 2077 + *(u64*)(r10 - 8) = r1; \ 2078 + r2 = r10; \ 2079 + r2 += -8; \ 2080 + r1 = %[map_hash_8b] ll; \ 2081 + call %[bpf_map_lookup_elem]; \ 2082 + if r0 == 0 goto l0_%=; \ 2083 + r9 = r0; \ 2084 + r6 = *(u64*)(r9 + 0); \ 2085 + r6 s>>= 63; \ 2086 + r6 &= 4; \ 2087 + /* \ 2088 + * r6 is 0 (pushed, 0&4==0) or 4 (current) \ 2089 + * both within value_size=8 \ 2090 + */ \ 2091 + if r6 s< 0 goto l0_%=; \ 2092 + r9 += r6; \ 2093 + r0 = *(u8*)(r9 + 0); \ 2094 + l0_%=: r0 = 0; \ 2095 + exit; \ 2096 + " : 2097 + : __imm(bpf_map_lookup_elem), 2098 + __imm_addr(map_hash_8b) 2099 + : __clobber_all); 2100 + } 2101 + 2102 + SEC("socket") 2103 + __description("maybe_fork_scalars: OR with constant allows in-bounds") 2104 + __success __retval(0) 2105 + __naked void or_scalar_fork_allows_inbounds(void) 2106 + { 2107 + asm volatile (" \ 2108 + r1 = 0; \ 2109 + *(u64*)(r10 - 8) = r1; \ 2110 + r2 = r10; \ 2111 + r2 += -8; \ 2112 + r1 = %[map_hash_8b] ll; \ 2113 + call %[bpf_map_lookup_elem]; \ 2114 + if r0 == 0 goto l0_%=; \ 2115 + r9 = r0; \ 2116 + r6 = *(u64*)(r9 + 0); \ 2117 + r6 s>>= 63; \ 2118 + r6 |= 4; \ 2119 + /* \ 2120 + * r6 is -1 (current) or 4 (pushed) \ 2121 + * pushed path: r6 = 4, within value_size=8 \ 2122 + */ \ 2123 + if r6 s< 0 goto l0_%=; \ 2124 + r9 += r6; \ 2125 + r0 = *(u8*)(r9 + 0); \ 2126 + l0_%=: r0 = 0; \ 2127 + exit; \ 2128 + " : 2129 + : __imm(bpf_map_lookup_elem), 2130 + __imm_addr(map_hash_8b) 2131 + : __clobber_all); 2132 + } 2133 + 2040 2134 char _license[] SEC("license") = "GPL";