16b99fe48SEduard Zingerman // SPDX-License-Identifier: GPL-2.0
26b99fe48SEduard Zingerman 
36b99fe48SEduard Zingerman #include <linux/bpf.h>
46b99fe48SEduard Zingerman #include <bpf/bpf_helpers.h>
56b99fe48SEduard Zingerman #include "bpf_misc.h"
66b99fe48SEduard Zingerman 
76b99fe48SEduard Zingerman struct {
86b99fe48SEduard Zingerman 	__uint(type, BPF_MAP_TYPE_ARRAY);
96b99fe48SEduard Zingerman 	__uint(max_entries, 8);
106b99fe48SEduard Zingerman 	__type(key, __u32);
116b99fe48SEduard Zingerman 	__type(value, __u64);
126b99fe48SEduard Zingerman } map SEC(".maps");
136b99fe48SEduard Zingerman 
146b99fe48SEduard Zingerman struct {
156b99fe48SEduard Zingerman 	__uint(type, BPF_MAP_TYPE_USER_RINGBUF);
166b99fe48SEduard Zingerman 	__uint(max_entries, 8);
176b99fe48SEduard Zingerman } ringbuf SEC(".maps");
186b99fe48SEduard Zingerman 
196b99fe48SEduard Zingerman struct vm_area_struct;
206b99fe48SEduard Zingerman struct bpf_map;
216b99fe48SEduard Zingerman 
226b99fe48SEduard Zingerman struct buf_context {
236b99fe48SEduard Zingerman 	char *buf;
246b99fe48SEduard Zingerman };
256b99fe48SEduard Zingerman 
266b99fe48SEduard Zingerman struct num_context {
276b99fe48SEduard Zingerman 	__u64 i;
285cac3cb6SEduard Zingerman 	__u64 j;
296b99fe48SEduard Zingerman };
306b99fe48SEduard Zingerman 
316b99fe48SEduard Zingerman __u8 choice_arr[2] = { 0, 1 };
326b99fe48SEduard Zingerman 
unsafe_on_2nd_iter_cb(__u32 idx,struct buf_context * ctx)336b99fe48SEduard Zingerman static int unsafe_on_2nd_iter_cb(__u32 idx, struct buf_context *ctx)
346b99fe48SEduard Zingerman {
356b99fe48SEduard Zingerman 	if (idx == 0) {
366b99fe48SEduard Zingerman 		ctx->buf = (char *)(0xDEAD);
376b99fe48SEduard Zingerman 		return 0;
386b99fe48SEduard Zingerman 	}
396b99fe48SEduard Zingerman 
406b99fe48SEduard Zingerman 	if (bpf_probe_read_user(ctx->buf, 8, (void *)(0xBADC0FFEE)))
416b99fe48SEduard Zingerman 		return 1;
426b99fe48SEduard Zingerman 
436b99fe48SEduard Zingerman 	return 0;
446b99fe48SEduard Zingerman }
456b99fe48SEduard Zingerman 
466b99fe48SEduard Zingerman SEC("?raw_tp")
476b99fe48SEduard Zingerman __failure __msg("R1 type=scalar expected=fp")
unsafe_on_2nd_iter(void * unused)486b99fe48SEduard Zingerman int unsafe_on_2nd_iter(void *unused)
496b99fe48SEduard Zingerman {
506b99fe48SEduard Zingerman 	char buf[4];
516b99fe48SEduard Zingerman 	struct buf_context loop_ctx = { .buf = buf };
526b99fe48SEduard Zingerman 
536b99fe48SEduard Zingerman 	bpf_loop(100, unsafe_on_2nd_iter_cb, &loop_ctx, 0);
546b99fe48SEduard Zingerman 	return 0;
556b99fe48SEduard Zingerman }
566b99fe48SEduard Zingerman 
unsafe_on_zero_iter_cb(__u32 idx,struct num_context * ctx)576b99fe48SEduard Zingerman static int unsafe_on_zero_iter_cb(__u32 idx, struct num_context *ctx)
586b99fe48SEduard Zingerman {
596b99fe48SEduard Zingerman 	ctx->i = 0;
606b99fe48SEduard Zingerman 	return 0;
616b99fe48SEduard Zingerman }
626b99fe48SEduard Zingerman 
636b99fe48SEduard Zingerman SEC("?raw_tp")
646b99fe48SEduard Zingerman __failure __msg("invalid access to map value, value_size=2 off=32 size=1")
unsafe_on_zero_iter(void * unused)656b99fe48SEduard Zingerman int unsafe_on_zero_iter(void *unused)
666b99fe48SEduard Zingerman {
676b99fe48SEduard Zingerman 	struct num_context loop_ctx = { .i = 32 };
686b99fe48SEduard Zingerman 
696b99fe48SEduard Zingerman 	bpf_loop(100, unsafe_on_zero_iter_cb, &loop_ctx, 0);
706b99fe48SEduard Zingerman 	return choice_arr[loop_ctx.i];
716b99fe48SEduard Zingerman }
726b99fe48SEduard Zingerman 
widening_cb(__u32 idx,struct num_context * ctx)735cac3cb6SEduard Zingerman static int widening_cb(__u32 idx, struct num_context *ctx)
745cac3cb6SEduard Zingerman {
755cac3cb6SEduard Zingerman 	++ctx->i;
765cac3cb6SEduard Zingerman 	return 0;
775cac3cb6SEduard Zingerman }
785cac3cb6SEduard Zingerman 
795cac3cb6SEduard Zingerman SEC("?raw_tp")
805cac3cb6SEduard Zingerman __success
widening(void * unused)815cac3cb6SEduard Zingerman int widening(void *unused)
825cac3cb6SEduard Zingerman {
835cac3cb6SEduard Zingerman 	struct num_context loop_ctx = { .i = 0, .j = 1 };
845cac3cb6SEduard Zingerman 
855cac3cb6SEduard Zingerman 	bpf_loop(100, widening_cb, &loop_ctx, 0);
865cac3cb6SEduard Zingerman 	/* loop_ctx.j is not changed during callback iteration,
875cac3cb6SEduard Zingerman 	 * verifier should not apply widening to it.
885cac3cb6SEduard Zingerman 	 */
895cac3cb6SEduard Zingerman 	return choice_arr[loop_ctx.j];
905cac3cb6SEduard Zingerman }
915cac3cb6SEduard Zingerman 
loop_detection_cb(__u32 idx,struct num_context * ctx)926b99fe48SEduard Zingerman static int loop_detection_cb(__u32 idx, struct num_context *ctx)
936b99fe48SEduard Zingerman {
946b99fe48SEduard Zingerman 	for (;;) {}
956b99fe48SEduard Zingerman 	return 0;
966b99fe48SEduard Zingerman }
976b99fe48SEduard Zingerman 
986b99fe48SEduard Zingerman SEC("?raw_tp")
996b99fe48SEduard Zingerman __failure __msg("infinite loop detected")
loop_detection(void * unused)1006b99fe48SEduard Zingerman int loop_detection(void *unused)
1016b99fe48SEduard Zingerman {
1026b99fe48SEduard Zingerman 	struct num_context loop_ctx = { .i = 0 };
1036b99fe48SEduard Zingerman 
1046b99fe48SEduard Zingerman 	bpf_loop(100, loop_detection_cb, &loop_ctx, 0);
1056b99fe48SEduard Zingerman 	return 0;
1066b99fe48SEduard Zingerman }
1076b99fe48SEduard Zingerman 
oob_state_machine(struct num_context * ctx)1086b99fe48SEduard Zingerman static __always_inline __u64 oob_state_machine(struct num_context *ctx)
1096b99fe48SEduard Zingerman {
1106b99fe48SEduard Zingerman 	switch (ctx->i) {
1116b99fe48SEduard Zingerman 	case 0:
1126b99fe48SEduard Zingerman 		ctx->i = 1;
1136b99fe48SEduard Zingerman 		break;
1146b99fe48SEduard Zingerman 	case 1:
1156b99fe48SEduard Zingerman 		ctx->i = 32;
1166b99fe48SEduard Zingerman 		break;
1176b99fe48SEduard Zingerman 	}
1186b99fe48SEduard Zingerman 	return 0;
1196b99fe48SEduard Zingerman }
1206b99fe48SEduard Zingerman 
for_each_map_elem_cb(struct bpf_map * map,__u32 * key,__u64 * val,void * data)1216b99fe48SEduard Zingerman static __u64 for_each_map_elem_cb(struct bpf_map *map, __u32 *key, __u64 *val, void *data)
1226b99fe48SEduard Zingerman {
1236b99fe48SEduard Zingerman 	return oob_state_machine(data);
1246b99fe48SEduard Zingerman }
1256b99fe48SEduard Zingerman 
1266b99fe48SEduard Zingerman SEC("?raw_tp")
1276b99fe48SEduard Zingerman __failure __msg("invalid access to map value, value_size=2 off=32 size=1")
unsafe_for_each_map_elem(void * unused)1286b99fe48SEduard Zingerman int unsafe_for_each_map_elem(void *unused)
1296b99fe48SEduard Zingerman {
1306b99fe48SEduard Zingerman 	struct num_context loop_ctx = { .i = 0 };
1316b99fe48SEduard Zingerman 
1326b99fe48SEduard Zingerman 	bpf_for_each_map_elem(&map, for_each_map_elem_cb, &loop_ctx, 0);
1336b99fe48SEduard Zingerman 	return choice_arr[loop_ctx.i];
1346b99fe48SEduard Zingerman }
1356b99fe48SEduard Zingerman 
ringbuf_drain_cb(struct bpf_dynptr * dynptr,void * data)1366b99fe48SEduard Zingerman static __u64 ringbuf_drain_cb(struct bpf_dynptr *dynptr, void *data)
1376b99fe48SEduard Zingerman {
1386b99fe48SEduard Zingerman 	return oob_state_machine(data);
1396b99fe48SEduard Zingerman }
1406b99fe48SEduard Zingerman 
1416b99fe48SEduard Zingerman SEC("?raw_tp")
1426b99fe48SEduard Zingerman __failure __msg("invalid access to map value, value_size=2 off=32 size=1")
unsafe_ringbuf_drain(void * unused)1436b99fe48SEduard Zingerman int unsafe_ringbuf_drain(void *unused)
1446b99fe48SEduard Zingerman {
1456b99fe48SEduard Zingerman 	struct num_context loop_ctx = { .i = 0 };
1466b99fe48SEduard Zingerman 
1476b99fe48SEduard Zingerman 	bpf_user_ringbuf_drain(&ringbuf, ringbuf_drain_cb, &loop_ctx, 0);
1486b99fe48SEduard Zingerman 	return choice_arr[loop_ctx.i];
1496b99fe48SEduard Zingerman }
1506b99fe48SEduard Zingerman 
find_vma_cb(struct task_struct * task,struct vm_area_struct * vma,void * data)1516b99fe48SEduard Zingerman static __u64 find_vma_cb(struct task_struct *task, struct vm_area_struct *vma, void *data)
1526b99fe48SEduard Zingerman {
1536b99fe48SEduard Zingerman 	return oob_state_machine(data);
1546b99fe48SEduard Zingerman }
1556b99fe48SEduard Zingerman 
1566b99fe48SEduard Zingerman SEC("?raw_tp")
1576b99fe48SEduard Zingerman __failure __msg("invalid access to map value, value_size=2 off=32 size=1")
unsafe_find_vma(void * unused)1586b99fe48SEduard Zingerman int unsafe_find_vma(void *unused)
1596b99fe48SEduard Zingerman {
1606b99fe48SEduard Zingerman 	struct task_struct *task = bpf_get_current_task_btf();
1616b99fe48SEduard Zingerman 	struct num_context loop_ctx = { .i = 0 };
1626b99fe48SEduard Zingerman 
1636b99fe48SEduard Zingerman 	bpf_find_vma(task, 0, find_vma_cb, &loop_ctx, 0);
1646b99fe48SEduard Zingerman 	return choice_arr[loop_ctx.i];
1656b99fe48SEduard Zingerman }
1666b99fe48SEduard Zingerman 
iter_limit_cb(__u32 idx,struct num_context * ctx)167*c7890937SEduard Zingerman static int iter_limit_cb(__u32 idx, struct num_context *ctx)
168*c7890937SEduard Zingerman {
169*c7890937SEduard Zingerman 	ctx->i++;
170*c7890937SEduard Zingerman 	return 0;
171*c7890937SEduard Zingerman }
172*c7890937SEduard Zingerman 
173*c7890937SEduard Zingerman SEC("?raw_tp")
174*c7890937SEduard Zingerman __success
bpf_loop_iter_limit_ok(void * unused)175*c7890937SEduard Zingerman int bpf_loop_iter_limit_ok(void *unused)
176*c7890937SEduard Zingerman {
177*c7890937SEduard Zingerman 	struct num_context ctx = { .i = 0 };
178*c7890937SEduard Zingerman 
179*c7890937SEduard Zingerman 	bpf_loop(1, iter_limit_cb, &ctx, 0);
180*c7890937SEduard Zingerman 	return choice_arr[ctx.i];
181*c7890937SEduard Zingerman }
182*c7890937SEduard Zingerman 
183*c7890937SEduard Zingerman SEC("?raw_tp")
184*c7890937SEduard Zingerman __failure __msg("invalid access to map value, value_size=2 off=2 size=1")
bpf_loop_iter_limit_overflow(void * unused)185*c7890937SEduard Zingerman int bpf_loop_iter_limit_overflow(void *unused)
186*c7890937SEduard Zingerman {
187*c7890937SEduard Zingerman 	struct num_context ctx = { .i = 0 };
188*c7890937SEduard Zingerman 
189*c7890937SEduard Zingerman 	bpf_loop(2, iter_limit_cb, &ctx, 0);
190*c7890937SEduard Zingerman 	return choice_arr[ctx.i];
191*c7890937SEduard Zingerman }
192*c7890937SEduard Zingerman 
iter_limit_level2a_cb(__u32 idx,struct num_context * ctx)193*c7890937SEduard Zingerman static int iter_limit_level2a_cb(__u32 idx, struct num_context *ctx)
194*c7890937SEduard Zingerman {
195*c7890937SEduard Zingerman 	ctx->i += 100;
196*c7890937SEduard Zingerman 	return 0;
197*c7890937SEduard Zingerman }
198*c7890937SEduard Zingerman 
iter_limit_level2b_cb(__u32 idx,struct num_context * ctx)199*c7890937SEduard Zingerman static int iter_limit_level2b_cb(__u32 idx, struct num_context *ctx)
200*c7890937SEduard Zingerman {
201*c7890937SEduard Zingerman 	ctx->i += 10;
202*c7890937SEduard Zingerman 	return 0;
203*c7890937SEduard Zingerman }
204*c7890937SEduard Zingerman 
iter_limit_level1_cb(__u32 idx,struct num_context * ctx)205*c7890937SEduard Zingerman static int iter_limit_level1_cb(__u32 idx, struct num_context *ctx)
206*c7890937SEduard Zingerman {
207*c7890937SEduard Zingerman 	ctx->i += 1;
208*c7890937SEduard Zingerman 	bpf_loop(1, iter_limit_level2a_cb, ctx, 0);
209*c7890937SEduard Zingerman 	bpf_loop(1, iter_limit_level2b_cb, ctx, 0);
210*c7890937SEduard Zingerman 	return 0;
211*c7890937SEduard Zingerman }
212*c7890937SEduard Zingerman 
213*c7890937SEduard Zingerman /* Check that path visiting every callback function once had been
214*c7890937SEduard Zingerman  * reached by verifier. Variables 'ctx{1,2}i' below serve as flags,
215*c7890937SEduard Zingerman  * with each decimal digit corresponding to a callback visit marker.
216*c7890937SEduard Zingerman  */
217*c7890937SEduard Zingerman SEC("socket")
218*c7890937SEduard Zingerman __success __retval(111111)
bpf_loop_iter_limit_nested(void * unused)219*c7890937SEduard Zingerman int bpf_loop_iter_limit_nested(void *unused)
220*c7890937SEduard Zingerman {
221*c7890937SEduard Zingerman 	struct num_context ctx1 = { .i = 0 };
222*c7890937SEduard Zingerman 	struct num_context ctx2 = { .i = 0 };
223*c7890937SEduard Zingerman 	__u64 a, b, c;
224*c7890937SEduard Zingerman 
225*c7890937SEduard Zingerman 	bpf_loop(1, iter_limit_level1_cb, &ctx1, 0);
226*c7890937SEduard Zingerman 	bpf_loop(1, iter_limit_level1_cb, &ctx2, 0);
227*c7890937SEduard Zingerman 	a = ctx1.i;
228*c7890937SEduard Zingerman 	b = ctx2.i;
229*c7890937SEduard Zingerman 	/* Force 'ctx1.i' and 'ctx2.i' precise. */
230*c7890937SEduard Zingerman 	c = choice_arr[(a + b) % 2];
231*c7890937SEduard Zingerman 	/* This makes 'c' zero, but neither clang nor verifier know it. */
232*c7890937SEduard Zingerman 	c /= 10;
233*c7890937SEduard Zingerman 	/* Make sure that verifier does not visit 'impossible' states:
234*c7890937SEduard Zingerman 	 * enumerate all possible callback visit masks.
235*c7890937SEduard Zingerman 	 */
236*c7890937SEduard Zingerman 	if (a != 0 && a != 1 && a != 11 && a != 101 && a != 111 &&
237*c7890937SEduard Zingerman 	    b != 0 && b != 1 && b != 11 && b != 101 && b != 111)
238*c7890937SEduard Zingerman 		asm volatile ("r0 /= 0;" ::: "r0");
239*c7890937SEduard Zingerman 	return 1000 * a + b + c;
240*c7890937SEduard Zingerman }
241*c7890937SEduard Zingerman 
2426b99fe48SEduard Zingerman char _license[] SEC("license") = "GPL";
243