365 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Converted from tools/testing/selftests/bpf/verifier/regalloc.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 22SEC("tracepoint")23__description("regalloc basic")24__success __flag(BPF_F_ANY_ALIGNMENT)25__naked void regalloc_basic(void)26{27 asm volatile (" \28 r6 = r1; \29 r1 = 0; \30 *(u64*)(r10 - 8) = r1; \31 r2 = r10; \32 r2 += -8; \33 r1 = %[map_hash_48b] ll; \34 call %[bpf_map_lookup_elem]; \35 if r0 == 0 goto l0_%=; \36 r7 = r0; \37 call %[bpf_get_prandom_u32]; \38 r2 = r0; \39 if r0 s> 20 goto l0_%=; \40 if r2 s< 0 goto l0_%=; \41 r7 += r0; \42 r7 += r2; \43 r0 = *(u64*)(r7 + 0); \44l0_%=: exit; \45" :46 : __imm(bpf_get_prandom_u32),47 __imm(bpf_map_lookup_elem),48 __imm_addr(map_hash_48b)49 : __clobber_all);50}51 52SEC("tracepoint")53__description("regalloc negative")54__failure __msg("invalid access to map value, value_size=48 off=48 size=1")55__naked void regalloc_negative(void)56{57 asm volatile (" \58 r6 = r1; \59 r1 = 0; \60 *(u64*)(r10 - 8) = r1; \61 r2 = r10; \62 r2 += -8; \63 r1 = %[map_hash_48b] ll; \64 call %[bpf_map_lookup_elem]; \65 if r0 == 0 goto l0_%=; \66 r7 = r0; \67 call %[bpf_get_prandom_u32]; \68 r2 = r0; \69 if r0 s> 24 goto l0_%=; \70 if r2 s< 0 goto l0_%=; \71 r7 += r0; \72 r7 += r2; \73 r0 = *(u8*)(r7 + 0); \74l0_%=: exit; \75" :76 : __imm(bpf_get_prandom_u32),77 __imm(bpf_map_lookup_elem),78 __imm_addr(map_hash_48b)79 : __clobber_all);80}81 82SEC("tracepoint")83__description("regalloc src_reg mark")84__success __flag(BPF_F_ANY_ALIGNMENT)85__naked void regalloc_src_reg_mark(void)86{87 asm volatile (" \88 r6 = r1; \89 r1 = 0; \90 *(u64*)(r10 - 8) = r1; \91 r2 = r10; \92 r2 += -8; \93 r1 = %[map_hash_48b] ll; \94 call %[bpf_map_lookup_elem]; \95 if r0 == 0 goto l0_%=; \96 r7 = r0; \97 call %[bpf_get_prandom_u32]; \98 r2 = r0; \99 if r0 s> 20 goto l0_%=; \100 r3 = 0; \101 if r3 s>= r2 goto l0_%=; \102 r7 += r0; \103 r7 += r2; \104 r0 = *(u64*)(r7 + 0); \105l0_%=: exit; \106" :107 : __imm(bpf_get_prandom_u32),108 __imm(bpf_map_lookup_elem),109 __imm_addr(map_hash_48b)110 : __clobber_all);111}112 113SEC("tracepoint")114__description("regalloc src_reg negative")115__failure __msg("invalid access to map value, value_size=48 off=44 size=8")116__flag(BPF_F_ANY_ALIGNMENT)117__naked void regalloc_src_reg_negative(void)118{119 asm volatile (" \120 r6 = r1; \121 r1 = 0; \122 *(u64*)(r10 - 8) = r1; \123 r2 = r10; \124 r2 += -8; \125 r1 = %[map_hash_48b] ll; \126 call %[bpf_map_lookup_elem]; \127 if r0 == 0 goto l0_%=; \128 r7 = r0; \129 call %[bpf_get_prandom_u32]; \130 r2 = r0; \131 if r0 s> 22 goto l0_%=; \132 r3 = 0; \133 if r3 s>= r2 goto l0_%=; \134 r7 += r0; \135 r7 += r2; \136 r0 = *(u64*)(r7 + 0); \137l0_%=: exit; \138" :139 : __imm(bpf_get_prandom_u32),140 __imm(bpf_map_lookup_elem),141 __imm_addr(map_hash_48b)142 : __clobber_all);143}144 145SEC("tracepoint")146__description("regalloc and spill")147__success __flag(BPF_F_ANY_ALIGNMENT)148__naked void regalloc_and_spill(void)149{150 asm volatile (" \151 r6 = r1; \152 r1 = 0; \153 *(u64*)(r10 - 8) = r1; \154 r2 = r10; \155 r2 += -8; \156 r1 = %[map_hash_48b] ll; \157 call %[bpf_map_lookup_elem]; \158 if r0 == 0 goto l0_%=; \159 r7 = r0; \160 call %[bpf_get_prandom_u32]; \161 r2 = r0; \162 if r0 s> 20 goto l0_%=; \163 /* r0 has upper bound that should propagate into r2 */\164 *(u64*)(r10 - 8) = r2; /* spill r2 */ \165 r0 = 0; \166 r2 = 0; /* clear r0 and r2 */\167 r3 = *(u64*)(r10 - 8); /* fill r3 */ \168 if r0 s>= r3 goto l0_%=; \169 /* r3 has lower and upper bounds */ \170 r7 += r3; \171 r0 = *(u64*)(r7 + 0); \172l0_%=: exit; \173" :174 : __imm(bpf_get_prandom_u32),175 __imm(bpf_map_lookup_elem),176 __imm_addr(map_hash_48b)177 : __clobber_all);178}179 180SEC("tracepoint")181__description("regalloc and spill negative")182__failure __msg("invalid access to map value, value_size=48 off=48 size=8")183__flag(BPF_F_ANY_ALIGNMENT)184__naked void regalloc_and_spill_negative(void)185{186 asm volatile (" \187 r6 = r1; \188 r1 = 0; \189 *(u64*)(r10 - 8) = r1; \190 r2 = r10; \191 r2 += -8; \192 r1 = %[map_hash_48b] ll; \193 call %[bpf_map_lookup_elem]; \194 if r0 == 0 goto l0_%=; \195 r7 = r0; \196 call %[bpf_get_prandom_u32]; \197 r2 = r0; \198 if r0 s> 48 goto l0_%=; \199 /* r0 has upper bound that should propagate into r2 */\200 *(u64*)(r10 - 8) = r2; /* spill r2 */ \201 r0 = 0; \202 r2 = 0; /* clear r0 and r2 */\203 r3 = *(u64*)(r10 - 8); /* fill r3 */\204 if r0 s>= r3 goto l0_%=; \205 /* r3 has lower and upper bounds */ \206 r7 += r3; \207 r0 = *(u64*)(r7 + 0); \208l0_%=: exit; \209" :210 : __imm(bpf_get_prandom_u32),211 __imm(bpf_map_lookup_elem),212 __imm_addr(map_hash_48b)213 : __clobber_all);214}215 216SEC("tracepoint")217__description("regalloc three regs")218__success __flag(BPF_F_ANY_ALIGNMENT)219__naked void regalloc_three_regs(void)220{221 asm volatile (" \222 r6 = r1; \223 r1 = 0; \224 *(u64*)(r10 - 8) = r1; \225 r2 = r10; \226 r2 += -8; \227 r1 = %[map_hash_48b] ll; \228 call %[bpf_map_lookup_elem]; \229 if r0 == 0 goto l0_%=; \230 r7 = r0; \231 call %[bpf_get_prandom_u32]; \232 r2 = r0; \233 r4 = r2; \234 if r0 s> 12 goto l0_%=; \235 if r2 s< 0 goto l0_%=; \236 r7 += r0; \237 r7 += r2; \238 r7 += r4; \239 r0 = *(u64*)(r7 + 0); \240l0_%=: exit; \241" :242 : __imm(bpf_get_prandom_u32),243 __imm(bpf_map_lookup_elem),244 __imm_addr(map_hash_48b)245 : __clobber_all);246}247 248SEC("tracepoint")249__description("regalloc after call")250__success __flag(BPF_F_ANY_ALIGNMENT)251__naked void regalloc_after_call(void)252{253 asm volatile (" \254 r6 = r1; \255 r1 = 0; \256 *(u64*)(r10 - 8) = r1; \257 r2 = r10; \258 r2 += -8; \259 r1 = %[map_hash_48b] ll; \260 call %[bpf_map_lookup_elem]; \261 if r0 == 0 goto l0_%=; \262 r7 = r0; \263 call %[bpf_get_prandom_u32]; \264 r8 = r0; \265 r9 = r0; \266 call regalloc_after_call__1; \267 if r8 s> 20 goto l0_%=; \268 if r9 s< 0 goto l0_%=; \269 r7 += r8; \270 r7 += r9; \271 r0 = *(u64*)(r7 + 0); \272l0_%=: exit; \273" :274 : __imm(bpf_get_prandom_u32),275 __imm(bpf_map_lookup_elem),276 __imm_addr(map_hash_48b)277 : __clobber_all);278}279 280static __naked __noinline __attribute__((used))281void regalloc_after_call__1(void)282{283 asm volatile (" \284 r0 = 0; \285 exit; \286" ::: __clobber_all);287}288 289SEC("tracepoint")290__description("regalloc in callee")291__success __flag(BPF_F_ANY_ALIGNMENT)292__naked void regalloc_in_callee(void)293{294 asm volatile (" \295 r6 = r1; \296 r1 = 0; \297 *(u64*)(r10 - 8) = r1; \298 r2 = r10; \299 r2 += -8; \300 r1 = %[map_hash_48b] ll; \301 call %[bpf_map_lookup_elem]; \302 if r0 == 0 goto l0_%=; \303 r7 = r0; \304 call %[bpf_get_prandom_u32]; \305 r1 = r0; \306 r2 = r0; \307 r3 = r7; \308 call regalloc_in_callee__1; \309l0_%=: exit; \310" :311 : __imm(bpf_get_prandom_u32),312 __imm(bpf_map_lookup_elem),313 __imm_addr(map_hash_48b)314 : __clobber_all);315}316 317static __naked __noinline __attribute__((used))318void regalloc_in_callee__1(void)319{320 asm volatile (" \321 if r1 s> 20 goto l0_%=; \322 if r2 s< 0 goto l0_%=; \323 r3 += r1; \324 r3 += r2; \325 r0 = *(u64*)(r3 + 0); \326 exit; \327l0_%=: r0 = 0; \328 exit; \329" ::: __clobber_all);330}331 332SEC("tracepoint")333__description("regalloc, spill, JEQ")334__success335__naked void regalloc_spill_jeq(void)336{337 asm volatile (" \338 r6 = r1; \339 r1 = 0; \340 *(u64*)(r10 - 8) = r1; \341 r2 = r10; \342 r2 += -8; \343 r1 = %[map_hash_48b] ll; \344 call %[bpf_map_lookup_elem]; \345 *(u64*)(r10 - 8) = r0; /* spill r0 */ \346 if r0 == 0 goto l0_%=; \347l0_%=: /* The verifier will walk the rest twice with r0 == 0 and r0 == map_value */\348 call %[bpf_get_prandom_u32]; \349 r2 = r0; \350 if r2 == 20 goto l1_%=; \351l1_%=: /* The verifier will walk the rest two more times with r0 == 20 and r0 == unknown */\352 r3 = *(u64*)(r10 - 8); /* fill r3 with map_value */\353 if r3 == 0 goto l2_%=; /* skip ldx if map_value == NULL */\354 /* Buggy verifier will think that r3 == 20 here */\355 r0 = *(u64*)(r3 + 0); /* read from map_value */\356l2_%=: exit; \357" :358 : __imm(bpf_get_prandom_u32),359 __imm(bpf_map_lookup_elem),360 __imm_addr(map_hash_48b)361 : __clobber_all);362}363 364char _license[] SEC("license") = "GPL";365