289 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Converted from tools/testing/selftests/bpf/verifier/value_or_null.c */3 4#include <linux/bpf.h>5#include <bpf/bpf_helpers.h>6#include "bpf_misc.h"7 8#define MAX_ENTRIES 119 10struct test_val {11 unsigned int index;12 int foo[MAX_ENTRIES];13};14 15struct {16 __uint(type, BPF_MAP_TYPE_HASH);17 __uint(max_entries, 1);18 __type(key, long long);19 __type(value, struct test_val);20} map_hash_48b SEC(".maps");21 22struct {23 __uint(type, BPF_MAP_TYPE_HASH);24 __uint(max_entries, 1);25 __type(key, long long);26 __type(value, long long);27} map_hash_8b SEC(".maps");28 29SEC("tc")30__description("multiple registers share map_lookup_elem result")31__success __retval(0)32__naked void share_map_lookup_elem_result(void)33{34 asm volatile (" \35 r1 = 10; \36 *(u64*)(r10 - 8) = r1; \37 r2 = r10; \38 r2 += -8; \39 r1 = %[map_hash_8b] ll; \40 call %[bpf_map_lookup_elem]; \41 r4 = r0; \42 if r0 == 0 goto l0_%=; \43 r1 = 0; \44 *(u64*)(r4 + 0) = r1; \45l0_%=: exit; \46" :47 : __imm(bpf_map_lookup_elem),48 __imm_addr(map_hash_8b)49 : __clobber_all);50}51 52SEC("tc")53__description("alu ops on ptr_to_map_value_or_null, 1")54__failure __msg("R4 pointer arithmetic on map_value_or_null")55__naked void map_value_or_null_1(void)56{57 asm volatile (" \58 r1 = 10; \59 *(u64*)(r10 - 8) = r1; \60 r2 = r10; \61 r2 += -8; \62 r1 = %[map_hash_8b] ll; \63 call %[bpf_map_lookup_elem]; \64 r4 = r0; \65 r4 += -2; \66 r4 += 2; \67 if r0 == 0 goto l0_%=; \68 r1 = 0; \69 *(u64*)(r4 + 0) = r1; \70l0_%=: exit; \71" :72 : __imm(bpf_map_lookup_elem),73 __imm_addr(map_hash_8b)74 : __clobber_all);75}76 77SEC("tc")78__description("alu ops on ptr_to_map_value_or_null, 2")79__failure __msg("R4 pointer arithmetic on map_value_or_null")80__naked void map_value_or_null_2(void)81{82 asm volatile (" \83 r1 = 10; \84 *(u64*)(r10 - 8) = r1; \85 r2 = r10; \86 r2 += -8; \87 r1 = %[map_hash_8b] ll; \88 call %[bpf_map_lookup_elem]; \89 r4 = r0; \90 r4 &= -1; \91 if r0 == 0 goto l0_%=; \92 r1 = 0; \93 *(u64*)(r4 + 0) = r1; \94l0_%=: exit; \95" :96 : __imm(bpf_map_lookup_elem),97 __imm_addr(map_hash_8b)98 : __clobber_all);99}100 101SEC("tc")102__description("alu ops on ptr_to_map_value_or_null, 3")103__failure __msg("R4 pointer arithmetic on map_value_or_null")104__naked void map_value_or_null_3(void)105{106 asm volatile (" \107 r1 = 10; \108 *(u64*)(r10 - 8) = r1; \109 r2 = r10; \110 r2 += -8; \111 r1 = %[map_hash_8b] ll; \112 call %[bpf_map_lookup_elem]; \113 r4 = r0; \114 r4 <<= 1; \115 if r0 == 0 goto l0_%=; \116 r1 = 0; \117 *(u64*)(r4 + 0) = r1; \118l0_%=: exit; \119" :120 : __imm(bpf_map_lookup_elem),121 __imm_addr(map_hash_8b)122 : __clobber_all);123}124 125SEC("tc")126__description("invalid memory access with multiple map_lookup_elem calls")127__failure __msg("R4 !read_ok")128__naked void multiple_map_lookup_elem_calls(void)129{130 asm volatile (" \131 r1 = 10; \132 *(u64*)(r10 - 8) = r1; \133 r2 = r10; \134 r2 += -8; \135 r1 = %[map_hash_8b] ll; \136 r8 = r1; \137 r7 = r2; \138 call %[bpf_map_lookup_elem]; \139 r4 = r0; \140 r1 = r8; \141 r2 = r7; \142 call %[bpf_map_lookup_elem]; \143 if r0 == 0 goto l0_%=; \144 r1 = 0; \145 *(u64*)(r4 + 0) = r1; \146l0_%=: exit; \147" :148 : __imm(bpf_map_lookup_elem),149 __imm_addr(map_hash_8b)150 : __clobber_all);151}152 153SEC("tc")154__description("valid indirect map_lookup_elem access with 2nd lookup in branch")155__success __retval(0)156__naked void with_2nd_lookup_in_branch(void)157{158 asm volatile (" \159 r1 = 10; \160 *(u64*)(r10 - 8) = r1; \161 r2 = r10; \162 r2 += -8; \163 r1 = %[map_hash_8b] ll; \164 r8 = r1; \165 r7 = r2; \166 call %[bpf_map_lookup_elem]; \167 r2 = 10; \168 if r2 != 0 goto l0_%=; \169 r1 = r8; \170 r2 = r7; \171 call %[bpf_map_lookup_elem]; \172l0_%=: r4 = r0; \173 if r0 == 0 goto l1_%=; \174 r1 = 0; \175 *(u64*)(r4 + 0) = r1; \176l1_%=: exit; \177" :178 : __imm(bpf_map_lookup_elem),179 __imm_addr(map_hash_8b)180 : __clobber_all);181}182 183SEC("socket")184__description("invalid map access from else condition")185__failure __msg("R0 unbounded memory access")186__failure_unpriv __msg_unpriv("R0 leaks addr")187__flag(BPF_F_ANY_ALIGNMENT)188__naked void map_access_from_else_condition(void)189{190 asm volatile (" \191 r1 = 0; \192 *(u64*)(r10 - 8) = r1; \193 r2 = r10; \194 r2 += -8; \195 r1 = %[map_hash_48b] ll; \196 call %[bpf_map_lookup_elem]; \197 if r0 == 0 goto l0_%=; \198 r1 = *(u32*)(r0 + 0); \199 if r1 >= %[__imm_0] goto l1_%=; \200 r1 += 1; \201l1_%=: r1 <<= 2; \202 r0 += r1; \203 r1 = %[test_val_foo]; \204 *(u64*)(r0 + 0) = r1; \205l0_%=: exit; \206" :207 : __imm(bpf_map_lookup_elem),208 __imm_addr(map_hash_48b),209 __imm_const(__imm_0, MAX_ENTRIES-1),210 __imm_const(test_val_foo, offsetof(struct test_val, foo))211 : __clobber_all);212}213 214SEC("tc")215__description("map lookup and null branch prediction")216__success __retval(0)217__naked void lookup_and_null_branch_prediction(void)218{219 asm volatile (" \220 r1 = 10; \221 *(u64*)(r10 - 8) = r1; \222 r2 = r10; \223 r2 += -8; \224 r1 = %[map_hash_8b] ll; \225 call %[bpf_map_lookup_elem]; \226 r6 = r0; \227 if r6 == 0 goto l0_%=; \228 if r6 != 0 goto l0_%=; \229 r10 += 10; \230l0_%=: exit; \231" :232 : __imm(bpf_map_lookup_elem),233 __imm_addr(map_hash_8b)234 : __clobber_all);235}236 237SEC("cgroup/skb")238__description("MAP_VALUE_OR_NULL check_ids() in regsafe()")239__failure __msg("R8 invalid mem access 'map_value_or_null'")240__failure_unpriv __msg_unpriv("")241__flag(BPF_F_TEST_STATE_FREQ)242__naked void null_check_ids_in_regsafe(void)243{244 asm volatile (" \245 r1 = 0; \246 *(u64*)(r10 - 8) = r1; \247 /* r9 = map_lookup_elem(...) */ \248 r2 = r10; \249 r2 += -8; \250 r1 = %[map_hash_8b] ll; \251 call %[bpf_map_lookup_elem]; \252 r9 = r0; \253 /* r8 = map_lookup_elem(...) */ \254 r2 = r10; \255 r2 += -8; \256 r1 = %[map_hash_8b] ll; \257 call %[bpf_map_lookup_elem]; \258 r8 = r0; \259 /* r7 = ktime_get_ns() */ \260 call %[bpf_ktime_get_ns]; \261 r7 = r0; \262 /* r6 = ktime_get_ns() */ \263 call %[bpf_ktime_get_ns]; \264 r6 = r0; \265 /* if r6 > r7 goto +1 ; no new information about the state is derived from\266 * ; this check, thus produced verifier states differ\267 * ; only in 'insn_idx' \268 * r9 = r8 ; optionally share ID between r9 and r8\269 */ \270 if r6 > r7 goto l0_%=; \271 r9 = r8; \272l0_%=: /* if r9 == 0 goto <exit> */ \273 if r9 == 0 goto l1_%=; \274 /* read map value via r8, this is not always \275 * safe because r8 might be not equal to r9. \276 */ \277 r0 = *(u64*)(r8 + 0); \278l1_%=: /* exit 0 */ \279 r0 = 0; \280 exit; \281" :282 : __imm(bpf_ktime_get_ns),283 __imm(bpf_map_lookup_elem),284 __imm_addr(map_hash_8b)285 : __clobber_all);286}287 288char _license[] SEC("license") = "GPL";289