xref: /linux/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c (revision 876f5ebd58a9ac42f48a7ead3d5b274a314e0ace)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <vmlinux.h>
4 #include <bpf/bpf_core_read.h>
5 #include "bpf_misc.h"
6 #include "../test_kmods/bpf_testmod_kfunc.h"
7 
8 SEC("socket")
9 __success
10 __retval(0)
11 int ldx_is_ok_bad_addr(void *ctx)
12 {
13 	char *p;
14 
15 	if (!bpf_core_enum_value_exists(enum bpf_features, BPF_FEAT_RDONLY_CAST_TO_VOID))
16 		return 42;
17 
18 	p = bpf_rdonly_cast(0, 0);
19 	return p[0x7fff];
20 }
21 
22 SEC("socket")
23 __success
24 __retval(1)
25 int ldx_is_ok_good_addr(void *ctx)
26 {
27 	int v, *p;
28 
29 	v = 1;
30 	p = bpf_rdonly_cast(&v, 0);
31 	return *p;
32 }
33 
34 SEC("socket")
35 __success
36 int offset_not_tracked(void *ctx)
37 {
38 	int *p, i, s;
39 
40 	p = bpf_rdonly_cast(0, 0);
41 	s = 0;
42 	bpf_for(i, 0, 1000 * 1000 * 1000) {
43 		p++;
44 		s += *p;
45 	}
46 	return s;
47 }
48 
49 SEC("socket")
50 __failure
51 __msg("cannot write into rdonly_untrusted_mem")
52 int stx_not_ok(void *ctx)
53 {
54 	int v, *p;
55 
56 	v = 1;
57 	p = bpf_rdonly_cast(&v, 0);
58 	*p = 1;
59 	return 0;
60 }
61 
62 SEC("socket")
63 __failure
64 __msg("cannot write into rdonly_untrusted_mem")
65 int atomic_not_ok(void *ctx)
66 {
67 	int v, *p;
68 
69 	v = 1;
70 	p = bpf_rdonly_cast(&v, 0);
71 	__sync_fetch_and_add(p, 1);
72 	return 0;
73 }
74 
75 SEC("socket")
76 __failure
77 __msg("cannot write into rdonly_untrusted_mem")
78 int atomic_rmw_not_ok(void *ctx)
79 {
80 	long v, *p;
81 
82 	v = 1;
83 	p = bpf_rdonly_cast(&v, 0);
84 	return __sync_val_compare_and_swap(p, 0, 42);
85 }
86 
87 SEC("socket")
88 __failure
89 __msg("invalid access to memory, mem_size=0 off=0 size=4")
90 __msg("R1 min value is outside of the allowed memory range")
91 int kfunc_param_not_ok(void *ctx)
92 {
93 	int *p;
94 
95 	p = bpf_rdonly_cast(0, 0);
96 	bpf_kfunc_trusted_num_test(p);
97 	return 0;
98 }
99 
100 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
101 __failure
102 __msg("R1 type=rdonly_untrusted_mem expected=")
103 int helper_param_not_ok(void *ctx)
104 {
105 	char *p;
106 
107 	p = bpf_rdonly_cast(0, 0);
108 	/*
109 	 * Any helper with ARG_CONST_SIZE_OR_ZERO constraint will do,
110 	 * the most permissive constraint
111 	 */
112 	bpf_copy_from_user(p, 0, (void *)42);
113 	return 0;
114 }
115 
116 static __noinline u64 *get_some_addr(void)
117 {
118 	if (bpf_get_prandom_u32())
119 		return bpf_rdonly_cast(0, bpf_core_type_id_kernel(struct sock));
120 	else
121 		return bpf_rdonly_cast(0, 0);
122 }
123 
124 SEC("socket")
125 __success
126 __retval(0)
127 int mixed_mem_type(void *ctx)
128 {
129 	u64 *p;
130 
131 	/* Try to avoid compiler hoisting load to if branches by using __noinline func. */
132 	p = get_some_addr();
133 	return *p;
134 }
135 
136 __attribute__((__aligned__(8)))
137 u8 global[] = {
138 	0x11, 0x22, 0x33, 0x44,
139 	0x55, 0x66, 0x77, 0x88,
140 	0x99
141 };
142 
143 __always_inline
144 static u64 combine(void *p)
145 {
146 	u64 acc;
147 
148 	acc = 0;
149 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
150 	acc |= (*(u64 *)p >> 56) << 24;
151 	acc |= (*(u32 *)p >> 24) << 16;
152 	acc |= (*(u16 *)p >> 8)  << 8;
153 	acc |= *(u8 *)p;
154 #else
155 	acc |= (*(u64 *)p & 0xff) << 24;
156 	acc |= (*(u32 *)p & 0xff) << 16;
157 	acc |= (*(u16 *)p & 0xff) << 8;
158 	acc |= *(u8 *)p;
159 #endif
160 	return acc;
161 }
162 
163 SEC("socket")
164 __retval(0x88442211)
165 int diff_size_access(void *ctx)
166 {
167 	return combine(bpf_rdonly_cast(&global, 0));
168 }
169 
170 SEC("socket")
171 __retval(0x99553322)
172 int misaligned_access(void *ctx)
173 {
174 	return combine(bpf_rdonly_cast(&global, 0) + 1);
175 }
176 
177 __weak int return_one(void)
178 {
179 	return 1;
180 }
181 
182 SEC("socket")
183 __success
184 __retval(1)
185 int null_check(void *ctx)
186 {
187 	int *p;
188 
189 	p = bpf_rdonly_cast(0, 0);
190 	if (p == 0)
191 		/* make this a function call to avoid compiler
192 		 * moving r0 assignment before check.
193 		 */
194 		return return_one();
195 	return 0;
196 }
197 
198 char _license[] SEC("license") = "GPL";
199