162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <errno.h>
562306a36Sopenharmony_ci#include <string.h>
662306a36Sopenharmony_ci#include <linux/bpf.h>
762306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
862306a36Sopenharmony_ci#include "bpf_misc.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define ITER_HELPERS						\
1362306a36Sopenharmony_ci	  __imm(bpf_iter_num_new),				\
1462306a36Sopenharmony_ci	  __imm(bpf_iter_num_next),				\
1562306a36Sopenharmony_ci	  __imm(bpf_iter_num_destroy)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciSEC("?raw_tp")
1862306a36Sopenharmony_ci__success
1962306a36Sopenharmony_ciint force_clang_to_emit_btf_for_externs(void *ctx)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	/* we need this as a workaround to enforce compiler emitting BTF
2262306a36Sopenharmony_ci	 * information for bpf_iter_num_{new,next,destroy}() kfuncs,
2362306a36Sopenharmony_ci	 * as, apparently, it doesn't emit it for symbols only referenced from
2462306a36Sopenharmony_ci	 * assembly (or cleanup attribute, for that matter, as well)
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci	bpf_repeat(0);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	return 0;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciSEC("?raw_tp")
3262306a36Sopenharmony_ci__success
3362306a36Sopenharmony_ciint consume_first_item_only(void *ctx)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct bpf_iter_num iter;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	asm volatile (
3862306a36Sopenharmony_ci		/* create iterator */
3962306a36Sopenharmony_ci		"r1 = %[iter];"
4062306a36Sopenharmony_ci		"r2 = 0;"
4162306a36Sopenharmony_ci		"r3 = 1000;"
4262306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci		/* consume first item */
4562306a36Sopenharmony_ci		"r1 = %[iter];"
4662306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci		"if r0 == 0 goto +1;"
4962306a36Sopenharmony_ci		"r0 = *(u32 *)(r0 + 0);"
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		/* destroy iterator */
5262306a36Sopenharmony_ci		"r1 = %[iter];"
5362306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
5462306a36Sopenharmony_ci		:
5562306a36Sopenharmony_ci		: __imm_ptr(iter), ITER_HELPERS
5662306a36Sopenharmony_ci		: __clobber_common
5762306a36Sopenharmony_ci	);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return 0;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciSEC("?raw_tp")
6362306a36Sopenharmony_ci__failure __msg("R0 invalid mem access 'scalar'")
6462306a36Sopenharmony_ciint missing_null_check_fail(void *ctx)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct bpf_iter_num iter;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	asm volatile (
6962306a36Sopenharmony_ci		/* create iterator */
7062306a36Sopenharmony_ci		"r1 = %[iter];"
7162306a36Sopenharmony_ci		"r2 = 0;"
7262306a36Sopenharmony_ci		"r3 = 1000;"
7362306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		/* consume first element */
7662306a36Sopenharmony_ci		"r1 = %[iter];"
7762306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		/* FAIL: deref with no NULL check */
8062306a36Sopenharmony_ci		"r1 = *(u32 *)(r0 + 0);"
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		/* destroy iterator */
8362306a36Sopenharmony_ci		"r1 = %[iter];"
8462306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
8562306a36Sopenharmony_ci		:
8662306a36Sopenharmony_ci		: __imm_ptr(iter), ITER_HELPERS
8762306a36Sopenharmony_ci		: __clobber_common
8862306a36Sopenharmony_ci	);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciSEC("?raw_tp")
9462306a36Sopenharmony_ci__failure
9562306a36Sopenharmony_ci__msg("invalid access to memory, mem_size=4 off=0 size=8")
9662306a36Sopenharmony_ci__msg("R0 min value is outside of the allowed memory range")
9762306a36Sopenharmony_ciint wrong_sized_read_fail(void *ctx)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct bpf_iter_num iter;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	asm volatile (
10262306a36Sopenharmony_ci		/* create iterator */
10362306a36Sopenharmony_ci		"r1 = %[iter];"
10462306a36Sopenharmony_ci		"r2 = 0;"
10562306a36Sopenharmony_ci		"r3 = 1000;"
10662306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		/* consume first element */
10962306a36Sopenharmony_ci		"r1 = %[iter];"
11062306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		"if r0 == 0 goto +1;"
11362306a36Sopenharmony_ci		/* FAIL: deref more than available 4 bytes */
11462306a36Sopenharmony_ci		"r0 = *(u64 *)(r0 + 0);"
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		/* destroy iterator */
11762306a36Sopenharmony_ci		"r1 = %[iter];"
11862306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
11962306a36Sopenharmony_ci		:
12062306a36Sopenharmony_ci		: __imm_ptr(iter), ITER_HELPERS
12162306a36Sopenharmony_ci		: __clobber_common
12262306a36Sopenharmony_ci	);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ciSEC("?raw_tp")
12862306a36Sopenharmony_ci__success __log_level(2)
12962306a36Sopenharmony_ci__flag(BPF_F_TEST_STATE_FREQ)
13062306a36Sopenharmony_ciint simplest_loop(void *ctx)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct bpf_iter_num iter;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	asm volatile (
13562306a36Sopenharmony_ci		"r6 = 0;" /* init sum */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		/* create iterator */
13862306a36Sopenharmony_ci		"r1 = %[iter];"
13962306a36Sopenharmony_ci		"r2 = 0;"
14062306a36Sopenharmony_ci		"r3 = 10;"
14162306a36Sopenharmony_ci		"call %[bpf_iter_num_new];"
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	"1:"
14462306a36Sopenharmony_ci		/* consume next item */
14562306a36Sopenharmony_ci		"r1 = %[iter];"
14662306a36Sopenharmony_ci		"call %[bpf_iter_num_next];"
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		"if r0 == 0 goto 2f;"
14962306a36Sopenharmony_ci		"r0 = *(u32 *)(r0 + 0);"
15062306a36Sopenharmony_ci		"r6 += r0;" /* accumulate sum */
15162306a36Sopenharmony_ci		"goto 1b;"
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	"2:"
15462306a36Sopenharmony_ci		/* destroy iterator */
15562306a36Sopenharmony_ci		"r1 = %[iter];"
15662306a36Sopenharmony_ci		"call %[bpf_iter_num_destroy];"
15762306a36Sopenharmony_ci		:
15862306a36Sopenharmony_ci		: __imm_ptr(iter), ITER_HELPERS
15962306a36Sopenharmony_ci		: __clobber_common, "r6"
16062306a36Sopenharmony_ci	);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
164