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