162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <stdbool.h>
562306a36Sopenharmony_ci#include <linux/bpf.h>
662306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
762306a36Sopenharmony_ci#include "bpf_misc.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic volatile int zero = 0;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciint my_pid;
1462306a36Sopenharmony_ciint arr[256];
1562306a36Sopenharmony_ciint small_arr[16] SEC(".data.small_arr");
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct {
1862306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
1962306a36Sopenharmony_ci	__uint(max_entries, 10);
2062306a36Sopenharmony_ci	__type(key, int);
2162306a36Sopenharmony_ci	__type(value, int);
2262306a36Sopenharmony_ci} amap SEC(".maps");
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#ifdef REAL_TEST
2562306a36Sopenharmony_ci#define MY_PID_GUARD() if (my_pid != (bpf_get_current_pid_tgid() >> 32)) return 0
2662306a36Sopenharmony_ci#else
2762306a36Sopenharmony_ci#define MY_PID_GUARD() ({ })
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciSEC("?raw_tp")
3162306a36Sopenharmony_ci__failure __msg("math between map_value pointer and register with unbounded min value is not allowed")
3262306a36Sopenharmony_ciint iter_err_unsafe_c_loop(const void *ctx)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	struct bpf_iter_num it;
3562306a36Sopenharmony_ci	int *v, i = zero; /* obscure initial value of i */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	MY_PID_GUARD();
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 1000);
4062306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
4162306a36Sopenharmony_ci		i++;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	small_arr[i] = 123; /* invalid */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	return 0;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciSEC("?raw_tp")
5162306a36Sopenharmony_ci__failure __msg("unbounded memory access")
5262306a36Sopenharmony_ciint iter_err_unsafe_asm_loop(const void *ctx)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct bpf_iter_num it;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	MY_PID_GUARD();
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	asm volatile (
5962306a36Sopenharmony_ci		"r6 = %[zero];" /* iteration counter */
6062306a36Sopenharmony_ci		"r1 = %[it];" /* iterator state */
6162306a36Sopenharmony_ci		"r2 = 0;"
6262306a36Sopenharmony_ci		"r3 = 1000;"
6362306a36Sopenharmony_ci		"r4 = 1;"
6462306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
6562306a36Sopenharmony_ci	"loop:"
6662306a36Sopenharmony_ci		"r1 = %[it];"
6762306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
6862306a36Sopenharmony_ci		"if r0 == 0 goto out;"
6962306a36Sopenharmony_ci		"r6 += 1;"
7062306a36Sopenharmony_ci		"goto loop;"
7162306a36Sopenharmony_ci	"out:"
7262306a36Sopenharmony_ci		"r1 = %[it];"
7362306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
7462306a36Sopenharmony_ci		"r1 = %[small_arr];"
7562306a36Sopenharmony_ci		"r2 = r6;"
7662306a36Sopenharmony_ci		"r2 <<= 2;"
7762306a36Sopenharmony_ci		"r1 += r2;"
7862306a36Sopenharmony_ci		"*(u32 *)(r1 + 0) = r6;" /* invalid */
7962306a36Sopenharmony_ci		:
8062306a36Sopenharmony_ci		: [it]"r"(&it),
8162306a36Sopenharmony_ci		  [small_arr]"p"(small_arr),
8262306a36Sopenharmony_ci		  [zero]"p"(zero),
8362306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
8462306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
8562306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy)
8662306a36Sopenharmony_ci		: __clobber_common, "r6"
8762306a36Sopenharmony_ci	);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciSEC("raw_tp")
9362306a36Sopenharmony_ci__success
9462306a36Sopenharmony_ciint iter_while_loop(const void *ctx)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct bpf_iter_num it;
9762306a36Sopenharmony_ci	int *v;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	MY_PID_GUARD();
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 3);
10262306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
10362306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return 0;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciSEC("raw_tp")
11162306a36Sopenharmony_ci__success
11262306a36Sopenharmony_ciint iter_while_loop_auto_cleanup(const void *ctx)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	__attribute__((cleanup(bpf_iter_num_destroy))) struct bpf_iter_num it;
11562306a36Sopenharmony_ci	int *v;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	MY_PID_GUARD();
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 3);
12062306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
12162306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci	/* (!) no explicit bpf_iter_num_destroy() */
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciSEC("raw_tp")
12962306a36Sopenharmony_ci__success
13062306a36Sopenharmony_ciint iter_for_loop(const void *ctx)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct bpf_iter_num it;
13362306a36Sopenharmony_ci	int *v;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	MY_PID_GUARD();
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	bpf_iter_num_new(&it, 5, 10);
13862306a36Sopenharmony_ci	for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) {
13962306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return 0;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciSEC("raw_tp")
14762306a36Sopenharmony_ci__success
14862306a36Sopenharmony_ciint iter_bpf_for_each_macro(const void *ctx)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	int *v;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	MY_PID_GUARD();
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	bpf_for_each(num, v, 5, 10) {
15562306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ciSEC("raw_tp")
16262306a36Sopenharmony_ci__success
16362306a36Sopenharmony_ciint iter_bpf_for_macro(const void *ctx)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	int i;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	MY_PID_GUARD();
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	bpf_for(i, 5, 10) {
17062306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E2 VAL: v=%d", i);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciSEC("raw_tp")
17762306a36Sopenharmony_ci__success
17862306a36Sopenharmony_ciint iter_pragma_unroll_loop(const void *ctx)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct bpf_iter_num it;
18162306a36Sopenharmony_ci	int *v, i;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	MY_PID_GUARD();
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 2);
18662306a36Sopenharmony_ci#pragma nounroll
18762306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
18862306a36Sopenharmony_ci		v = bpf_iter_num_next(&it);
18962306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return 0;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ciSEC("raw_tp")
19762306a36Sopenharmony_ci__success
19862306a36Sopenharmony_ciint iter_manual_unroll_loop(const void *ctx)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct bpf_iter_num it;
20162306a36Sopenharmony_ci	int *v;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	MY_PID_GUARD();
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	bpf_iter_num_new(&it, 100, 200);
20662306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
20762306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
20862306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
20962306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
21062306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
21162306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
21262306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
21362306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1);
21462306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return 0;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ciSEC("raw_tp")
22062306a36Sopenharmony_ci__success
22162306a36Sopenharmony_ciint iter_multiple_sequential_loops(const void *ctx)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct bpf_iter_num it;
22462306a36Sopenharmony_ci	int *v, i;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	MY_PID_GUARD();
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 3);
22962306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
23062306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	bpf_iter_num_new(&it, 5, 10);
23562306a36Sopenharmony_ci	for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) {
23662306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 2);
24162306a36Sopenharmony_ci#pragma nounroll
24262306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
24362306a36Sopenharmony_ci		v = bpf_iter_num_next(&it);
24462306a36Sopenharmony_ci		bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	bpf_iter_num_new(&it, 100, 200);
24962306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
25062306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
25162306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
25262306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
25362306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
25462306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
25562306a36Sopenharmony_ci	v = bpf_iter_num_next(&it);
25662306a36Sopenharmony_ci	bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1);
25762306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return 0;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciSEC("raw_tp")
26362306a36Sopenharmony_ci__success
26462306a36Sopenharmony_ciint iter_limit_cond_break_loop(const void *ctx)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct bpf_iter_num it;
26762306a36Sopenharmony_ci	int *v, i = 0, sum = 0;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	MY_PID_GUARD();
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 10);
27262306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
27362306a36Sopenharmony_ci		bpf_printk("ITER_SIMPLE: i=%d v=%d", i, *v);
27462306a36Sopenharmony_ci		sum += *v;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		i++;
27762306a36Sopenharmony_ci		if (i > 3)
27862306a36Sopenharmony_ci			break;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	bpf_printk("ITER_SIMPLE: sum=%d\n", sum);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return 0;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciSEC("raw_tp")
28862306a36Sopenharmony_ci__success
28962306a36Sopenharmony_ciint iter_obfuscate_counter(const void *ctx)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct bpf_iter_num it;
29262306a36Sopenharmony_ci	int *v, sum = 0;
29362306a36Sopenharmony_ci	/* Make i's initial value unknowable for verifier to prevent it from
29462306a36Sopenharmony_ci	 * pruning if/else branch inside the loop body and marking i as precise.
29562306a36Sopenharmony_ci	 */
29662306a36Sopenharmony_ci	int i = zero;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	MY_PID_GUARD();
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 10);
30162306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
30262306a36Sopenharmony_ci		int x;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		i += 1;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		/* If we initialized i as `int i = 0;` above, verifier would
30762306a36Sopenharmony_ci		 * track that i becomes 1 on first iteration after increment
30862306a36Sopenharmony_ci		 * above, and here verifier would eagerly prune else branch
30962306a36Sopenharmony_ci		 * and mark i as precise, ruining open-coded iterator logic
31062306a36Sopenharmony_ci		 * completely, as each next iteration would have a different
31162306a36Sopenharmony_ci		 * *precise* value of i, and thus there would be no
31262306a36Sopenharmony_ci		 * convergence of state. This would result in reaching maximum
31362306a36Sopenharmony_ci		 * instruction limit, no matter what the limit is.
31462306a36Sopenharmony_ci		 */
31562306a36Sopenharmony_ci		if (i == 1)
31662306a36Sopenharmony_ci			x = 123;
31762306a36Sopenharmony_ci		else
31862306a36Sopenharmony_ci			x = i * 3 + 1;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		bpf_printk("ITER_OBFUSCATE_COUNTER: i=%d v=%d x=%d", i, *v, x);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		sum += x;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	bpf_printk("ITER_OBFUSCATE_COUNTER: sum=%d\n", sum);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ciSEC("raw_tp")
33262306a36Sopenharmony_ci__success
33362306a36Sopenharmony_ciint iter_search_loop(const void *ctx)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct bpf_iter_num it;
33662306a36Sopenharmony_ci	int *v, *elem = NULL;
33762306a36Sopenharmony_ci	bool found = false;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	MY_PID_GUARD();
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, 10);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	while ((v = bpf_iter_num_next(&it))) {
34462306a36Sopenharmony_ci		bpf_printk("ITER_SEARCH_LOOP: v=%d", *v);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		if (*v == 2) {
34762306a36Sopenharmony_ci			found = true;
34862306a36Sopenharmony_ci			elem = v;
34962306a36Sopenharmony_ci			barrier_var(elem);
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* should fail to verify if bpf_iter_num_destroy() is here */
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (found)
35662306a36Sopenharmony_ci		/* here found element will be wrong, we should have copied
35762306a36Sopenharmony_ci		 * value to a variable, but here we want to make sure we can
35862306a36Sopenharmony_ci		 * access memory after the loop anyways
35962306a36Sopenharmony_ci		 */
36062306a36Sopenharmony_ci		bpf_printk("ITER_SEARCH_LOOP: FOUND IT = %d!\n", *elem);
36162306a36Sopenharmony_ci	else
36262306a36Sopenharmony_ci		bpf_printk("ITER_SEARCH_LOOP: NOT FOUND IT!\n");
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return 0;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciSEC("raw_tp")
37062306a36Sopenharmony_ci__success
37162306a36Sopenharmony_ciint iter_array_fill(const void *ctx)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	int sum, i;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	MY_PID_GUARD();
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	bpf_for(i, 0, ARRAY_SIZE(arr)) {
37862306a36Sopenharmony_ci		arr[i] = i * 2;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	sum = 0;
38262306a36Sopenharmony_ci	bpf_for(i, 0, ARRAY_SIZE(arr)) {
38362306a36Sopenharmony_ci		sum += arr[i];
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	bpf_printk("ITER_ARRAY_FILL: sum=%d (should be %d)\n", sum, 255 * 256);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return 0;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic int arr2d[4][5];
39262306a36Sopenharmony_cistatic int arr2d_row_sums[4];
39362306a36Sopenharmony_cistatic int arr2d_col_sums[5];
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ciSEC("raw_tp")
39662306a36Sopenharmony_ci__success
39762306a36Sopenharmony_ciint iter_nested_iters(const void *ctx)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	int sum, row, col;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	MY_PID_GUARD();
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
40462306a36Sopenharmony_ci		bpf_for( col, 0, ARRAY_SIZE(arr2d[0])) {
40562306a36Sopenharmony_ci			arr2d[row][col] = row * col;
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* zero-initialize sums */
41062306a36Sopenharmony_ci	sum = 0;
41162306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
41262306a36Sopenharmony_ci		arr2d_row_sums[row] = 0;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
41562306a36Sopenharmony_ci		arr2d_col_sums[col] = 0;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* calculate sums */
41962306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
42062306a36Sopenharmony_ci		bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
42162306a36Sopenharmony_ci			sum += arr2d[row][col];
42262306a36Sopenharmony_ci			arr2d_row_sums[row] += arr2d[row][col];
42362306a36Sopenharmony_ci			arr2d_col_sums[col] += arr2d[row][col];
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	bpf_printk("ITER_NESTED_ITERS: total sum=%d", sum);
42862306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
42962306a36Sopenharmony_ci		bpf_printk("ITER_NESTED_ITERS: row #%d sum=%d", row, arr2d_row_sums[row]);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
43262306a36Sopenharmony_ci		bpf_printk("ITER_NESTED_ITERS: col #%d sum=%d%s",
43362306a36Sopenharmony_ci			   col, arr2d_col_sums[col],
43462306a36Sopenharmony_ci			   col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : "");
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciSEC("raw_tp")
44162306a36Sopenharmony_ci__success
44262306a36Sopenharmony_ciint iter_nested_deeply_iters(const void *ctx)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	int sum = 0;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	MY_PID_GUARD();
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	bpf_repeat(10) {
44962306a36Sopenharmony_ci		bpf_repeat(10) {
45062306a36Sopenharmony_ci			bpf_repeat(10) {
45162306a36Sopenharmony_ci				bpf_repeat(10) {
45262306a36Sopenharmony_ci					bpf_repeat(10) {
45362306a36Sopenharmony_ci						sum += 1;
45462306a36Sopenharmony_ci					}
45562306a36Sopenharmony_ci				}
45662306a36Sopenharmony_ci			}
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci		/* validate that we can break from inside bpf_repeat() */
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	return sum;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic __noinline void fill_inner_dimension(int row)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	int col;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
47062306a36Sopenharmony_ci		arr2d[row][col] = row * col;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic __noinline int sum_inner_dimension(int row)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	int sum = 0, col;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
47962306a36Sopenharmony_ci		sum += arr2d[row][col];
48062306a36Sopenharmony_ci		arr2d_row_sums[row] += arr2d[row][col];
48162306a36Sopenharmony_ci		arr2d_col_sums[col] += arr2d[row][col];
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return sum;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ciSEC("raw_tp")
48862306a36Sopenharmony_ci__success
48962306a36Sopenharmony_ciint iter_subprog_iters(const void *ctx)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	int sum, row, col;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	MY_PID_GUARD();
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
49662306a36Sopenharmony_ci		fill_inner_dimension(row);
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* zero-initialize sums */
50062306a36Sopenharmony_ci	sum = 0;
50162306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
50262306a36Sopenharmony_ci		arr2d_row_sums[row] = 0;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
50562306a36Sopenharmony_ci		arr2d_col_sums[col] = 0;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/* calculate sums */
50962306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
51062306a36Sopenharmony_ci		sum += sum_inner_dimension(row);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	bpf_printk("ITER_SUBPROG_ITERS: total sum=%d", sum);
51462306a36Sopenharmony_ci	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
51562306a36Sopenharmony_ci		bpf_printk("ITER_SUBPROG_ITERS: row #%d sum=%d",
51662306a36Sopenharmony_ci			   row, arr2d_row_sums[row]);
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
51962306a36Sopenharmony_ci		bpf_printk("ITER_SUBPROG_ITERS: col #%d sum=%d%s",
52062306a36Sopenharmony_ci			   col, arr2d_col_sums[col],
52162306a36Sopenharmony_ci			   col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : "");
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	return 0;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistruct {
52862306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_ARRAY);
52962306a36Sopenharmony_ci	__type(key, int);
53062306a36Sopenharmony_ci	__type(value, int);
53162306a36Sopenharmony_ci	__uint(max_entries, 1000);
53262306a36Sopenharmony_ci} arr_map SEC(".maps");
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ciSEC("?raw_tp")
53562306a36Sopenharmony_ci__failure __msg("invalid mem access 'scalar'")
53662306a36Sopenharmony_ciint iter_err_too_permissive1(const void *ctx)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	int *map_val = NULL;
53962306a36Sopenharmony_ci	int key = 0;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	MY_PID_GUARD();
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	map_val = bpf_map_lookup_elem(&arr_map, &key);
54462306a36Sopenharmony_ci	if (!map_val)
54562306a36Sopenharmony_ci		return 0;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	bpf_repeat(1000000) {
54862306a36Sopenharmony_ci		map_val = NULL;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	*map_val = 123;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ciSEC("?raw_tp")
55762306a36Sopenharmony_ci__failure __msg("invalid mem access 'map_value_or_null'")
55862306a36Sopenharmony_ciint iter_err_too_permissive2(const void *ctx)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	int *map_val = NULL;
56162306a36Sopenharmony_ci	int key = 0;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	MY_PID_GUARD();
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	map_val = bpf_map_lookup_elem(&arr_map, &key);
56662306a36Sopenharmony_ci	if (!map_val)
56762306a36Sopenharmony_ci		return 0;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	bpf_repeat(1000000) {
57062306a36Sopenharmony_ci		map_val = bpf_map_lookup_elem(&arr_map, &key);
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	*map_val = 123;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return 0;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ciSEC("?raw_tp")
57962306a36Sopenharmony_ci__failure __msg("invalid mem access 'map_value_or_null'")
58062306a36Sopenharmony_ciint iter_err_too_permissive3(const void *ctx)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	int *map_val = NULL;
58362306a36Sopenharmony_ci	int key = 0;
58462306a36Sopenharmony_ci	bool found = false;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	MY_PID_GUARD();
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	bpf_repeat(1000000) {
58962306a36Sopenharmony_ci		map_val = bpf_map_lookup_elem(&arr_map, &key);
59062306a36Sopenharmony_ci		found = true;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (found)
59462306a36Sopenharmony_ci		*map_val = 123;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	return 0;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ciSEC("raw_tp")
60062306a36Sopenharmony_ci__success
60162306a36Sopenharmony_ciint iter_tricky_but_fine(const void *ctx)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	int *map_val = NULL;
60462306a36Sopenharmony_ci	int key = 0;
60562306a36Sopenharmony_ci	bool found = false;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	MY_PID_GUARD();
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	bpf_repeat(1000000) {
61062306a36Sopenharmony_ci		map_val = bpf_map_lookup_elem(&arr_map, &key);
61162306a36Sopenharmony_ci		if (map_val) {
61262306a36Sopenharmony_ci			found = true;
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (found)
61862306a36Sopenharmony_ci		*map_val = 123;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci#define __bpf_memzero(p, sz) bpf_probe_read_kernel((p), (sz), 0)
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciSEC("raw_tp")
62662306a36Sopenharmony_ci__success
62762306a36Sopenharmony_ciint iter_stack_array_loop(const void *ctx)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	long arr1[16], arr2[16], sum = 0;
63062306a36Sopenharmony_ci	int i;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	MY_PID_GUARD();
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* zero-init arr1 and arr2 in such a way that verifier doesn't know
63562306a36Sopenharmony_ci	 * it's all zeros; if we don't do that, we'll make BPF verifier track
63662306a36Sopenharmony_ci	 * all combination of zero/non-zero stack slots for arr1/arr2, which
63762306a36Sopenharmony_ci	 * will lead to O(2^(ARRAY_SIZE(arr1)+ARRAY_SIZE(arr2))) different
63862306a36Sopenharmony_ci	 * states
63962306a36Sopenharmony_ci	 */
64062306a36Sopenharmony_ci	__bpf_memzero(arr1, sizeof(arr1));
64162306a36Sopenharmony_ci	__bpf_memzero(arr2, sizeof(arr1));
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* validate that we can break and continue when using bpf_for() */
64462306a36Sopenharmony_ci	bpf_for(i, 0, ARRAY_SIZE(arr1)) {
64562306a36Sopenharmony_ci		if (i & 1) {
64662306a36Sopenharmony_ci			arr1[i] = i;
64762306a36Sopenharmony_ci			continue;
64862306a36Sopenharmony_ci		} else {
64962306a36Sopenharmony_ci			arr2[i] = i;
65062306a36Sopenharmony_ci			break;
65162306a36Sopenharmony_ci		}
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	bpf_for(i, 0, ARRAY_SIZE(arr1)) {
65562306a36Sopenharmony_ci		sum += arr1[i] + arr2[i];
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return sum;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic __noinline void fill(struct bpf_iter_num *it, int *arr, __u32 n, int mul)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	int *t, i;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	while ((t = bpf_iter_num_next(it))) {
66662306a36Sopenharmony_ci		i = *t;
66762306a36Sopenharmony_ci		if (i >= n)
66862306a36Sopenharmony_ci			break;
66962306a36Sopenharmony_ci		arr[i] =  i * mul;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	int *t, i, sum = 0;;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	while ((t = bpf_iter_num_next(it))) {
67862306a36Sopenharmony_ci		i = *t;
67962306a36Sopenharmony_ci		if (i >= n)
68062306a36Sopenharmony_ci			break;
68162306a36Sopenharmony_ci		sum += arr[i];
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return sum;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ciSEC("raw_tp")
68862306a36Sopenharmony_ci__success
68962306a36Sopenharmony_ciint iter_pass_iter_ptr_to_subprog(const void *ctx)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	int arr1[16], arr2[32];
69262306a36Sopenharmony_ci	struct bpf_iter_num it;
69362306a36Sopenharmony_ci	int n, sum1, sum2;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	MY_PID_GUARD();
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	/* fill arr1 */
69862306a36Sopenharmony_ci	n = ARRAY_SIZE(arr1);
69962306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, n);
70062306a36Sopenharmony_ci	fill(&it, arr1, n, 2);
70162306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* fill arr2 */
70462306a36Sopenharmony_ci	n = ARRAY_SIZE(arr2);
70562306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, n);
70662306a36Sopenharmony_ci	fill(&it, arr2, n, 10);
70762306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* sum arr1 */
71062306a36Sopenharmony_ci	n = ARRAY_SIZE(arr1);
71162306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, n);
71262306a36Sopenharmony_ci	sum1 = sum(&it, arr1, n);
71362306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* sum arr2 */
71662306a36Sopenharmony_ci	n = ARRAY_SIZE(arr2);
71762306a36Sopenharmony_ci	bpf_iter_num_new(&it, 0, n);
71862306a36Sopenharmony_ci	sum2 = sum(&it, arr2, n);
71962306a36Sopenharmony_ci	bpf_iter_num_destroy(&it);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	bpf_printk("sum1=%d, sum2=%d", sum1, sum2);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	return 0;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ciSEC("?raw_tp")
72762306a36Sopenharmony_ci__failure
72862306a36Sopenharmony_ci__msg("R1 type=scalar expected=fp")
72962306a36Sopenharmony_ci__naked int delayed_read_mark(void)
73062306a36Sopenharmony_ci{
73162306a36Sopenharmony_ci	/* This is equivalent to C program below.
73262306a36Sopenharmony_ci	 * The call to bpf_iter_num_next() is reachable with r7 values &fp[-16] and 0xdead.
73362306a36Sopenharmony_ci	 * State with r7=&fp[-16] is visited first and follows r6 != 42 ... continue branch.
73462306a36Sopenharmony_ci	 * At this point iterator next() call is reached with r7 that has no read mark.
73562306a36Sopenharmony_ci	 * Loop body with r7=0xdead would only be visited if verifier would decide to continue
73662306a36Sopenharmony_ci	 * with second loop iteration. Absence of read mark on r7 might affect state
73762306a36Sopenharmony_ci	 * equivalent logic used for iterator convergence tracking.
73862306a36Sopenharmony_ci	 *
73962306a36Sopenharmony_ci	 * r7 = &fp[-16]
74062306a36Sopenharmony_ci	 * fp[-16] = 0
74162306a36Sopenharmony_ci	 * r6 = bpf_get_prandom_u32()
74262306a36Sopenharmony_ci	 * bpf_iter_num_new(&fp[-8], 0, 10)
74362306a36Sopenharmony_ci	 * while (bpf_iter_num_next(&fp[-8])) {
74462306a36Sopenharmony_ci	 *   r6++
74562306a36Sopenharmony_ci	 *   if (r6 != 42) {
74662306a36Sopenharmony_ci	 *     r7 = 0xdead
74762306a36Sopenharmony_ci	 *     continue;
74862306a36Sopenharmony_ci	 *   }
74962306a36Sopenharmony_ci	 *   bpf_probe_read_user(r7, 8, 0xdeadbeef); // this is not safe
75062306a36Sopenharmony_ci	 * }
75162306a36Sopenharmony_ci	 * bpf_iter_num_destroy(&fp[-8])
75262306a36Sopenharmony_ci	 * return 0
75362306a36Sopenharmony_ci	 */
75462306a36Sopenharmony_ci	asm volatile (
75562306a36Sopenharmony_ci		"r7 = r10;"
75662306a36Sopenharmony_ci		"r7 += -16;"
75762306a36Sopenharmony_ci		"r0 = 0;"
75862306a36Sopenharmony_ci		"*(u64 *)(r7 + 0) = r0;"
75962306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
76062306a36Sopenharmony_ci		"r6 = r0;"
76162306a36Sopenharmony_ci		"r1 = r10;"
76262306a36Sopenharmony_ci		"r1 += -8;"
76362306a36Sopenharmony_ci		"r2 = 0;"
76462306a36Sopenharmony_ci		"r3 = 10;"
76562306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
76662306a36Sopenharmony_ci	"1:"
76762306a36Sopenharmony_ci		"r1 = r10;"
76862306a36Sopenharmony_ci		"r1 += -8;"
76962306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
77062306a36Sopenharmony_ci		"if r0 == 0 goto 2f;"
77162306a36Sopenharmony_ci		"r6 += 1;"
77262306a36Sopenharmony_ci		"if r6 != 42 goto 3f;"
77362306a36Sopenharmony_ci		"r7 = 0xdead;"
77462306a36Sopenharmony_ci		"goto 1b;"
77562306a36Sopenharmony_ci	"3:"
77662306a36Sopenharmony_ci		"r1 = r7;"
77762306a36Sopenharmony_ci		"r2 = 8;"
77862306a36Sopenharmony_ci		"r3 = 0xdeadbeef;"
77962306a36Sopenharmony_ci		"call %[bpf_probe_read_user];"
78062306a36Sopenharmony_ci		"goto 1b;"
78162306a36Sopenharmony_ci	"2:"
78262306a36Sopenharmony_ci		"r1 = r10;"
78362306a36Sopenharmony_ci		"r1 += -8;"
78462306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
78562306a36Sopenharmony_ci		"r0 = 0;"
78662306a36Sopenharmony_ci		"exit;"
78762306a36Sopenharmony_ci		:
78862306a36Sopenharmony_ci		: __imm(bpf_get_prandom_u32),
78962306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
79062306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
79162306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy),
79262306a36Sopenharmony_ci		  __imm(bpf_probe_read_user)
79362306a36Sopenharmony_ci		: __clobber_all
79462306a36Sopenharmony_ci	);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ciSEC("?raw_tp")
79862306a36Sopenharmony_ci__failure
79962306a36Sopenharmony_ci__msg("math between fp pointer and register with unbounded")
80062306a36Sopenharmony_ci__naked int delayed_precision_mark(void)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	/* This is equivalent to C program below.
80362306a36Sopenharmony_ci	 * The test is similar to delayed_iter_mark but verifies that incomplete
80462306a36Sopenharmony_ci	 * precision don't fool verifier.
80562306a36Sopenharmony_ci	 * The call to bpf_iter_num_next() is reachable with r7 values -16 and -32.
80662306a36Sopenharmony_ci	 * State with r7=-16 is visited first and follows r6 != 42 ... continue branch.
80762306a36Sopenharmony_ci	 * At this point iterator next() call is reached with r7 that has no read
80862306a36Sopenharmony_ci	 * and precision marks.
80962306a36Sopenharmony_ci	 * Loop body with r7=-32 would only be visited if verifier would decide to continue
81062306a36Sopenharmony_ci	 * with second loop iteration. Absence of precision mark on r7 might affect state
81162306a36Sopenharmony_ci	 * equivalent logic used for iterator convergence tracking.
81262306a36Sopenharmony_ci	 *
81362306a36Sopenharmony_ci	 * r8 = 0
81462306a36Sopenharmony_ci	 * fp[-16] = 0
81562306a36Sopenharmony_ci	 * r7 = -16
81662306a36Sopenharmony_ci	 * r6 = bpf_get_prandom_u32()
81762306a36Sopenharmony_ci	 * bpf_iter_num_new(&fp[-8], 0, 10)
81862306a36Sopenharmony_ci	 * while (bpf_iter_num_next(&fp[-8])) {
81962306a36Sopenharmony_ci	 *   if (r6 != 42) {
82062306a36Sopenharmony_ci	 *     r7 = -32
82162306a36Sopenharmony_ci	 *     r6 = bpf_get_prandom_u32()
82262306a36Sopenharmony_ci	 *     continue;
82362306a36Sopenharmony_ci	 *   }
82462306a36Sopenharmony_ci	 *   r0 = r10
82562306a36Sopenharmony_ci	 *   r0 += r7
82662306a36Sopenharmony_ci	 *   r8 = *(u64 *)(r0 + 0)           // this is not safe
82762306a36Sopenharmony_ci	 *   r6 = bpf_get_prandom_u32()
82862306a36Sopenharmony_ci	 * }
82962306a36Sopenharmony_ci	 * bpf_iter_num_destroy(&fp[-8])
83062306a36Sopenharmony_ci	 * return r8
83162306a36Sopenharmony_ci	 */
83262306a36Sopenharmony_ci	asm volatile (
83362306a36Sopenharmony_ci		"r8 = 0;"
83462306a36Sopenharmony_ci		"*(u64 *)(r10 - 16) = r8;"
83562306a36Sopenharmony_ci		"r7 = -16;"
83662306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
83762306a36Sopenharmony_ci		"r6 = r0;"
83862306a36Sopenharmony_ci		"r1 = r10;"
83962306a36Sopenharmony_ci		"r1 += -8;"
84062306a36Sopenharmony_ci		"r2 = 0;"
84162306a36Sopenharmony_ci		"r3 = 10;"
84262306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
84362306a36Sopenharmony_ci	"1:"
84462306a36Sopenharmony_ci		"r1 = r10;"
84562306a36Sopenharmony_ci		"r1 += -8;\n"
84662306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
84762306a36Sopenharmony_ci		"if r0 == 0 goto 2f;"
84862306a36Sopenharmony_ci		"if r6 != 42 goto 3f;"
84962306a36Sopenharmony_ci		"r7 = -32;"
85062306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
85162306a36Sopenharmony_ci		"r6 = r0;"
85262306a36Sopenharmony_ci		"goto 1b;\n"
85362306a36Sopenharmony_ci	"3:"
85462306a36Sopenharmony_ci		"r0 = r10;"
85562306a36Sopenharmony_ci		"r0 += r7;"
85662306a36Sopenharmony_ci		"r8 = *(u64 *)(r0 + 0);"
85762306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
85862306a36Sopenharmony_ci		"r6 = r0;"
85962306a36Sopenharmony_ci		"goto 1b;\n"
86062306a36Sopenharmony_ci	"2:"
86162306a36Sopenharmony_ci		"r1 = r10;"
86262306a36Sopenharmony_ci		"r1 += -8;"
86362306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
86462306a36Sopenharmony_ci		"r0 = r8;"
86562306a36Sopenharmony_ci		"exit;"
86662306a36Sopenharmony_ci		:
86762306a36Sopenharmony_ci		: __imm(bpf_get_prandom_u32),
86862306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
86962306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
87062306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy),
87162306a36Sopenharmony_ci		  __imm(bpf_probe_read_user)
87262306a36Sopenharmony_ci		: __clobber_all
87362306a36Sopenharmony_ci	);
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ciSEC("?raw_tp")
87762306a36Sopenharmony_ci__failure
87862306a36Sopenharmony_ci__msg("math between fp pointer and register with unbounded")
87962306a36Sopenharmony_ci__flag(BPF_F_TEST_STATE_FREQ)
88062306a36Sopenharmony_ci__naked int loop_state_deps1(void)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	/* This is equivalent to C program below.
88362306a36Sopenharmony_ci	 *
88462306a36Sopenharmony_ci	 * The case turns out to be tricky in a sense that:
88562306a36Sopenharmony_ci	 * - states with c=-25 are explored only on a second iteration
88662306a36Sopenharmony_ci	 *   of the outer loop;
88762306a36Sopenharmony_ci	 * - states with read+precise mark on c are explored only on
88862306a36Sopenharmony_ci	 *   second iteration of the inner loop and in a state which
88962306a36Sopenharmony_ci	 *   is pushed to states stack first.
89062306a36Sopenharmony_ci	 *
89162306a36Sopenharmony_ci	 * Depending on the details of iterator convergence logic
89262306a36Sopenharmony_ci	 * verifier might stop states traversal too early and miss
89362306a36Sopenharmony_ci	 * unsafe c=-25 memory access.
89462306a36Sopenharmony_ci	 *
89562306a36Sopenharmony_ci	 *   j = iter_new();		 // fp[-16]
89662306a36Sopenharmony_ci	 *   a = 0;			 // r6
89762306a36Sopenharmony_ci	 *   b = 0;			 // r7
89862306a36Sopenharmony_ci	 *   c = -24;			 // r8
89962306a36Sopenharmony_ci	 *   while (iter_next(j)) {
90062306a36Sopenharmony_ci	 *     i = iter_new();		 // fp[-8]
90162306a36Sopenharmony_ci	 *     a = 0;			 // r6
90262306a36Sopenharmony_ci	 *     b = 0;			 // r7
90362306a36Sopenharmony_ci	 *     while (iter_next(i)) {
90462306a36Sopenharmony_ci	 *	 if (a == 1) {
90562306a36Sopenharmony_ci	 *	   a = 0;
90662306a36Sopenharmony_ci	 *	   b = 1;
90762306a36Sopenharmony_ci	 *	 } else if (a == 0) {
90862306a36Sopenharmony_ci	 *	   a = 1;
90962306a36Sopenharmony_ci	 *	   if (random() == 42)
91062306a36Sopenharmony_ci	 *	     continue;
91162306a36Sopenharmony_ci	 *	   if (b == 1) {
91262306a36Sopenharmony_ci	 *	     *(r10 + c) = 7;  // this is not safe
91362306a36Sopenharmony_ci	 *	     iter_destroy(i);
91462306a36Sopenharmony_ci	 *	     iter_destroy(j);
91562306a36Sopenharmony_ci	 *	     return;
91662306a36Sopenharmony_ci	 *	   }
91762306a36Sopenharmony_ci	 *	 }
91862306a36Sopenharmony_ci	 *     }
91962306a36Sopenharmony_ci	 *     iter_destroy(i);
92062306a36Sopenharmony_ci	 *     a = 0;
92162306a36Sopenharmony_ci	 *     b = 0;
92262306a36Sopenharmony_ci	 *     c = -25;
92362306a36Sopenharmony_ci	 *   }
92462306a36Sopenharmony_ci	 *   iter_destroy(j);
92562306a36Sopenharmony_ci	 *   return;
92662306a36Sopenharmony_ci	 */
92762306a36Sopenharmony_ci	asm volatile (
92862306a36Sopenharmony_ci		"r1 = r10;"
92962306a36Sopenharmony_ci		"r1 += -16;"
93062306a36Sopenharmony_ci		"r2 = 0;"
93162306a36Sopenharmony_ci		"r3 = 10;"
93262306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
93362306a36Sopenharmony_ci		"r6 = 0;"
93462306a36Sopenharmony_ci		"r7 = 0;"
93562306a36Sopenharmony_ci		"r8 = -24;"
93662306a36Sopenharmony_ci	"j_loop_%=:"
93762306a36Sopenharmony_ci		"r1 = r10;"
93862306a36Sopenharmony_ci		"r1 += -16;"
93962306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
94062306a36Sopenharmony_ci		"if r0 == 0 goto j_loop_end_%=;"
94162306a36Sopenharmony_ci		"r1 = r10;"
94262306a36Sopenharmony_ci		"r1 += -8;"
94362306a36Sopenharmony_ci		"r2 = 0;"
94462306a36Sopenharmony_ci		"r3 = 10;"
94562306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
94662306a36Sopenharmony_ci		"r6 = 0;"
94762306a36Sopenharmony_ci		"r7 = 0;"
94862306a36Sopenharmony_ci	"i_loop_%=:"
94962306a36Sopenharmony_ci		"r1 = r10;"
95062306a36Sopenharmony_ci		"r1 += -8;"
95162306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
95262306a36Sopenharmony_ci		"if r0 == 0 goto i_loop_end_%=;"
95362306a36Sopenharmony_ci	"check_one_r6_%=:"
95462306a36Sopenharmony_ci		"if r6 != 1 goto check_zero_r6_%=;"
95562306a36Sopenharmony_ci		"r6 = 0;"
95662306a36Sopenharmony_ci		"r7 = 1;"
95762306a36Sopenharmony_ci		"goto i_loop_%=;"
95862306a36Sopenharmony_ci	"check_zero_r6_%=:"
95962306a36Sopenharmony_ci		"if r6 != 0 goto i_loop_%=;"
96062306a36Sopenharmony_ci		"r6 = 1;"
96162306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
96262306a36Sopenharmony_ci		"if r0 != 42 goto check_one_r7_%=;"
96362306a36Sopenharmony_ci		"goto i_loop_%=;"
96462306a36Sopenharmony_ci	"check_one_r7_%=:"
96562306a36Sopenharmony_ci		"if r7 != 1 goto i_loop_%=;"
96662306a36Sopenharmony_ci		"r0 = r10;"
96762306a36Sopenharmony_ci		"r0 += r8;"
96862306a36Sopenharmony_ci		"r1 = 7;"
96962306a36Sopenharmony_ci		"*(u64 *)(r0 + 0) = r1;"
97062306a36Sopenharmony_ci		"r1 = r10;"
97162306a36Sopenharmony_ci		"r1 += -8;"
97262306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
97362306a36Sopenharmony_ci		"r1 = r10;"
97462306a36Sopenharmony_ci		"r1 += -16;"
97562306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
97662306a36Sopenharmony_ci		"r0 = 0;"
97762306a36Sopenharmony_ci		"exit;"
97862306a36Sopenharmony_ci	"i_loop_end_%=:"
97962306a36Sopenharmony_ci		"r1 = r10;"
98062306a36Sopenharmony_ci		"r1 += -8;"
98162306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
98262306a36Sopenharmony_ci		"r6 = 0;"
98362306a36Sopenharmony_ci		"r7 = 0;"
98462306a36Sopenharmony_ci		"r8 = -25;"
98562306a36Sopenharmony_ci		"goto j_loop_%=;"
98662306a36Sopenharmony_ci	"j_loop_end_%=:"
98762306a36Sopenharmony_ci		"r1 = r10;"
98862306a36Sopenharmony_ci		"r1 += -16;"
98962306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
99062306a36Sopenharmony_ci		"r0 = 0;"
99162306a36Sopenharmony_ci		"exit;"
99262306a36Sopenharmony_ci		:
99362306a36Sopenharmony_ci		: __imm(bpf_get_prandom_u32),
99462306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
99562306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
99662306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy)
99762306a36Sopenharmony_ci		: __clobber_all
99862306a36Sopenharmony_ci	);
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ciSEC("?raw_tp")
100262306a36Sopenharmony_ci__failure
100362306a36Sopenharmony_ci__msg("math between fp pointer and register with unbounded")
100462306a36Sopenharmony_ci__flag(BPF_F_TEST_STATE_FREQ)
100562306a36Sopenharmony_ci__naked int loop_state_deps2(void)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	/* This is equivalent to C program below.
100862306a36Sopenharmony_ci	 *
100962306a36Sopenharmony_ci	 * The case turns out to be tricky in a sense that:
101062306a36Sopenharmony_ci	 * - states with read+precise mark on c are explored only on a second
101162306a36Sopenharmony_ci	 *   iteration of the first inner loop and in a state which is pushed to
101262306a36Sopenharmony_ci	 *   states stack first.
101362306a36Sopenharmony_ci	 * - states with c=-25 are explored only on a second iteration of the
101462306a36Sopenharmony_ci	 *   second inner loop and in a state which is pushed to states stack
101562306a36Sopenharmony_ci	 *   first.
101662306a36Sopenharmony_ci	 *
101762306a36Sopenharmony_ci	 * Depending on the details of iterator convergence logic
101862306a36Sopenharmony_ci	 * verifier might stop states traversal too early and miss
101962306a36Sopenharmony_ci	 * unsafe c=-25 memory access.
102062306a36Sopenharmony_ci	 *
102162306a36Sopenharmony_ci	 *   j = iter_new();             // fp[-16]
102262306a36Sopenharmony_ci	 *   a = 0;                      // r6
102362306a36Sopenharmony_ci	 *   b = 0;                      // r7
102462306a36Sopenharmony_ci	 *   c = -24;                    // r8
102562306a36Sopenharmony_ci	 *   while (iter_next(j)) {
102662306a36Sopenharmony_ci	 *     i = iter_new();           // fp[-8]
102762306a36Sopenharmony_ci	 *     a = 0;                    // r6
102862306a36Sopenharmony_ci	 *     b = 0;                    // r7
102962306a36Sopenharmony_ci	 *     while (iter_next(i)) {
103062306a36Sopenharmony_ci	 *       if (a == 1) {
103162306a36Sopenharmony_ci	 *         a = 0;
103262306a36Sopenharmony_ci	 *         b = 1;
103362306a36Sopenharmony_ci	 *       } else if (a == 0) {
103462306a36Sopenharmony_ci	 *         a = 1;
103562306a36Sopenharmony_ci	 *         if (random() == 42)
103662306a36Sopenharmony_ci	 *           continue;
103762306a36Sopenharmony_ci	 *         if (b == 1) {
103862306a36Sopenharmony_ci	 *           *(r10 + c) = 7;     // this is not safe
103962306a36Sopenharmony_ci	 *           iter_destroy(i);
104062306a36Sopenharmony_ci	 *           iter_destroy(j);
104162306a36Sopenharmony_ci	 *           return;
104262306a36Sopenharmony_ci	 *         }
104362306a36Sopenharmony_ci	 *       }
104462306a36Sopenharmony_ci	 *     }
104562306a36Sopenharmony_ci	 *     iter_destroy(i);
104662306a36Sopenharmony_ci	 *     i = iter_new();           // fp[-8]
104762306a36Sopenharmony_ci	 *     a = 0;                    // r6
104862306a36Sopenharmony_ci	 *     b = 0;                    // r7
104962306a36Sopenharmony_ci	 *     while (iter_next(i)) {
105062306a36Sopenharmony_ci	 *       if (a == 1) {
105162306a36Sopenharmony_ci	 *         a = 0;
105262306a36Sopenharmony_ci	 *         b = 1;
105362306a36Sopenharmony_ci	 *       } else if (a == 0) {
105462306a36Sopenharmony_ci	 *         a = 1;
105562306a36Sopenharmony_ci	 *         if (random() == 42)
105662306a36Sopenharmony_ci	 *           continue;
105762306a36Sopenharmony_ci	 *         if (b == 1) {
105862306a36Sopenharmony_ci	 *           a = 0;
105962306a36Sopenharmony_ci	 *           c = -25;
106062306a36Sopenharmony_ci	 *         }
106162306a36Sopenharmony_ci	 *       }
106262306a36Sopenharmony_ci	 *     }
106362306a36Sopenharmony_ci	 *     iter_destroy(i);
106462306a36Sopenharmony_ci	 *   }
106562306a36Sopenharmony_ci	 *   iter_destroy(j);
106662306a36Sopenharmony_ci	 *   return;
106762306a36Sopenharmony_ci	 */
106862306a36Sopenharmony_ci	asm volatile (
106962306a36Sopenharmony_ci		"r1 = r10;"
107062306a36Sopenharmony_ci		"r1 += -16;"
107162306a36Sopenharmony_ci		"r2 = 0;"
107262306a36Sopenharmony_ci		"r3 = 10;"
107362306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
107462306a36Sopenharmony_ci		"r6 = 0;"
107562306a36Sopenharmony_ci		"r7 = 0;"
107662306a36Sopenharmony_ci		"r8 = -24;"
107762306a36Sopenharmony_ci	"j_loop_%=:"
107862306a36Sopenharmony_ci		"r1 = r10;"
107962306a36Sopenharmony_ci		"r1 += -16;"
108062306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
108162306a36Sopenharmony_ci		"if r0 == 0 goto j_loop_end_%=;"
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci		/* first inner loop */
108462306a36Sopenharmony_ci		"r1 = r10;"
108562306a36Sopenharmony_ci		"r1 += -8;"
108662306a36Sopenharmony_ci		"r2 = 0;"
108762306a36Sopenharmony_ci		"r3 = 10;"
108862306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
108962306a36Sopenharmony_ci		"r6 = 0;"
109062306a36Sopenharmony_ci		"r7 = 0;"
109162306a36Sopenharmony_ci	"i_loop_%=:"
109262306a36Sopenharmony_ci		"r1 = r10;"
109362306a36Sopenharmony_ci		"r1 += -8;"
109462306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
109562306a36Sopenharmony_ci		"if r0 == 0 goto i_loop_end_%=;"
109662306a36Sopenharmony_ci	"check_one_r6_%=:"
109762306a36Sopenharmony_ci		"if r6 != 1 goto check_zero_r6_%=;"
109862306a36Sopenharmony_ci		"r6 = 0;"
109962306a36Sopenharmony_ci		"r7 = 1;"
110062306a36Sopenharmony_ci		"goto i_loop_%=;"
110162306a36Sopenharmony_ci	"check_zero_r6_%=:"
110262306a36Sopenharmony_ci		"if r6 != 0 goto i_loop_%=;"
110362306a36Sopenharmony_ci		"r6 = 1;"
110462306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
110562306a36Sopenharmony_ci		"if r0 != 42 goto check_one_r7_%=;"
110662306a36Sopenharmony_ci		"goto i_loop_%=;"
110762306a36Sopenharmony_ci	"check_one_r7_%=:"
110862306a36Sopenharmony_ci		"if r7 != 1 goto i_loop_%=;"
110962306a36Sopenharmony_ci		"r0 = r10;"
111062306a36Sopenharmony_ci		"r0 += r8;"
111162306a36Sopenharmony_ci		"r1 = 7;"
111262306a36Sopenharmony_ci		"*(u64 *)(r0 + 0) = r1;"
111362306a36Sopenharmony_ci		"r1 = r10;"
111462306a36Sopenharmony_ci		"r1 += -8;"
111562306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
111662306a36Sopenharmony_ci		"r1 = r10;"
111762306a36Sopenharmony_ci		"r1 += -16;"
111862306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
111962306a36Sopenharmony_ci		"r0 = 0;"
112062306a36Sopenharmony_ci		"exit;"
112162306a36Sopenharmony_ci	"i_loop_end_%=:"
112262306a36Sopenharmony_ci		"r1 = r10;"
112362306a36Sopenharmony_ci		"r1 += -8;"
112462306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		/* second inner loop */
112762306a36Sopenharmony_ci		"r1 = r10;"
112862306a36Sopenharmony_ci		"r1 += -8;"
112962306a36Sopenharmony_ci		"r2 = 0;"
113062306a36Sopenharmony_ci		"r3 = 10;"
113162306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
113262306a36Sopenharmony_ci		"r6 = 0;"
113362306a36Sopenharmony_ci		"r7 = 0;"
113462306a36Sopenharmony_ci	"i2_loop_%=:"
113562306a36Sopenharmony_ci		"r1 = r10;"
113662306a36Sopenharmony_ci		"r1 += -8;"
113762306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
113862306a36Sopenharmony_ci		"if r0 == 0 goto i2_loop_end_%=;"
113962306a36Sopenharmony_ci	"check2_one_r6_%=:"
114062306a36Sopenharmony_ci		"if r6 != 1 goto check2_zero_r6_%=;"
114162306a36Sopenharmony_ci		"r6 = 0;"
114262306a36Sopenharmony_ci		"r7 = 1;"
114362306a36Sopenharmony_ci		"goto i2_loop_%=;"
114462306a36Sopenharmony_ci	"check2_zero_r6_%=:"
114562306a36Sopenharmony_ci		"if r6 != 0 goto i2_loop_%=;"
114662306a36Sopenharmony_ci		"r6 = 1;"
114762306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
114862306a36Sopenharmony_ci		"if r0 != 42 goto check2_one_r7_%=;"
114962306a36Sopenharmony_ci		"goto i2_loop_%=;"
115062306a36Sopenharmony_ci	"check2_one_r7_%=:"
115162306a36Sopenharmony_ci		"if r7 != 1 goto i2_loop_%=;"
115262306a36Sopenharmony_ci		"r6 = 0;"
115362306a36Sopenharmony_ci		"r8 = -25;"
115462306a36Sopenharmony_ci		"goto i2_loop_%=;"
115562306a36Sopenharmony_ci	"i2_loop_end_%=:"
115662306a36Sopenharmony_ci		"r1 = r10;"
115762306a36Sopenharmony_ci		"r1 += -8;"
115862306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci		"r6 = 0;"
116162306a36Sopenharmony_ci		"r7 = 0;"
116262306a36Sopenharmony_ci		"goto j_loop_%=;"
116362306a36Sopenharmony_ci	"j_loop_end_%=:"
116462306a36Sopenharmony_ci		"r1 = r10;"
116562306a36Sopenharmony_ci		"r1 += -16;"
116662306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
116762306a36Sopenharmony_ci		"r0 = 0;"
116862306a36Sopenharmony_ci		"exit;"
116962306a36Sopenharmony_ci		:
117062306a36Sopenharmony_ci		: __imm(bpf_get_prandom_u32),
117162306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
117262306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
117362306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy)
117462306a36Sopenharmony_ci		: __clobber_all
117562306a36Sopenharmony_ci	);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ciSEC("?raw_tp")
117962306a36Sopenharmony_ci__success
118062306a36Sopenharmony_ci__naked int triple_continue(void)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	/* This is equivalent to C program below.
118362306a36Sopenharmony_ci	 * High branching factor of the loop body turned out to be
118462306a36Sopenharmony_ci	 * problematic for one of the iterator convergence tracking
118562306a36Sopenharmony_ci	 * algorithms explored.
118662306a36Sopenharmony_ci	 *
118762306a36Sopenharmony_ci	 * r6 = bpf_get_prandom_u32()
118862306a36Sopenharmony_ci	 * bpf_iter_num_new(&fp[-8], 0, 10)
118962306a36Sopenharmony_ci	 * while (bpf_iter_num_next(&fp[-8])) {
119062306a36Sopenharmony_ci	 *   if (bpf_get_prandom_u32() != 42)
119162306a36Sopenharmony_ci	 *     continue;
119262306a36Sopenharmony_ci	 *   if (bpf_get_prandom_u32() != 42)
119362306a36Sopenharmony_ci	 *     continue;
119462306a36Sopenharmony_ci	 *   if (bpf_get_prandom_u32() != 42)
119562306a36Sopenharmony_ci	 *     continue;
119662306a36Sopenharmony_ci	 *   r0 += 0;
119762306a36Sopenharmony_ci	 * }
119862306a36Sopenharmony_ci	 * bpf_iter_num_destroy(&fp[-8])
119962306a36Sopenharmony_ci	 * return 0
120062306a36Sopenharmony_ci	 */
120162306a36Sopenharmony_ci	asm volatile (
120262306a36Sopenharmony_ci		"r1 = r10;"
120362306a36Sopenharmony_ci		"r1 += -8;"
120462306a36Sopenharmony_ci		"r2 = 0;"
120562306a36Sopenharmony_ci		"r3 = 10;"
120662306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
120762306a36Sopenharmony_ci	"loop_%=:"
120862306a36Sopenharmony_ci		"r1 = r10;"
120962306a36Sopenharmony_ci		"r1 += -8;"
121062306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
121162306a36Sopenharmony_ci		"if r0 == 0 goto loop_end_%=;"
121262306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
121362306a36Sopenharmony_ci		"if r0 != 42 goto loop_%=;"
121462306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
121562306a36Sopenharmony_ci		"if r0 != 42 goto loop_%=;"
121662306a36Sopenharmony_ci		"call %[bpf_get_prandom_u32];"
121762306a36Sopenharmony_ci		"if r0 != 42 goto loop_%=;"
121862306a36Sopenharmony_ci		"r0 += 0;"
121962306a36Sopenharmony_ci		"goto loop_%=;"
122062306a36Sopenharmony_ci	"loop_end_%=:"
122162306a36Sopenharmony_ci		"r1 = r10;"
122262306a36Sopenharmony_ci		"r1 += -8;"
122362306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
122462306a36Sopenharmony_ci		"r0 = 0;"
122562306a36Sopenharmony_ci		"exit;"
122662306a36Sopenharmony_ci		:
122762306a36Sopenharmony_ci		: __imm(bpf_get_prandom_u32),
122862306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
122962306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
123062306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy)
123162306a36Sopenharmony_ci		: __clobber_all
123262306a36Sopenharmony_ci	);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ciSEC("?raw_tp")
123662306a36Sopenharmony_ci__success
123762306a36Sopenharmony_ci__naked int widen_spill(void)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	/* This is equivalent to C program below.
124062306a36Sopenharmony_ci	 * The counter is stored in fp[-16], if this counter is not widened
124162306a36Sopenharmony_ci	 * verifier states representing loop iterations would never converge.
124262306a36Sopenharmony_ci	 *
124362306a36Sopenharmony_ci	 * fp[-16] = 0
124462306a36Sopenharmony_ci	 * bpf_iter_num_new(&fp[-8], 0, 10)
124562306a36Sopenharmony_ci	 * while (bpf_iter_num_next(&fp[-8])) {
124662306a36Sopenharmony_ci	 *   r0 = fp[-16];
124762306a36Sopenharmony_ci	 *   r0 += 1;
124862306a36Sopenharmony_ci	 *   fp[-16] = r0;
124962306a36Sopenharmony_ci	 * }
125062306a36Sopenharmony_ci	 * bpf_iter_num_destroy(&fp[-8])
125162306a36Sopenharmony_ci	 * return 0
125262306a36Sopenharmony_ci	 */
125362306a36Sopenharmony_ci	asm volatile (
125462306a36Sopenharmony_ci		"r0 = 0;"
125562306a36Sopenharmony_ci		"*(u64 *)(r10 - 16) = r0;"
125662306a36Sopenharmony_ci		"r1 = r10;"
125762306a36Sopenharmony_ci		"r1 += -8;"
125862306a36Sopenharmony_ci		"r2 = 0;"
125962306a36Sopenharmony_ci		"r3 = 10;"
126062306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
126162306a36Sopenharmony_ci	"loop_%=:"
126262306a36Sopenharmony_ci		"r1 = r10;"
126362306a36Sopenharmony_ci		"r1 += -8;"
126462306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
126562306a36Sopenharmony_ci		"if r0 == 0 goto loop_end_%=;"
126662306a36Sopenharmony_ci		"r0 = *(u64 *)(r10 - 16);"
126762306a36Sopenharmony_ci		"r0 += 1;"
126862306a36Sopenharmony_ci		"*(u64 *)(r10 - 16) = r0;"
126962306a36Sopenharmony_ci		"goto loop_%=;"
127062306a36Sopenharmony_ci	"loop_end_%=:"
127162306a36Sopenharmony_ci		"r1 = r10;"
127262306a36Sopenharmony_ci		"r1 += -8;"
127362306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
127462306a36Sopenharmony_ci		"r0 = 0;"
127562306a36Sopenharmony_ci		"exit;"
127662306a36Sopenharmony_ci		:
127762306a36Sopenharmony_ci		: __imm(bpf_iter_num_new),
127862306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
127962306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy)
128062306a36Sopenharmony_ci		: __clobber_all
128162306a36Sopenharmony_ci	);
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ciSEC("raw_tp")
128562306a36Sopenharmony_ci__success
128662306a36Sopenharmony_ci__naked int checkpoint_states_deletion(void)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	/* This is equivalent to C program below.
128962306a36Sopenharmony_ci	 *
129062306a36Sopenharmony_ci	 *   int *a, *b, *c, *d, *e, *f;
129162306a36Sopenharmony_ci	 *   int i, sum = 0;
129262306a36Sopenharmony_ci	 *   bpf_for(i, 0, 10) {
129362306a36Sopenharmony_ci	 *     a = bpf_map_lookup_elem(&amap, &i);
129462306a36Sopenharmony_ci	 *     b = bpf_map_lookup_elem(&amap, &i);
129562306a36Sopenharmony_ci	 *     c = bpf_map_lookup_elem(&amap, &i);
129662306a36Sopenharmony_ci	 *     d = bpf_map_lookup_elem(&amap, &i);
129762306a36Sopenharmony_ci	 *     e = bpf_map_lookup_elem(&amap, &i);
129862306a36Sopenharmony_ci	 *     f = bpf_map_lookup_elem(&amap, &i);
129962306a36Sopenharmony_ci	 *     if (a) sum += 1;
130062306a36Sopenharmony_ci	 *     if (b) sum += 1;
130162306a36Sopenharmony_ci	 *     if (c) sum += 1;
130262306a36Sopenharmony_ci	 *     if (d) sum += 1;
130362306a36Sopenharmony_ci	 *     if (e) sum += 1;
130462306a36Sopenharmony_ci	 *     if (f) sum += 1;
130562306a36Sopenharmony_ci	 *   }
130662306a36Sopenharmony_ci	 *   return 0;
130762306a36Sopenharmony_ci	 *
130862306a36Sopenharmony_ci	 * The body of the loop spawns multiple simulation paths
130962306a36Sopenharmony_ci	 * with different combination of NULL/non-NULL information for a/b/c/d/e/f.
131062306a36Sopenharmony_ci	 * Each combination is unique from states_equal() point of view.
131162306a36Sopenharmony_ci	 * Explored states checkpoint is created after each iterator next call.
131262306a36Sopenharmony_ci	 * Iterator convergence logic expects that eventually current state
131362306a36Sopenharmony_ci	 * would get equal to one of the explored states and thus loop
131462306a36Sopenharmony_ci	 * exploration would be finished (at-least for a specific path).
131562306a36Sopenharmony_ci	 * Verifier evicts explored states with high miss to hit ratio
131662306a36Sopenharmony_ci	 * to to avoid comparing current state with too many explored
131762306a36Sopenharmony_ci	 * states per instruction.
131862306a36Sopenharmony_ci	 * This test is designed to "stress test" eviction policy defined using formula:
131962306a36Sopenharmony_ci	 *
132062306a36Sopenharmony_ci	 *    sl->miss_cnt > sl->hit_cnt * N + N // if true sl->state is evicted
132162306a36Sopenharmony_ci	 *
132262306a36Sopenharmony_ci	 * Currently N is set to 64, which allows for 6 variables in this test.
132362306a36Sopenharmony_ci	 */
132462306a36Sopenharmony_ci	asm volatile (
132562306a36Sopenharmony_ci		"r6 = 0;"                  /* a */
132662306a36Sopenharmony_ci		"r7 = 0;"                  /* b */
132762306a36Sopenharmony_ci		"r8 = 0;"                  /* c */
132862306a36Sopenharmony_ci		"*(u64 *)(r10 - 24) = r6;" /* d */
132962306a36Sopenharmony_ci		"*(u64 *)(r10 - 32) = r6;" /* e */
133062306a36Sopenharmony_ci		"*(u64 *)(r10 - 40) = r6;" /* f */
133162306a36Sopenharmony_ci		"r9 = 0;"                  /* sum */
133262306a36Sopenharmony_ci		"r1 = r10;"
133362306a36Sopenharmony_ci		"r1 += -8;"
133462306a36Sopenharmony_ci		"r2 = 0;"
133562306a36Sopenharmony_ci		"r3 = 10;"
133662306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
133762306a36Sopenharmony_ci	"loop_%=:"
133862306a36Sopenharmony_ci		"r1 = r10;"
133962306a36Sopenharmony_ci		"r1 += -8;"
134062306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
134162306a36Sopenharmony_ci		"if r0 == 0 goto loop_end_%=;"
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci		"*(u64 *)(r10 - 16) = r0;"
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci		"r1 = %[amap] ll;"
134662306a36Sopenharmony_ci		"r2 = r10;"
134762306a36Sopenharmony_ci		"r2 += -16;"
134862306a36Sopenharmony_ci		"call %[bpf_map_lookup_elem];"
134962306a36Sopenharmony_ci		"r6 = r0;"
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		"r1 = %[amap] ll;"
135262306a36Sopenharmony_ci		"r2 = r10;"
135362306a36Sopenharmony_ci		"r2 += -16;"
135462306a36Sopenharmony_ci		"call %[bpf_map_lookup_elem];"
135562306a36Sopenharmony_ci		"r7 = r0;"
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		"r1 = %[amap] ll;"
135862306a36Sopenharmony_ci		"r2 = r10;"
135962306a36Sopenharmony_ci		"r2 += -16;"
136062306a36Sopenharmony_ci		"call %[bpf_map_lookup_elem];"
136162306a36Sopenharmony_ci		"r8 = r0;"
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci		"r1 = %[amap] ll;"
136462306a36Sopenharmony_ci		"r2 = r10;"
136562306a36Sopenharmony_ci		"r2 += -16;"
136662306a36Sopenharmony_ci		"call %[bpf_map_lookup_elem];"
136762306a36Sopenharmony_ci		"*(u64 *)(r10 - 24) = r0;"
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		"r1 = %[amap] ll;"
137062306a36Sopenharmony_ci		"r2 = r10;"
137162306a36Sopenharmony_ci		"r2 += -16;"
137262306a36Sopenharmony_ci		"call %[bpf_map_lookup_elem];"
137362306a36Sopenharmony_ci		"*(u64 *)(r10 - 32) = r0;"
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		"r1 = %[amap] ll;"
137662306a36Sopenharmony_ci		"r2 = r10;"
137762306a36Sopenharmony_ci		"r2 += -16;"
137862306a36Sopenharmony_ci		"call %[bpf_map_lookup_elem];"
137962306a36Sopenharmony_ci		"*(u64 *)(r10 - 40) = r0;"
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		"if r6 == 0 goto +1;"
138262306a36Sopenharmony_ci		"r9 += 1;"
138362306a36Sopenharmony_ci		"if r7 == 0 goto +1;"
138462306a36Sopenharmony_ci		"r9 += 1;"
138562306a36Sopenharmony_ci		"if r8 == 0 goto +1;"
138662306a36Sopenharmony_ci		"r9 += 1;"
138762306a36Sopenharmony_ci		"r0 = *(u64 *)(r10 - 24);"
138862306a36Sopenharmony_ci		"if r0 == 0 goto +1;"
138962306a36Sopenharmony_ci		"r9 += 1;"
139062306a36Sopenharmony_ci		"r0 = *(u64 *)(r10 - 32);"
139162306a36Sopenharmony_ci		"if r0 == 0 goto +1;"
139262306a36Sopenharmony_ci		"r9 += 1;"
139362306a36Sopenharmony_ci		"r0 = *(u64 *)(r10 - 40);"
139462306a36Sopenharmony_ci		"if r0 == 0 goto +1;"
139562306a36Sopenharmony_ci		"r9 += 1;"
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci		"goto loop_%=;"
139862306a36Sopenharmony_ci	"loop_end_%=:"
139962306a36Sopenharmony_ci		"r1 = r10;"
140062306a36Sopenharmony_ci		"r1 += -8;"
140162306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
140262306a36Sopenharmony_ci		"r0 = 0;"
140362306a36Sopenharmony_ci		"exit;"
140462306a36Sopenharmony_ci		:
140562306a36Sopenharmony_ci		: __imm(bpf_map_lookup_elem),
140662306a36Sopenharmony_ci		  __imm(bpf_iter_num_new),
140762306a36Sopenharmony_ci		  __imm(bpf_iter_num_next),
140862306a36Sopenharmony_ci		  __imm(bpf_iter_num_destroy),
140962306a36Sopenharmony_ci		  __imm_addr(amap)
141062306a36Sopenharmony_ci		: __clobber_all
141162306a36Sopenharmony_ci	);
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
1415