struct kfunc_btf_id_pair { constchar *kfunc; int insn_idx;
};
struct bpf_test { constchar *descr; struct bpf_insn insns[MAX_INSNS]; struct bpf_insn *fill_insns; /* If specified, test engine looks for this sequence of *instructionsintheBPFprogramafterloading.Allowsto *testrewritesappliedbyverifier.Usevalues *INSN_OFF_MASKandINSN_IMM_MASKtomask`off`and`imm` *fieldsifcontentdoesnotmatter.Thetestcasefailsif *specifiedinstructionsarenotfound. * *Thesequencecouldbesplitintosub-sequencesbyadding *SKIP_INSNSinstructionattheendofeachsub-sequence.In *suchcasesub-sequencesaresearchedforoneafteranother.
*/ struct bpf_insn expected_insns[MAX_EXPECTED_INSNS]; /* If specified, test engine applies same pattern matching *logicasfor`expected_insns`.Ifthespecifiedpatternis *matchedtestcaseismarkedasfailed.
*/ struct bpf_insn unexpected_insns[MAX_UNEXPECTED_INSNS]; int fixup_map_hash_8b[MAX_FIXUPS]; int fixup_map_hash_48b[MAX_FIXUPS]; int fixup_map_hash_16b[MAX_FIXUPS]; int fixup_map_array_48b[MAX_FIXUPS]; int fixup_map_sockmap[MAX_FIXUPS]; int fixup_map_sockhash[MAX_FIXUPS]; int fixup_map_xskmap[MAX_FIXUPS]; int fixup_map_stacktrace[MAX_FIXUPS]; int fixup_prog1[MAX_FIXUPS]; int fixup_prog2[MAX_FIXUPS]; int fixup_map_in_map[MAX_FIXUPS]; int fixup_cgroup_storage[MAX_FIXUPS]; int fixup_percpu_cgroup_storage[MAX_FIXUPS]; int fixup_map_spin_lock[MAX_FIXUPS]; int fixup_map_array_ro[MAX_FIXUPS]; int fixup_map_array_wo[MAX_FIXUPS]; int fixup_map_array_small[MAX_FIXUPS]; int fixup_sk_storage_map[MAX_FIXUPS]; int fixup_map_event_output[MAX_FIXUPS]; int fixup_map_reuseport_array[MAX_FIXUPS]; int fixup_map_ringbuf[MAX_FIXUPS]; int fixup_map_timer[MAX_FIXUPS]; int fixup_map_kptr[MAX_FIXUPS]; struct kfunc_btf_id_pair fixup_kfunc_btf_id[MAX_FIXUPS]; /* Expected verifier log output for result REJECT or VERBOSE_ACCEPT. *Canbeatab-separatedsequenceofexpectedstrings.Anemptystring *meansnologverification.
*/ constchar *errstr; constchar *errstr_unpriv;
uint32_t insn_processed; int prog_len; enum {
UNDEF,
ACCEPT,
REJECT,
VERBOSE_ACCEPT,
} result, result_unpriv; enum bpf_prog_type prog_type;
uint8_t flags; void (*fill_helper)(struct bpf_test *self); int runs; #define bpf_testdata_struct_t \ struct { \
uint32_t retval, retval_unpriv; \ union { \
__u8 data[TEST_DATA_LEN]; \
__u64 data64[TEST_DATA_LEN / 8]; \
}; \
} union {
bpf_testdata_struct_t;
bpf_testdata_struct_t retvals[MAX_TEST_RUNS];
}; enum bpf_attach_type expected_attach_type; constchar *kfunc; struct bpf_func_info func_info[MAX_FUNC_INFOS]; int func_info_cnt; char btf_strings[MAX_BTF_STRINGS]; /* A set of BTF types to load when specified, *usemacrodefinitionsfromtest_btf.h, *mustendwithBTF_END_RAW
*/
__u32 btf_types[MAX_BTF_TYPES];
};
/* Note we want this to be 64 bit aligned so that the end of our array is *actuallytheendofthestructure.
*/ #define MAX_ENTRIES 11
struct test_val { unsignedint index; int foo[MAX_ENTRIES];
};
struct other_val { longlong foo; longlong bar;
};
staticvoid bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
{ /* test: {skb->data[0], vlan_push} x 51 + {skb->data[0], vlan_pop} x 51 */ #define PUSH_CNT 51 /* jump range is limited to 16 bit. PUSH_CNT of ld_abs needs room */ unsignedint len = (1 << 15) - PUSH_CNT * 2 * 5 * 6; struct bpf_insn *insn = self->fill_insns; int i = 0, j, k = 0;
staticvoid bpf_fill_jump_around_ld_abs(struct bpf_test *self)
{ struct bpf_insn *insn = self->fill_insns; /* jump range is limited to 16 bit. every ld_abs is replaced by 6 insns, *butonarcheslikearm,ppcetc,therewillbeoneBPF_ZEXTinserted *toextendtheerrorvalueoftheinlinedld_abssequencewhichthen *contains7insns.so,setthedividendto7sothetestcasecould *workonallarches.
*/ unsignedint len = (1 << 15) / 7; int i = 0;
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
insn[i++] = BPF_LD_ABS(BPF_B, 0);
insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 10, len - i - 2);
i++; while (i < len - 1)
insn[i++] = BPF_LD_ABS(BPF_B, 1);
insn[i] = BPF_EXIT_INSN();
self->prog_len = i + 1;
}
staticvoid bpf_fill_rand_ld_dw(struct bpf_test *self)
{ struct bpf_insn *insn = self->fill_insns;
uint64_t res = 0; int i = 0;
insn[i++] = BPF_MOV32_IMM(BPF_REG_0, 0); while (i < self->retval) {
uint64_t val = bpf_semi_rand_get(); struct bpf_insn tmp[2] = { BPF_LD_IMM64(BPF_REG_1, val) };
/* test the sequence of 8k jumps */ staticvoid bpf_fill_scale1(struct bpf_test *self)
{ struct bpf_insn *insn = self->fill_insns; int i = 0, k = 0;
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); /* test to check that the long sequence of jumps is acceptable */ while (k++ < MAX_JMP_SEQ) {
insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_get_prandom_u32);
insn[i++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, bpf_semi_rand_get(), 2);
insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10);
insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
-8 * (k % 64 + 1));
} /* is_state_visited() doesn't allocate state for pruning for every jump. *Hencemultiplyjmpsby4toaccommodatethatheuristic
*/ while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4)
insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42);
insn[i] = BPF_EXIT_INSN();
self->prog_len = i + 1;
self->retval = 42;
}
/* test the sequence of 8k jumps in inner most function (function depth 8)*/ staticvoid bpf_fill_scale2(struct bpf_test *self)
{ struct bpf_insn *insn = self->fill_insns; int i = 0, k = 0;
#define FUNC_NEST 7 for (k = 0; k < FUNC_NEST; k++) {
insn[i++] = BPF_CALL_REL(1);
insn[i++] = BPF_EXIT_INSN();
}
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); /* test to check that the long sequence of jumps is acceptable */
k = 0; while (k++ < MAX_JMP_SEQ) {
insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_get_prandom_u32);
insn[i++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, bpf_semi_rand_get(), 2);
insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10);
insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6,
-8 * (k % (64 - 4 * FUNC_NEST) + 1));
} while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4)
insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42);
insn[i] = BPF_EXIT_INSN();
self->prog_len = i + 1;
self->retval = 42;
}
staticvoid bpf_fill_big_prog_with_loop_1(struct bpf_test *self)
{ struct bpf_insn *insn = self->fill_insns; /* This test was added to catch a specific use after free *error,whichhappeneduponBPFprogramreallocation. *Reallocationishandledbycore.c:bpf_prog_realloc,which *reusesoldmemoryifpageboundaryisnotcrossed.The *valueof`len`ischosentocrossthisboundaryonbpf_loop *patching.
*/ constint len = getpagesize() - 25; int callback_load_idx; int callback_idx; int i = 0;
if (strcmp("bpf_testmod", name)) {
close(fd); continue;
}
btf = btf__load_from_kernel_by_id_split(id, vmlinux); if (!btf) {
close(fd); break;
}
/* We need the fd to stay open so it can be used in fd_array. *Thefinalcleanupcalltobtf__freewillfreebtfobject *andclosethefiledescriptor.
*/
btf__set_fd(btf, fd); break;
}
staticvoid do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, struct bpf_insn *prog, int *map_fds, int *fd_array)
{ int *fixup_map_hash_8b = test->fixup_map_hash_8b; int *fixup_map_hash_48b = test->fixup_map_hash_48b; int *fixup_map_hash_16b = test->fixup_map_hash_16b; int *fixup_map_array_48b = test->fixup_map_array_48b; int *fixup_map_sockmap = test->fixup_map_sockmap; int *fixup_map_sockhash = test->fixup_map_sockhash; int *fixup_map_xskmap = test->fixup_map_xskmap; int *fixup_map_stacktrace = test->fixup_map_stacktrace; int *fixup_prog1 = test->fixup_prog1; int *fixup_prog2 = test->fixup_prog2; int *fixup_map_in_map = test->fixup_map_in_map; int *fixup_cgroup_storage = test->fixup_cgroup_storage; int *fixup_percpu_cgroup_storage = test->fixup_percpu_cgroup_storage; int *fixup_map_spin_lock = test->fixup_map_spin_lock; int *fixup_map_array_ro = test->fixup_map_array_ro; int *fixup_map_array_wo = test->fixup_map_array_wo; int *fixup_map_array_small = test->fixup_map_array_small; int *fixup_sk_storage_map = test->fixup_sk_storage_map; int *fixup_map_event_output = test->fixup_map_event_output; int *fixup_map_reuseport_array = test->fixup_map_reuseport_array; int *fixup_map_ringbuf = test->fixup_map_ringbuf; int *fixup_map_timer = test->fixup_map_timer; int *fixup_map_kptr = test->fixup_map_kptr;
if (test->fill_helper) {
test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn));
test->fill_helper(test);
}
/* Allocating HTs with 1 elem is fine here, since we only test *forverifierandnotdoaruntimelookup,sotheonlything *thatreallymattersisvaluesizeinthiscase.
*/ if (*fixup_map_hash_8b) {
map_fds[0] = create_map(BPF_MAP_TYPE_HASH, sizeof(longlong), sizeof(longlong), 1); do {
prog[*fixup_map_hash_8b].imm = map_fds[0];
fixup_map_hash_8b++;
} while (*fixup_map_hash_8b);
}
if (*fixup_map_hash_48b) {
map_fds[1] = create_map(BPF_MAP_TYPE_HASH, sizeof(longlong), sizeof(struct test_val), 1); do {
prog[*fixup_map_hash_48b].imm = map_fds[1];
fixup_map_hash_48b++;
} while (*fixup_map_hash_48b);
}
if (*fixup_map_hash_16b) {
map_fds[2] = create_map(BPF_MAP_TYPE_HASH, sizeof(longlong), sizeof(struct other_val), 1); do {
prog[*fixup_map_hash_16b].imm = map_fds[2];
fixup_map_hash_16b++;
} while (*fixup_map_hash_16b);
}
if (*fixup_map_array_48b) {
map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(struct test_val), 1);
update_map(map_fds[3], 0); do {
prog[*fixup_map_array_48b].imm = map_fds[3];
fixup_map_array_48b++;
} while (*fixup_map_array_48b);
}
if (*fixup_prog1) {
map_fds[4] = create_prog_array(prog_type, 4, 0, 1, 2); do {
prog[*fixup_prog1].imm = map_fds[4];
fixup_prog1++;
} while (*fixup_prog1);
}
if (*fixup_prog2) {
map_fds[5] = create_prog_array(prog_type, 8, 7, 1, 2); do {
prog[*fixup_prog2].imm = map_fds[5];
fixup_prog2++;
} while (*fixup_prog2);
}
if (*fixup_map_in_map) {
map_fds[6] = create_map_in_map(); do {
prog[*fixup_map_in_map].imm = map_fds[6];
fixup_map_in_map++;
} while (*fixup_map_in_map);
}
if (*fixup_cgroup_storage) {
map_fds[7] = create_cgroup_storage(false); do {
prog[*fixup_cgroup_storage].imm = map_fds[7];
fixup_cgroup_storage++;
} while (*fixup_cgroup_storage);
}
if (*fixup_percpu_cgroup_storage) {
map_fds[8] = create_cgroup_storage(true); do {
prog[*fixup_percpu_cgroup_storage].imm = map_fds[8];
fixup_percpu_cgroup_storage++;
} while (*fixup_percpu_cgroup_storage);
} if (*fixup_map_sockmap) {
map_fds[9] = create_map(BPF_MAP_TYPE_SOCKMAP, sizeof(int), sizeof(int), 1); do {
prog[*fixup_map_sockmap].imm = map_fds[9];
fixup_map_sockmap++;
} while (*fixup_map_sockmap);
} if (*fixup_map_sockhash) {
map_fds[10] = create_map(BPF_MAP_TYPE_SOCKHASH, sizeof(int), sizeof(int), 1); do {
prog[*fixup_map_sockhash].imm = map_fds[10];
fixup_map_sockhash++;
} while (*fixup_map_sockhash);
} if (*fixup_map_xskmap) {
map_fds[11] = create_map(BPF_MAP_TYPE_XSKMAP, sizeof(int), sizeof(int), 1); do {
prog[*fixup_map_xskmap].imm = map_fds[11];
fixup_map_xskmap++;
} while (*fixup_map_xskmap);
} if (*fixup_map_stacktrace) {
map_fds[12] = create_map(BPF_MAP_TYPE_STACK_TRACE, sizeof(u32), sizeof(u64), 1); do {
prog[*fixup_map_stacktrace].imm = map_fds[12];
fixup_map_stacktrace++;
} while (*fixup_map_stacktrace);
} if (*fixup_map_spin_lock) {
map_fds[13] = create_map_spin_lock(); do {
prog[*fixup_map_spin_lock].imm = map_fds[13];
fixup_map_spin_lock++;
} while (*fixup_map_spin_lock);
} if (*fixup_map_array_ro) {
map_fds[14] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(struct test_val), 1,
BPF_F_RDONLY_PROG);
update_map(map_fds[14], 0); do {
prog[*fixup_map_array_ro].imm = map_fds[14];
fixup_map_array_ro++;
} while (*fixup_map_array_ro);
} if (*fixup_map_array_wo) {
map_fds[15] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(struct test_val), 1,
BPF_F_WRONLY_PROG);
update_map(map_fds[15], 0); do {
prog[*fixup_map_array_wo].imm = map_fds[15];
fixup_map_array_wo++;
} while (*fixup_map_array_wo);
} if (*fixup_map_array_small) {
map_fds[16] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), 1, 1, 0);
update_map(map_fds[16], 0); do {
prog[*fixup_map_array_small].imm = map_fds[16];
fixup_map_array_small++;
} while (*fixup_map_array_small);
} if (*fixup_sk_storage_map) {
map_fds[17] = create_sk_storage_map(); do {
prog[*fixup_sk_storage_map].imm = map_fds[17];
fixup_sk_storage_map++;
} while (*fixup_sk_storage_map);
} if (*fixup_map_event_output) {
map_fds[18] = __create_map(BPF_MAP_TYPE_PERF_EVENT_ARRAY, sizeof(int), sizeof(int), 1, 0); do {
prog[*fixup_map_event_output].imm = map_fds[18];
fixup_map_event_output++;
} while (*fixup_map_event_output);
} if (*fixup_map_reuseport_array) {
map_fds[19] = __create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, sizeof(u32), sizeof(u64), 1, 0); do {
prog[*fixup_map_reuseport_array].imm = map_fds[19];
fixup_map_reuseport_array++;
} while (*fixup_map_reuseport_array);
} if (*fixup_map_ringbuf) {
map_fds[20] = create_map(BPF_MAP_TYPE_RINGBUF, 0, 0, getpagesize()); do {
prog[*fixup_map_ringbuf].imm = map_fds[20];
fixup_map_ringbuf++;
} while (*fixup_map_ringbuf);
} if (*fixup_map_timer) {
map_fds[21] = create_map_timer(); do {
prog[*fixup_map_timer].imm = map_fds[21];
fixup_map_timer++;
} while (*fixup_map_timer);
} if (*fixup_map_kptr) {
map_fds[22] = create_map_kptr(); do {
prog[*fixup_map_kptr].imm = map_fds[22];
fixup_map_kptr++;
} while (*fixup_map_kptr);
}
if (unpriv)
set_admin(true);
err = bpf_prog_test_run_opts(fd_prog, &topts);
saved_errno = errno;
if (unpriv)
set_admin(false);
if (err) { switch (saved_errno) { case ENOTSUPP:
printf("Did not run the program (not supported) "); return0; case EPERM: if (unpriv) {
printf("Did not run the program (no permission) "); return0;
} /* fallthrough; */ default:
printf("FAIL: Unexpected bpf_prog_test_run error (%s) ",
strerror(saved_errno)); return err;
}
}
/* Returns true if every part of exp (tab-separated) appears in log, in order. * *Ifexpisanemptystring,returnstrue.
*/ staticbool cmp_str_seq(constchar *log, constchar *exp)
{ char needle[200]; constchar *p, *q; int len;
do { if (!strlen(exp)) break;
p = strchr(exp, '\t'); if (!p)
p = exp + strlen(exp);
len = p - exp; if (len >= sizeof(needle) || !len) {
printf("FAIL\nTestcase bug\n"); returnfalse;
}
strncpy(needle, exp, len);
needle[len] = 0;
q = strstr(log, needle); if (!q) {
printf("FAIL\nUnexpected verifier log!\n" "EXP: %s\nRES:\n", needle); returnfalse;
}
log = q + len;
exp = p + 1;
} while (*p); returntrue;
}
staticint find_insn_subseq(struct bpf_insn *seq, struct bpf_insn *subseq, int seq_len, int subseq_len)
{ int i, j;
if (subseq_len > seq_len) return -1;
for (i = 0; i < seq_len - subseq_len + 1; ++i) { bool found = true;
for (j = 0; j < subseq_len; ++j) { if (!compare_masked_insn(&seq[i + j], &subseq[j])) {
found = false; break;
}
} if (found) return i;
}
return -1;
}
staticint find_skip_insn_marker(struct bpf_insn *seq, int len)
{ int i;
for (i = 0; i < len; ++i) if (is_skip_insn(&seq[i])) return i;
return -1;
}
/* Return true if all sub-sequences in `subseqs` could be found in *`seq`oneafteranother.Sub-sequencesareseparatedbyasingle *nilinstruction.
*/ staticbool find_all_insn_subseqs(struct bpf_insn *seq, struct bpf_insn *subseqs, int seq_len, int max_subseqs_len)
{ int subseqs_len = null_terminated_insn_len(subseqs, max_subseqs_len);
while (subseqs_len > 0) { int skip_idx = find_skip_insn_marker(subseqs, subseqs_len); int cur_subseq_len = skip_idx < 0 ? subseqs_len : skip_idx; int subseq_idx = find_insn_subseq(seq, subseqs,
seq_len, cur_subseq_len);
if (!check_expected && !check_unexpected) goto out;
if (get_xlated_program(fd_prog, &buf, &cnt)) {
printf("FAIL: can't get xlated program\n");
result = false; goto out;
}
if (check_expected &&
!find_all_insn_subseqs(buf, test->expected_insns,
cnt, MAX_EXPECTED_INSNS)) {
printf("FAIL: can't find expected subsequence of instructions\n");
result = false; if (verbose) {
printf("Program:\n");
print_insn(buf, cnt);
printf("Expected subsequence:\n");
print_insn(test->expected_insns, MAX_EXPECTED_INSNS);
}
}
if (check_unexpected &&
find_all_insn_subseqs(buf, test->unexpected_insns,
cnt, MAX_UNEXPECTED_INSNS)) {
printf("FAIL: found unexpected subsequence of instructions\n");
result = false; if (verbose) {
printf("Program:\n");
print_insn(buf, cnt);
printf("Un-expected subsequence:\n");
print_insn(test->unexpected_insns, MAX_UNEXPECTED_INSNS);
}
}
free(buf);
out: return result;
}
staticvoid do_test_single(struct bpf_test *test, bool unpriv, int *passes, int *errors)
{ int fd_prog, btf_fd, expected_ret, alignment_prevented_execution; int prog_len, prog_type = test->prog_type; struct bpf_insn *prog = test->insns;
LIBBPF_OPTS(bpf_prog_load_opts, opts); int run_errs, run_successes; int map_fds[MAX_NR_MAPS]; constchar *expected_err; int fd_array[2] = { -1, -1 }; int saved_errno; int fixup_skips;
__u32 pflags; int i, err;
fd_prog = -1; for (i = 0; i < MAX_NR_MAPS; i++)
map_fds[i] = -1;
btf_fd = -1;
if (!prog_type)
prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
fixup_skips = skips;
do_test_fixup(test, prog_type, prog, map_fds, &fd_array[1]); if (test->fill_insns) {
prog = test->fill_insns;
prog_len = test->prog_len;
} else {
prog_len = probe_filter_length(prog);
} /* If there were some map skips during fixup due to missing bpf *features,skipthistest.
*/ if (fixup_skips != skips) return;
pflags = testing_prog_flags(); if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT)
pflags |= BPF_F_STRICT_ALIGNMENT; if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
pflags |= BPF_F_ANY_ALIGNMENT; if (test->flags & ~3)
pflags |= test->flags;
if ((prog_type == BPF_PROG_TYPE_TRACING ||
prog_type == BPF_PROG_TYPE_LSM) && test->kfunc) { int attach_btf_id;
attach_btf_id = libbpf_find_vmlinux_btf_id(test->kfunc,
opts.expected_attach_type); if (attach_btf_id < 0) {
printf("FAIL\nFailed to find BTF ID for '%s'!\n",
test->kfunc);
(*errors)++; return;
}
opts.attach_btf_id = attach_btf_id;
}
if (test->btf_types[0] != 0) {
btf_fd = load_btf_for_test(test); if (btf_fd < 0) goto fail_log;
opts.prog_btf_fd = btf_fd;
}
for (i = 0; i < test->runs; i++) { if (unpriv && test->retvals[i].retval_unpriv)
expected_val = test->retvals[i].retval_unpriv; else
expected_val = test->retvals[i].retval;
if (!run_errs) {
(*passes)++; if (run_successes > 1)
printf("%d cases ", run_successes);
printf("OK"); if (alignment_prevented_execution)
printf(" (NOTE: not executed due to unknown alignment)");
printf("\n");
} else {
printf("\n"); goto fail_log;
}
close_fds: if (test->fill_insns)
free(test->fill_insns);
close(fd_prog);
close(btf_fd); for (i = 0; i < MAX_NR_MAPS; i++)
close(map_fds[i]);
sched_yield(); return;
fail_log:
(*errors)++;
printf("%s", bpf_vlog); goto close_fds;
}
staticbool is_admin(void)
{
__u64 caps;
/* The test checks for finer cap as CAP_NET_ADMIN, *CAP_PERFMON,andCAP_BPFinsteadofCAP_SYS_ADMIN. *Thus,disableCAP_SYS_ADMINatthebeginning.
*/ if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
perror("cap_disable_effective(CAP_SYS_ADMIN)"); returnfalse;
}
return (caps & ADMIN_CAPS) == ADMIN_CAPS;
}
staticbool test_as_unpriv(struct bpf_test *test)
{ #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS /* Some architectures have strict alignment requirements. In *thatcase,theBPFverifierdetectsifaprogramhas *unalignedaccessesandrejectsthem.Ausercanpass *BPF_F_ANY_ALIGNMENTtoaprogramtooverridethis *check.That,however,willonlyworkwhenaprivilegeduser *loadsaprogram.Anunprivilegeduserloadingaprogram *withthisflagwillberejectedpriorenteringthe *verifier.
*/ if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) returnfalse; #endif return !test->prog_type ||
test->prog_type == BPF_PROG_TYPE_SOCKET_FILTER ||
test->prog_type == BPF_PROG_TYPE_CGROUP_SKB;
}
staticint do_test(bool unpriv, unsignedint from, unsignedint to)
{ int i, passes = 0, errors = 0;
/* ensure previous instance of the module is unloaded */
unload_bpf_testmod(verbose);
if (load_bpf_testmod(verbose)) return EXIT_FAILURE;
for (i = from; i < to; i++) { struct bpf_test *test = &tests[i];
/* Program types that are not supported by non-root we *skiprightaway.
*/ if (test_as_unpriv(test) && unpriv_disabled) {
printf("#%d/u %s SKIP\n", i, test->descr);
skips++;
} elseif (test_as_unpriv(test)) { if (!unpriv)
set_admin(false);
printf("#%d/u %s ", i, test->descr);
do_test_single(test, true, &passes, &errors); if (!unpriv)
set_admin(true);
}
if (unpriv) {
printf("#%d/p %s SKIP\n", i, test->descr);
skips++;
} else {
printf("#%d/p %s ", i, test->descr);
do_test_single(test, false, &passes, &errors);
}
}
if (argc == 3) { unsignedint l = atoi(argv[arg]); unsignedint u = atoi(argv[arg + 1]);
if (l < to && u < to) {
from = l;
to = u + 1;
}
} elseif (argc == 2) { unsignedint t = atoi(argv[arg]);
if (t < to) {
from = t;
to = t + 1;
}
}
unpriv_disabled = get_unpriv_disabled(); if (unpriv && unpriv_disabled) {
printf("Cannot run as unprivileged user with sysctl %s.\n",
UNPRIV_SYSCTL); return EXIT_FAILURE;
}
jit_disabled = !is_jit_enabled();
/* Use libbpf 1.0 API mode */
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.