162587Sitojun// SPDX-License-Identifier: GPL-2.0
278064Sume/* Converted from tools/testing/selftests/bpf/verifier/helper_value_access.c */
362587Sitojun
453541Sshin#include <linux/bpf.h>
553541Sshin#include <bpf/bpf_helpers.h>
653541Sshin#include "bpf_misc.h"
753541Sshin
853541Sshinstruct other_val {
953541Sshin	long long foo;
1053541Sshin	long long bar;
1153541Sshin};
1253541Sshin
1353541Sshinstruct {
1453541Sshin	__uint(type, BPF_MAP_TYPE_HASH);
1553541Sshin	__uint(max_entries, 1);
1653541Sshin	__type(key, long long);
1753541Sshin	__type(value, struct other_val);
1853541Sshin} map_hash_16b SEC(".maps");
1953541Sshin
2053541Sshin#define MAX_ENTRIES 11
2153541Sshin
2253541Sshinstruct test_val {
2353541Sshin	unsigned int index;
2453541Sshin	int foo[MAX_ENTRIES];
2553541Sshin};
2653541Sshin
2753541Sshinstruct {
2853541Sshin	__uint(type, BPF_MAP_TYPE_HASH);
2953541Sshin	__uint(max_entries, 1);
3053541Sshin	__type(key, long long);
3162587Sitojun	__type(value, struct test_val);
3262587Sitojun} map_hash_48b SEC(".maps");
3362587Sitojun
3462587Sitojunstruct {
3562587Sitojun	__uint(type, BPF_MAP_TYPE_HASH);
3653541Sshin	__uint(max_entries, 1);
3762587Sitojun	__type(key, long long);
3862587Sitojun	__type(value, long long);
3962587Sitojun} map_hash_8b SEC(".maps");
4062587Sitojun
4162587SitojunSEC("tracepoint")
4262587Sitojun__description("helper access to map: full range")
4362587Sitojun__success
4462587Sitojun__naked void access_to_map_full_range(void)
4562587Sitojun{
4662587Sitojun	asm volatile ("					\
4762587Sitojun	r2 = r10;					\
4862587Sitojun	r2 += -8;					\
4962587Sitojun	r1 = 0;						\
5062587Sitojun	*(u64*)(r2 + 0) = r1;				\
5162587Sitojun	r1 = %[map_hash_48b] ll;			\
5262587Sitojun	call %[bpf_map_lookup_elem];			\
5362587Sitojun	if r0 == 0 goto l0_%=;				\
5462587Sitojun	r1 = r0;					\
5562587Sitojun	r2 = %[sizeof_test_val];			\
5662587Sitojun	r3 = 0;						\
5762587Sitojun	call %[bpf_probe_read_kernel];			\
5862587Sitojunl0_%=:	exit;						\
5962587Sitojun"	:
6062587Sitojun	: __imm(bpf_map_lookup_elem),
6162587Sitojun	  __imm(bpf_probe_read_kernel),
6262587Sitojun	  __imm_addr(map_hash_48b),
6362587Sitojun	  __imm_const(sizeof_test_val, sizeof(struct test_val))
6462587Sitojun	: __clobber_all);
6562587Sitojun}
6653541Sshin
6753541SshinSEC("tracepoint")
6853541Sshin__description("helper access to map: partial range")
6962587Sitojun__success
7053541Sshin__naked void access_to_map_partial_range(void)
7162587Sitojun{
7262587Sitojun	asm volatile ("					\
7353541Sshin	r2 = r10;					\
7462587Sitojun	r2 += -8;					\
7562587Sitojun	r1 = 0;						\
7662587Sitojun	*(u64*)(r2 + 0) = r1;				\
7762587Sitojun	r1 = %[map_hash_48b] ll;			\
7862587Sitojun	call %[bpf_map_lookup_elem];			\
7962587Sitojun	if r0 == 0 goto l0_%=;				\
8062587Sitojun	r1 = r0;					\
8162587Sitojun	r2 = 8;						\
8262587Sitojun	r3 = 0;						\
8378064Sume	call %[bpf_probe_read_kernel];			\
8462587Sitojunl0_%=:	exit;						\
8562587Sitojun"	:
8662587Sitojun	: __imm(bpf_map_lookup_elem),
8762587Sitojun	  __imm(bpf_probe_read_kernel),
8862587Sitojun	  __imm_addr(map_hash_48b)
8962587Sitojun	: __clobber_all);
9062587Sitojun}
9162587Sitojun
9262587Sitojun/* Call a function taking a pointer and a size which doesn't allow the size to
9362587Sitojun * be zero (i.e. bpf_trace_printk() declares the second argument to be
9462587Sitojun * ARG_CONST_SIZE, not ARG_CONST_SIZE_OR_ZERO). We attempt to pass zero for the
9562587Sitojun * size and expect to fail.
9662587Sitojun */
9762587SitojunSEC("tracepoint")
9862587Sitojun__description("helper access to map: empty range")
9962587Sitojun__failure __msg("R2 invalid zero-sized read: u64=[0,0]")
10062587Sitojun__naked void access_to_map_empty_range(void)
10162587Sitojun{
10262587Sitojun	asm volatile ("					\
10362587Sitojun	r2 = r10;					\
10462587Sitojun	r2 += -8;					\
10562587Sitojun	r1 = 0;						\
10662587Sitojun	*(u64*)(r2 + 0) = r1;				\
10762587Sitojun	r1 = %[map_hash_48b] ll;			\
10862587Sitojun	call %[bpf_map_lookup_elem];			\
10962587Sitojun	if r0 == 0 goto l0_%=;				\
11062587Sitojun	r1 = r0;					\
11162587Sitojun	r2 = 0;						\
11262587Sitojun	call %[bpf_trace_printk];			\
11362587Sitojunl0_%=:	exit;						\
11462587Sitojun"	:
11562587Sitojun	: __imm(bpf_map_lookup_elem),
11662587Sitojun	  __imm(bpf_trace_printk),
11762587Sitojun	  __imm_addr(map_hash_48b)
11862587Sitojun	: __clobber_all);
11962587Sitojun}
12062587Sitojun
12162587Sitojun/* Like the test above, but this time the size register is not known to be zero;
12262587Sitojun * its lower-bound is zero though, which is still unacceptable.
12362587Sitojun */
12462587SitojunSEC("tracepoint")
12562587Sitojun__description("helper access to map: possibly-empty ange")
12662587Sitojun__failure __msg("R2 invalid zero-sized read: u64=[0,4]")
12778064Sume__naked void access_to_map_possibly_empty_range(void)
12878064Sume{
12978064Sume	asm volatile ("                                         \
13078064Sume	r2 = r10;                                               \
13162587Sitojun	r2 += -8;                                               \
13262587Sitojun	r1 = 0;                                                 \
13362587Sitojun	*(u64*)(r2 + 0) = r1;                                   \
13462587Sitojun	r1 = %[map_hash_48b] ll;                                \
13562587Sitojun	call %[bpf_map_lookup_elem];                            \
13662587Sitojun	if r0 == 0 goto l0_%=;                                  \
13762587Sitojun	r1 = r0;                                                \
13862587Sitojun	/* Read an unknown value */                             \
13962587Sitojun	r7 = *(u64*)(r0 + 0);                                   \
14062587Sitojun	/* Make it small and positive, to avoid other errors */ \
14162587Sitojun	r7 &= 4;                                                \
14262587Sitojun	r2 = 0;                                                 \
14362587Sitojun	r2 += r7;                                               \
14462587Sitojun	call %[bpf_trace_printk];                               \
14562587Sitojunl0_%=:	exit;                                               \
14662587Sitojun"	:
14762587Sitojun	: __imm(bpf_map_lookup_elem),
14862587Sitojun	  __imm(bpf_trace_printk),
14962587Sitojun	  __imm_addr(map_hash_48b)
15062587Sitojun	: __clobber_all);
15162587Sitojun}
15278064Sume
15362587SitojunSEC("tracepoint")
15462587Sitojun__description("helper access to map: out-of-bound range")
15562587Sitojun__failure __msg("invalid access to map value, value_size=48 off=0 size=56")
15662587Sitojun__naked void map_out_of_bound_range(void)
15762587Sitojun{
15862587Sitojun	asm volatile ("					\
15962587Sitojun	r2 = r10;					\
16062587Sitojun	r2 += -8;					\
16162587Sitojun	r1 = 0;						\
16262587Sitojun	*(u64*)(r2 + 0) = r1;				\
16362587Sitojun	r1 = %[map_hash_48b] ll;			\
16462587Sitojun	call %[bpf_map_lookup_elem];			\
16562587Sitojun	if r0 == 0 goto l0_%=;				\
16662587Sitojun	r1 = r0;					\
16762587Sitojun	r2 = %[__imm_0];				\
16862587Sitojun	r3 = 0;						\
16962587Sitojun	call %[bpf_probe_read_kernel];			\
17078064Sumel0_%=:	exit;						\
17162587Sitojun"	:
17262587Sitojun	: __imm(bpf_map_lookup_elem),
17362587Sitojun	  __imm(bpf_probe_read_kernel),
17462587Sitojun	  __imm_addr(map_hash_48b),
17562587Sitojun	  __imm_const(__imm_0, sizeof(struct test_val) + 8)
17662587Sitojun	: __clobber_all);
17762587Sitojun}
17862587Sitojun
17962587SitojunSEC("tracepoint")
18062587Sitojun__description("helper access to map: negative range")
18162587Sitojun__failure __msg("R2 min value is negative")
18262587Sitojun__naked void access_to_map_negative_range(void)
18362587Sitojun{
18462587Sitojun	asm volatile ("					\
18578064Sume	r2 = r10;					\
18662587Sitojun	r2 += -8;					\
18762587Sitojun	r1 = 0;						\
18862587Sitojun	*(u64*)(r2 + 0) = r1;				\
18962587Sitojun	r1 = %[map_hash_48b] ll;			\
19062587Sitojun	call %[bpf_map_lookup_elem];			\
19162587Sitojun	if r0 == 0 goto l0_%=;				\
19262587Sitojun	r1 = r0;					\
19362587Sitojun	r2 = -8;					\
19462587Sitojun	r3 = 0;						\
19562587Sitojun	call %[bpf_probe_read_kernel];			\
19662587Sitojunl0_%=:	exit;						\
19778064Sume"	:
19862587Sitojun	: __imm(bpf_map_lookup_elem),
19962587Sitojun	  __imm(bpf_probe_read_kernel),
20062587Sitojun	  __imm_addr(map_hash_48b)
20162587Sitojun	: __clobber_all);
20262587Sitojun}
20362587Sitojun
20462587SitojunSEC("tracepoint")
20562587Sitojun__description("helper access to adjusted map (via const imm): full range")
20678064Sume__success
20778064Sume__naked void via_const_imm_full_range(void)
20878064Sume{
20978064Sume	asm volatile ("					\
21078064Sume	r2 = r10;					\
21178064Sume	r2 += -8;					\
21278064Sume	r1 = 0;						\
21378064Sume	*(u64*)(r2 + 0) = r1;				\
21478064Sume	r1 = %[map_hash_48b] ll;			\
21578064Sume	call %[bpf_map_lookup_elem];			\
21678064Sume	if r0 == 0 goto l0_%=;				\
21778064Sume	r1 = r0;					\
21878064Sume	r1 += %[test_val_foo];				\
21962587Sitojun	r2 = %[__imm_0];				\
22062587Sitojun	r3 = 0;						\
22162587Sitojun	call %[bpf_probe_read_kernel];			\
22262587Sitojunl0_%=:	exit;						\
22362587Sitojun"	:
22462587Sitojun	: __imm(bpf_map_lookup_elem),
22578064Sume	  __imm(bpf_probe_read_kernel),
22662587Sitojun	  __imm_addr(map_hash_48b),
22762587Sitojun	  __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo)),
22862587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
22962587Sitojun	: __clobber_all);
23062587Sitojun}
23162587Sitojun
23262587SitojunSEC("tracepoint")
23362587Sitojun__description("helper access to adjusted map (via const imm): partial range")
23462587Sitojun__success
23562587Sitojun__naked void via_const_imm_partial_range(void)
23678064Sume{
23762587Sitojun	asm volatile ("					\
23862587Sitojun	r2 = r10;					\
23962587Sitojun	r2 += -8;					\
24062587Sitojun	r1 = 0;						\
24162587Sitojun	*(u64*)(r2 + 0) = r1;				\
24262587Sitojun	r1 = %[map_hash_48b] ll;			\
24362587Sitojun	call %[bpf_map_lookup_elem];			\
24462587Sitojun	if r0 == 0 goto l0_%=;				\
24562587Sitojun	r1 = r0;					\
24662587Sitojun	r1 += %[test_val_foo];				\
24762587Sitojun	r2 = 8;						\
24862587Sitojun	r3 = 0;						\
24962587Sitojun	call %[bpf_probe_read_kernel];			\
25062587Sitojunl0_%=:	exit;						\
25162587Sitojun"	:
25262587Sitojun	: __imm(bpf_map_lookup_elem),
25362587Sitojun	  __imm(bpf_probe_read_kernel),
25462587Sitojun	  __imm_addr(map_hash_48b),
25562587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
25662587Sitojun	: __clobber_all);
25762587Sitojun}
25862587Sitojun
25978064SumeSEC("tracepoint")
26062587Sitojun__description("helper access to adjusted map (via const imm): empty range")
26162587Sitojun__failure __msg("R2 invalid zero-sized read")
26262587Sitojun__naked void via_const_imm_empty_range(void)
26362587Sitojun{
26462587Sitojun	asm volatile ("					\
26562587Sitojun	r2 = r10;					\
26662587Sitojun	r2 += -8;					\
26762587Sitojun	r1 = 0;						\
26862587Sitojun	*(u64*)(r2 + 0) = r1;				\
26962587Sitojun	r1 = %[map_hash_48b] ll;			\
27078064Sume	call %[bpf_map_lookup_elem];			\
27162587Sitojun	if r0 == 0 goto l0_%=;				\
27262587Sitojun	r1 = r0;					\
27362587Sitojun	r1 += %[test_val_foo];				\
27462587Sitojun	r2 = 0;						\
27562587Sitojun	call %[bpf_trace_printk];			\
27662587Sitojunl0_%=:	exit;						\
27778064Sume"	:
27862587Sitojun	: __imm(bpf_map_lookup_elem),
27962587Sitojun	  __imm(bpf_trace_printk),
28062587Sitojun	  __imm_addr(map_hash_48b),
28162587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
28262587Sitojun	: __clobber_all);
28362587Sitojun}
28462587Sitojun
28562587SitojunSEC("tracepoint")
28662587Sitojun__description("helper access to adjusted map (via const imm): out-of-bound range")
28762587Sitojun__failure __msg("invalid access to map value, value_size=48 off=4 size=52")
28878064Sume__naked void imm_out_of_bound_range(void)
28962587Sitojun{
29062587Sitojun	asm volatile ("					\
29162587Sitojun	r2 = r10;					\
29262587Sitojun	r2 += -8;					\
29362587Sitojun	r1 = 0;						\
29462587Sitojun	*(u64*)(r2 + 0) = r1;				\
29562587Sitojun	r1 = %[map_hash_48b] ll;			\
29662587Sitojun	call %[bpf_map_lookup_elem];			\
29762587Sitojun	if r0 == 0 goto l0_%=;				\
29862587Sitojun	r1 = r0;					\
29978064Sume	r1 += %[test_val_foo];				\
30062587Sitojun	r2 = %[__imm_0];				\
30162587Sitojun	r3 = 0;						\
30262587Sitojun	call %[bpf_probe_read_kernel];			\
30362587Sitojunl0_%=:	exit;						\
30462587Sitojun"	:
30562587Sitojun	: __imm(bpf_map_lookup_elem),
30678064Sume	  __imm(bpf_probe_read_kernel),
30762587Sitojun	  __imm_addr(map_hash_48b),
30878064Sume	  __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo) + 8),
30978064Sume	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
31078064Sume	: __clobber_all);
31178064Sume}
31278064Sume
31378064SumeSEC("tracepoint")
31478064Sume__description("helper access to adjusted map (via const imm): negative range (> adjustment)")
31578064Sume__failure __msg("R2 min value is negative")
31662587Sitojun__naked void const_imm_negative_range_adjustment_1(void)
31762587Sitojun{
31862587Sitojun	asm volatile ("					\
31962587Sitojun	r2 = r10;					\
32062587Sitojun	r2 += -8;					\
32162587Sitojun	r1 = 0;						\
32262587Sitojun	*(u64*)(r2 + 0) = r1;				\
32362587Sitojun	r1 = %[map_hash_48b] ll;			\
32462587Sitojun	call %[bpf_map_lookup_elem];			\
32562587Sitojun	if r0 == 0 goto l0_%=;				\
32662587Sitojun	r1 = r0;					\
32762587Sitojun	r1 += %[test_val_foo];				\
32862587Sitojun	r2 = -8;					\
32978064Sume	r3 = 0;						\
33062587Sitojun	call %[bpf_probe_read_kernel];			\
33162587Sitojunl0_%=:	exit;						\
33262587Sitojun"	:
33362587Sitojun	: __imm(bpf_map_lookup_elem),
33462587Sitojun	  __imm(bpf_probe_read_kernel),
33562587Sitojun	  __imm_addr(map_hash_48b),
33662587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
33762587Sitojun	: __clobber_all);
33878064Sume}
33962587Sitojun
34062587SitojunSEC("tracepoint")
34162587Sitojun__description("helper access to adjusted map (via const imm): negative range (< adjustment)")
34262587Sitojun__failure __msg("R2 min value is negative")
34362587Sitojun__naked void const_imm_negative_range_adjustment_2(void)
34462587Sitojun{
34562587Sitojun	asm volatile ("					\
34662587Sitojun	r2 = r10;					\
34762587Sitojun	r2 += -8;					\
34878064Sume	r1 = 0;						\
34978064Sume	*(u64*)(r2 + 0) = r1;				\
35078064Sume	r1 = %[map_hash_48b] ll;			\
35178064Sume	call %[bpf_map_lookup_elem];			\
35262587Sitojun	if r0 == 0 goto l0_%=;				\
35362587Sitojun	r1 = r0;					\
35462587Sitojun	r1 += %[test_val_foo];				\
35562587Sitojun	r2 = -1;					\
35662587Sitojun	r3 = 0;						\
35762587Sitojun	call %[bpf_probe_read_kernel];			\
35862587Sitojunl0_%=:	exit;						\
35962587Sitojun"	:
36062587Sitojun	: __imm(bpf_map_lookup_elem),
36162587Sitojun	  __imm(bpf_probe_read_kernel),
36262587Sitojun	  __imm_addr(map_hash_48b),
36362587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
36462587Sitojun	: __clobber_all);
36562587Sitojun}
36662587Sitojun
36762587SitojunSEC("tracepoint")
36862587Sitojun__description("helper access to adjusted map (via const reg): full range")
36962587Sitojun__success
37062587Sitojun__naked void via_const_reg_full_range(void)
37162587Sitojun{
37262587Sitojun	asm volatile ("					\
37362587Sitojun	r2 = r10;					\
37462587Sitojun	r2 += -8;					\
37562587Sitojun	r1 = 0;						\
37662587Sitojun	*(u64*)(r2 + 0) = r1;				\
37762587Sitojun	r1 = %[map_hash_48b] ll;			\
37862587Sitojun	call %[bpf_map_lookup_elem];			\
37962587Sitojun	if r0 == 0 goto l0_%=;				\
38062587Sitojun	r1 = r0;					\
38162587Sitojun	r3 = %[test_val_foo];				\
38262587Sitojun	r1 += r3;					\
38362587Sitojun	r2 = %[__imm_0];				\
38462587Sitojun	r3 = 0;						\
38562587Sitojun	call %[bpf_probe_read_kernel];			\
38662587Sitojunl0_%=:	exit;						\
38762587Sitojun"	:
38862587Sitojun	: __imm(bpf_map_lookup_elem),
38962587Sitojun	  __imm(bpf_probe_read_kernel),
39062587Sitojun	  __imm_addr(map_hash_48b),
39162587Sitojun	  __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo)),
39262587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
39362587Sitojun	: __clobber_all);
39462587Sitojun}
39562587Sitojun
39662587SitojunSEC("tracepoint")
39762587Sitojun__description("helper access to adjusted map (via const reg): partial range")
39862587Sitojun__success
39962587Sitojun__naked void via_const_reg_partial_range(void)
40062587Sitojun{
40178064Sume	asm volatile ("					\
40262587Sitojun	r2 = r10;					\
40362587Sitojun	r2 += -8;					\
40462587Sitojun	r1 = 0;						\
40562587Sitojun	*(u64*)(r2 + 0) = r1;				\
40662587Sitojun	r1 = %[map_hash_48b] ll;			\
40762587Sitojun	call %[bpf_map_lookup_elem];			\
40862587Sitojun	if r0 == 0 goto l0_%=;				\
40962587Sitojun	r1 = r0;					\
41062587Sitojun	r3 = %[test_val_foo];				\
41162587Sitojun	r1 += r3;					\
41278064Sume	r2 = 8;						\
41362587Sitojun	r3 = 0;						\
41478064Sume	call %[bpf_probe_read_kernel];			\
41578064Sumel0_%=:	exit;						\
41678064Sume"	:
41778064Sume	: __imm(bpf_map_lookup_elem),
41878064Sume	  __imm(bpf_probe_read_kernel),
41978064Sume	  __imm_addr(map_hash_48b),
42062587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
42162587Sitojun	: __clobber_all);
42262587Sitojun}
42362587Sitojun
42462587SitojunSEC("tracepoint")
42562587Sitojun__description("helper access to adjusted map (via const reg): empty range")
42662587Sitojun__failure __msg("R2 invalid zero-sized read")
42762587Sitojun__naked void via_const_reg_empty_range(void)
42862587Sitojun{
42962587Sitojun	asm volatile ("					\
43062587Sitojun	r2 = r10;					\
43162587Sitojun	r2 += -8;					\
43262587Sitojun	r1 = 0;						\
43362587Sitojun	*(u64*)(r2 + 0) = r1;				\
43478064Sume	r1 = %[map_hash_48b] ll;			\
43562587Sitojun	call %[bpf_map_lookup_elem];			\
43662587Sitojun	if r0 == 0 goto l0_%=;				\
43762587Sitojun	r1 = r0;					\
43862587Sitojun	r3 = 0;						\
43962587Sitojun	r1 += r3;					\
44062587Sitojun	r2 = 0;						\
44162587Sitojun	call %[bpf_trace_printk];			\
44262587Sitojunl0_%=:	exit;						\
44362587Sitojun"	:
44462587Sitojun	: __imm(bpf_map_lookup_elem),
44562587Sitojun	  __imm(bpf_trace_printk),
44662587Sitojun	  __imm_addr(map_hash_48b)
44762587Sitojun	: __clobber_all);
44862587Sitojun}
44962587Sitojun
45078064SumeSEC("tracepoint")
45162587Sitojun__description("helper access to adjusted map (via const reg): out-of-bound range")
45262587Sitojun__failure __msg("invalid access to map value, value_size=48 off=4 size=52")
45362587Sitojun__naked void reg_out_of_bound_range(void)
45462587Sitojun{
45562587Sitojun	asm volatile ("					\
45662587Sitojun	r2 = r10;					\
45762587Sitojun	r2 += -8;					\
45862587Sitojun	r1 = 0;						\
45962587Sitojun	*(u64*)(r2 + 0) = r1;				\
46062587Sitojun	r1 = %[map_hash_48b] ll;			\
46162587Sitojun	call %[bpf_map_lookup_elem];			\
46262587Sitojun	if r0 == 0 goto l0_%=;				\
46362587Sitojun	r1 = r0;					\
46462587Sitojun	r3 = %[test_val_foo];				\
46562587Sitojun	r1 += r3;					\
46662587Sitojun	r2 = %[__imm_0];				\
46762587Sitojun	r3 = 0;						\
46878064Sume	call %[bpf_probe_read_kernel];			\
46962587Sitojunl0_%=:	exit;						\
47062587Sitojun"	:
47162587Sitojun	: __imm(bpf_map_lookup_elem),
47262587Sitojun	  __imm(bpf_probe_read_kernel),
47378064Sume	  __imm_addr(map_hash_48b),
47478064Sume	  __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo) + 8),
47562587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
47662587Sitojun	: __clobber_all);
47762587Sitojun}
47862587Sitojun
47962587SitojunSEC("tracepoint")
48062587Sitojun__description("helper access to adjusted map (via const reg): negative range (> adjustment)")
48162587Sitojun__failure __msg("R2 min value is negative")
48262587Sitojun__naked void const_reg_negative_range_adjustment_1(void)
48362587Sitojun{
48462587Sitojun	asm volatile ("					\
48562587Sitojun	r2 = r10;					\
48662587Sitojun	r2 += -8;					\
48762587Sitojun	r1 = 0;						\
48862587Sitojun	*(u64*)(r2 + 0) = r1;				\
48962587Sitojun	r1 = %[map_hash_48b] ll;			\
49062587Sitojun	call %[bpf_map_lookup_elem];			\
49162587Sitojun	if r0 == 0 goto l0_%=;				\
49262587Sitojun	r1 = r0;					\
49362587Sitojun	r3 = %[test_val_foo];				\
49462587Sitojun	r1 += r3;					\
49562587Sitojun	r2 = -8;					\
49662587Sitojun	r3 = 0;						\
49762587Sitojun	call %[bpf_probe_read_kernel];			\
49862587Sitojunl0_%=:	exit;						\
49962587Sitojun"	:
50062587Sitojun	: __imm(bpf_map_lookup_elem),
50162587Sitojun	  __imm(bpf_probe_read_kernel),
50262587Sitojun	  __imm_addr(map_hash_48b),
50362587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
50462587Sitojun	: __clobber_all);
50562587Sitojun}
50662587Sitojun
50762587SitojunSEC("tracepoint")
50862587Sitojun__description("helper access to adjusted map (via const reg): negative range (< adjustment)")
50962587Sitojun__failure __msg("R2 min value is negative")
51062587Sitojun__naked void const_reg_negative_range_adjustment_2(void)
51162587Sitojun{
51262587Sitojun	asm volatile ("					\
51362587Sitojun	r2 = r10;					\
51462587Sitojun	r2 += -8;					\
51562587Sitojun	r1 = 0;						\
51662587Sitojun	*(u64*)(r2 + 0) = r1;				\
51762587Sitojun	r1 = %[map_hash_48b] ll;			\
51862587Sitojun	call %[bpf_map_lookup_elem];			\
51962587Sitojun	if r0 == 0 goto l0_%=;				\
52062587Sitojun	r1 = r0;					\
52162587Sitojun	r3 = %[test_val_foo];				\
52262587Sitojun	r1 += r3;					\
52362587Sitojun	r2 = -1;					\
52462587Sitojun	r3 = 0;						\
52562587Sitojun	call %[bpf_probe_read_kernel];			\
52662587Sitojunl0_%=:	exit;						\
52762587Sitojun"	:
52862587Sitojun	: __imm(bpf_map_lookup_elem),
52962587Sitojun	  __imm(bpf_probe_read_kernel),
53062587Sitojun	  __imm_addr(map_hash_48b),
53162587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
53262587Sitojun	: __clobber_all);
53362587Sitojun}
53462587Sitojun
53562587SitojunSEC("tracepoint")
53662587Sitojun__description("helper access to adjusted map (via variable): full range")
53762587Sitojun__success
53862587Sitojun__naked void map_via_variable_full_range(void)
53962587Sitojun{
54062587Sitojun	asm volatile ("					\
54162587Sitojun	r2 = r10;					\
54262587Sitojun	r2 += -8;					\
54362587Sitojun	r1 = 0;						\
54462587Sitojun	*(u64*)(r2 + 0) = r1;				\
54562587Sitojun	r1 = %[map_hash_48b] ll;			\
54662587Sitojun	call %[bpf_map_lookup_elem];			\
54762587Sitojun	if r0 == 0 goto l0_%=;				\
54862587Sitojun	r1 = r0;					\
54962587Sitojun	r3 = *(u32*)(r0 + 0);				\
55062587Sitojun	if r3 > %[test_val_foo] goto l0_%=;		\
55162587Sitojun	r1 += r3;					\
55262587Sitojun	r2 = %[__imm_0];				\
55362587Sitojun	r3 = 0;						\
55462587Sitojun	call %[bpf_probe_read_kernel];			\
55562587Sitojunl0_%=:	exit;						\
55662587Sitojun"	:
55762587Sitojun	: __imm(bpf_map_lookup_elem),
55862587Sitojun	  __imm(bpf_probe_read_kernel),
55962587Sitojun	  __imm_addr(map_hash_48b),
56062587Sitojun	  __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo)),
56162587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
56262587Sitojun	: __clobber_all);
56362587Sitojun}
56478064Sume
56578064SumeSEC("tracepoint")
56678064Sume__description("helper access to adjusted map (via variable): partial range")
56778064Sume__success
56878064Sume__naked void map_via_variable_partial_range(void)
56978064Sume{
57078064Sume	asm volatile ("					\
57162587Sitojun	r2 = r10;					\
57262587Sitojun	r2 += -8;					\
57362587Sitojun	r1 = 0;						\
57462587Sitojun	*(u64*)(r2 + 0) = r1;				\
57562587Sitojun	r1 = %[map_hash_48b] ll;			\
57662587Sitojun	call %[bpf_map_lookup_elem];			\
57762587Sitojun	if r0 == 0 goto l0_%=;				\
57862587Sitojun	r1 = r0;					\
57978064Sume	r3 = *(u32*)(r0 + 0);				\
58062587Sitojun	if r3 > %[test_val_foo] goto l0_%=;		\
58178064Sume	r1 += r3;					\
58262587Sitojun	r2 = 8;						\
58362587Sitojun	r3 = 0;						\
58462587Sitojun	call %[bpf_probe_read_kernel];			\
58562587Sitojunl0_%=:	exit;						\
58662587Sitojun"	:
58762587Sitojun	: __imm(bpf_map_lookup_elem),
58862587Sitojun	  __imm(bpf_probe_read_kernel),
58962587Sitojun	  __imm_addr(map_hash_48b),
59062587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
59178064Sume	: __clobber_all);
59278064Sume}
59378064Sume
59478064SumeSEC("tracepoint")
59578064Sume__description("helper access to adjusted map (via variable): empty range")
59678064Sume__failure __msg("R2 invalid zero-sized read")
59762587Sitojun__naked void map_via_variable_empty_range(void)
59862587Sitojun{
59962587Sitojun	asm volatile ("					\
60062587Sitojun	r2 = r10;					\
60162587Sitojun	r2 += -8;					\
60262587Sitojun	r1 = 0;						\
60362587Sitojun	*(u64*)(r2 + 0) = r1;				\
60478064Sume	r1 = %[map_hash_48b] ll;			\
60562587Sitojun	call %[bpf_map_lookup_elem];			\
60662587Sitojun	if r0 == 0 goto l0_%=;				\
60762587Sitojun	r1 = r0;					\
60862587Sitojun	r3 = *(u32*)(r0 + 0);				\
60962587Sitojun	if r3 > %[test_val_foo] goto l0_%=;		\
61062587Sitojun	r1 += r3;					\
61162587Sitojun	r2 = 0;						\
61262587Sitojun	call %[bpf_trace_printk];			\
61362587Sitojunl0_%=:	exit;						\
61462587Sitojun"	:
61578064Sume	: __imm(bpf_map_lookup_elem),
61678064Sume	  __imm(bpf_trace_printk),
61778064Sume	  __imm_addr(map_hash_48b),
61878064Sume	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
61978064Sume	: __clobber_all);
62062587Sitojun}
62162587Sitojun
62262587SitojunSEC("tracepoint")
62362587Sitojun__description("helper access to adjusted map (via variable): no max check")
62462587Sitojun__failure __msg("R1 unbounded memory access")
62562587Sitojun__naked void via_variable_no_max_check_1(void)
62662587Sitojun{
62762587Sitojun	asm volatile ("					\
62862587Sitojun	r2 = r10;					\
62962587Sitojun	r2 += -8;					\
63062587Sitojun	r1 = 0;						\
63162587Sitojun	*(u64*)(r2 + 0) = r1;				\
63262587Sitojun	r1 = %[map_hash_48b] ll;			\
63362587Sitojun	call %[bpf_map_lookup_elem];			\
63462587Sitojun	if r0 == 0 goto l0_%=;				\
63562587Sitojun	r1 = r0;					\
63662587Sitojun	r3 = *(u32*)(r0 + 0);				\
63762587Sitojun	r1 += r3;					\
63862587Sitojun	r2 = 1;						\
63962587Sitojun	r3 = 0;						\
64078064Sume	call %[bpf_probe_read_kernel];			\
64178064Sumel0_%=:	exit;						\
64278064Sume"	:
64362587Sitojun	: __imm(bpf_map_lookup_elem),
64462587Sitojun	  __imm(bpf_probe_read_kernel),
64562587Sitojun	  __imm_addr(map_hash_48b)
64662587Sitojun	: __clobber_all);
64762587Sitojun}
64862587Sitojun
64962587SitojunSEC("tracepoint")
65062587Sitojun__description("helper access to adjusted map (via variable): wrong max check")
65162587Sitojun__failure __msg("invalid access to map value, value_size=48 off=4 size=45")
65262587Sitojun__naked void via_variable_wrong_max_check_1(void)
65362587Sitojun{
65462587Sitojun	asm volatile ("					\
65562587Sitojun	r2 = r10;					\
65662587Sitojun	r2 += -8;					\
65762587Sitojun	r1 = 0;						\
65862587Sitojun	*(u64*)(r2 + 0) = r1;				\
65962587Sitojun	r1 = %[map_hash_48b] ll;			\
66062587Sitojun	call %[bpf_map_lookup_elem];			\
66162587Sitojun	if r0 == 0 goto l0_%=;				\
66262587Sitojun	r1 = r0;					\
66362587Sitojun	r3 = *(u32*)(r0 + 0);				\
66462587Sitojun	if r3 > %[test_val_foo] goto l0_%=;		\
66562587Sitojun	r1 += r3;					\
66662587Sitojun	r2 = %[__imm_0];				\
66762587Sitojun	r3 = 0;						\
66862587Sitojun	call %[bpf_probe_read_kernel];			\
66962587Sitojunl0_%=:	exit;						\
67062587Sitojun"	:
67162587Sitojun	: __imm(bpf_map_lookup_elem),
67262587Sitojun	  __imm(bpf_probe_read_kernel),
67362587Sitojun	  __imm_addr(map_hash_48b),
67462587Sitojun	  __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo) + 1),
67562587Sitojun	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
67662587Sitojun	: __clobber_all);
67762587Sitojun}
67862587Sitojun
67962587SitojunSEC("tracepoint")
68062587Sitojun__description("helper access to map: bounds check using <, good access")
68162587Sitojun__success
68262587Sitojun__naked void bounds_check_using_good_access_1(void)
68362587Sitojun{
68462587Sitojun	asm volatile ("					\
68562587Sitojun	r2 = r10;					\
68662587Sitojun	r2 += -8;					\
68762587Sitojun	r1 = 0;						\
68862587Sitojun	*(u64*)(r2 + 0) = r1;				\
68962587Sitojun	r1 = %[map_hash_48b] ll;			\
69062587Sitojun	call %[bpf_map_lookup_elem];			\
69162587Sitojun	if r0 == 0 goto l0_%=;				\
69262587Sitojun	r1 = r0;					\
69362587Sitojun	r3 = *(u32*)(r0 + 0);				\
69462587Sitojun	if r3 < 32 goto l1_%=;				\
69562587Sitojun	r0 = 0;						\
69662587Sitojunl0_%=:	exit;						\
69762587Sitojunl1_%=:	r1 += r3;					\
69862587Sitojun	r0 = 0;						\
69962587Sitojun	*(u8*)(r1 + 0) = r0;				\
70062587Sitojun	r0 = 0;						\
70162587Sitojun	exit;						\
70262587Sitojun"	:
70362587Sitojun	: __imm(bpf_map_lookup_elem),
70462587Sitojun	  __imm_addr(map_hash_48b)
70562587Sitojun	: __clobber_all);
70662587Sitojun}
70762587Sitojun
70862587SitojunSEC("tracepoint")
70962587Sitojun__description("helper access to map: bounds check using <, bad access")
71062587Sitojun__failure __msg("R1 unbounded memory access")
711__naked void bounds_check_using_bad_access_1(void)
712{
713	asm volatile ("					\
714	r2 = r10;					\
715	r2 += -8;					\
716	r1 = 0;						\
717	*(u64*)(r2 + 0) = r1;				\
718	r1 = %[map_hash_48b] ll;			\
719	call %[bpf_map_lookup_elem];			\
720	if r0 == 0 goto l0_%=;				\
721	r1 = r0;					\
722	r3 = *(u32*)(r0 + 0);				\
723	if r3 < 32 goto l1_%=;				\
724	r1 += r3;					\
725l0_%=:	r0 = 0;						\
726	*(u8*)(r1 + 0) = r0;				\
727	r0 = 0;						\
728	exit;						\
729l1_%=:	r0 = 0;						\
730	exit;						\
731"	:
732	: __imm(bpf_map_lookup_elem),
733	  __imm_addr(map_hash_48b)
734	: __clobber_all);
735}
736
737SEC("tracepoint")
738__description("helper access to map: bounds check using <=, good access")
739__success
740__naked void bounds_check_using_good_access_2(void)
741{
742	asm volatile ("					\
743	r2 = r10;					\
744	r2 += -8;					\
745	r1 = 0;						\
746	*(u64*)(r2 + 0) = r1;				\
747	r1 = %[map_hash_48b] ll;			\
748	call %[bpf_map_lookup_elem];			\
749	if r0 == 0 goto l0_%=;				\
750	r1 = r0;					\
751	r3 = *(u32*)(r0 + 0);				\
752	if r3 <= 32 goto l1_%=;				\
753	r0 = 0;						\
754l0_%=:	exit;						\
755l1_%=:	r1 += r3;					\
756	r0 = 0;						\
757	*(u8*)(r1 + 0) = r0;				\
758	r0 = 0;						\
759	exit;						\
760"	:
761	: __imm(bpf_map_lookup_elem),
762	  __imm_addr(map_hash_48b)
763	: __clobber_all);
764}
765
766SEC("tracepoint")
767__description("helper access to map: bounds check using <=, bad access")
768__failure __msg("R1 unbounded memory access")
769__naked void bounds_check_using_bad_access_2(void)
770{
771	asm volatile ("					\
772	r2 = r10;					\
773	r2 += -8;					\
774	r1 = 0;						\
775	*(u64*)(r2 + 0) = r1;				\
776	r1 = %[map_hash_48b] ll;			\
777	call %[bpf_map_lookup_elem];			\
778	if r0 == 0 goto l0_%=;				\
779	r1 = r0;					\
780	r3 = *(u32*)(r0 + 0);				\
781	if r3 <= 32 goto l1_%=;				\
782	r1 += r3;					\
783l0_%=:	r0 = 0;						\
784	*(u8*)(r1 + 0) = r0;				\
785	r0 = 0;						\
786	exit;						\
787l1_%=:	r0 = 0;						\
788	exit;						\
789"	:
790	: __imm(bpf_map_lookup_elem),
791	  __imm_addr(map_hash_48b)
792	: __clobber_all);
793}
794
795SEC("tracepoint")
796__description("helper access to map: bounds check using s<, good access")
797__success
798__naked void check_using_s_good_access_1(void)
799{
800	asm volatile ("					\
801	r2 = r10;					\
802	r2 += -8;					\
803	r1 = 0;						\
804	*(u64*)(r2 + 0) = r1;				\
805	r1 = %[map_hash_48b] ll;			\
806	call %[bpf_map_lookup_elem];			\
807	if r0 == 0 goto l0_%=;				\
808	r1 = r0;					\
809	r3 = *(u32*)(r0 + 0);				\
810	if r3 s< 32 goto l1_%=;				\
811l2_%=:	r0 = 0;						\
812l0_%=:	exit;						\
813l1_%=:	if r3 s< 0 goto l2_%=;				\
814	r1 += r3;					\
815	r0 = 0;						\
816	*(u8*)(r1 + 0) = r0;				\
817	r0 = 0;						\
818	exit;						\
819"	:
820	: __imm(bpf_map_lookup_elem),
821	  __imm_addr(map_hash_48b)
822	: __clobber_all);
823}
824
825SEC("tracepoint")
826__description("helper access to map: bounds check using s<, good access 2")
827__success
828__naked void using_s_good_access_2_1(void)
829{
830	asm volatile ("					\
831	r2 = r10;					\
832	r2 += -8;					\
833	r1 = 0;						\
834	*(u64*)(r2 + 0) = r1;				\
835	r1 = %[map_hash_48b] ll;			\
836	call %[bpf_map_lookup_elem];			\
837	if r0 == 0 goto l0_%=;				\
838	r1 = r0;					\
839	r3 = *(u32*)(r0 + 0);				\
840	if r3 s< 32 goto l1_%=;				\
841l2_%=:	r0 = 0;						\
842l0_%=:	exit;						\
843l1_%=:	if r3 s< -3 goto l2_%=;				\
844	r1 += r3;					\
845	r0 = 0;						\
846	*(u8*)(r1 + 0) = r0;				\
847	r0 = 0;						\
848	exit;						\
849"	:
850	: __imm(bpf_map_lookup_elem),
851	  __imm_addr(map_hash_48b)
852	: __clobber_all);
853}
854
855SEC("tracepoint")
856__description("helper access to map: bounds check using s<, bad access")
857__failure __msg("R1 min value is negative")
858__naked void check_using_s_bad_access_1(void)
859{
860	asm volatile ("					\
861	r2 = r10;					\
862	r2 += -8;					\
863	r1 = 0;						\
864	*(u64*)(r2 + 0) = r1;				\
865	r1 = %[map_hash_48b] ll;			\
866	call %[bpf_map_lookup_elem];			\
867	if r0 == 0 goto l0_%=;				\
868	r1 = r0;					\
869	r3 = *(u64*)(r0 + 0);				\
870	if r3 s< 32 goto l1_%=;				\
871l2_%=:	r0 = 0;						\
872l0_%=:	exit;						\
873l1_%=:	if r3 s< -3 goto l2_%=;				\
874	r1 += r3;					\
875	r0 = 0;						\
876	*(u8*)(r1 + 0) = r0;				\
877	r0 = 0;						\
878	exit;						\
879"	:
880	: __imm(bpf_map_lookup_elem),
881	  __imm_addr(map_hash_48b)
882	: __clobber_all);
883}
884
885SEC("tracepoint")
886__description("helper access to map: bounds check using s<=, good access")
887__success
888__naked void check_using_s_good_access_2(void)
889{
890	asm volatile ("					\
891	r2 = r10;					\
892	r2 += -8;					\
893	r1 = 0;						\
894	*(u64*)(r2 + 0) = r1;				\
895	r1 = %[map_hash_48b] ll;			\
896	call %[bpf_map_lookup_elem];			\
897	if r0 == 0 goto l0_%=;				\
898	r1 = r0;					\
899	r3 = *(u32*)(r0 + 0);				\
900	if r3 s<= 32 goto l1_%=;			\
901l2_%=:	r0 = 0;						\
902l0_%=:	exit;						\
903l1_%=:	if r3 s<= 0 goto l2_%=;				\
904	r1 += r3;					\
905	r0 = 0;						\
906	*(u8*)(r1 + 0) = r0;				\
907	r0 = 0;						\
908	exit;						\
909"	:
910	: __imm(bpf_map_lookup_elem),
911	  __imm_addr(map_hash_48b)
912	: __clobber_all);
913}
914
915SEC("tracepoint")
916__description("helper access to map: bounds check using s<=, good access 2")
917__success
918__naked void using_s_good_access_2_2(void)
919{
920	asm volatile ("					\
921	r2 = r10;					\
922	r2 += -8;					\
923	r1 = 0;						\
924	*(u64*)(r2 + 0) = r1;				\
925	r1 = %[map_hash_48b] ll;			\
926	call %[bpf_map_lookup_elem];			\
927	if r0 == 0 goto l0_%=;				\
928	r1 = r0;					\
929	r3 = *(u32*)(r0 + 0);				\
930	if r3 s<= 32 goto l1_%=;			\
931l2_%=:	r0 = 0;						\
932l0_%=:	exit;						\
933l1_%=:	if r3 s<= -3 goto l2_%=;			\
934	r1 += r3;					\
935	r0 = 0;						\
936	*(u8*)(r1 + 0) = r0;				\
937	r0 = 0;						\
938	exit;						\
939"	:
940	: __imm(bpf_map_lookup_elem),
941	  __imm_addr(map_hash_48b)
942	: __clobber_all);
943}
944
945SEC("tracepoint")
946__description("helper access to map: bounds check using s<=, bad access")
947__failure __msg("R1 min value is negative")
948__naked void check_using_s_bad_access_2(void)
949{
950	asm volatile ("					\
951	r2 = r10;					\
952	r2 += -8;					\
953	r1 = 0;						\
954	*(u64*)(r2 + 0) = r1;				\
955	r1 = %[map_hash_48b] ll;			\
956	call %[bpf_map_lookup_elem];			\
957	if r0 == 0 goto l0_%=;				\
958	r1 = r0;					\
959	r3 = *(u64*)(r0 + 0);				\
960	if r3 s<= 32 goto l1_%=;			\
961l2_%=:	r0 = 0;						\
962l0_%=:	exit;						\
963l1_%=:	if r3 s<= -3 goto l2_%=;			\
964	r1 += r3;					\
965	r0 = 0;						\
966	*(u8*)(r1 + 0) = r0;				\
967	r0 = 0;						\
968	exit;						\
969"	:
970	: __imm(bpf_map_lookup_elem),
971	  __imm_addr(map_hash_48b)
972	: __clobber_all);
973}
974
975SEC("tracepoint")
976__description("map lookup helper access to map")
977__success
978__naked void lookup_helper_access_to_map(void)
979{
980	asm volatile ("					\
981	r2 = r10;					\
982	r2 += -8;					\
983	r1 = 0;						\
984	*(u64*)(r2 + 0) = r1;				\
985	r1 = %[map_hash_16b] ll;			\
986	call %[bpf_map_lookup_elem];			\
987	if r0 == 0 goto l0_%=;				\
988	r2 = r0;					\
989	r1 = %[map_hash_16b] ll;			\
990	call %[bpf_map_lookup_elem];			\
991l0_%=:	exit;						\
992"	:
993	: __imm(bpf_map_lookup_elem),
994	  __imm_addr(map_hash_16b)
995	: __clobber_all);
996}
997
998SEC("tracepoint")
999__description("map update helper access to map")
1000__success
1001__naked void update_helper_access_to_map(void)
1002{
1003	asm volatile ("					\
1004	r2 = r10;					\
1005	r2 += -8;					\
1006	r1 = 0;						\
1007	*(u64*)(r2 + 0) = r1;				\
1008	r1 = %[map_hash_16b] ll;			\
1009	call %[bpf_map_lookup_elem];			\
1010	if r0 == 0 goto l0_%=;				\
1011	r4 = 0;						\
1012	r3 = r0;					\
1013	r2 = r0;					\
1014	r1 = %[map_hash_16b] ll;			\
1015	call %[bpf_map_update_elem];			\
1016l0_%=:	exit;						\
1017"	:
1018	: __imm(bpf_map_lookup_elem),
1019	  __imm(bpf_map_update_elem),
1020	  __imm_addr(map_hash_16b)
1021	: __clobber_all);
1022}
1023
1024SEC("tracepoint")
1025__description("map update helper access to map: wrong size")
1026__failure __msg("invalid access to map value, value_size=8 off=0 size=16")
1027__naked void access_to_map_wrong_size(void)
1028{
1029	asm volatile ("					\
1030	r2 = r10;					\
1031	r2 += -8;					\
1032	r1 = 0;						\
1033	*(u64*)(r2 + 0) = r1;				\
1034	r1 = %[map_hash_8b] ll;				\
1035	call %[bpf_map_lookup_elem];			\
1036	if r0 == 0 goto l0_%=;				\
1037	r4 = 0;						\
1038	r3 = r0;					\
1039	r2 = r0;					\
1040	r1 = %[map_hash_16b] ll;			\
1041	call %[bpf_map_update_elem];			\
1042l0_%=:	exit;						\
1043"	:
1044	: __imm(bpf_map_lookup_elem),
1045	  __imm(bpf_map_update_elem),
1046	  __imm_addr(map_hash_16b),
1047	  __imm_addr(map_hash_8b)
1048	: __clobber_all);
1049}
1050
1051SEC("tracepoint")
1052__description("map helper access to adjusted map (via const imm)")
1053__success
1054__naked void adjusted_map_via_const_imm(void)
1055{
1056	asm volatile ("					\
1057	r2 = r10;					\
1058	r2 += -8;					\
1059	r1 = 0;						\
1060	*(u64*)(r2 + 0) = r1;				\
1061	r1 = %[map_hash_16b] ll;			\
1062	call %[bpf_map_lookup_elem];			\
1063	if r0 == 0 goto l0_%=;				\
1064	r2 = r0;					\
1065	r2 += %[other_val_bar];				\
1066	r1 = %[map_hash_16b] ll;			\
1067	call %[bpf_map_lookup_elem];			\
1068l0_%=:	exit;						\
1069"	:
1070	: __imm(bpf_map_lookup_elem),
1071	  __imm_addr(map_hash_16b),
1072	  __imm_const(other_val_bar, offsetof(struct other_val, bar))
1073	: __clobber_all);
1074}
1075
1076SEC("tracepoint")
1077__description("map helper access to adjusted map (via const imm): out-of-bound 1")
1078__failure __msg("invalid access to map value, value_size=16 off=12 size=8")
1079__naked void imm_out_of_bound_1(void)
1080{
1081	asm volatile ("					\
1082	r2 = r10;					\
1083	r2 += -8;					\
1084	r1 = 0;						\
1085	*(u64*)(r2 + 0) = r1;				\
1086	r1 = %[map_hash_16b] ll;			\
1087	call %[bpf_map_lookup_elem];			\
1088	if r0 == 0 goto l0_%=;				\
1089	r2 = r0;					\
1090	r2 += %[__imm_0];				\
1091	r1 = %[map_hash_16b] ll;			\
1092	call %[bpf_map_lookup_elem];			\
1093l0_%=:	exit;						\
1094"	:
1095	: __imm(bpf_map_lookup_elem),
1096	  __imm_addr(map_hash_16b),
1097	  __imm_const(__imm_0, sizeof(struct other_val) - 4)
1098	: __clobber_all);
1099}
1100
1101SEC("tracepoint")
1102__description("map helper access to adjusted map (via const imm): out-of-bound 2")
1103__failure __msg("invalid access to map value, value_size=16 off=-4 size=8")
1104__naked void imm_out_of_bound_2(void)
1105{
1106	asm volatile ("					\
1107	r2 = r10;					\
1108	r2 += -8;					\
1109	r1 = 0;						\
1110	*(u64*)(r2 + 0) = r1;				\
1111	r1 = %[map_hash_16b] ll;			\
1112	call %[bpf_map_lookup_elem];			\
1113	if r0 == 0 goto l0_%=;				\
1114	r2 = r0;					\
1115	r2 += -4;					\
1116	r1 = %[map_hash_16b] ll;			\
1117	call %[bpf_map_lookup_elem];			\
1118l0_%=:	exit;						\
1119"	:
1120	: __imm(bpf_map_lookup_elem),
1121	  __imm_addr(map_hash_16b)
1122	: __clobber_all);
1123}
1124
1125SEC("tracepoint")
1126__description("map helper access to adjusted map (via const reg)")
1127__success
1128__naked void adjusted_map_via_const_reg(void)
1129{
1130	asm volatile ("					\
1131	r2 = r10;					\
1132	r2 += -8;					\
1133	r1 = 0;						\
1134	*(u64*)(r2 + 0) = r1;				\
1135	r1 = %[map_hash_16b] ll;			\
1136	call %[bpf_map_lookup_elem];			\
1137	if r0 == 0 goto l0_%=;				\
1138	r2 = r0;					\
1139	r3 = %[other_val_bar];				\
1140	r2 += r3;					\
1141	r1 = %[map_hash_16b] ll;			\
1142	call %[bpf_map_lookup_elem];			\
1143l0_%=:	exit;						\
1144"	:
1145	: __imm(bpf_map_lookup_elem),
1146	  __imm_addr(map_hash_16b),
1147	  __imm_const(other_val_bar, offsetof(struct other_val, bar))
1148	: __clobber_all);
1149}
1150
1151SEC("tracepoint")
1152__description("map helper access to adjusted map (via const reg): out-of-bound 1")
1153__failure __msg("invalid access to map value, value_size=16 off=12 size=8")
1154__naked void reg_out_of_bound_1(void)
1155{
1156	asm volatile ("					\
1157	r2 = r10;					\
1158	r2 += -8;					\
1159	r1 = 0;						\
1160	*(u64*)(r2 + 0) = r1;				\
1161	r1 = %[map_hash_16b] ll;			\
1162	call %[bpf_map_lookup_elem];			\
1163	if r0 == 0 goto l0_%=;				\
1164	r2 = r0;					\
1165	r3 = %[__imm_0];				\
1166	r2 += r3;					\
1167	r1 = %[map_hash_16b] ll;			\
1168	call %[bpf_map_lookup_elem];			\
1169l0_%=:	exit;						\
1170"	:
1171	: __imm(bpf_map_lookup_elem),
1172	  __imm_addr(map_hash_16b),
1173	  __imm_const(__imm_0, sizeof(struct other_val) - 4)
1174	: __clobber_all);
1175}
1176
1177SEC("tracepoint")
1178__description("map helper access to adjusted map (via const reg): out-of-bound 2")
1179__failure __msg("invalid access to map value, value_size=16 off=-4 size=8")
1180__naked void reg_out_of_bound_2(void)
1181{
1182	asm volatile ("					\
1183	r2 = r10;					\
1184	r2 += -8;					\
1185	r1 = 0;						\
1186	*(u64*)(r2 + 0) = r1;				\
1187	r1 = %[map_hash_16b] ll;			\
1188	call %[bpf_map_lookup_elem];			\
1189	if r0 == 0 goto l0_%=;				\
1190	r2 = r0;					\
1191	r3 = -4;					\
1192	r2 += r3;					\
1193	r1 = %[map_hash_16b] ll;			\
1194	call %[bpf_map_lookup_elem];			\
1195l0_%=:	exit;						\
1196"	:
1197	: __imm(bpf_map_lookup_elem),
1198	  __imm_addr(map_hash_16b)
1199	: __clobber_all);
1200}
1201
1202SEC("tracepoint")
1203__description("map helper access to adjusted map (via variable)")
1204__success
1205__naked void to_adjusted_map_via_variable(void)
1206{
1207	asm volatile ("					\
1208	r2 = r10;					\
1209	r2 += -8;					\
1210	r1 = 0;						\
1211	*(u64*)(r2 + 0) = r1;				\
1212	r1 = %[map_hash_16b] ll;			\
1213	call %[bpf_map_lookup_elem];			\
1214	if r0 == 0 goto l0_%=;				\
1215	r2 = r0;					\
1216	r3 = *(u32*)(r0 + 0);				\
1217	if r3 > %[other_val_bar] goto l0_%=;		\
1218	r2 += r3;					\
1219	r1 = %[map_hash_16b] ll;			\
1220	call %[bpf_map_lookup_elem];			\
1221l0_%=:	exit;						\
1222"	:
1223	: __imm(bpf_map_lookup_elem),
1224	  __imm_addr(map_hash_16b),
1225	  __imm_const(other_val_bar, offsetof(struct other_val, bar))
1226	: __clobber_all);
1227}
1228
1229SEC("tracepoint")
1230__description("map helper access to adjusted map (via variable): no max check")
1231__failure
1232__msg("R2 unbounded memory access, make sure to bounds check any such access")
1233__naked void via_variable_no_max_check_2(void)
1234{
1235	asm volatile ("					\
1236	r2 = r10;					\
1237	r2 += -8;					\
1238	r1 = 0;						\
1239	*(u64*)(r2 + 0) = r1;				\
1240	r1 = %[map_hash_16b] ll;			\
1241	call %[bpf_map_lookup_elem];			\
1242	if r0 == 0 goto l0_%=;				\
1243	r2 = r0;					\
1244	r3 = *(u32*)(r0 + 0);				\
1245	r2 += r3;					\
1246	r1 = %[map_hash_16b] ll;			\
1247	call %[bpf_map_lookup_elem];			\
1248l0_%=:	exit;						\
1249"	:
1250	: __imm(bpf_map_lookup_elem),
1251	  __imm_addr(map_hash_16b)
1252	: __clobber_all);
1253}
1254
1255SEC("tracepoint")
1256__description("map helper access to adjusted map (via variable): wrong max check")
1257__failure __msg("invalid access to map value, value_size=16 off=9 size=8")
1258__naked void via_variable_wrong_max_check_2(void)
1259{
1260	asm volatile ("					\
1261	r2 = r10;					\
1262	r2 += -8;					\
1263	r1 = 0;						\
1264	*(u64*)(r2 + 0) = r1;				\
1265	r1 = %[map_hash_16b] ll;			\
1266	call %[bpf_map_lookup_elem];			\
1267	if r0 == 0 goto l0_%=;				\
1268	r2 = r0;					\
1269	r3 = *(u32*)(r0 + 0);				\
1270	if r3 > %[__imm_0] goto l0_%=;			\
1271	r2 += r3;					\
1272	r1 = %[map_hash_16b] ll;			\
1273	call %[bpf_map_lookup_elem];			\
1274l0_%=:	exit;						\
1275"	:
1276	: __imm(bpf_map_lookup_elem),
1277	  __imm_addr(map_hash_16b),
1278	  __imm_const(__imm_0, offsetof(struct other_val, bar) + 1)
1279	: __clobber_all);
1280}
1281
1282char _license[] SEC("license") = "GPL";
1283