530 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Converted from tools/testing/selftests/bpf/verifier/array_access.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_ARRAY);17 __uint(max_entries, 1);18 __type(key, int);19 __type(value, struct test_val);20 __uint(map_flags, BPF_F_RDONLY_PROG);21} map_array_ro SEC(".maps");22 23struct {24 __uint(type, BPF_MAP_TYPE_ARRAY);25 __uint(max_entries, 1);26 __type(key, int);27 __type(value, struct test_val);28 __uint(map_flags, BPF_F_WRONLY_PROG);29} map_array_wo SEC(".maps");30 31struct {32 __uint(type, BPF_MAP_TYPE_HASH);33 __uint(max_entries, 1);34 __type(key, long long);35 __type(value, struct test_val);36} map_hash_48b SEC(".maps");37 38SEC("socket")39__description("valid map access into an array with a constant")40__success __failure_unpriv __msg_unpriv("R0 leaks addr")41__retval(0)42__naked void an_array_with_a_constant_1(void)43{44 asm volatile (" \45 r1 = 0; \46 *(u64*)(r10 - 8) = r1; \47 r2 = r10; \48 r2 += -8; \49 r1 = %[map_hash_48b] ll; \50 call %[bpf_map_lookup_elem]; \51 if r0 == 0 goto l0_%=; \52 r1 = %[test_val_foo]; \53 *(u64*)(r0 + 0) = r1; \54l0_%=: exit; \55" :56 : __imm(bpf_map_lookup_elem),57 __imm_addr(map_hash_48b),58 __imm_const(test_val_foo, offsetof(struct test_val, foo))59 : __clobber_all);60}61 62SEC("socket")63__description("valid map access into an array with a register")64__success __failure_unpriv __msg_unpriv("R0 leaks addr")65__retval(0) __flag(BPF_F_ANY_ALIGNMENT)66__naked void an_array_with_a_register_1(void)67{68 asm volatile (" \69 r1 = 0; \70 *(u64*)(r10 - 8) = r1; \71 r2 = r10; \72 r2 += -8; \73 r1 = %[map_hash_48b] ll; \74 call %[bpf_map_lookup_elem]; \75 if r0 == 0 goto l0_%=; \76 r1 = 4; \77 r1 <<= 2; \78 r0 += r1; \79 r1 = %[test_val_foo]; \80 *(u64*)(r0 + 0) = r1; \81l0_%=: exit; \82" :83 : __imm(bpf_map_lookup_elem),84 __imm_addr(map_hash_48b),85 __imm_const(test_val_foo, offsetof(struct test_val, foo))86 : __clobber_all);87}88 89SEC("socket")90__description("valid map access into an array with a variable")91__success __failure_unpriv __msg_unpriv("R0 leaks addr")92__retval(0) __flag(BPF_F_ANY_ALIGNMENT)93__naked void an_array_with_a_variable_1(void)94{95 asm volatile (" \96 r1 = 0; \97 *(u64*)(r10 - 8) = r1; \98 r2 = r10; \99 r2 += -8; \100 r1 = %[map_hash_48b] ll; \101 call %[bpf_map_lookup_elem]; \102 if r0 == 0 goto l0_%=; \103 r1 = *(u32*)(r0 + 0); \104 if r1 >= %[max_entries] goto l0_%=; \105 r1 <<= 2; \106 r0 += r1; \107 r1 = %[test_val_foo]; \108 *(u64*)(r0 + 0) = r1; \109l0_%=: exit; \110" :111 : __imm(bpf_map_lookup_elem),112 __imm_addr(map_hash_48b),113 __imm_const(max_entries, MAX_ENTRIES),114 __imm_const(test_val_foo, offsetof(struct test_val, foo))115 : __clobber_all);116}117 118SEC("socket")119__description("valid map access into an array with a signed variable")120__success __failure_unpriv __msg_unpriv("R0 leaks addr")121__retval(0) __flag(BPF_F_ANY_ALIGNMENT)122__naked void array_with_a_signed_variable(void)123{124 asm volatile (" \125 r1 = 0; \126 *(u64*)(r10 - 8) = r1; \127 r2 = r10; \128 r2 += -8; \129 r1 = %[map_hash_48b] ll; \130 call %[bpf_map_lookup_elem]; \131 if r0 == 0 goto l0_%=; \132 r1 = *(u32*)(r0 + 0); \133 if w1 s> 0xffffffff goto l1_%=; \134 w1 = 0; \135l1_%=: w2 = %[max_entries]; \136 if r2 s> r1 goto l2_%=; \137 w1 = 0; \138l2_%=: w1 <<= 2; \139 r0 += r1; \140 r1 = %[test_val_foo]; \141 *(u64*)(r0 + 0) = r1; \142l0_%=: exit; \143" :144 : __imm(bpf_map_lookup_elem),145 __imm_addr(map_hash_48b),146 __imm_const(max_entries, MAX_ENTRIES),147 __imm_const(test_val_foo, offsetof(struct test_val, foo))148 : __clobber_all);149}150 151SEC("socket")152__description("invalid map access into an array with a constant")153__failure __msg("invalid access to map value, value_size=48 off=48 size=8")154__failure_unpriv155__naked void an_array_with_a_constant_2(void)156{157 asm volatile (" \158 r1 = 0; \159 *(u64*)(r10 - 8) = r1; \160 r2 = r10; \161 r2 += -8; \162 r1 = %[map_hash_48b] ll; \163 call %[bpf_map_lookup_elem]; \164 if r0 == 0 goto l0_%=; \165 r1 = %[test_val_foo]; \166 *(u64*)(r0 + %[__imm_0]) = r1; \167l0_%=: exit; \168" :169 : __imm(bpf_map_lookup_elem),170 __imm_addr(map_hash_48b),171 __imm_const(__imm_0, (MAX_ENTRIES + 1) << 2),172 __imm_const(test_val_foo, offsetof(struct test_val, foo))173 : __clobber_all);174}175 176SEC("socket")177__description("invalid map access into an array with a register")178__failure __msg("R0 min value is outside of the allowed memory range")179__failure_unpriv180__flag(BPF_F_ANY_ALIGNMENT)181__naked void an_array_with_a_register_2(void)182{183 asm volatile (" \184 r1 = 0; \185 *(u64*)(r10 - 8) = r1; \186 r2 = r10; \187 r2 += -8; \188 r1 = %[map_hash_48b] ll; \189 call %[bpf_map_lookup_elem]; \190 if r0 == 0 goto l0_%=; \191 r1 = %[__imm_0]; \192 r1 <<= 2; \193 r0 += r1; \194 r1 = %[test_val_foo]; \195 *(u64*)(r0 + 0) = r1; \196l0_%=: exit; \197" :198 : __imm(bpf_map_lookup_elem),199 __imm_addr(map_hash_48b),200 __imm_const(__imm_0, MAX_ENTRIES + 1),201 __imm_const(test_val_foo, offsetof(struct test_val, foo))202 : __clobber_all);203}204 205SEC("socket")206__description("invalid map access into an array with a variable")207__failure208__msg("R0 unbounded memory access, make sure to bounds check any such access")209__failure_unpriv210__flag(BPF_F_ANY_ALIGNMENT)211__naked void an_array_with_a_variable_2(void)212{213 asm volatile (" \214 r1 = 0; \215 *(u64*)(r10 - 8) = r1; \216 r2 = r10; \217 r2 += -8; \218 r1 = %[map_hash_48b] ll; \219 call %[bpf_map_lookup_elem]; \220 if r0 == 0 goto l0_%=; \221 r1 = *(u32*)(r0 + 0); \222 r1 <<= 2; \223 r0 += r1; \224 r1 = %[test_val_foo]; \225 *(u64*)(r0 + 0) = r1; \226l0_%=: exit; \227" :228 : __imm(bpf_map_lookup_elem),229 __imm_addr(map_hash_48b),230 __imm_const(test_val_foo, offsetof(struct test_val, foo))231 : __clobber_all);232}233 234SEC("socket")235__description("invalid map access into an array with no floor check")236__failure __msg("R0 unbounded memory access")237__failure_unpriv __msg_unpriv("R0 leaks addr")238__flag(BPF_F_ANY_ALIGNMENT)239__naked void array_with_no_floor_check(void)240{241 asm volatile (" \242 r1 = 0; \243 *(u64*)(r10 - 8) = r1; \244 r2 = r10; \245 r2 += -8; \246 r1 = %[map_hash_48b] ll; \247 call %[bpf_map_lookup_elem]; \248 if r0 == 0 goto l0_%=; \249 r1 = *(u64*)(r0 + 0); \250 w2 = %[max_entries]; \251 if r2 s> r1 goto l1_%=; \252 w1 = 0; \253l1_%=: w1 <<= 2; \254 r0 += r1; \255 r1 = %[test_val_foo]; \256 *(u64*)(r0 + 0) = r1; \257l0_%=: exit; \258" :259 : __imm(bpf_map_lookup_elem),260 __imm_addr(map_hash_48b),261 __imm_const(max_entries, MAX_ENTRIES),262 __imm_const(test_val_foo, offsetof(struct test_val, foo))263 : __clobber_all);264}265 266SEC("socket")267__description("invalid map access into an array with a invalid max check")268__failure __msg("invalid access to map value, value_size=48 off=44 size=8")269__failure_unpriv __msg_unpriv("R0 leaks addr")270__flag(BPF_F_ANY_ALIGNMENT)271__naked void with_a_invalid_max_check_1(void)272{273 asm volatile (" \274 r1 = 0; \275 *(u64*)(r10 - 8) = r1; \276 r2 = r10; \277 r2 += -8; \278 r1 = %[map_hash_48b] ll; \279 call %[bpf_map_lookup_elem]; \280 if r0 == 0 goto l0_%=; \281 r1 = *(u32*)(r0 + 0); \282 w2 = %[__imm_0]; \283 if r2 > r1 goto l1_%=; \284 w1 = 0; \285l1_%=: w1 <<= 2; \286 r0 += r1; \287 r1 = %[test_val_foo]; \288 *(u64*)(r0 + 0) = r1; \289l0_%=: exit; \290" :291 : __imm(bpf_map_lookup_elem),292 __imm_addr(map_hash_48b),293 __imm_const(__imm_0, MAX_ENTRIES + 1),294 __imm_const(test_val_foo, offsetof(struct test_val, foo))295 : __clobber_all);296}297 298SEC("socket")299__description("invalid map access into an array with a invalid max check")300__failure __msg("R0 pointer += pointer")301__failure_unpriv302__flag(BPF_F_ANY_ALIGNMENT)303__naked void with_a_invalid_max_check_2(void)304{305 asm volatile (" \306 r1 = 0; \307 *(u64*)(r10 - 8) = r1; \308 r2 = r10; \309 r2 += -8; \310 r1 = %[map_hash_48b] ll; \311 call %[bpf_map_lookup_elem]; \312 if r0 == 0 goto l0_%=; \313 r8 = r0; \314 r1 = 0; \315 *(u64*)(r10 - 8) = r1; \316 r2 = r10; \317 r2 += -8; \318 r1 = %[map_hash_48b] ll; \319 call %[bpf_map_lookup_elem]; \320 if r0 == 0 goto l0_%=; \321 r0 += r8; \322 r0 = *(u32*)(r0 + %[test_val_foo]); \323l0_%=: exit; \324" :325 : __imm(bpf_map_lookup_elem),326 __imm_addr(map_hash_48b),327 __imm_const(test_val_foo, offsetof(struct test_val, foo))328 : __clobber_all);329}330 331SEC("socket")332__description("valid read map access into a read-only array 1")333__success __success_unpriv __retval(28)334__naked void a_read_only_array_1_1(void)335{336 asm volatile (" \337 r1 = 0; \338 *(u64*)(r10 - 8) = r1; \339 r2 = r10; \340 r2 += -8; \341 r1 = %[map_array_ro] ll; \342 call %[bpf_map_lookup_elem]; \343 if r0 == 0 goto l0_%=; \344 r0 = *(u32*)(r0 + 0); \345l0_%=: exit; \346" :347 : __imm(bpf_map_lookup_elem),348 __imm_addr(map_array_ro)349 : __clobber_all);350}351 352SEC("tc")353__description("valid read map access into a read-only array 2")354__success __retval(65507)355__naked void a_read_only_array_2_1(void)356{357 asm volatile (" \358 r1 = 0; \359 *(u64*)(r10 - 8) = r1; \360 r2 = r10; \361 r2 += -8; \362 r1 = %[map_array_ro] ll; \363 call %[bpf_map_lookup_elem]; \364 if r0 == 0 goto l0_%=; \365 r1 = r0; \366 r2 = 4; \367 r3 = 0; \368 r4 = 0; \369 r5 = 0; \370 call %[bpf_csum_diff]; \371l0_%=: r0 &= 0xffff; \372 exit; \373" :374 : __imm(bpf_csum_diff),375 __imm(bpf_map_lookup_elem),376 __imm_addr(map_array_ro)377 : __clobber_all);378}379 380SEC("socket")381__description("invalid write map access into a read-only array 1")382__failure __msg("write into map forbidden")383__failure_unpriv384__naked void a_read_only_array_1_2(void)385{386 asm volatile (" \387 r1 = 0; \388 *(u64*)(r10 - 8) = r1; \389 r2 = r10; \390 r2 += -8; \391 r1 = %[map_array_ro] ll; \392 call %[bpf_map_lookup_elem]; \393 if r0 == 0 goto l0_%=; \394 r1 = 42; \395 *(u64*)(r0 + 0) = r1; \396l0_%=: exit; \397" :398 : __imm(bpf_map_lookup_elem),399 __imm_addr(map_array_ro)400 : __clobber_all);401}402 403SEC("tc")404__description("invalid write map access into a read-only array 2")405__failure __msg("write into map forbidden")406__naked void a_read_only_array_2_2(void)407{408 asm volatile (" \409 r6 = r1; \410 r1 = 0; \411 *(u64*)(r10 - 8) = r1; \412 r2 = r10; \413 r2 += -8; \414 r1 = %[map_array_ro] ll; \415 call %[bpf_map_lookup_elem]; \416 if r0 == 0 goto l0_%=; \417 r1 = r6; \418 r2 = 0; \419 r3 = r0; \420 r4 = 8; \421 call %[bpf_skb_load_bytes]; \422l0_%=: exit; \423" :424 : __imm(bpf_map_lookup_elem),425 __imm(bpf_skb_load_bytes),426 __imm_addr(map_array_ro)427 : __clobber_all);428}429 430SEC("socket")431__description("valid write map access into a write-only array 1")432__success __success_unpriv __retval(1)433__naked void a_write_only_array_1_1(void)434{435 asm volatile (" \436 r1 = 0; \437 *(u64*)(r10 - 8) = r1; \438 r2 = r10; \439 r2 += -8; \440 r1 = %[map_array_wo] ll; \441 call %[bpf_map_lookup_elem]; \442 if r0 == 0 goto l0_%=; \443 r1 = 42; \444 *(u64*)(r0 + 0) = r1; \445l0_%=: r0 = 1; \446 exit; \447" :448 : __imm(bpf_map_lookup_elem),449 __imm_addr(map_array_wo)450 : __clobber_all);451}452 453SEC("tc")454__description("valid write map access into a write-only array 2")455__success __retval(0)456__naked void a_write_only_array_2_1(void)457{458 asm volatile (" \459 r6 = r1; \460 r1 = 0; \461 *(u64*)(r10 - 8) = r1; \462 r2 = r10; \463 r2 += -8; \464 r1 = %[map_array_wo] ll; \465 call %[bpf_map_lookup_elem]; \466 if r0 == 0 goto l0_%=; \467 r1 = r6; \468 r2 = 0; \469 r3 = r0; \470 r4 = 8; \471 call %[bpf_skb_load_bytes]; \472l0_%=: exit; \473" :474 : __imm(bpf_map_lookup_elem),475 __imm(bpf_skb_load_bytes),476 __imm_addr(map_array_wo)477 : __clobber_all);478}479 480SEC("socket")481__description("invalid read map access into a write-only array 1")482__failure __msg("read from map forbidden")483__failure_unpriv484__naked void a_write_only_array_1_2(void)485{486 asm volatile (" \487 r1 = 0; \488 *(u64*)(r10 - 8) = r1; \489 r2 = r10; \490 r2 += -8; \491 r1 = %[map_array_wo] ll; \492 call %[bpf_map_lookup_elem]; \493 if r0 == 0 goto l0_%=; \494 r0 = *(u64*)(r0 + 0); \495l0_%=: exit; \496" :497 : __imm(bpf_map_lookup_elem),498 __imm_addr(map_array_wo)499 : __clobber_all);500}501 502SEC("tc")503__description("invalid read map access into a write-only array 2")504__failure __msg("read from map forbidden")505__naked void a_write_only_array_2_2(void)506{507 asm volatile (" \508 r1 = 0; \509 *(u64*)(r10 - 8) = r1; \510 r2 = r10; \511 r2 += -8; \512 r1 = %[map_array_wo] ll; \513 call %[bpf_map_lookup_elem]; \514 if r0 == 0 goto l0_%=; \515 r1 = r0; \516 r2 = 4; \517 r3 = 0; \518 r4 = 0; \519 r5 = 0; \520 call %[bpf_csum_diff]; \521l0_%=: exit; \522" :523 : __imm(bpf_csum_diff),524 __imm(bpf_map_lookup_elem),525 __imm_addr(map_array_wo)526 : __clobber_all);527}528 529char _license[] SEC("license") = "GPL";530