162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Testsuite for eBPF verifier
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
662306a36Sopenharmony_ci * Copyright (c) 2017 Facebook
762306a36Sopenharmony_ci * Copyright (c) 2018 Covalent IO, Inc. http://covalent.io
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <endian.h>
1162306a36Sopenharmony_ci#include <asm/types.h>
1262306a36Sopenharmony_ci#include <linux/types.h>
1362306a36Sopenharmony_ci#include <stdint.h>
1462306a36Sopenharmony_ci#include <stdio.h>
1562306a36Sopenharmony_ci#include <stdlib.h>
1662306a36Sopenharmony_ci#include <unistd.h>
1762306a36Sopenharmony_ci#include <errno.h>
1862306a36Sopenharmony_ci#include <string.h>
1962306a36Sopenharmony_ci#include <stddef.h>
2062306a36Sopenharmony_ci#include <stdbool.h>
2162306a36Sopenharmony_ci#include <sched.h>
2262306a36Sopenharmony_ci#include <limits.h>
2362306a36Sopenharmony_ci#include <assert.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/unistd.h>
2662306a36Sopenharmony_ci#include <linux/filter.h>
2762306a36Sopenharmony_ci#include <linux/bpf_perf_event.h>
2862306a36Sopenharmony_ci#include <linux/bpf.h>
2962306a36Sopenharmony_ci#include <linux/if_ether.h>
3062306a36Sopenharmony_ci#include <linux/btf.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <bpf/btf.h>
3362306a36Sopenharmony_ci#include <bpf/bpf.h>
3462306a36Sopenharmony_ci#include <bpf/libbpf.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "autoconf_helper.h"
3762306a36Sopenharmony_ci#include "unpriv_helpers.h"
3862306a36Sopenharmony_ci#include "cap_helpers.h"
3962306a36Sopenharmony_ci#include "bpf_rand.h"
4062306a36Sopenharmony_ci#include "bpf_util.h"
4162306a36Sopenharmony_ci#include "test_btf.h"
4262306a36Sopenharmony_ci#include "../../../include/linux/filter.h"
4362306a36Sopenharmony_ci#include "testing_helpers.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#ifndef ENOTSUPP
4662306a36Sopenharmony_ci#define ENOTSUPP 524
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define MAX_INSNS	BPF_MAXINSNS
5062306a36Sopenharmony_ci#define MAX_EXPECTED_INSNS	32
5162306a36Sopenharmony_ci#define MAX_UNEXPECTED_INSNS	32
5262306a36Sopenharmony_ci#define MAX_TEST_INSNS	1000000
5362306a36Sopenharmony_ci#define MAX_FIXUPS	8
5462306a36Sopenharmony_ci#define MAX_NR_MAPS	23
5562306a36Sopenharmony_ci#define MAX_TEST_RUNS	8
5662306a36Sopenharmony_ci#define POINTER_VALUE	0xcafe4all
5762306a36Sopenharmony_ci#define TEST_DATA_LEN	64
5862306a36Sopenharmony_ci#define MAX_FUNC_INFOS	8
5962306a36Sopenharmony_ci#define MAX_BTF_STRINGS	256
6062306a36Sopenharmony_ci#define MAX_BTF_TYPES	256
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define INSN_OFF_MASK	((__s16)0xFFFF)
6362306a36Sopenharmony_ci#define INSN_IMM_MASK	((__s32)0xFFFFFFFF)
6462306a36Sopenharmony_ci#define SKIP_INSNS()	BPF_RAW_INSN(0xde, 0xa, 0xd, 0xbeef, 0xdeadbeef)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define DEFAULT_LIBBPF_LOG_LEVEL	4
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS	(1 << 0)
6962306a36Sopenharmony_ci#define F_LOAD_WITH_STRICT_ALIGNMENT		(1 << 1)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
7262306a36Sopenharmony_ci#define ADMIN_CAPS (1ULL << CAP_NET_ADMIN |	\
7362306a36Sopenharmony_ci		    1ULL << CAP_PERFMON |	\
7462306a36Sopenharmony_ci		    1ULL << CAP_BPF)
7562306a36Sopenharmony_ci#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
7662306a36Sopenharmony_cistatic bool unpriv_disabled = false;
7762306a36Sopenharmony_cistatic int skips;
7862306a36Sopenharmony_cistatic bool verbose = false;
7962306a36Sopenharmony_cistatic int verif_log_level = 0;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct kfunc_btf_id_pair {
8262306a36Sopenharmony_ci	const char *kfunc;
8362306a36Sopenharmony_ci	int insn_idx;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct bpf_test {
8762306a36Sopenharmony_ci	const char *descr;
8862306a36Sopenharmony_ci	struct bpf_insn	insns[MAX_INSNS];
8962306a36Sopenharmony_ci	struct bpf_insn	*fill_insns;
9062306a36Sopenharmony_ci	/* If specified, test engine looks for this sequence of
9162306a36Sopenharmony_ci	 * instructions in the BPF program after loading. Allows to
9262306a36Sopenharmony_ci	 * test rewrites applied by verifier.  Use values
9362306a36Sopenharmony_ci	 * INSN_OFF_MASK and INSN_IMM_MASK to mask `off` and `imm`
9462306a36Sopenharmony_ci	 * fields if content does not matter.  The test case fails if
9562306a36Sopenharmony_ci	 * specified instructions are not found.
9662306a36Sopenharmony_ci	 *
9762306a36Sopenharmony_ci	 * The sequence could be split into sub-sequences by adding
9862306a36Sopenharmony_ci	 * SKIP_INSNS instruction at the end of each sub-sequence. In
9962306a36Sopenharmony_ci	 * such case sub-sequences are searched for one after another.
10062306a36Sopenharmony_ci	 */
10162306a36Sopenharmony_ci	struct bpf_insn expected_insns[MAX_EXPECTED_INSNS];
10262306a36Sopenharmony_ci	/* If specified, test engine applies same pattern matching
10362306a36Sopenharmony_ci	 * logic as for `expected_insns`. If the specified pattern is
10462306a36Sopenharmony_ci	 * matched test case is marked as failed.
10562306a36Sopenharmony_ci	 */
10662306a36Sopenharmony_ci	struct bpf_insn unexpected_insns[MAX_UNEXPECTED_INSNS];
10762306a36Sopenharmony_ci	int fixup_map_hash_8b[MAX_FIXUPS];
10862306a36Sopenharmony_ci	int fixup_map_hash_48b[MAX_FIXUPS];
10962306a36Sopenharmony_ci	int fixup_map_hash_16b[MAX_FIXUPS];
11062306a36Sopenharmony_ci	int fixup_map_array_48b[MAX_FIXUPS];
11162306a36Sopenharmony_ci	int fixup_map_sockmap[MAX_FIXUPS];
11262306a36Sopenharmony_ci	int fixup_map_sockhash[MAX_FIXUPS];
11362306a36Sopenharmony_ci	int fixup_map_xskmap[MAX_FIXUPS];
11462306a36Sopenharmony_ci	int fixup_map_stacktrace[MAX_FIXUPS];
11562306a36Sopenharmony_ci	int fixup_prog1[MAX_FIXUPS];
11662306a36Sopenharmony_ci	int fixup_prog2[MAX_FIXUPS];
11762306a36Sopenharmony_ci	int fixup_map_in_map[MAX_FIXUPS];
11862306a36Sopenharmony_ci	int fixup_cgroup_storage[MAX_FIXUPS];
11962306a36Sopenharmony_ci	int fixup_percpu_cgroup_storage[MAX_FIXUPS];
12062306a36Sopenharmony_ci	int fixup_map_spin_lock[MAX_FIXUPS];
12162306a36Sopenharmony_ci	int fixup_map_array_ro[MAX_FIXUPS];
12262306a36Sopenharmony_ci	int fixup_map_array_wo[MAX_FIXUPS];
12362306a36Sopenharmony_ci	int fixup_map_array_small[MAX_FIXUPS];
12462306a36Sopenharmony_ci	int fixup_sk_storage_map[MAX_FIXUPS];
12562306a36Sopenharmony_ci	int fixup_map_event_output[MAX_FIXUPS];
12662306a36Sopenharmony_ci	int fixup_map_reuseport_array[MAX_FIXUPS];
12762306a36Sopenharmony_ci	int fixup_map_ringbuf[MAX_FIXUPS];
12862306a36Sopenharmony_ci	int fixup_map_timer[MAX_FIXUPS];
12962306a36Sopenharmony_ci	int fixup_map_kptr[MAX_FIXUPS];
13062306a36Sopenharmony_ci	struct kfunc_btf_id_pair fixup_kfunc_btf_id[MAX_FIXUPS];
13162306a36Sopenharmony_ci	/* Expected verifier log output for result REJECT or VERBOSE_ACCEPT.
13262306a36Sopenharmony_ci	 * Can be a tab-separated sequence of expected strings. An empty string
13362306a36Sopenharmony_ci	 * means no log verification.
13462306a36Sopenharmony_ci	 */
13562306a36Sopenharmony_ci	const char *errstr;
13662306a36Sopenharmony_ci	const char *errstr_unpriv;
13762306a36Sopenharmony_ci	uint32_t insn_processed;
13862306a36Sopenharmony_ci	int prog_len;
13962306a36Sopenharmony_ci	enum {
14062306a36Sopenharmony_ci		UNDEF,
14162306a36Sopenharmony_ci		ACCEPT,
14262306a36Sopenharmony_ci		REJECT,
14362306a36Sopenharmony_ci		VERBOSE_ACCEPT,
14462306a36Sopenharmony_ci	} result, result_unpriv;
14562306a36Sopenharmony_ci	enum bpf_prog_type prog_type;
14662306a36Sopenharmony_ci	uint8_t flags;
14762306a36Sopenharmony_ci	void (*fill_helper)(struct bpf_test *self);
14862306a36Sopenharmony_ci	int runs;
14962306a36Sopenharmony_ci#define bpf_testdata_struct_t					\
15062306a36Sopenharmony_ci	struct {						\
15162306a36Sopenharmony_ci		uint32_t retval, retval_unpriv;			\
15262306a36Sopenharmony_ci		union {						\
15362306a36Sopenharmony_ci			__u8 data[TEST_DATA_LEN];		\
15462306a36Sopenharmony_ci			__u64 data64[TEST_DATA_LEN / 8];	\
15562306a36Sopenharmony_ci		};						\
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci	union {
15862306a36Sopenharmony_ci		bpf_testdata_struct_t;
15962306a36Sopenharmony_ci		bpf_testdata_struct_t retvals[MAX_TEST_RUNS];
16062306a36Sopenharmony_ci	};
16162306a36Sopenharmony_ci	enum bpf_attach_type expected_attach_type;
16262306a36Sopenharmony_ci	const char *kfunc;
16362306a36Sopenharmony_ci	struct bpf_func_info func_info[MAX_FUNC_INFOS];
16462306a36Sopenharmony_ci	int func_info_cnt;
16562306a36Sopenharmony_ci	char btf_strings[MAX_BTF_STRINGS];
16662306a36Sopenharmony_ci	/* A set of BTF types to load when specified,
16762306a36Sopenharmony_ci	 * use macro definitions from test_btf.h,
16862306a36Sopenharmony_ci	 * must end with BTF_END_RAW
16962306a36Sopenharmony_ci	 */
17062306a36Sopenharmony_ci	__u32 btf_types[MAX_BTF_TYPES];
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Note we want this to be 64 bit aligned so that the end of our array is
17462306a36Sopenharmony_ci * actually the end of the structure.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_ci#define MAX_ENTRIES 11
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistruct test_val {
17962306a36Sopenharmony_ci	unsigned int index;
18062306a36Sopenharmony_ci	int foo[MAX_ENTRIES];
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistruct other_val {
18462306a36Sopenharmony_ci	long long foo;
18562306a36Sopenharmony_ci	long long bar;
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	/* test: {skb->data[0], vlan_push} x 51 + {skb->data[0], vlan_pop} x 51 */
19162306a36Sopenharmony_ci#define PUSH_CNT 51
19262306a36Sopenharmony_ci	/* jump range is limited to 16 bit. PUSH_CNT of ld_abs needs room */
19362306a36Sopenharmony_ci	unsigned int len = (1 << 15) - PUSH_CNT * 2 * 5 * 6;
19462306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
19562306a36Sopenharmony_ci	int i = 0, j, k = 0;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
19862306a36Sopenharmony_ciloop:
19962306a36Sopenharmony_ci	for (j = 0; j < PUSH_CNT; j++) {
20062306a36Sopenharmony_ci		insn[i++] = BPF_LD_ABS(BPF_B, 0);
20162306a36Sopenharmony_ci		/* jump to error label */
20262306a36Sopenharmony_ci		insn[i] = BPF_JMP32_IMM(BPF_JNE, BPF_REG_0, 0x34, len - i - 3);
20362306a36Sopenharmony_ci		i++;
20462306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6);
20562306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_IMM(BPF_REG_2, 1);
20662306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_IMM(BPF_REG_3, 2);
20762306a36Sopenharmony_ci		insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
20862306a36Sopenharmony_ci					 BPF_FUNC_skb_vlan_push);
20962306a36Sopenharmony_ci		insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, len - i - 3);
21062306a36Sopenharmony_ci		i++;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	for (j = 0; j < PUSH_CNT; j++) {
21462306a36Sopenharmony_ci		insn[i++] = BPF_LD_ABS(BPF_B, 0);
21562306a36Sopenharmony_ci		insn[i] = BPF_JMP32_IMM(BPF_JNE, BPF_REG_0, 0x34, len - i - 3);
21662306a36Sopenharmony_ci		i++;
21762306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6);
21862306a36Sopenharmony_ci		insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
21962306a36Sopenharmony_ci					 BPF_FUNC_skb_vlan_pop);
22062306a36Sopenharmony_ci		insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, len - i - 3);
22162306a36Sopenharmony_ci		i++;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci	if (++k < 5)
22462306a36Sopenharmony_ci		goto loop;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for (; i < len - 3; i++)
22762306a36Sopenharmony_ci		insn[i] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0xbef);
22862306a36Sopenharmony_ci	insn[len - 3] = BPF_JMP_A(1);
22962306a36Sopenharmony_ci	/* error label */
23062306a36Sopenharmony_ci	insn[len - 2] = BPF_MOV32_IMM(BPF_REG_0, 0);
23162306a36Sopenharmony_ci	insn[len - 1] = BPF_EXIT_INSN();
23262306a36Sopenharmony_ci	self->prog_len = len;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void bpf_fill_jump_around_ld_abs(struct bpf_test *self)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
23862306a36Sopenharmony_ci	/* jump range is limited to 16 bit. every ld_abs is replaced by 6 insns,
23962306a36Sopenharmony_ci	 * but on arches like arm, ppc etc, there will be one BPF_ZEXT inserted
24062306a36Sopenharmony_ci	 * to extend the error value of the inlined ld_abs sequence which then
24162306a36Sopenharmony_ci	 * contains 7 insns. so, set the dividend to 7 so the testcase could
24262306a36Sopenharmony_ci	 * work on all arches.
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci	unsigned int len = (1 << 15) / 7;
24562306a36Sopenharmony_ci	int i = 0;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
24862306a36Sopenharmony_ci	insn[i++] = BPF_LD_ABS(BPF_B, 0);
24962306a36Sopenharmony_ci	insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 10, len - i - 2);
25062306a36Sopenharmony_ci	i++;
25162306a36Sopenharmony_ci	while (i < len - 1)
25262306a36Sopenharmony_ci		insn[i++] = BPF_LD_ABS(BPF_B, 1);
25362306a36Sopenharmony_ci	insn[i] = BPF_EXIT_INSN();
25462306a36Sopenharmony_ci	self->prog_len = i + 1;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic void bpf_fill_rand_ld_dw(struct bpf_test *self)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
26062306a36Sopenharmony_ci	uint64_t res = 0;
26162306a36Sopenharmony_ci	int i = 0;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	insn[i++] = BPF_MOV32_IMM(BPF_REG_0, 0);
26462306a36Sopenharmony_ci	while (i < self->retval) {
26562306a36Sopenharmony_ci		uint64_t val = bpf_semi_rand_get();
26662306a36Sopenharmony_ci		struct bpf_insn tmp[2] = { BPF_LD_IMM64(BPF_REG_1, val) };
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		res ^= val;
26962306a36Sopenharmony_ci		insn[i++] = tmp[0];
27062306a36Sopenharmony_ci		insn[i++] = tmp[1];
27162306a36Sopenharmony_ci		insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1);
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_0);
27462306a36Sopenharmony_ci	insn[i++] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 32);
27562306a36Sopenharmony_ci	insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1);
27662306a36Sopenharmony_ci	insn[i] = BPF_EXIT_INSN();
27762306a36Sopenharmony_ci	self->prog_len = i + 1;
27862306a36Sopenharmony_ci	res ^= (res >> 32);
27962306a36Sopenharmony_ci	self->retval = (uint32_t)res;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#define MAX_JMP_SEQ 8192
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* test the sequence of 8k jumps */
28562306a36Sopenharmony_cistatic void bpf_fill_scale1(struct bpf_test *self)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
28862306a36Sopenharmony_ci	int i = 0, k = 0;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
29162306a36Sopenharmony_ci	/* test to check that the long sequence of jumps is acceptable */
29262306a36Sopenharmony_ci	while (k++ < MAX_JMP_SEQ) {
29362306a36Sopenharmony_ci		insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
29462306a36Sopenharmony_ci					 BPF_FUNC_get_prandom_u32);
29562306a36Sopenharmony_ci		insn[i++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, bpf_semi_rand_get(), 2);
29662306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10);
29762306a36Sopenharmony_ci		insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
29862306a36Sopenharmony_ci					-8 * (k % 64 + 1));
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	/* is_state_visited() doesn't allocate state for pruning for every jump.
30162306a36Sopenharmony_ci	 * Hence multiply jmps by 4 to accommodate that heuristic
30262306a36Sopenharmony_ci	 */
30362306a36Sopenharmony_ci	while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4)
30462306a36Sopenharmony_ci		insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42);
30562306a36Sopenharmony_ci	insn[i] = BPF_EXIT_INSN();
30662306a36Sopenharmony_ci	self->prog_len = i + 1;
30762306a36Sopenharmony_ci	self->retval = 42;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci/* test the sequence of 8k jumps in inner most function (function depth 8)*/
31162306a36Sopenharmony_cistatic void bpf_fill_scale2(struct bpf_test *self)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
31462306a36Sopenharmony_ci	int i = 0, k = 0;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci#define FUNC_NEST 7
31762306a36Sopenharmony_ci	for (k = 0; k < FUNC_NEST; k++) {
31862306a36Sopenharmony_ci		insn[i++] = BPF_CALL_REL(1);
31962306a36Sopenharmony_ci		insn[i++] = BPF_EXIT_INSN();
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci	insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
32262306a36Sopenharmony_ci	/* test to check that the long sequence of jumps is acceptable */
32362306a36Sopenharmony_ci	k = 0;
32462306a36Sopenharmony_ci	while (k++ < MAX_JMP_SEQ) {
32562306a36Sopenharmony_ci		insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
32662306a36Sopenharmony_ci					 BPF_FUNC_get_prandom_u32);
32762306a36Sopenharmony_ci		insn[i++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, bpf_semi_rand_get(), 2);
32862306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10);
32962306a36Sopenharmony_ci		insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
33062306a36Sopenharmony_ci					-8 * (k % (64 - 4 * FUNC_NEST) + 1));
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4)
33362306a36Sopenharmony_ci		insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42);
33462306a36Sopenharmony_ci	insn[i] = BPF_EXIT_INSN();
33562306a36Sopenharmony_ci	self->prog_len = i + 1;
33662306a36Sopenharmony_ci	self->retval = 42;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void bpf_fill_scale(struct bpf_test *self)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	switch (self->retval) {
34262306a36Sopenharmony_ci	case 1:
34362306a36Sopenharmony_ci		return bpf_fill_scale1(self);
34462306a36Sopenharmony_ci	case 2:
34562306a36Sopenharmony_ci		return bpf_fill_scale2(self);
34662306a36Sopenharmony_ci	default:
34762306a36Sopenharmony_ci		self->prog_len = 0;
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int bpf_fill_torturous_jumps_insn_1(struct bpf_insn *insn)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	unsigned int len = 259, hlen = 128;
35562306a36Sopenharmony_ci	int i;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	insn[0] = BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32);
35862306a36Sopenharmony_ci	for (i = 1; i <= hlen; i++) {
35962306a36Sopenharmony_ci		insn[i]        = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, i, hlen);
36062306a36Sopenharmony_ci		insn[i + hlen] = BPF_JMP_A(hlen - i);
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci	insn[len - 2] = BPF_MOV64_IMM(BPF_REG_0, 1);
36362306a36Sopenharmony_ci	insn[len - 1] = BPF_EXIT_INSN();
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return len;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int bpf_fill_torturous_jumps_insn_2(struct bpf_insn *insn)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	unsigned int len = 4100, jmp_off = 2048;
37162306a36Sopenharmony_ci	int i, j;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	insn[0] = BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32);
37462306a36Sopenharmony_ci	for (i = 1; i <= jmp_off; i++) {
37562306a36Sopenharmony_ci		insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, i, jmp_off);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	insn[i++] = BPF_JMP_A(jmp_off);
37862306a36Sopenharmony_ci	for (; i <= jmp_off * 2 + 1; i+=16) {
37962306a36Sopenharmony_ci		for (j = 0; j < 16; j++) {
38062306a36Sopenharmony_ci			insn[i + j] = BPF_JMP_A(16 - j - 1);
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	insn[len - 2] = BPF_MOV64_IMM(BPF_REG_0, 2);
38562306a36Sopenharmony_ci	insn[len - 1] = BPF_EXIT_INSN();
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return len;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void bpf_fill_torturous_jumps(struct bpf_test *self)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
39362306a36Sopenharmony_ci	int i = 0;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	switch (self->retval) {
39662306a36Sopenharmony_ci	case 1:
39762306a36Sopenharmony_ci		self->prog_len = bpf_fill_torturous_jumps_insn_1(insn);
39862306a36Sopenharmony_ci		return;
39962306a36Sopenharmony_ci	case 2:
40062306a36Sopenharmony_ci		self->prog_len = bpf_fill_torturous_jumps_insn_2(insn);
40162306a36Sopenharmony_ci		return;
40262306a36Sopenharmony_ci	case 3:
40362306a36Sopenharmony_ci		/* main */
40462306a36Sopenharmony_ci		insn[i++] = BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 4);
40562306a36Sopenharmony_ci		insn[i++] = BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 262);
40662306a36Sopenharmony_ci		insn[i++] = BPF_ST_MEM(BPF_B, BPF_REG_10, -32, 0);
40762306a36Sopenharmony_ci		insn[i++] = BPF_MOV64_IMM(BPF_REG_0, 3);
40862306a36Sopenharmony_ci		insn[i++] = BPF_EXIT_INSN();
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		/* subprog 1 */
41162306a36Sopenharmony_ci		i += bpf_fill_torturous_jumps_insn_1(insn + i);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		/* subprog 2 */
41462306a36Sopenharmony_ci		i += bpf_fill_torturous_jumps_insn_2(insn + i);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		self->prog_len = i;
41762306a36Sopenharmony_ci		return;
41862306a36Sopenharmony_ci	default:
41962306a36Sopenharmony_ci		self->prog_len = 0;
42062306a36Sopenharmony_ci		break;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic void bpf_fill_big_prog_with_loop_1(struct bpf_test *self)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct bpf_insn *insn = self->fill_insns;
42762306a36Sopenharmony_ci	/* This test was added to catch a specific use after free
42862306a36Sopenharmony_ci	 * error, which happened upon BPF program reallocation.
42962306a36Sopenharmony_ci	 * Reallocation is handled by core.c:bpf_prog_realloc, which
43062306a36Sopenharmony_ci	 * reuses old memory if page boundary is not crossed. The
43162306a36Sopenharmony_ci	 * value of `len` is chosen to cross this boundary on bpf_loop
43262306a36Sopenharmony_ci	 * patching.
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci	const int len = getpagesize() - 25;
43562306a36Sopenharmony_ci	int callback_load_idx;
43662306a36Sopenharmony_ci	int callback_idx;
43762306a36Sopenharmony_ci	int i = 0;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1);
44062306a36Sopenharmony_ci	callback_load_idx = i;
44162306a36Sopenharmony_ci	insn[i++] = BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW,
44262306a36Sopenharmony_ci				 BPF_REG_2, BPF_PSEUDO_FUNC, 0,
44362306a36Sopenharmony_ci				 777 /* filled below */);
44462306a36Sopenharmony_ci	insn[i++] = BPF_RAW_INSN(0, 0, 0, 0, 0);
44562306a36Sopenharmony_ci	insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0);
44662306a36Sopenharmony_ci	insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0);
44762306a36Sopenharmony_ci	insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	while (i < len - 3)
45062306a36Sopenharmony_ci		insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0);
45162306a36Sopenharmony_ci	insn[i++] = BPF_EXIT_INSN();
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	callback_idx = i;
45462306a36Sopenharmony_ci	insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0);
45562306a36Sopenharmony_ci	insn[i++] = BPF_EXIT_INSN();
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	insn[callback_load_idx].imm = callback_idx - callback_load_idx - 1;
45862306a36Sopenharmony_ci	self->func_info[1].insn_off = callback_idx;
45962306a36Sopenharmony_ci	self->prog_len = i;
46062306a36Sopenharmony_ci	assert(i == len);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci/* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */
46462306a36Sopenharmony_ci#define BPF_SK_LOOKUP(func)						\
46562306a36Sopenharmony_ci	/* struct bpf_sock_tuple tuple = {} */				\
46662306a36Sopenharmony_ci	BPF_MOV64_IMM(BPF_REG_2, 0),					\
46762306a36Sopenharmony_ci	BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8),			\
46862306a36Sopenharmony_ci	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -16),		\
46962306a36Sopenharmony_ci	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -24),		\
47062306a36Sopenharmony_ci	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -32),		\
47162306a36Sopenharmony_ci	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -40),		\
47262306a36Sopenharmony_ci	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -48),		\
47362306a36Sopenharmony_ci	/* sk = func(ctx, &tuple, sizeof tuple, 0, 0) */		\
47462306a36Sopenharmony_ci	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),				\
47562306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48),				\
47662306a36Sopenharmony_ci	BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_sock_tuple)),	\
47762306a36Sopenharmony_ci	BPF_MOV64_IMM(BPF_REG_4, 0),					\
47862306a36Sopenharmony_ci	BPF_MOV64_IMM(BPF_REG_5, 0),					\
47962306a36Sopenharmony_ci	BPF_EMIT_CALL(BPF_FUNC_ ## func)
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci/* BPF_DIRECT_PKT_R2 contains 7 instructions, it initializes default return
48262306a36Sopenharmony_ci * value into 0 and does necessary preparation for direct packet access
48362306a36Sopenharmony_ci * through r2. The allowed access range is 8 bytes.
48462306a36Sopenharmony_ci */
48562306a36Sopenharmony_ci#define BPF_DIRECT_PKT_R2						\
48662306a36Sopenharmony_ci	BPF_MOV64_IMM(BPF_REG_0, 0),					\
48762306a36Sopenharmony_ci	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,			\
48862306a36Sopenharmony_ci		    offsetof(struct __sk_buff, data)),			\
48962306a36Sopenharmony_ci	BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,			\
49062306a36Sopenharmony_ci		    offsetof(struct __sk_buff, data_end)),		\
49162306a36Sopenharmony_ci	BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),				\
49262306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),				\
49362306a36Sopenharmony_ci	BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1),			\
49462306a36Sopenharmony_ci	BPF_EXIT_INSN()
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/* BPF_RAND_UEXT_R7 contains 4 instructions, it initializes R7 into a random
49762306a36Sopenharmony_ci * positive u32, and zero-extend it into 64-bit.
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_ci#define BPF_RAND_UEXT_R7						\
50062306a36Sopenharmony_ci	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,			\
50162306a36Sopenharmony_ci		     BPF_FUNC_get_prandom_u32),				\
50262306a36Sopenharmony_ci	BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),				\
50362306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 33),				\
50462306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 33)
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/* BPF_RAND_SEXT_R7 contains 5 instructions, it initializes R7 into a random
50762306a36Sopenharmony_ci * negative u32, and sign-extend it into 64-bit.
50862306a36Sopenharmony_ci */
50962306a36Sopenharmony_ci#define BPF_RAND_SEXT_R7						\
51062306a36Sopenharmony_ci	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,			\
51162306a36Sopenharmony_ci		     BPF_FUNC_get_prandom_u32),				\
51262306a36Sopenharmony_ci	BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),				\
51362306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_OR, BPF_REG_7, 0x80000000),			\
51462306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 32),				\
51562306a36Sopenharmony_ci	BPF_ALU64_IMM(BPF_ARSH, BPF_REG_7, 32)
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic struct bpf_test tests[] = {
51862306a36Sopenharmony_ci#define FILL_ARRAY
51962306a36Sopenharmony_ci#include <verifier/tests.h>
52062306a36Sopenharmony_ci#undef FILL_ARRAY
52162306a36Sopenharmony_ci};
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic int probe_filter_length(const struct bpf_insn *fp)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	int len;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	for (len = MAX_INSNS - 1; len > 0; --len)
52862306a36Sopenharmony_ci		if (fp[len].code != 0 || fp[len].imm != 0)
52962306a36Sopenharmony_ci			break;
53062306a36Sopenharmony_ci	return len + 1;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic bool skip_unsupported_map(enum bpf_map_type map_type)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	if (!libbpf_probe_bpf_map_type(map_type, NULL)) {
53662306a36Sopenharmony_ci		printf("SKIP (unsupported map type %d)\n", map_type);
53762306a36Sopenharmony_ci		skips++;
53862306a36Sopenharmony_ci		return true;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	return false;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int __create_map(uint32_t type, uint32_t size_key,
54462306a36Sopenharmony_ci			uint32_t size_value, uint32_t max_elem,
54562306a36Sopenharmony_ci			uint32_t extra_flags)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts);
54862306a36Sopenharmony_ci	int fd;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	opts.map_flags = (type == BPF_MAP_TYPE_HASH ? BPF_F_NO_PREALLOC : 0) | extra_flags;
55162306a36Sopenharmony_ci	fd = bpf_map_create(type, NULL, size_key, size_value, max_elem, &opts);
55262306a36Sopenharmony_ci	if (fd < 0) {
55362306a36Sopenharmony_ci		if (skip_unsupported_map(type))
55462306a36Sopenharmony_ci			return -1;
55562306a36Sopenharmony_ci		printf("Failed to create hash map '%s'!\n", strerror(errno));
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return fd;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int create_map(uint32_t type, uint32_t size_key,
56262306a36Sopenharmony_ci		      uint32_t size_value, uint32_t max_elem)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	return __create_map(type, size_key, size_value, max_elem, 0);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic void update_map(int fd, int index)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct test_val value = {
57062306a36Sopenharmony_ci		.index = (6 + 1) * sizeof(int),
57162306a36Sopenharmony_ci		.foo[6] = 0xabcdef12,
57262306a36Sopenharmony_ci	};
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	assert(!bpf_map_update_elem(fd, &index, &value, 0));
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int create_prog_dummy_simple(enum bpf_prog_type prog_type, int ret)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct bpf_insn prog[] = {
58062306a36Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, ret),
58162306a36Sopenharmony_ci		BPF_EXIT_INSN(),
58262306a36Sopenharmony_ci	};
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return bpf_prog_load(prog_type, NULL, "GPL", prog, ARRAY_SIZE(prog), NULL);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic int create_prog_dummy_loop(enum bpf_prog_type prog_type, int mfd,
58862306a36Sopenharmony_ci				  int idx, int ret)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct bpf_insn prog[] = {
59162306a36Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_3, idx),
59262306a36Sopenharmony_ci		BPF_LD_MAP_FD(BPF_REG_2, mfd),
59362306a36Sopenharmony_ci		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
59462306a36Sopenharmony_ci			     BPF_FUNC_tail_call),
59562306a36Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, ret),
59662306a36Sopenharmony_ci		BPF_EXIT_INSN(),
59762306a36Sopenharmony_ci	};
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return bpf_prog_load(prog_type, NULL, "GPL", prog, ARRAY_SIZE(prog), NULL);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic int create_prog_array(enum bpf_prog_type prog_type, uint32_t max_elem,
60362306a36Sopenharmony_ci			     int p1key, int p2key, int p3key)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	int mfd, p1fd, p2fd, p3fd;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	mfd = bpf_map_create(BPF_MAP_TYPE_PROG_ARRAY, NULL, sizeof(int),
60862306a36Sopenharmony_ci			     sizeof(int), max_elem, NULL);
60962306a36Sopenharmony_ci	if (mfd < 0) {
61062306a36Sopenharmony_ci		if (skip_unsupported_map(BPF_MAP_TYPE_PROG_ARRAY))
61162306a36Sopenharmony_ci			return -1;
61262306a36Sopenharmony_ci		printf("Failed to create prog array '%s'!\n", strerror(errno));
61362306a36Sopenharmony_ci		return -1;
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	p1fd = create_prog_dummy_simple(prog_type, 42);
61762306a36Sopenharmony_ci	p2fd = create_prog_dummy_loop(prog_type, mfd, p2key, 41);
61862306a36Sopenharmony_ci	p3fd = create_prog_dummy_simple(prog_type, 24);
61962306a36Sopenharmony_ci	if (p1fd < 0 || p2fd < 0 || p3fd < 0)
62062306a36Sopenharmony_ci		goto err;
62162306a36Sopenharmony_ci	if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0)
62262306a36Sopenharmony_ci		goto err;
62362306a36Sopenharmony_ci	if (bpf_map_update_elem(mfd, &p2key, &p2fd, BPF_ANY) < 0)
62462306a36Sopenharmony_ci		goto err;
62562306a36Sopenharmony_ci	if (bpf_map_update_elem(mfd, &p3key, &p3fd, BPF_ANY) < 0) {
62662306a36Sopenharmony_cierr:
62762306a36Sopenharmony_ci		close(mfd);
62862306a36Sopenharmony_ci		mfd = -1;
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci	close(p3fd);
63162306a36Sopenharmony_ci	close(p2fd);
63262306a36Sopenharmony_ci	close(p1fd);
63362306a36Sopenharmony_ci	return mfd;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int create_map_in_map(void)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts);
63962306a36Sopenharmony_ci	int inner_map_fd, outer_map_fd;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	inner_map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(int),
64262306a36Sopenharmony_ci				      sizeof(int), 1, NULL);
64362306a36Sopenharmony_ci	if (inner_map_fd < 0) {
64462306a36Sopenharmony_ci		if (skip_unsupported_map(BPF_MAP_TYPE_ARRAY))
64562306a36Sopenharmony_ci			return -1;
64662306a36Sopenharmony_ci		printf("Failed to create array '%s'!\n", strerror(errno));
64762306a36Sopenharmony_ci		return inner_map_fd;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	opts.inner_map_fd = inner_map_fd;
65162306a36Sopenharmony_ci	outer_map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL,
65262306a36Sopenharmony_ci				      sizeof(int), sizeof(int), 1, &opts);
65362306a36Sopenharmony_ci	if (outer_map_fd < 0) {
65462306a36Sopenharmony_ci		if (skip_unsupported_map(BPF_MAP_TYPE_ARRAY_OF_MAPS))
65562306a36Sopenharmony_ci			return -1;
65662306a36Sopenharmony_ci		printf("Failed to create array of maps '%s'!\n",
65762306a36Sopenharmony_ci		       strerror(errno));
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	close(inner_map_fd);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	return outer_map_fd;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic int create_cgroup_storage(bool percpu)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	enum bpf_map_type type = percpu ? BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE :
66862306a36Sopenharmony_ci		BPF_MAP_TYPE_CGROUP_STORAGE;
66962306a36Sopenharmony_ci	int fd;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	fd = bpf_map_create(type, NULL, sizeof(struct bpf_cgroup_storage_key),
67262306a36Sopenharmony_ci			    TEST_DATA_LEN, 0, NULL);
67362306a36Sopenharmony_ci	if (fd < 0) {
67462306a36Sopenharmony_ci		if (skip_unsupported_map(type))
67562306a36Sopenharmony_ci			return -1;
67662306a36Sopenharmony_ci		printf("Failed to create cgroup storage '%s'!\n",
67762306a36Sopenharmony_ci		       strerror(errno));
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	return fd;
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci/* struct bpf_spin_lock {
68462306a36Sopenharmony_ci *   int val;
68562306a36Sopenharmony_ci * };
68662306a36Sopenharmony_ci * struct val {
68762306a36Sopenharmony_ci *   int cnt;
68862306a36Sopenharmony_ci *   struct bpf_spin_lock l;
68962306a36Sopenharmony_ci * };
69062306a36Sopenharmony_ci * struct bpf_timer {
69162306a36Sopenharmony_ci *   __u64 :64;
69262306a36Sopenharmony_ci *   __u64 :64;
69362306a36Sopenharmony_ci * } __attribute__((aligned(8)));
69462306a36Sopenharmony_ci * struct timer {
69562306a36Sopenharmony_ci *   struct bpf_timer t;
69662306a36Sopenharmony_ci * };
69762306a36Sopenharmony_ci * struct btf_ptr {
69862306a36Sopenharmony_ci *   struct prog_test_ref_kfunc __kptr_untrusted *ptr;
69962306a36Sopenharmony_ci *   struct prog_test_ref_kfunc __kptr *ptr;
70062306a36Sopenharmony_ci *   struct prog_test_member __kptr *ptr;
70162306a36Sopenharmony_ci * }
70262306a36Sopenharmony_ci */
70362306a36Sopenharmony_cistatic const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l\0bpf_timer\0timer\0t"
70462306a36Sopenharmony_ci				  "\0btf_ptr\0prog_test_ref_kfunc\0ptr\0kptr\0kptr_untrusted"
70562306a36Sopenharmony_ci				  "\0prog_test_member";
70662306a36Sopenharmony_cistatic __u32 btf_raw_types[] = {
70762306a36Sopenharmony_ci	/* int */
70862306a36Sopenharmony_ci	BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
70962306a36Sopenharmony_ci	/* struct bpf_spin_lock */                      /* [2] */
71062306a36Sopenharmony_ci	BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4),
71162306a36Sopenharmony_ci	BTF_MEMBER_ENC(15, 1, 0), /* int val; */
71262306a36Sopenharmony_ci	/* struct val */                                /* [3] */
71362306a36Sopenharmony_ci	BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
71462306a36Sopenharmony_ci	BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
71562306a36Sopenharmony_ci	BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
71662306a36Sopenharmony_ci	/* struct bpf_timer */                          /* [4] */
71762306a36Sopenharmony_ci	BTF_TYPE_ENC(25, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 0), 16),
71862306a36Sopenharmony_ci	/* struct timer */                              /* [5] */
71962306a36Sopenharmony_ci	BTF_TYPE_ENC(35, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 16),
72062306a36Sopenharmony_ci	BTF_MEMBER_ENC(41, 4, 0), /* struct bpf_timer t; */
72162306a36Sopenharmony_ci	/* struct prog_test_ref_kfunc */		/* [6] */
72262306a36Sopenharmony_ci	BTF_STRUCT_ENC(51, 0, 0),
72362306a36Sopenharmony_ci	BTF_STRUCT_ENC(95, 0, 0),			/* [7] */
72462306a36Sopenharmony_ci	/* type tag "kptr_untrusted" */
72562306a36Sopenharmony_ci	BTF_TYPE_TAG_ENC(80, 6),			/* [8] */
72662306a36Sopenharmony_ci	/* type tag "kptr" */
72762306a36Sopenharmony_ci	BTF_TYPE_TAG_ENC(75, 6),			/* [9] */
72862306a36Sopenharmony_ci	BTF_TYPE_TAG_ENC(75, 7),			/* [10] */
72962306a36Sopenharmony_ci	BTF_PTR_ENC(8),					/* [11] */
73062306a36Sopenharmony_ci	BTF_PTR_ENC(9),					/* [12] */
73162306a36Sopenharmony_ci	BTF_PTR_ENC(10),				/* [13] */
73262306a36Sopenharmony_ci	/* struct btf_ptr */				/* [14] */
73362306a36Sopenharmony_ci	BTF_STRUCT_ENC(43, 3, 24),
73462306a36Sopenharmony_ci	BTF_MEMBER_ENC(71, 11, 0), /* struct prog_test_ref_kfunc __kptr_untrusted *ptr; */
73562306a36Sopenharmony_ci	BTF_MEMBER_ENC(71, 12, 64), /* struct prog_test_ref_kfunc __kptr *ptr; */
73662306a36Sopenharmony_ci	BTF_MEMBER_ENC(71, 13, 128), /* struct prog_test_member __kptr *ptr; */
73762306a36Sopenharmony_ci};
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic char bpf_vlog[UINT_MAX >> 8];
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic int load_btf_spec(__u32 *types, int types_len,
74262306a36Sopenharmony_ci			 const char *strings, int strings_len)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct btf_header hdr = {
74562306a36Sopenharmony_ci		.magic = BTF_MAGIC,
74662306a36Sopenharmony_ci		.version = BTF_VERSION,
74762306a36Sopenharmony_ci		.hdr_len = sizeof(struct btf_header),
74862306a36Sopenharmony_ci		.type_len = types_len,
74962306a36Sopenharmony_ci		.str_off = types_len,
75062306a36Sopenharmony_ci		.str_len = strings_len,
75162306a36Sopenharmony_ci	};
75262306a36Sopenharmony_ci	void *ptr, *raw_btf;
75362306a36Sopenharmony_ci	int btf_fd;
75462306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_btf_load_opts, opts,
75562306a36Sopenharmony_ci		    .log_buf = bpf_vlog,
75662306a36Sopenharmony_ci		    .log_size = sizeof(bpf_vlog),
75762306a36Sopenharmony_ci		    .log_level = (verbose
75862306a36Sopenharmony_ci				  ? verif_log_level
75962306a36Sopenharmony_ci				  : DEFAULT_LIBBPF_LOG_LEVEL),
76062306a36Sopenharmony_ci	);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	raw_btf = malloc(sizeof(hdr) + types_len + strings_len);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	ptr = raw_btf;
76562306a36Sopenharmony_ci	memcpy(ptr, &hdr, sizeof(hdr));
76662306a36Sopenharmony_ci	ptr += sizeof(hdr);
76762306a36Sopenharmony_ci	memcpy(ptr, types, hdr.type_len);
76862306a36Sopenharmony_ci	ptr += hdr.type_len;
76962306a36Sopenharmony_ci	memcpy(ptr, strings, hdr.str_len);
77062306a36Sopenharmony_ci	ptr += hdr.str_len;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	btf_fd = bpf_btf_load(raw_btf, ptr - raw_btf, &opts);
77362306a36Sopenharmony_ci	if (btf_fd < 0)
77462306a36Sopenharmony_ci		printf("Failed to load BTF spec: '%s'\n", strerror(errno));
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	free(raw_btf);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return btf_fd < 0 ? -1 : btf_fd;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int load_btf(void)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	return load_btf_spec(btf_raw_types, sizeof(btf_raw_types),
78462306a36Sopenharmony_ci			     btf_str_sec, sizeof(btf_str_sec));
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int load_btf_for_test(struct bpf_test *test)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	int types_num = 0;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	while (types_num < MAX_BTF_TYPES &&
79262306a36Sopenharmony_ci	       test->btf_types[types_num] != BTF_END_RAW)
79362306a36Sopenharmony_ci		++types_num;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	int types_len = types_num * sizeof(test->btf_types[0]);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return load_btf_spec(test->btf_types, types_len,
79862306a36Sopenharmony_ci			     test->btf_strings, sizeof(test->btf_strings));
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic int create_map_spin_lock(void)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts,
80462306a36Sopenharmony_ci		.btf_key_type_id = 1,
80562306a36Sopenharmony_ci		.btf_value_type_id = 3,
80662306a36Sopenharmony_ci	);
80762306a36Sopenharmony_ci	int fd, btf_fd;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	btf_fd = load_btf();
81062306a36Sopenharmony_ci	if (btf_fd < 0)
81162306a36Sopenharmony_ci		return -1;
81262306a36Sopenharmony_ci	opts.btf_fd = btf_fd;
81362306a36Sopenharmony_ci	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "test_map", 4, 8, 1, &opts);
81462306a36Sopenharmony_ci	if (fd < 0)
81562306a36Sopenharmony_ci		printf("Failed to create map with spin_lock\n");
81662306a36Sopenharmony_ci	return fd;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int create_sk_storage_map(void)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts,
82262306a36Sopenharmony_ci		.map_flags = BPF_F_NO_PREALLOC,
82362306a36Sopenharmony_ci		.btf_key_type_id = 1,
82462306a36Sopenharmony_ci		.btf_value_type_id = 3,
82562306a36Sopenharmony_ci	);
82662306a36Sopenharmony_ci	int fd, btf_fd;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	btf_fd = load_btf();
82962306a36Sopenharmony_ci	if (btf_fd < 0)
83062306a36Sopenharmony_ci		return -1;
83162306a36Sopenharmony_ci	opts.btf_fd = btf_fd;
83262306a36Sopenharmony_ci	fd = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "test_map", 4, 8, 0, &opts);
83362306a36Sopenharmony_ci	close(opts.btf_fd);
83462306a36Sopenharmony_ci	if (fd < 0)
83562306a36Sopenharmony_ci		printf("Failed to create sk_storage_map\n");
83662306a36Sopenharmony_ci	return fd;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int create_map_timer(void)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts,
84262306a36Sopenharmony_ci		.btf_key_type_id = 1,
84362306a36Sopenharmony_ci		.btf_value_type_id = 5,
84462306a36Sopenharmony_ci	);
84562306a36Sopenharmony_ci	int fd, btf_fd;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	btf_fd = load_btf();
84862306a36Sopenharmony_ci	if (btf_fd < 0)
84962306a36Sopenharmony_ci		return -1;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	opts.btf_fd = btf_fd;
85262306a36Sopenharmony_ci	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "test_map", 4, 16, 1, &opts);
85362306a36Sopenharmony_ci	if (fd < 0)
85462306a36Sopenharmony_ci		printf("Failed to create map with timer\n");
85562306a36Sopenharmony_ci	return fd;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int create_map_kptr(void)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts,
86162306a36Sopenharmony_ci		.btf_key_type_id = 1,
86262306a36Sopenharmony_ci		.btf_value_type_id = 14,
86362306a36Sopenharmony_ci	);
86462306a36Sopenharmony_ci	int fd, btf_fd;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	btf_fd = load_btf();
86762306a36Sopenharmony_ci	if (btf_fd < 0)
86862306a36Sopenharmony_ci		return -1;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	opts.btf_fd = btf_fd;
87162306a36Sopenharmony_ci	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "test_map", 4, 24, 1, &opts);
87262306a36Sopenharmony_ci	if (fd < 0)
87362306a36Sopenharmony_ci		printf("Failed to create map with btf_id pointer\n");
87462306a36Sopenharmony_ci	return fd;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic void set_root(bool set)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	__u64 caps;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if (set) {
88262306a36Sopenharmony_ci		if (cap_enable_effective(1ULL << CAP_SYS_ADMIN, &caps))
88362306a36Sopenharmony_ci			perror("cap_disable_effective(CAP_SYS_ADMIN)");
88462306a36Sopenharmony_ci	} else {
88562306a36Sopenharmony_ci		if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps))
88662306a36Sopenharmony_ci			perror("cap_disable_effective(CAP_SYS_ADMIN)");
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic __u64 ptr_to_u64(const void *ptr)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	return (uintptr_t) ptr;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic struct btf *btf__load_testmod_btf(struct btf *vmlinux)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct bpf_btf_info info;
89862306a36Sopenharmony_ci	__u32 len = sizeof(info);
89962306a36Sopenharmony_ci	struct btf *btf = NULL;
90062306a36Sopenharmony_ci	char name[64];
90162306a36Sopenharmony_ci	__u32 id = 0;
90262306a36Sopenharmony_ci	int err, fd;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* Iterate all loaded BTF objects and find bpf_testmod,
90562306a36Sopenharmony_ci	 * we need SYS_ADMIN cap for that.
90662306a36Sopenharmony_ci	 */
90762306a36Sopenharmony_ci	set_root(true);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	while (true) {
91062306a36Sopenharmony_ci		err = bpf_btf_get_next_id(id, &id);
91162306a36Sopenharmony_ci		if (err) {
91262306a36Sopenharmony_ci			if (errno == ENOENT)
91362306a36Sopenharmony_ci				break;
91462306a36Sopenharmony_ci			perror("bpf_btf_get_next_id failed");
91562306a36Sopenharmony_ci			break;
91662306a36Sopenharmony_ci		}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci		fd = bpf_btf_get_fd_by_id(id);
91962306a36Sopenharmony_ci		if (fd < 0) {
92062306a36Sopenharmony_ci			if (errno == ENOENT)
92162306a36Sopenharmony_ci				continue;
92262306a36Sopenharmony_ci			perror("bpf_btf_get_fd_by_id failed");
92362306a36Sopenharmony_ci			break;
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		memset(&info, 0, sizeof(info));
92762306a36Sopenharmony_ci		info.name_len = sizeof(name);
92862306a36Sopenharmony_ci		info.name = ptr_to_u64(name);
92962306a36Sopenharmony_ci		len = sizeof(info);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		err = bpf_obj_get_info_by_fd(fd, &info, &len);
93262306a36Sopenharmony_ci		if (err) {
93362306a36Sopenharmony_ci			close(fd);
93462306a36Sopenharmony_ci			perror("bpf_obj_get_info_by_fd failed");
93562306a36Sopenharmony_ci			break;
93662306a36Sopenharmony_ci		}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		if (strcmp("bpf_testmod", name)) {
93962306a36Sopenharmony_ci			close(fd);
94062306a36Sopenharmony_ci			continue;
94162306a36Sopenharmony_ci		}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		btf = btf__load_from_kernel_by_id_split(id, vmlinux);
94462306a36Sopenharmony_ci		if (!btf) {
94562306a36Sopenharmony_ci			close(fd);
94662306a36Sopenharmony_ci			break;
94762306a36Sopenharmony_ci		}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		/* We need the fd to stay open so it can be used in fd_array.
95062306a36Sopenharmony_ci		 * The final cleanup call to btf__free will free btf object
95162306a36Sopenharmony_ci		 * and close the file descriptor.
95262306a36Sopenharmony_ci		 */
95362306a36Sopenharmony_ci		btf__set_fd(btf, fd);
95462306a36Sopenharmony_ci		break;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	set_root(false);
95862306a36Sopenharmony_ci	return btf;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic struct btf *testmod_btf;
96262306a36Sopenharmony_cistatic struct btf *vmlinux_btf;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic void kfuncs_cleanup(void)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	btf__free(testmod_btf);
96762306a36Sopenharmony_ci	btf__free(vmlinux_btf);
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic void fixup_prog_kfuncs(struct bpf_insn *prog, int *fd_array,
97162306a36Sopenharmony_ci			      struct kfunc_btf_id_pair *fixup_kfunc_btf_id)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	/* Patch in kfunc BTF IDs */
97462306a36Sopenharmony_ci	while (fixup_kfunc_btf_id->kfunc) {
97562306a36Sopenharmony_ci		int btf_id = 0;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		/* try to find kfunc in kernel BTF */
97862306a36Sopenharmony_ci		vmlinux_btf = vmlinux_btf ?: btf__load_vmlinux_btf();
97962306a36Sopenharmony_ci		if (vmlinux_btf) {
98062306a36Sopenharmony_ci			btf_id = btf__find_by_name_kind(vmlinux_btf,
98162306a36Sopenharmony_ci							fixup_kfunc_btf_id->kfunc,
98262306a36Sopenharmony_ci							BTF_KIND_FUNC);
98362306a36Sopenharmony_ci			btf_id = btf_id < 0 ? 0 : btf_id;
98462306a36Sopenharmony_ci		}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci		/* kfunc not found in kernel BTF, try bpf_testmod BTF */
98762306a36Sopenharmony_ci		if (!btf_id) {
98862306a36Sopenharmony_ci			testmod_btf = testmod_btf ?: btf__load_testmod_btf(vmlinux_btf);
98962306a36Sopenharmony_ci			if (testmod_btf) {
99062306a36Sopenharmony_ci				btf_id = btf__find_by_name_kind(testmod_btf,
99162306a36Sopenharmony_ci								fixup_kfunc_btf_id->kfunc,
99262306a36Sopenharmony_ci								BTF_KIND_FUNC);
99362306a36Sopenharmony_ci				btf_id = btf_id < 0 ? 0 : btf_id;
99462306a36Sopenharmony_ci				if (btf_id) {
99562306a36Sopenharmony_ci					/* We put bpf_testmod module fd into fd_array
99662306a36Sopenharmony_ci					 * and its index 1 into instruction 'off'.
99762306a36Sopenharmony_ci					 */
99862306a36Sopenharmony_ci					*fd_array = btf__fd(testmod_btf);
99962306a36Sopenharmony_ci					prog[fixup_kfunc_btf_id->insn_idx].off = 1;
100062306a36Sopenharmony_ci				}
100162306a36Sopenharmony_ci			}
100262306a36Sopenharmony_ci		}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id;
100562306a36Sopenharmony_ci		fixup_kfunc_btf_id++;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
101062306a36Sopenharmony_ci			  struct bpf_insn *prog, int *map_fds, int *fd_array)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	int *fixup_map_hash_8b = test->fixup_map_hash_8b;
101362306a36Sopenharmony_ci	int *fixup_map_hash_48b = test->fixup_map_hash_48b;
101462306a36Sopenharmony_ci	int *fixup_map_hash_16b = test->fixup_map_hash_16b;
101562306a36Sopenharmony_ci	int *fixup_map_array_48b = test->fixup_map_array_48b;
101662306a36Sopenharmony_ci	int *fixup_map_sockmap = test->fixup_map_sockmap;
101762306a36Sopenharmony_ci	int *fixup_map_sockhash = test->fixup_map_sockhash;
101862306a36Sopenharmony_ci	int *fixup_map_xskmap = test->fixup_map_xskmap;
101962306a36Sopenharmony_ci	int *fixup_map_stacktrace = test->fixup_map_stacktrace;
102062306a36Sopenharmony_ci	int *fixup_prog1 = test->fixup_prog1;
102162306a36Sopenharmony_ci	int *fixup_prog2 = test->fixup_prog2;
102262306a36Sopenharmony_ci	int *fixup_map_in_map = test->fixup_map_in_map;
102362306a36Sopenharmony_ci	int *fixup_cgroup_storage = test->fixup_cgroup_storage;
102462306a36Sopenharmony_ci	int *fixup_percpu_cgroup_storage = test->fixup_percpu_cgroup_storage;
102562306a36Sopenharmony_ci	int *fixup_map_spin_lock = test->fixup_map_spin_lock;
102662306a36Sopenharmony_ci	int *fixup_map_array_ro = test->fixup_map_array_ro;
102762306a36Sopenharmony_ci	int *fixup_map_array_wo = test->fixup_map_array_wo;
102862306a36Sopenharmony_ci	int *fixup_map_array_small = test->fixup_map_array_small;
102962306a36Sopenharmony_ci	int *fixup_sk_storage_map = test->fixup_sk_storage_map;
103062306a36Sopenharmony_ci	int *fixup_map_event_output = test->fixup_map_event_output;
103162306a36Sopenharmony_ci	int *fixup_map_reuseport_array = test->fixup_map_reuseport_array;
103262306a36Sopenharmony_ci	int *fixup_map_ringbuf = test->fixup_map_ringbuf;
103362306a36Sopenharmony_ci	int *fixup_map_timer = test->fixup_map_timer;
103462306a36Sopenharmony_ci	int *fixup_map_kptr = test->fixup_map_kptr;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	if (test->fill_helper) {
103762306a36Sopenharmony_ci		test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn));
103862306a36Sopenharmony_ci		test->fill_helper(test);
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/* Allocating HTs with 1 elem is fine here, since we only test
104262306a36Sopenharmony_ci	 * for verifier and not do a runtime lookup, so the only thing
104362306a36Sopenharmony_ci	 * that really matters is value size in this case.
104462306a36Sopenharmony_ci	 */
104562306a36Sopenharmony_ci	if (*fixup_map_hash_8b) {
104662306a36Sopenharmony_ci		map_fds[0] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long),
104762306a36Sopenharmony_ci					sizeof(long long), 1);
104862306a36Sopenharmony_ci		do {
104962306a36Sopenharmony_ci			prog[*fixup_map_hash_8b].imm = map_fds[0];
105062306a36Sopenharmony_ci			fixup_map_hash_8b++;
105162306a36Sopenharmony_ci		} while (*fixup_map_hash_8b);
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (*fixup_map_hash_48b) {
105562306a36Sopenharmony_ci		map_fds[1] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long),
105662306a36Sopenharmony_ci					sizeof(struct test_val), 1);
105762306a36Sopenharmony_ci		do {
105862306a36Sopenharmony_ci			prog[*fixup_map_hash_48b].imm = map_fds[1];
105962306a36Sopenharmony_ci			fixup_map_hash_48b++;
106062306a36Sopenharmony_ci		} while (*fixup_map_hash_48b);
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (*fixup_map_hash_16b) {
106462306a36Sopenharmony_ci		map_fds[2] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long),
106562306a36Sopenharmony_ci					sizeof(struct other_val), 1);
106662306a36Sopenharmony_ci		do {
106762306a36Sopenharmony_ci			prog[*fixup_map_hash_16b].imm = map_fds[2];
106862306a36Sopenharmony_ci			fixup_map_hash_16b++;
106962306a36Sopenharmony_ci		} while (*fixup_map_hash_16b);
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	if (*fixup_map_array_48b) {
107362306a36Sopenharmony_ci		map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
107462306a36Sopenharmony_ci					sizeof(struct test_val), 1);
107562306a36Sopenharmony_ci		update_map(map_fds[3], 0);
107662306a36Sopenharmony_ci		do {
107762306a36Sopenharmony_ci			prog[*fixup_map_array_48b].imm = map_fds[3];
107862306a36Sopenharmony_ci			fixup_map_array_48b++;
107962306a36Sopenharmony_ci		} while (*fixup_map_array_48b);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (*fixup_prog1) {
108362306a36Sopenharmony_ci		map_fds[4] = create_prog_array(prog_type, 4, 0, 1, 2);
108462306a36Sopenharmony_ci		do {
108562306a36Sopenharmony_ci			prog[*fixup_prog1].imm = map_fds[4];
108662306a36Sopenharmony_ci			fixup_prog1++;
108762306a36Sopenharmony_ci		} while (*fixup_prog1);
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (*fixup_prog2) {
109162306a36Sopenharmony_ci		map_fds[5] = create_prog_array(prog_type, 8, 7, 1, 2);
109262306a36Sopenharmony_ci		do {
109362306a36Sopenharmony_ci			prog[*fixup_prog2].imm = map_fds[5];
109462306a36Sopenharmony_ci			fixup_prog2++;
109562306a36Sopenharmony_ci		} while (*fixup_prog2);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (*fixup_map_in_map) {
109962306a36Sopenharmony_ci		map_fds[6] = create_map_in_map();
110062306a36Sopenharmony_ci		do {
110162306a36Sopenharmony_ci			prog[*fixup_map_in_map].imm = map_fds[6];
110262306a36Sopenharmony_ci			fixup_map_in_map++;
110362306a36Sopenharmony_ci		} while (*fixup_map_in_map);
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (*fixup_cgroup_storage) {
110762306a36Sopenharmony_ci		map_fds[7] = create_cgroup_storage(false);
110862306a36Sopenharmony_ci		do {
110962306a36Sopenharmony_ci			prog[*fixup_cgroup_storage].imm = map_fds[7];
111062306a36Sopenharmony_ci			fixup_cgroup_storage++;
111162306a36Sopenharmony_ci		} while (*fixup_cgroup_storage);
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (*fixup_percpu_cgroup_storage) {
111562306a36Sopenharmony_ci		map_fds[8] = create_cgroup_storage(true);
111662306a36Sopenharmony_ci		do {
111762306a36Sopenharmony_ci			prog[*fixup_percpu_cgroup_storage].imm = map_fds[8];
111862306a36Sopenharmony_ci			fixup_percpu_cgroup_storage++;
111962306a36Sopenharmony_ci		} while (*fixup_percpu_cgroup_storage);
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci	if (*fixup_map_sockmap) {
112262306a36Sopenharmony_ci		map_fds[9] = create_map(BPF_MAP_TYPE_SOCKMAP, sizeof(int),
112362306a36Sopenharmony_ci					sizeof(int), 1);
112462306a36Sopenharmony_ci		do {
112562306a36Sopenharmony_ci			prog[*fixup_map_sockmap].imm = map_fds[9];
112662306a36Sopenharmony_ci			fixup_map_sockmap++;
112762306a36Sopenharmony_ci		} while (*fixup_map_sockmap);
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci	if (*fixup_map_sockhash) {
113062306a36Sopenharmony_ci		map_fds[10] = create_map(BPF_MAP_TYPE_SOCKHASH, sizeof(int),
113162306a36Sopenharmony_ci					sizeof(int), 1);
113262306a36Sopenharmony_ci		do {
113362306a36Sopenharmony_ci			prog[*fixup_map_sockhash].imm = map_fds[10];
113462306a36Sopenharmony_ci			fixup_map_sockhash++;
113562306a36Sopenharmony_ci		} while (*fixup_map_sockhash);
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci	if (*fixup_map_xskmap) {
113862306a36Sopenharmony_ci		map_fds[11] = create_map(BPF_MAP_TYPE_XSKMAP, sizeof(int),
113962306a36Sopenharmony_ci					sizeof(int), 1);
114062306a36Sopenharmony_ci		do {
114162306a36Sopenharmony_ci			prog[*fixup_map_xskmap].imm = map_fds[11];
114262306a36Sopenharmony_ci			fixup_map_xskmap++;
114362306a36Sopenharmony_ci		} while (*fixup_map_xskmap);
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci	if (*fixup_map_stacktrace) {
114662306a36Sopenharmony_ci		map_fds[12] = create_map(BPF_MAP_TYPE_STACK_TRACE, sizeof(u32),
114762306a36Sopenharmony_ci					 sizeof(u64), 1);
114862306a36Sopenharmony_ci		do {
114962306a36Sopenharmony_ci			prog[*fixup_map_stacktrace].imm = map_fds[12];
115062306a36Sopenharmony_ci			fixup_map_stacktrace++;
115162306a36Sopenharmony_ci		} while (*fixup_map_stacktrace);
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci	if (*fixup_map_spin_lock) {
115462306a36Sopenharmony_ci		map_fds[13] = create_map_spin_lock();
115562306a36Sopenharmony_ci		do {
115662306a36Sopenharmony_ci			prog[*fixup_map_spin_lock].imm = map_fds[13];
115762306a36Sopenharmony_ci			fixup_map_spin_lock++;
115862306a36Sopenharmony_ci		} while (*fixup_map_spin_lock);
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci	if (*fixup_map_array_ro) {
116162306a36Sopenharmony_ci		map_fds[14] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
116262306a36Sopenharmony_ci					   sizeof(struct test_val), 1,
116362306a36Sopenharmony_ci					   BPF_F_RDONLY_PROG);
116462306a36Sopenharmony_ci		update_map(map_fds[14], 0);
116562306a36Sopenharmony_ci		do {
116662306a36Sopenharmony_ci			prog[*fixup_map_array_ro].imm = map_fds[14];
116762306a36Sopenharmony_ci			fixup_map_array_ro++;
116862306a36Sopenharmony_ci		} while (*fixup_map_array_ro);
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci	if (*fixup_map_array_wo) {
117162306a36Sopenharmony_ci		map_fds[15] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
117262306a36Sopenharmony_ci					   sizeof(struct test_val), 1,
117362306a36Sopenharmony_ci					   BPF_F_WRONLY_PROG);
117462306a36Sopenharmony_ci		update_map(map_fds[15], 0);
117562306a36Sopenharmony_ci		do {
117662306a36Sopenharmony_ci			prog[*fixup_map_array_wo].imm = map_fds[15];
117762306a36Sopenharmony_ci			fixup_map_array_wo++;
117862306a36Sopenharmony_ci		} while (*fixup_map_array_wo);
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci	if (*fixup_map_array_small) {
118162306a36Sopenharmony_ci		map_fds[16] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
118262306a36Sopenharmony_ci					   1, 1, 0);
118362306a36Sopenharmony_ci		update_map(map_fds[16], 0);
118462306a36Sopenharmony_ci		do {
118562306a36Sopenharmony_ci			prog[*fixup_map_array_small].imm = map_fds[16];
118662306a36Sopenharmony_ci			fixup_map_array_small++;
118762306a36Sopenharmony_ci		} while (*fixup_map_array_small);
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci	if (*fixup_sk_storage_map) {
119062306a36Sopenharmony_ci		map_fds[17] = create_sk_storage_map();
119162306a36Sopenharmony_ci		do {
119262306a36Sopenharmony_ci			prog[*fixup_sk_storage_map].imm = map_fds[17];
119362306a36Sopenharmony_ci			fixup_sk_storage_map++;
119462306a36Sopenharmony_ci		} while (*fixup_sk_storage_map);
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci	if (*fixup_map_event_output) {
119762306a36Sopenharmony_ci		map_fds[18] = __create_map(BPF_MAP_TYPE_PERF_EVENT_ARRAY,
119862306a36Sopenharmony_ci					   sizeof(int), sizeof(int), 1, 0);
119962306a36Sopenharmony_ci		do {
120062306a36Sopenharmony_ci			prog[*fixup_map_event_output].imm = map_fds[18];
120162306a36Sopenharmony_ci			fixup_map_event_output++;
120262306a36Sopenharmony_ci		} while (*fixup_map_event_output);
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci	if (*fixup_map_reuseport_array) {
120562306a36Sopenharmony_ci		map_fds[19] = __create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
120662306a36Sopenharmony_ci					   sizeof(u32), sizeof(u64), 1, 0);
120762306a36Sopenharmony_ci		do {
120862306a36Sopenharmony_ci			prog[*fixup_map_reuseport_array].imm = map_fds[19];
120962306a36Sopenharmony_ci			fixup_map_reuseport_array++;
121062306a36Sopenharmony_ci		} while (*fixup_map_reuseport_array);
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci	if (*fixup_map_ringbuf) {
121362306a36Sopenharmony_ci		map_fds[20] = create_map(BPF_MAP_TYPE_RINGBUF, 0,
121462306a36Sopenharmony_ci					 0, getpagesize());
121562306a36Sopenharmony_ci		do {
121662306a36Sopenharmony_ci			prog[*fixup_map_ringbuf].imm = map_fds[20];
121762306a36Sopenharmony_ci			fixup_map_ringbuf++;
121862306a36Sopenharmony_ci		} while (*fixup_map_ringbuf);
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci	if (*fixup_map_timer) {
122162306a36Sopenharmony_ci		map_fds[21] = create_map_timer();
122262306a36Sopenharmony_ci		do {
122362306a36Sopenharmony_ci			prog[*fixup_map_timer].imm = map_fds[21];
122462306a36Sopenharmony_ci			fixup_map_timer++;
122562306a36Sopenharmony_ci		} while (*fixup_map_timer);
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci	if (*fixup_map_kptr) {
122862306a36Sopenharmony_ci		map_fds[22] = create_map_kptr();
122962306a36Sopenharmony_ci		do {
123062306a36Sopenharmony_ci			prog[*fixup_map_kptr].imm = map_fds[22];
123162306a36Sopenharmony_ci			fixup_map_kptr++;
123262306a36Sopenharmony_ci		} while (*fixup_map_kptr);
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	fixup_prog_kfuncs(prog, fd_array, test->fixup_kfunc_btf_id);
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistruct libcap {
123962306a36Sopenharmony_ci	struct __user_cap_header_struct hdr;
124062306a36Sopenharmony_ci	struct __user_cap_data_struct data[2];
124162306a36Sopenharmony_ci};
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic int set_admin(bool admin)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	int err;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	if (admin) {
124862306a36Sopenharmony_ci		err = cap_enable_effective(ADMIN_CAPS, NULL);
124962306a36Sopenharmony_ci		if (err)
125062306a36Sopenharmony_ci			perror("cap_enable_effective(ADMIN_CAPS)");
125162306a36Sopenharmony_ci	} else {
125262306a36Sopenharmony_ci		err = cap_disable_effective(ADMIN_CAPS, NULL);
125362306a36Sopenharmony_ci		if (err)
125462306a36Sopenharmony_ci			perror("cap_disable_effective(ADMIN_CAPS)");
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	return err;
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
126162306a36Sopenharmony_ci			    void *data, size_t size_data)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	__u8 tmp[TEST_DATA_LEN << 2];
126462306a36Sopenharmony_ci	__u32 size_tmp = sizeof(tmp);
126562306a36Sopenharmony_ci	int err, saved_errno;
126662306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_test_run_opts, topts,
126762306a36Sopenharmony_ci		.data_in = data,
126862306a36Sopenharmony_ci		.data_size_in = size_data,
126962306a36Sopenharmony_ci		.data_out = tmp,
127062306a36Sopenharmony_ci		.data_size_out = size_tmp,
127162306a36Sopenharmony_ci		.repeat = 1,
127262306a36Sopenharmony_ci	);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (unpriv)
127562306a36Sopenharmony_ci		set_admin(true);
127662306a36Sopenharmony_ci	err = bpf_prog_test_run_opts(fd_prog, &topts);
127762306a36Sopenharmony_ci	saved_errno = errno;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	if (unpriv)
128062306a36Sopenharmony_ci		set_admin(false);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	if (err) {
128362306a36Sopenharmony_ci		switch (saved_errno) {
128462306a36Sopenharmony_ci		case ENOTSUPP:
128562306a36Sopenharmony_ci			printf("Did not run the program (not supported) ");
128662306a36Sopenharmony_ci			return 0;
128762306a36Sopenharmony_ci		case EPERM:
128862306a36Sopenharmony_ci			if (unpriv) {
128962306a36Sopenharmony_ci				printf("Did not run the program (no permission) ");
129062306a36Sopenharmony_ci				return 0;
129162306a36Sopenharmony_ci			}
129262306a36Sopenharmony_ci			/* fallthrough; */
129362306a36Sopenharmony_ci		default:
129462306a36Sopenharmony_ci			printf("FAIL: Unexpected bpf_prog_test_run error (%s) ",
129562306a36Sopenharmony_ci				strerror(saved_errno));
129662306a36Sopenharmony_ci			return err;
129762306a36Sopenharmony_ci		}
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	if (topts.retval != expected_val && expected_val != POINTER_VALUE) {
130162306a36Sopenharmony_ci		printf("FAIL retval %d != %d ", topts.retval, expected_val);
130262306a36Sopenharmony_ci		return 1;
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return 0;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci/* Returns true if every part of exp (tab-separated) appears in log, in order.
130962306a36Sopenharmony_ci *
131062306a36Sopenharmony_ci * If exp is an empty string, returns true.
131162306a36Sopenharmony_ci */
131262306a36Sopenharmony_cistatic bool cmp_str_seq(const char *log, const char *exp)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	char needle[200];
131562306a36Sopenharmony_ci	const char *p, *q;
131662306a36Sopenharmony_ci	int len;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	do {
131962306a36Sopenharmony_ci		if (!strlen(exp))
132062306a36Sopenharmony_ci			break;
132162306a36Sopenharmony_ci		p = strchr(exp, '\t');
132262306a36Sopenharmony_ci		if (!p)
132362306a36Sopenharmony_ci			p = exp + strlen(exp);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci		len = p - exp;
132662306a36Sopenharmony_ci		if (len >= sizeof(needle) || !len) {
132762306a36Sopenharmony_ci			printf("FAIL\nTestcase bug\n");
132862306a36Sopenharmony_ci			return false;
132962306a36Sopenharmony_ci		}
133062306a36Sopenharmony_ci		strncpy(needle, exp, len);
133162306a36Sopenharmony_ci		needle[len] = 0;
133262306a36Sopenharmony_ci		q = strstr(log, needle);
133362306a36Sopenharmony_ci		if (!q) {
133462306a36Sopenharmony_ci			printf("FAIL\nUnexpected verifier log!\n"
133562306a36Sopenharmony_ci			       "EXP: %s\nRES:\n", needle);
133662306a36Sopenharmony_ci			return false;
133762306a36Sopenharmony_ci		}
133862306a36Sopenharmony_ci		log = q + len;
133962306a36Sopenharmony_ci		exp = p + 1;
134062306a36Sopenharmony_ci	} while (*p);
134162306a36Sopenharmony_ci	return true;
134262306a36Sopenharmony_ci}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_cistatic struct bpf_insn *get_xlated_program(int fd_prog, int *cnt)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	__u32 buf_element_size = sizeof(struct bpf_insn);
134762306a36Sopenharmony_ci	struct bpf_prog_info info = {};
134862306a36Sopenharmony_ci	__u32 info_len = sizeof(info);
134962306a36Sopenharmony_ci	__u32 xlated_prog_len;
135062306a36Sopenharmony_ci	struct bpf_insn *buf;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
135362306a36Sopenharmony_ci		perror("bpf_prog_get_info_by_fd failed");
135462306a36Sopenharmony_ci		return NULL;
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	xlated_prog_len = info.xlated_prog_len;
135862306a36Sopenharmony_ci	if (xlated_prog_len % buf_element_size) {
135962306a36Sopenharmony_ci		printf("Program length %d is not multiple of %d\n",
136062306a36Sopenharmony_ci		       xlated_prog_len, buf_element_size);
136162306a36Sopenharmony_ci		return NULL;
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	*cnt = xlated_prog_len / buf_element_size;
136562306a36Sopenharmony_ci	buf = calloc(*cnt, buf_element_size);
136662306a36Sopenharmony_ci	if (!buf) {
136762306a36Sopenharmony_ci		perror("can't allocate xlated program buffer");
136862306a36Sopenharmony_ci		return NULL;
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	bzero(&info, sizeof(info));
137262306a36Sopenharmony_ci	info.xlated_prog_len = xlated_prog_len;
137362306a36Sopenharmony_ci	info.xlated_prog_insns = (__u64)(unsigned long)buf;
137462306a36Sopenharmony_ci	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
137562306a36Sopenharmony_ci		perror("second bpf_prog_get_info_by_fd failed");
137662306a36Sopenharmony_ci		goto out_free_buf;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	return buf;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ciout_free_buf:
138262306a36Sopenharmony_ci	free(buf);
138362306a36Sopenharmony_ci	return NULL;
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_cistatic bool is_null_insn(struct bpf_insn *insn)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	struct bpf_insn null_insn = {};
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	return memcmp(insn, &null_insn, sizeof(null_insn)) == 0;
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic bool is_skip_insn(struct bpf_insn *insn)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct bpf_insn skip_insn = SKIP_INSNS();
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	return memcmp(insn, &skip_insn, sizeof(skip_insn)) == 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic int null_terminated_insn_len(struct bpf_insn *seq, int max_len)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	int i;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	for (i = 0; i < max_len; ++i) {
140562306a36Sopenharmony_ci		if (is_null_insn(&seq[i]))
140662306a36Sopenharmony_ci			return i;
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci	return max_len;
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic bool compare_masked_insn(struct bpf_insn *orig, struct bpf_insn *masked)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	struct bpf_insn orig_masked;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	memcpy(&orig_masked, orig, sizeof(orig_masked));
141662306a36Sopenharmony_ci	if (masked->imm == INSN_IMM_MASK)
141762306a36Sopenharmony_ci		orig_masked.imm = INSN_IMM_MASK;
141862306a36Sopenharmony_ci	if (masked->off == INSN_OFF_MASK)
141962306a36Sopenharmony_ci		orig_masked.off = INSN_OFF_MASK;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	return memcmp(&orig_masked, masked, sizeof(orig_masked)) == 0;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic int find_insn_subseq(struct bpf_insn *seq, struct bpf_insn *subseq,
142562306a36Sopenharmony_ci			    int seq_len, int subseq_len)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	int i, j;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if (subseq_len > seq_len)
143062306a36Sopenharmony_ci		return -1;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	for (i = 0; i < seq_len - subseq_len + 1; ++i) {
143362306a36Sopenharmony_ci		bool found = true;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		for (j = 0; j < subseq_len; ++j) {
143662306a36Sopenharmony_ci			if (!compare_masked_insn(&seq[i + j], &subseq[j])) {
143762306a36Sopenharmony_ci				found = false;
143862306a36Sopenharmony_ci				break;
143962306a36Sopenharmony_ci			}
144062306a36Sopenharmony_ci		}
144162306a36Sopenharmony_ci		if (found)
144262306a36Sopenharmony_ci			return i;
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	return -1;
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_cistatic int find_skip_insn_marker(struct bpf_insn *seq, int len)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	int i;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	for (i = 0; i < len; ++i)
145362306a36Sopenharmony_ci		if (is_skip_insn(&seq[i]))
145462306a36Sopenharmony_ci			return i;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	return -1;
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci/* Return true if all sub-sequences in `subseqs` could be found in
146062306a36Sopenharmony_ci * `seq` one after another. Sub-sequences are separated by a single
146162306a36Sopenharmony_ci * nil instruction.
146262306a36Sopenharmony_ci */
146362306a36Sopenharmony_cistatic bool find_all_insn_subseqs(struct bpf_insn *seq, struct bpf_insn *subseqs,
146462306a36Sopenharmony_ci				  int seq_len, int max_subseqs_len)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	int subseqs_len = null_terminated_insn_len(subseqs, max_subseqs_len);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	while (subseqs_len > 0) {
146962306a36Sopenharmony_ci		int skip_idx = find_skip_insn_marker(subseqs, subseqs_len);
147062306a36Sopenharmony_ci		int cur_subseq_len = skip_idx < 0 ? subseqs_len : skip_idx;
147162306a36Sopenharmony_ci		int subseq_idx = find_insn_subseq(seq, subseqs,
147262306a36Sopenharmony_ci						  seq_len, cur_subseq_len);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		if (subseq_idx < 0)
147562306a36Sopenharmony_ci			return false;
147662306a36Sopenharmony_ci		seq += subseq_idx + cur_subseq_len;
147762306a36Sopenharmony_ci		seq_len -= subseq_idx + cur_subseq_len;
147862306a36Sopenharmony_ci		subseqs += cur_subseq_len + 1;
147962306a36Sopenharmony_ci		subseqs_len -= cur_subseq_len + 1;
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	return true;
148362306a36Sopenharmony_ci}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_cistatic void print_insn(struct bpf_insn *buf, int cnt)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	int i;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	printf("  addr  op d s off  imm\n");
149062306a36Sopenharmony_ci	for (i = 0; i < cnt; ++i) {
149162306a36Sopenharmony_ci		struct bpf_insn *insn = &buf[i];
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		if (is_null_insn(insn))
149462306a36Sopenharmony_ci			break;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		if (is_skip_insn(insn))
149762306a36Sopenharmony_ci			printf("  ...\n");
149862306a36Sopenharmony_ci		else
149962306a36Sopenharmony_ci			printf("  %04x: %02x %1x %x %04hx %08x\n",
150062306a36Sopenharmony_ci			       i, insn->code, insn->dst_reg,
150162306a36Sopenharmony_ci			       insn->src_reg, insn->off, insn->imm);
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_cistatic bool check_xlated_program(struct bpf_test *test, int fd_prog)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	struct bpf_insn *buf;
150862306a36Sopenharmony_ci	int cnt;
150962306a36Sopenharmony_ci	bool result = true;
151062306a36Sopenharmony_ci	bool check_expected = !is_null_insn(test->expected_insns);
151162306a36Sopenharmony_ci	bool check_unexpected = !is_null_insn(test->unexpected_insns);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!check_expected && !check_unexpected)
151462306a36Sopenharmony_ci		goto out;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	buf = get_xlated_program(fd_prog, &cnt);
151762306a36Sopenharmony_ci	if (!buf) {
151862306a36Sopenharmony_ci		printf("FAIL: can't get xlated program\n");
151962306a36Sopenharmony_ci		result = false;
152062306a36Sopenharmony_ci		goto out;
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (check_expected &&
152462306a36Sopenharmony_ci	    !find_all_insn_subseqs(buf, test->expected_insns,
152562306a36Sopenharmony_ci				   cnt, MAX_EXPECTED_INSNS)) {
152662306a36Sopenharmony_ci		printf("FAIL: can't find expected subsequence of instructions\n");
152762306a36Sopenharmony_ci		result = false;
152862306a36Sopenharmony_ci		if (verbose) {
152962306a36Sopenharmony_ci			printf("Program:\n");
153062306a36Sopenharmony_ci			print_insn(buf, cnt);
153162306a36Sopenharmony_ci			printf("Expected subsequence:\n");
153262306a36Sopenharmony_ci			print_insn(test->expected_insns, MAX_EXPECTED_INSNS);
153362306a36Sopenharmony_ci		}
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	if (check_unexpected &&
153762306a36Sopenharmony_ci	    find_all_insn_subseqs(buf, test->unexpected_insns,
153862306a36Sopenharmony_ci				  cnt, MAX_UNEXPECTED_INSNS)) {
153962306a36Sopenharmony_ci		printf("FAIL: found unexpected subsequence of instructions\n");
154062306a36Sopenharmony_ci		result = false;
154162306a36Sopenharmony_ci		if (verbose) {
154262306a36Sopenharmony_ci			printf("Program:\n");
154362306a36Sopenharmony_ci			print_insn(buf, cnt);
154462306a36Sopenharmony_ci			printf("Un-expected subsequence:\n");
154562306a36Sopenharmony_ci			print_insn(test->unexpected_insns, MAX_UNEXPECTED_INSNS);
154662306a36Sopenharmony_ci		}
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	free(buf);
155062306a36Sopenharmony_ci out:
155162306a36Sopenharmony_ci	return result;
155262306a36Sopenharmony_ci}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_cistatic void do_test_single(struct bpf_test *test, bool unpriv,
155562306a36Sopenharmony_ci			   int *passes, int *errors)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	int fd_prog, btf_fd, expected_ret, alignment_prevented_execution;
155862306a36Sopenharmony_ci	int prog_len, prog_type = test->prog_type;
155962306a36Sopenharmony_ci	struct bpf_insn *prog = test->insns;
156062306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_prog_load_opts, opts);
156162306a36Sopenharmony_ci	int run_errs, run_successes;
156262306a36Sopenharmony_ci	int map_fds[MAX_NR_MAPS];
156362306a36Sopenharmony_ci	const char *expected_err;
156462306a36Sopenharmony_ci	int fd_array[2] = { -1, -1 };
156562306a36Sopenharmony_ci	int saved_errno;
156662306a36Sopenharmony_ci	int fixup_skips;
156762306a36Sopenharmony_ci	__u32 pflags;
156862306a36Sopenharmony_ci	int i, err;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	fd_prog = -1;
157162306a36Sopenharmony_ci	for (i = 0; i < MAX_NR_MAPS; i++)
157262306a36Sopenharmony_ci		map_fds[i] = -1;
157362306a36Sopenharmony_ci	btf_fd = -1;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (!prog_type)
157662306a36Sopenharmony_ci		prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
157762306a36Sopenharmony_ci	fixup_skips = skips;
157862306a36Sopenharmony_ci	do_test_fixup(test, prog_type, prog, map_fds, &fd_array[1]);
157962306a36Sopenharmony_ci	if (test->fill_insns) {
158062306a36Sopenharmony_ci		prog = test->fill_insns;
158162306a36Sopenharmony_ci		prog_len = test->prog_len;
158262306a36Sopenharmony_ci	} else {
158362306a36Sopenharmony_ci		prog_len = probe_filter_length(prog);
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci	/* If there were some map skips during fixup due to missing bpf
158662306a36Sopenharmony_ci	 * features, skip this test.
158762306a36Sopenharmony_ci	 */
158862306a36Sopenharmony_ci	if (fixup_skips != skips)
158962306a36Sopenharmony_ci		return;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	pflags = BPF_F_TEST_RND_HI32;
159262306a36Sopenharmony_ci	if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT)
159362306a36Sopenharmony_ci		pflags |= BPF_F_STRICT_ALIGNMENT;
159462306a36Sopenharmony_ci	if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
159562306a36Sopenharmony_ci		pflags |= BPF_F_ANY_ALIGNMENT;
159662306a36Sopenharmony_ci	if (test->flags & ~3)
159762306a36Sopenharmony_ci		pflags |= test->flags;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	expected_ret = unpriv && test->result_unpriv != UNDEF ?
160062306a36Sopenharmony_ci		       test->result_unpriv : test->result;
160162306a36Sopenharmony_ci	expected_err = unpriv && test->errstr_unpriv ?
160262306a36Sopenharmony_ci		       test->errstr_unpriv : test->errstr;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	opts.expected_attach_type = test->expected_attach_type;
160562306a36Sopenharmony_ci	if (verbose)
160662306a36Sopenharmony_ci		opts.log_level = verif_log_level | 4; /* force stats */
160762306a36Sopenharmony_ci	else if (expected_ret == VERBOSE_ACCEPT)
160862306a36Sopenharmony_ci		opts.log_level = 2;
160962306a36Sopenharmony_ci	else
161062306a36Sopenharmony_ci		opts.log_level = DEFAULT_LIBBPF_LOG_LEVEL;
161162306a36Sopenharmony_ci	opts.prog_flags = pflags;
161262306a36Sopenharmony_ci	if (fd_array[1] != -1)
161362306a36Sopenharmony_ci		opts.fd_array = &fd_array[0];
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	if ((prog_type == BPF_PROG_TYPE_TRACING ||
161662306a36Sopenharmony_ci	     prog_type == BPF_PROG_TYPE_LSM) && test->kfunc) {
161762306a36Sopenharmony_ci		int attach_btf_id;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		attach_btf_id = libbpf_find_vmlinux_btf_id(test->kfunc,
162062306a36Sopenharmony_ci						opts.expected_attach_type);
162162306a36Sopenharmony_ci		if (attach_btf_id < 0) {
162262306a36Sopenharmony_ci			printf("FAIL\nFailed to find BTF ID for '%s'!\n",
162362306a36Sopenharmony_ci				test->kfunc);
162462306a36Sopenharmony_ci			(*errors)++;
162562306a36Sopenharmony_ci			return;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		opts.attach_btf_id = attach_btf_id;
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	if (test->btf_types[0] != 0) {
163262306a36Sopenharmony_ci		btf_fd = load_btf_for_test(test);
163362306a36Sopenharmony_ci		if (btf_fd < 0)
163462306a36Sopenharmony_ci			goto fail_log;
163562306a36Sopenharmony_ci		opts.prog_btf_fd = btf_fd;
163662306a36Sopenharmony_ci	}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	if (test->func_info_cnt != 0) {
163962306a36Sopenharmony_ci		opts.func_info = test->func_info;
164062306a36Sopenharmony_ci		opts.func_info_cnt = test->func_info_cnt;
164162306a36Sopenharmony_ci		opts.func_info_rec_size = sizeof(test->func_info[0]);
164262306a36Sopenharmony_ci	}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	opts.log_buf = bpf_vlog;
164562306a36Sopenharmony_ci	opts.log_size = sizeof(bpf_vlog);
164662306a36Sopenharmony_ci	fd_prog = bpf_prog_load(prog_type, NULL, "GPL", prog, prog_len, &opts);
164762306a36Sopenharmony_ci	saved_errno = errno;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	/* BPF_PROG_TYPE_TRACING requires more setup and
165062306a36Sopenharmony_ci	 * bpf_probe_prog_type won't give correct answer
165162306a36Sopenharmony_ci	 */
165262306a36Sopenharmony_ci	if (fd_prog < 0 && prog_type != BPF_PROG_TYPE_TRACING &&
165362306a36Sopenharmony_ci	    !libbpf_probe_bpf_prog_type(prog_type, NULL)) {
165462306a36Sopenharmony_ci		printf("SKIP (unsupported program type %d)\n", prog_type);
165562306a36Sopenharmony_ci		skips++;
165662306a36Sopenharmony_ci		goto close_fds;
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	if (fd_prog < 0 && saved_errno == ENOTSUPP) {
166062306a36Sopenharmony_ci		printf("SKIP (program uses an unsupported feature)\n");
166162306a36Sopenharmony_ci		skips++;
166262306a36Sopenharmony_ci		goto close_fds;
166362306a36Sopenharmony_ci	}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	alignment_prevented_execution = 0;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (expected_ret == ACCEPT || expected_ret == VERBOSE_ACCEPT) {
166862306a36Sopenharmony_ci		if (fd_prog < 0) {
166962306a36Sopenharmony_ci			printf("FAIL\nFailed to load prog '%s'!\n",
167062306a36Sopenharmony_ci			       strerror(saved_errno));
167162306a36Sopenharmony_ci			goto fail_log;
167262306a36Sopenharmony_ci		}
167362306a36Sopenharmony_ci#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
167462306a36Sopenharmony_ci		if (fd_prog >= 0 &&
167562306a36Sopenharmony_ci		    (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS))
167662306a36Sopenharmony_ci			alignment_prevented_execution = 1;
167762306a36Sopenharmony_ci#endif
167862306a36Sopenharmony_ci		if (expected_ret == VERBOSE_ACCEPT && !cmp_str_seq(bpf_vlog, expected_err)) {
167962306a36Sopenharmony_ci			goto fail_log;
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci	} else {
168262306a36Sopenharmony_ci		if (fd_prog >= 0) {
168362306a36Sopenharmony_ci			printf("FAIL\nUnexpected success to load!\n");
168462306a36Sopenharmony_ci			goto fail_log;
168562306a36Sopenharmony_ci		}
168662306a36Sopenharmony_ci		if (!expected_err || !cmp_str_seq(bpf_vlog, expected_err)) {
168762306a36Sopenharmony_ci			printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n",
168862306a36Sopenharmony_ci			      expected_err, bpf_vlog);
168962306a36Sopenharmony_ci			goto fail_log;
169062306a36Sopenharmony_ci		}
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (!unpriv && test->insn_processed) {
169462306a36Sopenharmony_ci		uint32_t insn_processed;
169562306a36Sopenharmony_ci		char *proc;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci		proc = strstr(bpf_vlog, "processed ");
169862306a36Sopenharmony_ci		insn_processed = atoi(proc + 10);
169962306a36Sopenharmony_ci		if (test->insn_processed != insn_processed) {
170062306a36Sopenharmony_ci			printf("FAIL\nUnexpected insn_processed %u vs %u\n",
170162306a36Sopenharmony_ci			       insn_processed, test->insn_processed);
170262306a36Sopenharmony_ci			goto fail_log;
170362306a36Sopenharmony_ci		}
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (verbose)
170762306a36Sopenharmony_ci		printf(", verifier log:\n%s", bpf_vlog);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	if (!check_xlated_program(test, fd_prog))
171062306a36Sopenharmony_ci		goto fail_log;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	run_errs = 0;
171362306a36Sopenharmony_ci	run_successes = 0;
171462306a36Sopenharmony_ci	if (!alignment_prevented_execution && fd_prog >= 0 && test->runs >= 0) {
171562306a36Sopenharmony_ci		uint32_t expected_val;
171662306a36Sopenharmony_ci		int i;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci		if (!test->runs)
171962306a36Sopenharmony_ci			test->runs = 1;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci		for (i = 0; i < test->runs; i++) {
172262306a36Sopenharmony_ci			if (unpriv && test->retvals[i].retval_unpriv)
172362306a36Sopenharmony_ci				expected_val = test->retvals[i].retval_unpriv;
172462306a36Sopenharmony_ci			else
172562306a36Sopenharmony_ci				expected_val = test->retvals[i].retval;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci			err = do_prog_test_run(fd_prog, unpriv, expected_val,
172862306a36Sopenharmony_ci					       test->retvals[i].data,
172962306a36Sopenharmony_ci					       sizeof(test->retvals[i].data));
173062306a36Sopenharmony_ci			if (err) {
173162306a36Sopenharmony_ci				printf("(run %d/%d) ", i + 1, test->runs);
173262306a36Sopenharmony_ci				run_errs++;
173362306a36Sopenharmony_ci			} else {
173462306a36Sopenharmony_ci				run_successes++;
173562306a36Sopenharmony_ci			}
173662306a36Sopenharmony_ci		}
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	if (!run_errs) {
174062306a36Sopenharmony_ci		(*passes)++;
174162306a36Sopenharmony_ci		if (run_successes > 1)
174262306a36Sopenharmony_ci			printf("%d cases ", run_successes);
174362306a36Sopenharmony_ci		printf("OK");
174462306a36Sopenharmony_ci		if (alignment_prevented_execution)
174562306a36Sopenharmony_ci			printf(" (NOTE: not executed due to unknown alignment)");
174662306a36Sopenharmony_ci		printf("\n");
174762306a36Sopenharmony_ci	} else {
174862306a36Sopenharmony_ci		printf("\n");
174962306a36Sopenharmony_ci		goto fail_log;
175062306a36Sopenharmony_ci	}
175162306a36Sopenharmony_ciclose_fds:
175262306a36Sopenharmony_ci	if (test->fill_insns)
175362306a36Sopenharmony_ci		free(test->fill_insns);
175462306a36Sopenharmony_ci	close(fd_prog);
175562306a36Sopenharmony_ci	close(btf_fd);
175662306a36Sopenharmony_ci	for (i = 0; i < MAX_NR_MAPS; i++)
175762306a36Sopenharmony_ci		close(map_fds[i]);
175862306a36Sopenharmony_ci	sched_yield();
175962306a36Sopenharmony_ci	return;
176062306a36Sopenharmony_cifail_log:
176162306a36Sopenharmony_ci	(*errors)++;
176262306a36Sopenharmony_ci	printf("%s", bpf_vlog);
176362306a36Sopenharmony_ci	goto close_fds;
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_cistatic bool is_admin(void)
176762306a36Sopenharmony_ci{
176862306a36Sopenharmony_ci	__u64 caps;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	/* The test checks for finer cap as CAP_NET_ADMIN,
177162306a36Sopenharmony_ci	 * CAP_PERFMON, and CAP_BPF instead of CAP_SYS_ADMIN.
177262306a36Sopenharmony_ci	 * Thus, disable CAP_SYS_ADMIN at the beginning.
177362306a36Sopenharmony_ci	 */
177462306a36Sopenharmony_ci	if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
177562306a36Sopenharmony_ci		perror("cap_disable_effective(CAP_SYS_ADMIN)");
177662306a36Sopenharmony_ci		return false;
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	return (caps & ADMIN_CAPS) == ADMIN_CAPS;
178062306a36Sopenharmony_ci}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_cistatic bool test_as_unpriv(struct bpf_test *test)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
178562306a36Sopenharmony_ci	/* Some architectures have strict alignment requirements. In
178662306a36Sopenharmony_ci	 * that case, the BPF verifier detects if a program has
178762306a36Sopenharmony_ci	 * unaligned accesses and rejects them. A user can pass
178862306a36Sopenharmony_ci	 * BPF_F_ANY_ALIGNMENT to a program to override this
178962306a36Sopenharmony_ci	 * check. That, however, will only work when a privileged user
179062306a36Sopenharmony_ci	 * loads a program. An unprivileged user loading a program
179162306a36Sopenharmony_ci	 * with this flag will be rejected prior entering the
179262306a36Sopenharmony_ci	 * verifier.
179362306a36Sopenharmony_ci	 */
179462306a36Sopenharmony_ci	if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
179562306a36Sopenharmony_ci		return false;
179662306a36Sopenharmony_ci#endif
179762306a36Sopenharmony_ci	return !test->prog_type ||
179862306a36Sopenharmony_ci	       test->prog_type == BPF_PROG_TYPE_SOCKET_FILTER ||
179962306a36Sopenharmony_ci	       test->prog_type == BPF_PROG_TYPE_CGROUP_SKB;
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic int do_test(bool unpriv, unsigned int from, unsigned int to)
180362306a36Sopenharmony_ci{
180462306a36Sopenharmony_ci	int i, passes = 0, errors = 0;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* ensure previous instance of the module is unloaded */
180762306a36Sopenharmony_ci	unload_bpf_testmod(verbose);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	if (load_bpf_testmod(verbose))
181062306a36Sopenharmony_ci		return EXIT_FAILURE;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	for (i = from; i < to; i++) {
181362306a36Sopenharmony_ci		struct bpf_test *test = &tests[i];
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci		/* Program types that are not supported by non-root we
181662306a36Sopenharmony_ci		 * skip right away.
181762306a36Sopenharmony_ci		 */
181862306a36Sopenharmony_ci		if (test_as_unpriv(test) && unpriv_disabled) {
181962306a36Sopenharmony_ci			printf("#%d/u %s SKIP\n", i, test->descr);
182062306a36Sopenharmony_ci			skips++;
182162306a36Sopenharmony_ci		} else if (test_as_unpriv(test)) {
182262306a36Sopenharmony_ci			if (!unpriv)
182362306a36Sopenharmony_ci				set_admin(false);
182462306a36Sopenharmony_ci			printf("#%d/u %s ", i, test->descr);
182562306a36Sopenharmony_ci			do_test_single(test, true, &passes, &errors);
182662306a36Sopenharmony_ci			if (!unpriv)
182762306a36Sopenharmony_ci				set_admin(true);
182862306a36Sopenharmony_ci		}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci		if (unpriv) {
183162306a36Sopenharmony_ci			printf("#%d/p %s SKIP\n", i, test->descr);
183262306a36Sopenharmony_ci			skips++;
183362306a36Sopenharmony_ci		} else {
183462306a36Sopenharmony_ci			printf("#%d/p %s ", i, test->descr);
183562306a36Sopenharmony_ci			do_test_single(test, false, &passes, &errors);
183662306a36Sopenharmony_ci		}
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	unload_bpf_testmod(verbose);
184062306a36Sopenharmony_ci	kfuncs_cleanup();
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes,
184362306a36Sopenharmony_ci	       skips, errors);
184462306a36Sopenharmony_ci	return errors ? EXIT_FAILURE : EXIT_SUCCESS;
184562306a36Sopenharmony_ci}
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ciint main(int argc, char **argv)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	unsigned int from = 0, to = ARRAY_SIZE(tests);
185062306a36Sopenharmony_ci	bool unpriv = !is_admin();
185162306a36Sopenharmony_ci	int arg = 1;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	if (argc > 1 && strcmp(argv[1], "-v") == 0) {
185462306a36Sopenharmony_ci		arg++;
185562306a36Sopenharmony_ci		verbose = true;
185662306a36Sopenharmony_ci		verif_log_level = 1;
185762306a36Sopenharmony_ci		argc--;
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci	if (argc > 1 && strcmp(argv[1], "-vv") == 0) {
186062306a36Sopenharmony_ci		arg++;
186162306a36Sopenharmony_ci		verbose = true;
186262306a36Sopenharmony_ci		verif_log_level = 2;
186362306a36Sopenharmony_ci		argc--;
186462306a36Sopenharmony_ci	}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	if (argc == 3) {
186762306a36Sopenharmony_ci		unsigned int l = atoi(argv[arg]);
186862306a36Sopenharmony_ci		unsigned int u = atoi(argv[arg + 1]);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci		if (l < to && u < to) {
187162306a36Sopenharmony_ci			from = l;
187262306a36Sopenharmony_ci			to   = u + 1;
187362306a36Sopenharmony_ci		}
187462306a36Sopenharmony_ci	} else if (argc == 2) {
187562306a36Sopenharmony_ci		unsigned int t = atoi(argv[arg]);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci		if (t < to) {
187862306a36Sopenharmony_ci			from = t;
187962306a36Sopenharmony_ci			to   = t + 1;
188062306a36Sopenharmony_ci		}
188162306a36Sopenharmony_ci	}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	unpriv_disabled = get_unpriv_disabled();
188462306a36Sopenharmony_ci	if (unpriv && unpriv_disabled) {
188562306a36Sopenharmony_ci		printf("Cannot run as unprivileged user with sysctl %s.\n",
188662306a36Sopenharmony_ci		       UNPRIV_SYSCTL);
188762306a36Sopenharmony_ci		return EXIT_FAILURE;
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	/* Use libbpf 1.0 API mode */
189162306a36Sopenharmony_ci	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	bpf_semi_rand_init();
189462306a36Sopenharmony_ci	return do_test(unpriv, from, to);
189562306a36Sopenharmony_ci}
1896