125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25aa5bd14SDaniel Borkmann /* 35aa5bd14SDaniel Borkmann * Testsuite for eBPF verifier 45aa5bd14SDaniel Borkmann * 55aa5bd14SDaniel Borkmann * Copyright (c) 2014 PLUMgrid, http://plumgrid.com 6a7ff3ecaSAlexei Starovoitov * Copyright (c) 2017 Facebook 7b584ab88SJoe Stringer * Copyright (c) 2018 Covalent IO, Inc. http://covalent.io 85aa5bd14SDaniel Borkmann */ 95aa5bd14SDaniel Borkmann 102c460621SDaniel Borkmann #include <endian.h> 111da8ac7cSAlexei Starovoitov #include <asm/types.h> 121da8ac7cSAlexei Starovoitov #include <linux/types.h> 13702498a1SMickaël Salaün #include <stdint.h> 145aa5bd14SDaniel Borkmann #include <stdio.h> 15702498a1SMickaël Salaün #include <stdlib.h> 165aa5bd14SDaniel Borkmann #include <unistd.h> 175aa5bd14SDaniel Borkmann #include <errno.h> 185aa5bd14SDaniel Borkmann #include <string.h> 195aa5bd14SDaniel Borkmann #include <stddef.h> 205aa5bd14SDaniel Borkmann #include <stdbool.h> 215aa5bd14SDaniel Borkmann #include <sched.h> 2221ccaf21SDaniel Borkmann #include <limits.h> 2380c9b2faSDaniel Borkmann #include <assert.h> 245aa5bd14SDaniel Borkmann 25d02d8986SMickaël Salaün #include <sys/capability.h> 265aa5bd14SDaniel Borkmann 275aa5bd14SDaniel Borkmann #include <linux/unistd.h> 285aa5bd14SDaniel Borkmann #include <linux/filter.h> 295aa5bd14SDaniel Borkmann #include <linux/bpf_perf_event.h> 305aa5bd14SDaniel Borkmann #include <linux/bpf.h> 31111e6b45SAlexei Starovoitov #include <linux/if_ether.h> 32b4d4556cSAlexei Starovoitov #include <linux/btf.h> 335aa5bd14SDaniel Borkmann 342ee89fb9SMickaël Salaün #include <bpf/bpf.h> 358184d44cSStanislav Fomichev #include <bpf/libbpf.h> 362ee89fb9SMickaël Salaün 3702ea80b1SDaniel Borkmann #ifdef HAVE_GENHDR 3802ea80b1SDaniel Borkmann # include "autoconf.h" 3902ea80b1SDaniel Borkmann #else 4002ea80b1SDaniel Borkmann # if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__) 4102ea80b1SDaniel Borkmann # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 4202ea80b1SDaniel Borkmann # endif 4302ea80b1SDaniel Borkmann #endif 44fe8d662aSDaniel Borkmann #include "bpf_rlimit.h" 45a82d8cd3SDaniel Borkmann #include "bpf_rand.h" 46aa5f0c96SMartin KaFai Lau #include "bpf_util.h" 477a9bb976SMartin KaFai Lau #include "test_btf.h" 485aa5bd14SDaniel Borkmann #include "../../../include/linux/filter.h" 495aa5bd14SDaniel Borkmann 50*5319255bSIlya Leoshkevich #ifndef ENOTSUPP 51*5319255bSIlya Leoshkevich #define ENOTSUPP 524 52*5319255bSIlya Leoshkevich #endif 53*5319255bSIlya Leoshkevich 5493731ef0SDaniel Borkmann #define MAX_INSNS BPF_MAXINSNS 558aa2d4b4SAlexei Starovoitov #define MAX_TEST_INSNS 1000000 565aa5bd14SDaniel Borkmann #define MAX_FIXUPS 8 574237e9f4SGilad Reti #define MAX_NR_MAPS 21 585a8d5209SJakub Kicinski #define MAX_TEST_RUNS 8 59111e6b45SAlexei Starovoitov #define POINTER_VALUE 0xcafe4all 60111e6b45SAlexei Starovoitov #define TEST_DATA_LEN 64 615aa5bd14SDaniel Borkmann 6202ea80b1SDaniel Borkmann #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) 63614d0d77SDaniel Borkmann #define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1) 6402ea80b1SDaniel Borkmann 650a674874SJoe Stringer #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" 660a674874SJoe Stringer static bool unpriv_disabled = false; 678184d44cSStanislav Fomichev static int skips; 68e8c13c4dSAlexei Starovoitov static bool verbose = false; 690a674874SJoe Stringer 705aa5bd14SDaniel Borkmann struct bpf_test { 715aa5bd14SDaniel Borkmann const char *descr; 725aa5bd14SDaniel Borkmann struct bpf_insn insns[MAX_INSNS]; 738aa2d4b4SAlexei Starovoitov struct bpf_insn *fill_insns; 74908142e6SPrashant Bhole int fixup_map_hash_8b[MAX_FIXUPS]; 75908142e6SPrashant Bhole int fixup_map_hash_48b[MAX_FIXUPS]; 76908142e6SPrashant Bhole int fixup_map_hash_16b[MAX_FIXUPS]; 77908142e6SPrashant Bhole int fixup_map_array_48b[MAX_FIXUPS]; 787c85c448SPrashant Bhole int fixup_map_sockmap[MAX_FIXUPS]; 797c85c448SPrashant Bhole int fixup_map_sockhash[MAX_FIXUPS]; 807c85c448SPrashant Bhole int fixup_map_xskmap[MAX_FIXUPS]; 817c85c448SPrashant Bhole int fixup_map_stacktrace[MAX_FIXUPS]; 8206be0864SDaniel Borkmann int fixup_prog1[MAX_FIXUPS]; 8306be0864SDaniel Borkmann int fixup_prog2[MAX_FIXUPS]; 84fb30d4b7SMartin KaFai Lau int fixup_map_in_map[MAX_FIXUPS]; 85d4c9f573SRoman Gushchin int fixup_cgroup_storage[MAX_FIXUPS]; 86a3c6054fSRoman Gushchin int fixup_percpu_cgroup_storage[MAX_FIXUPS]; 87b4d4556cSAlexei Starovoitov int fixup_map_spin_lock[MAX_FIXUPS]; 88fb2abb73SDaniel Borkmann int fixup_map_array_ro[MAX_FIXUPS]; 89fb2abb73SDaniel Borkmann int fixup_map_array_wo[MAX_FIXUPS]; 90fb2abb73SDaniel Borkmann int fixup_map_array_small[MAX_FIXUPS]; 917a9bb976SMartin KaFai Lau int fixup_sk_storage_map[MAX_FIXUPS]; 9203cd1d1aSAllan Zhang int fixup_map_event_output[MAX_FIXUPS]; 93c3210222SJakub Sitnicki int fixup_map_reuseport_array[MAX_FIXUPS]; 944237e9f4SGilad Reti int fixup_map_ringbuf[MAX_FIXUPS]; 95060fd103SAndrei Matei /* Expected verifier log output for result REJECT or VERBOSE_ACCEPT. 96060fd103SAndrei Matei * Can be a tab-separated sequence of expected strings. An empty string 97060fd103SAndrei Matei * means no log verification. 98060fd103SAndrei Matei */ 995aa5bd14SDaniel Borkmann const char *errstr; 1005aa5bd14SDaniel Borkmann const char *errstr_unpriv; 101d5e1db99SAndrii Nakryiko uint32_t insn_processed; 1028aa2d4b4SAlexei Starovoitov int prog_len; 1035aa5bd14SDaniel Borkmann enum { 1045aa5bd14SDaniel Borkmann UNDEF, 1055aa5bd14SDaniel Borkmann ACCEPT, 106e8c13c4dSAlexei Starovoitov REJECT, 107e8c13c4dSAlexei Starovoitov VERBOSE_ACCEPT, 1085aa5bd14SDaniel Borkmann } result, result_unpriv; 1095aa5bd14SDaniel Borkmann enum bpf_prog_type prog_type; 11002ea80b1SDaniel Borkmann uint8_t flags; 11193731ef0SDaniel Borkmann void (*fill_helper)(struct bpf_test *self); 112b4f89463SLorenz Bauer int runs; 113d5e1db99SAndrii Nakryiko #define bpf_testdata_struct_t \ 114d5e1db99SAndrii Nakryiko struct { \ 115d5e1db99SAndrii Nakryiko uint32_t retval, retval_unpriv; \ 116d5e1db99SAndrii Nakryiko union { \ 117d5e1db99SAndrii Nakryiko __u8 data[TEST_DATA_LEN]; \ 118d5e1db99SAndrii Nakryiko __u64 data64[TEST_DATA_LEN / 8]; \ 119d5e1db99SAndrii Nakryiko }; \ 120d5e1db99SAndrii Nakryiko } 1215a8d5209SJakub Kicinski union { 122d5e1db99SAndrii Nakryiko bpf_testdata_struct_t; 123d5e1db99SAndrii Nakryiko bpf_testdata_struct_t retvals[MAX_TEST_RUNS]; 1245a8d5209SJakub Kicinski }; 12576d95077SStanislav Fomichev enum bpf_attach_type expected_attach_type; 126762f8515SJiri Olsa const char *kfunc; 1275aa5bd14SDaniel Borkmann }; 1285aa5bd14SDaniel Borkmann 1295aa5bd14SDaniel Borkmann /* Note we want this to be 64 bit aligned so that the end of our array is 1305aa5bd14SDaniel Borkmann * actually the end of the structure. 1315aa5bd14SDaniel Borkmann */ 1325aa5bd14SDaniel Borkmann #define MAX_ENTRIES 11 1335aa5bd14SDaniel Borkmann 1345aa5bd14SDaniel Borkmann struct test_val { 1355aa5bd14SDaniel Borkmann unsigned int index; 1365aa5bd14SDaniel Borkmann int foo[MAX_ENTRIES]; 1375aa5bd14SDaniel Borkmann }; 1385aa5bd14SDaniel Borkmann 1395f90dd6aSPaul Chaignon struct other_val { 1405f90dd6aSPaul Chaignon long long foo; 1415f90dd6aSPaul Chaignon long long bar; 1425f90dd6aSPaul Chaignon }; 1435f90dd6aSPaul Chaignon 14493731ef0SDaniel Borkmann static void bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self) 14593731ef0SDaniel Borkmann { 1468aa2d4b4SAlexei Starovoitov /* test: {skb->data[0], vlan_push} x 51 + {skb->data[0], vlan_pop} x 51 */ 14793731ef0SDaniel Borkmann #define PUSH_CNT 51 1488aa2d4b4SAlexei Starovoitov /* jump range is limited to 16 bit. PUSH_CNT of ld_abs needs room */ 1498aa2d4b4SAlexei Starovoitov unsigned int len = (1 << 15) - PUSH_CNT * 2 * 5 * 6; 1508aa2d4b4SAlexei Starovoitov struct bpf_insn *insn = self->fill_insns; 15193731ef0SDaniel Borkmann int i = 0, j, k = 0; 15293731ef0SDaniel Borkmann 15393731ef0SDaniel Borkmann insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); 15493731ef0SDaniel Borkmann loop: 15593731ef0SDaniel Borkmann for (j = 0; j < PUSH_CNT; j++) { 15693731ef0SDaniel Borkmann insn[i++] = BPF_LD_ABS(BPF_B, 0); 157f3b55abbSJiong Wang /* jump to error label */ 158f3b55abbSJiong Wang insn[i] = BPF_JMP32_IMM(BPF_JNE, BPF_REG_0, 0x34, len - i - 3); 15993731ef0SDaniel Borkmann i++; 16093731ef0SDaniel Borkmann insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6); 16193731ef0SDaniel Borkmann insn[i++] = BPF_MOV64_IMM(BPF_REG_2, 1); 16293731ef0SDaniel Borkmann insn[i++] = BPF_MOV64_IMM(BPF_REG_3, 2); 16393731ef0SDaniel Borkmann insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 16493731ef0SDaniel Borkmann BPF_FUNC_skb_vlan_push), 165f3b55abbSJiong Wang insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, len - i - 3); 16693731ef0SDaniel Borkmann i++; 16793731ef0SDaniel Borkmann } 16893731ef0SDaniel Borkmann 16993731ef0SDaniel Borkmann for (j = 0; j < PUSH_CNT; j++) { 17093731ef0SDaniel Borkmann insn[i++] = BPF_LD_ABS(BPF_B, 0); 171f3b55abbSJiong Wang insn[i] = BPF_JMP32_IMM(BPF_JNE, BPF_REG_0, 0x34, len - i - 3); 17293731ef0SDaniel Borkmann i++; 17393731ef0SDaniel Borkmann insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6); 17493731ef0SDaniel Borkmann insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 17593731ef0SDaniel Borkmann BPF_FUNC_skb_vlan_pop), 176f3b55abbSJiong Wang insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, len - i - 3); 17793731ef0SDaniel Borkmann i++; 17893731ef0SDaniel Borkmann } 17993731ef0SDaniel Borkmann if (++k < 5) 18093731ef0SDaniel Borkmann goto loop; 18193731ef0SDaniel Borkmann 182f3b55abbSJiong Wang for (; i < len - 3; i++) 183f3b55abbSJiong Wang insn[i] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0xbef); 184f3b55abbSJiong Wang insn[len - 3] = BPF_JMP_A(1); 185f3b55abbSJiong Wang /* error label */ 186f3b55abbSJiong Wang insn[len - 2] = BPF_MOV32_IMM(BPF_REG_0, 0); 18793731ef0SDaniel Borkmann insn[len - 1] = BPF_EXIT_INSN(); 1888aa2d4b4SAlexei Starovoitov self->prog_len = len; 18993731ef0SDaniel Borkmann } 19093731ef0SDaniel Borkmann 19193731ef0SDaniel Borkmann static void bpf_fill_jump_around_ld_abs(struct bpf_test *self) 19293731ef0SDaniel Borkmann { 1938aa2d4b4SAlexei Starovoitov struct bpf_insn *insn = self->fill_insns; 194f3b55abbSJiong Wang /* jump range is limited to 16 bit. every ld_abs is replaced by 6 insns, 195f3b55abbSJiong Wang * but on arches like arm, ppc etc, there will be one BPF_ZEXT inserted 196f3b55abbSJiong Wang * to extend the error value of the inlined ld_abs sequence which then 197f3b55abbSJiong Wang * contains 7 insns. so, set the dividend to 7 so the testcase could 198f3b55abbSJiong Wang * work on all arches. 199f3b55abbSJiong Wang */ 200f3b55abbSJiong Wang unsigned int len = (1 << 15) / 7; 20193731ef0SDaniel Borkmann int i = 0; 20293731ef0SDaniel Borkmann 20393731ef0SDaniel Borkmann insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); 20493731ef0SDaniel Borkmann insn[i++] = BPF_LD_ABS(BPF_B, 0); 20593731ef0SDaniel Borkmann insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 10, len - i - 2); 20693731ef0SDaniel Borkmann i++; 20793731ef0SDaniel Borkmann while (i < len - 1) 20893731ef0SDaniel Borkmann insn[i++] = BPF_LD_ABS(BPF_B, 1); 20993731ef0SDaniel Borkmann insn[i] = BPF_EXIT_INSN(); 2108aa2d4b4SAlexei Starovoitov self->prog_len = i + 1; 21193731ef0SDaniel Borkmann } 21293731ef0SDaniel Borkmann 213a82d8cd3SDaniel Borkmann static void bpf_fill_rand_ld_dw(struct bpf_test *self) 214a82d8cd3SDaniel Borkmann { 2158aa2d4b4SAlexei Starovoitov struct bpf_insn *insn = self->fill_insns; 216a82d8cd3SDaniel Borkmann uint64_t res = 0; 217a82d8cd3SDaniel Borkmann int i = 0; 218a82d8cd3SDaniel Borkmann 219a82d8cd3SDaniel Borkmann insn[i++] = BPF_MOV32_IMM(BPF_REG_0, 0); 220a82d8cd3SDaniel Borkmann while (i < self->retval) { 221a82d8cd3SDaniel Borkmann uint64_t val = bpf_semi_rand_get(); 222a82d8cd3SDaniel Borkmann struct bpf_insn tmp[2] = { BPF_LD_IMM64(BPF_REG_1, val) }; 223a82d8cd3SDaniel Borkmann 224a82d8cd3SDaniel Borkmann res ^= val; 225a82d8cd3SDaniel Borkmann insn[i++] = tmp[0]; 226a82d8cd3SDaniel Borkmann insn[i++] = tmp[1]; 227a82d8cd3SDaniel Borkmann insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1); 228a82d8cd3SDaniel Borkmann } 229a82d8cd3SDaniel Borkmann insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_0); 230a82d8cd3SDaniel Borkmann insn[i++] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 32); 231a82d8cd3SDaniel Borkmann insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1); 232a82d8cd3SDaniel Borkmann insn[i] = BPF_EXIT_INSN(); 2338aa2d4b4SAlexei Starovoitov self->prog_len = i + 1; 234a82d8cd3SDaniel Borkmann res ^= (res >> 32); 235a82d8cd3SDaniel Borkmann self->retval = (uint32_t)res; 236a82d8cd3SDaniel Borkmann } 237a82d8cd3SDaniel Borkmann 2387c0c6095SAlexei Starovoitov #define MAX_JMP_SEQ 8192 2397c0c6095SAlexei Starovoitov 2407c0c6095SAlexei Starovoitov /* test the sequence of 8k jumps */ 24108de198cSAlexei Starovoitov static void bpf_fill_scale1(struct bpf_test *self) 24208de198cSAlexei Starovoitov { 24308de198cSAlexei Starovoitov struct bpf_insn *insn = self->fill_insns; 24408de198cSAlexei Starovoitov int i = 0, k = 0; 24508de198cSAlexei Starovoitov 24608de198cSAlexei Starovoitov insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); 2477c0c6095SAlexei Starovoitov /* test to check that the long sequence of jumps is acceptable */ 2487c0c6095SAlexei Starovoitov while (k++ < MAX_JMP_SEQ) { 24908de198cSAlexei Starovoitov insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 25008de198cSAlexei Starovoitov BPF_FUNC_get_prandom_u32); 2517c0c6095SAlexei Starovoitov insn[i++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, bpf_semi_rand_get(), 2); 25208de198cSAlexei Starovoitov insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10); 25308de198cSAlexei Starovoitov insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 25408de198cSAlexei Starovoitov -8 * (k % 64 + 1)); 25508de198cSAlexei Starovoitov } 256aeee380cSAlexei Starovoitov /* is_state_visited() doesn't allocate state for pruning for every jump. 257aeee380cSAlexei Starovoitov * Hence multiply jmps by 4 to accommodate that heuristic 25808de198cSAlexei Starovoitov */ 259aeee380cSAlexei Starovoitov while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4) 260f3b55abbSJiong Wang insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42); 26108de198cSAlexei Starovoitov insn[i] = BPF_EXIT_INSN(); 26208de198cSAlexei Starovoitov self->prog_len = i + 1; 26308de198cSAlexei Starovoitov self->retval = 42; 26408de198cSAlexei Starovoitov } 26508de198cSAlexei Starovoitov 2667c0c6095SAlexei Starovoitov /* test the sequence of 8k jumps in inner most function (function depth 8)*/ 26708de198cSAlexei Starovoitov static void bpf_fill_scale2(struct bpf_test *self) 26808de198cSAlexei Starovoitov { 26908de198cSAlexei Starovoitov struct bpf_insn *insn = self->fill_insns; 27008de198cSAlexei Starovoitov int i = 0, k = 0; 27108de198cSAlexei Starovoitov 27208de198cSAlexei Starovoitov #define FUNC_NEST 7 27308de198cSAlexei Starovoitov for (k = 0; k < FUNC_NEST; k++) { 27408de198cSAlexei Starovoitov insn[i++] = BPF_CALL_REL(1); 27508de198cSAlexei Starovoitov insn[i++] = BPF_EXIT_INSN(); 27608de198cSAlexei Starovoitov } 27708de198cSAlexei Starovoitov insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); 2787c0c6095SAlexei Starovoitov /* test to check that the long sequence of jumps is acceptable */ 2797c0c6095SAlexei Starovoitov k = 0; 2807c0c6095SAlexei Starovoitov while (k++ < MAX_JMP_SEQ) { 28108de198cSAlexei Starovoitov insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 28208de198cSAlexei Starovoitov BPF_FUNC_get_prandom_u32); 2837c0c6095SAlexei Starovoitov insn[i++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, bpf_semi_rand_get(), 2); 28408de198cSAlexei Starovoitov insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10); 28508de198cSAlexei Starovoitov insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 28608de198cSAlexei Starovoitov -8 * (k % (64 - 4 * FUNC_NEST) + 1)); 28708de198cSAlexei Starovoitov } 288aeee380cSAlexei Starovoitov while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4) 289f3b55abbSJiong Wang insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42); 29008de198cSAlexei Starovoitov insn[i] = BPF_EXIT_INSN(); 29108de198cSAlexei Starovoitov self->prog_len = i + 1; 29208de198cSAlexei Starovoitov self->retval = 42; 29308de198cSAlexei Starovoitov } 29408de198cSAlexei Starovoitov 29508de198cSAlexei Starovoitov static void bpf_fill_scale(struct bpf_test *self) 29608de198cSAlexei Starovoitov { 29708de198cSAlexei Starovoitov switch (self->retval) { 29808de198cSAlexei Starovoitov case 1: 29908de198cSAlexei Starovoitov return bpf_fill_scale1(self); 30008de198cSAlexei Starovoitov case 2: 30108de198cSAlexei Starovoitov return bpf_fill_scale2(self); 30208de198cSAlexei Starovoitov default: 30308de198cSAlexei Starovoitov self->prog_len = 0; 30408de198cSAlexei Starovoitov break; 30508de198cSAlexei Starovoitov } 30608de198cSAlexei Starovoitov } 30708de198cSAlexei Starovoitov 30879d1b684SGary Lin static int bpf_fill_torturous_jumps_insn_1(struct bpf_insn *insn) 30979d1b684SGary Lin { 31079d1b684SGary Lin unsigned int len = 259, hlen = 128; 31179d1b684SGary Lin int i; 31279d1b684SGary Lin 31379d1b684SGary Lin insn[0] = BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32); 31479d1b684SGary Lin for (i = 1; i <= hlen; i++) { 31579d1b684SGary Lin insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, i, hlen); 31679d1b684SGary Lin insn[i + hlen] = BPF_JMP_A(hlen - i); 31779d1b684SGary Lin } 31879d1b684SGary Lin insn[len - 2] = BPF_MOV64_IMM(BPF_REG_0, 1); 31979d1b684SGary Lin insn[len - 1] = BPF_EXIT_INSN(); 32079d1b684SGary Lin 32179d1b684SGary Lin return len; 32279d1b684SGary Lin } 32379d1b684SGary Lin 32479d1b684SGary Lin static int bpf_fill_torturous_jumps_insn_2(struct bpf_insn *insn) 32579d1b684SGary Lin { 32679d1b684SGary Lin unsigned int len = 4100, jmp_off = 2048; 32779d1b684SGary Lin int i, j; 32879d1b684SGary Lin 32979d1b684SGary Lin insn[0] = BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32); 33079d1b684SGary Lin for (i = 1; i <= jmp_off; i++) { 33179d1b684SGary Lin insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, i, jmp_off); 33279d1b684SGary Lin } 33379d1b684SGary Lin insn[i++] = BPF_JMP_A(jmp_off); 33479d1b684SGary Lin for (; i <= jmp_off * 2 + 1; i+=16) { 33579d1b684SGary Lin for (j = 0; j < 16; j++) { 33679d1b684SGary Lin insn[i + j] = BPF_JMP_A(16 - j - 1); 33779d1b684SGary Lin } 33879d1b684SGary Lin } 33979d1b684SGary Lin 34079d1b684SGary Lin insn[len - 2] = BPF_MOV64_IMM(BPF_REG_0, 2); 34179d1b684SGary Lin insn[len - 1] = BPF_EXIT_INSN(); 34279d1b684SGary Lin 34379d1b684SGary Lin return len; 34479d1b684SGary Lin } 34579d1b684SGary Lin 34679d1b684SGary Lin static void bpf_fill_torturous_jumps(struct bpf_test *self) 34779d1b684SGary Lin { 34879d1b684SGary Lin struct bpf_insn *insn = self->fill_insns; 34979d1b684SGary Lin int i = 0; 35079d1b684SGary Lin 35179d1b684SGary Lin switch (self->retval) { 35279d1b684SGary Lin case 1: 35379d1b684SGary Lin self->prog_len = bpf_fill_torturous_jumps_insn_1(insn); 35479d1b684SGary Lin return; 35579d1b684SGary Lin case 2: 35679d1b684SGary Lin self->prog_len = bpf_fill_torturous_jumps_insn_2(insn); 35779d1b684SGary Lin return; 35879d1b684SGary Lin case 3: 35979d1b684SGary Lin /* main */ 36079d1b684SGary Lin insn[i++] = BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 4); 36179d1b684SGary Lin insn[i++] = BPF_RAW_INSN(BPF_JMP|BPF_CALL, 0, 1, 0, 262); 36279d1b684SGary Lin insn[i++] = BPF_ST_MEM(BPF_B, BPF_REG_10, -32, 0); 36379d1b684SGary Lin insn[i++] = BPF_MOV64_IMM(BPF_REG_0, 3); 36479d1b684SGary Lin insn[i++] = BPF_EXIT_INSN(); 36579d1b684SGary Lin 36679d1b684SGary Lin /* subprog 1 */ 36779d1b684SGary Lin i += bpf_fill_torturous_jumps_insn_1(insn + i); 36879d1b684SGary Lin 36979d1b684SGary Lin /* subprog 2 */ 37079d1b684SGary Lin i += bpf_fill_torturous_jumps_insn_2(insn + i); 37179d1b684SGary Lin 37279d1b684SGary Lin self->prog_len = i; 37379d1b684SGary Lin return; 37479d1b684SGary Lin default: 37579d1b684SGary Lin self->prog_len = 0; 37679d1b684SGary Lin break; 37779d1b684SGary Lin } 37879d1b684SGary Lin } 37979d1b684SGary Lin 380b584ab88SJoe Stringer /* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */ 381dbaf2877SLorenz Bauer #define BPF_SK_LOOKUP(func) \ 382b584ab88SJoe Stringer /* struct bpf_sock_tuple tuple = {} */ \ 383b584ab88SJoe Stringer BPF_MOV64_IMM(BPF_REG_2, 0), \ 384b584ab88SJoe Stringer BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8), \ 385b584ab88SJoe Stringer BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -16), \ 386b584ab88SJoe Stringer BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -24), \ 387b584ab88SJoe Stringer BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -32), \ 388b584ab88SJoe Stringer BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -40), \ 389b584ab88SJoe Stringer BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -48), \ 390dbaf2877SLorenz Bauer /* sk = func(ctx, &tuple, sizeof tuple, 0, 0) */ \ 391b584ab88SJoe Stringer BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), \ 392b584ab88SJoe Stringer BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48), \ 393b584ab88SJoe Stringer BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_sock_tuple)), \ 394b584ab88SJoe Stringer BPF_MOV64_IMM(BPF_REG_4, 0), \ 395b584ab88SJoe Stringer BPF_MOV64_IMM(BPF_REG_5, 0), \ 396dbaf2877SLorenz Bauer BPF_EMIT_CALL(BPF_FUNC_ ## func) 397b584ab88SJoe Stringer 3986ea848b5SJiong Wang /* BPF_DIRECT_PKT_R2 contains 7 instructions, it initializes default return 3996ea848b5SJiong Wang * value into 0 and does necessary preparation for direct packet access 4006ea848b5SJiong Wang * through r2. The allowed access range is 8 bytes. 4016ea848b5SJiong Wang */ 4026ea848b5SJiong Wang #define BPF_DIRECT_PKT_R2 \ 4036ea848b5SJiong Wang BPF_MOV64_IMM(BPF_REG_0, 0), \ 4046ea848b5SJiong Wang BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \ 4056ea848b5SJiong Wang offsetof(struct __sk_buff, data)), \ 4066ea848b5SJiong Wang BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \ 4076ea848b5SJiong Wang offsetof(struct __sk_buff, data_end)), \ 4086ea848b5SJiong Wang BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), \ 4096ea848b5SJiong Wang BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), \ 4106ea848b5SJiong Wang BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1), \ 4116ea848b5SJiong Wang BPF_EXIT_INSN() 4126ea848b5SJiong Wang 4136ea848b5SJiong Wang /* BPF_RAND_UEXT_R7 contains 4 instructions, it initializes R7 into a random 4146ea848b5SJiong Wang * positive u32, and zero-extend it into 64-bit. 4156ea848b5SJiong Wang */ 4166ea848b5SJiong Wang #define BPF_RAND_UEXT_R7 \ 4176ea848b5SJiong Wang BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, \ 4186ea848b5SJiong Wang BPF_FUNC_get_prandom_u32), \ 4196ea848b5SJiong Wang BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), \ 4206ea848b5SJiong Wang BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 33), \ 4216ea848b5SJiong Wang BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 33) 4226ea848b5SJiong Wang 4236ea848b5SJiong Wang /* BPF_RAND_SEXT_R7 contains 5 instructions, it initializes R7 into a random 4246ea848b5SJiong Wang * negative u32, and sign-extend it into 64-bit. 4256ea848b5SJiong Wang */ 4266ea848b5SJiong Wang #define BPF_RAND_SEXT_R7 \ 4276ea848b5SJiong Wang BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, \ 4286ea848b5SJiong Wang BPF_FUNC_get_prandom_u32), \ 4296ea848b5SJiong Wang BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), \ 4306ea848b5SJiong Wang BPF_ALU64_IMM(BPF_OR, BPF_REG_7, 0x80000000), \ 4316ea848b5SJiong Wang BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 32), \ 4326ea848b5SJiong Wang BPF_ALU64_IMM(BPF_ARSH, BPF_REG_7, 32) 4336ea848b5SJiong Wang 4345aa5bd14SDaniel Borkmann static struct bpf_test tests[] = { 4352dfb4012SJakub Kicinski #define FILL_ARRAY 4362dfb4012SJakub Kicinski #include <verifier/tests.h> 4372dfb4012SJakub Kicinski #undef FILL_ARRAY 4385aa5bd14SDaniel Borkmann }; 4395aa5bd14SDaniel Borkmann 4405aa5bd14SDaniel Borkmann static int probe_filter_length(const struct bpf_insn *fp) 4415aa5bd14SDaniel Borkmann { 4425aa5bd14SDaniel Borkmann int len; 4435aa5bd14SDaniel Borkmann 4445aa5bd14SDaniel Borkmann for (len = MAX_INSNS - 1; len > 0; --len) 4455aa5bd14SDaniel Borkmann if (fp[len].code != 0 || fp[len].imm != 0) 4465aa5bd14SDaniel Borkmann break; 4475aa5bd14SDaniel Borkmann return len + 1; 4485aa5bd14SDaniel Borkmann } 4495aa5bd14SDaniel Borkmann 4509acea337SStanislav Fomichev static bool skip_unsupported_map(enum bpf_map_type map_type) 4519acea337SStanislav Fomichev { 4529acea337SStanislav Fomichev if (!bpf_probe_map_type(map_type, 0)) { 4539acea337SStanislav Fomichev printf("SKIP (unsupported map type %d)\n", map_type); 4549acea337SStanislav Fomichev skips++; 4559acea337SStanislav Fomichev return true; 4569acea337SStanislav Fomichev } 4579acea337SStanislav Fomichev return false; 4589acea337SStanislav Fomichev } 4599acea337SStanislav Fomichev 460fb2abb73SDaniel Borkmann static int __create_map(uint32_t type, uint32_t size_key, 461fb2abb73SDaniel Borkmann uint32_t size_value, uint32_t max_elem, 462fb2abb73SDaniel Borkmann uint32_t extra_flags) 4635aa5bd14SDaniel Borkmann { 4645aa5bd14SDaniel Borkmann int fd; 4655aa5bd14SDaniel Borkmann 46606be0864SDaniel Borkmann fd = bpf_create_map(type, size_key, size_value, max_elem, 467fb2abb73SDaniel Borkmann (type == BPF_MAP_TYPE_HASH ? 468fb2abb73SDaniel Borkmann BPF_F_NO_PREALLOC : 0) | extra_flags); 4699acea337SStanislav Fomichev if (fd < 0) { 4709acea337SStanislav Fomichev if (skip_unsupported_map(type)) 4719acea337SStanislav Fomichev return -1; 4725aa5bd14SDaniel Borkmann printf("Failed to create hash map '%s'!\n", strerror(errno)); 4739acea337SStanislav Fomichev } 4745aa5bd14SDaniel Borkmann 4755aa5bd14SDaniel Borkmann return fd; 4765aa5bd14SDaniel Borkmann } 4775aa5bd14SDaniel Borkmann 478fb2abb73SDaniel Borkmann static int create_map(uint32_t type, uint32_t size_key, 479fb2abb73SDaniel Borkmann uint32_t size_value, uint32_t max_elem) 480fb2abb73SDaniel Borkmann { 481fb2abb73SDaniel Borkmann return __create_map(type, size_key, size_value, max_elem, 0); 482fb2abb73SDaniel Borkmann } 483fb2abb73SDaniel Borkmann 48480c9b2faSDaniel Borkmann static void update_map(int fd, int index) 48580c9b2faSDaniel Borkmann { 48680c9b2faSDaniel Borkmann struct test_val value = { 48780c9b2faSDaniel Borkmann .index = (6 + 1) * sizeof(int), 48880c9b2faSDaniel Borkmann .foo[6] = 0xabcdef12, 48980c9b2faSDaniel Borkmann }; 49080c9b2faSDaniel Borkmann 49180c9b2faSDaniel Borkmann assert(!bpf_map_update_elem(fd, &index, &value, 0)); 49280c9b2faSDaniel Borkmann } 49380c9b2faSDaniel Borkmann 4943123d801SDaniel Borkmann static int create_prog_dummy_simple(enum bpf_prog_type prog_type, int ret) 495b33eb735SDaniel Borkmann { 496b33eb735SDaniel Borkmann struct bpf_insn prog[] = { 4973123d801SDaniel Borkmann BPF_MOV64_IMM(BPF_REG_0, ret), 498b33eb735SDaniel Borkmann BPF_EXIT_INSN(), 499b33eb735SDaniel Borkmann }; 500b33eb735SDaniel Borkmann 5010c586079SJoe Stringer return bpf_load_program(prog_type, prog, 502b33eb735SDaniel Borkmann ARRAY_SIZE(prog), "GPL", 0, NULL, 0); 503b33eb735SDaniel Borkmann } 504b33eb735SDaniel Borkmann 5053123d801SDaniel Borkmann static int create_prog_dummy_loop(enum bpf_prog_type prog_type, int mfd, 5063123d801SDaniel Borkmann int idx, int ret) 507b33eb735SDaniel Borkmann { 508b33eb735SDaniel Borkmann struct bpf_insn prog[] = { 509b33eb735SDaniel Borkmann BPF_MOV64_IMM(BPF_REG_3, idx), 510b33eb735SDaniel Borkmann BPF_LD_MAP_FD(BPF_REG_2, mfd), 511b33eb735SDaniel Borkmann BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 512b33eb735SDaniel Borkmann BPF_FUNC_tail_call), 5133123d801SDaniel Borkmann BPF_MOV64_IMM(BPF_REG_0, ret), 514b33eb735SDaniel Borkmann BPF_EXIT_INSN(), 515b33eb735SDaniel Borkmann }; 516b33eb735SDaniel Borkmann 5170c586079SJoe Stringer return bpf_load_program(prog_type, prog, 518b33eb735SDaniel Borkmann ARRAY_SIZE(prog), "GPL", 0, NULL, 0); 519b33eb735SDaniel Borkmann } 520b33eb735SDaniel Borkmann 521aca1a80eSStanislav Fomichev static int create_prog_array(enum bpf_prog_type prog_type, uint32_t max_elem, 5223123d801SDaniel Borkmann int p1key, int p2key, int p3key) 5235aa5bd14SDaniel Borkmann { 5243123d801SDaniel Borkmann int mfd, p1fd, p2fd, p3fd; 5255aa5bd14SDaniel Borkmann 526b33eb735SDaniel Borkmann mfd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int), 52706be0864SDaniel Borkmann sizeof(int), max_elem, 0); 528b33eb735SDaniel Borkmann if (mfd < 0) { 5299acea337SStanislav Fomichev if (skip_unsupported_map(BPF_MAP_TYPE_PROG_ARRAY)) 5309acea337SStanislav Fomichev return -1; 5315aa5bd14SDaniel Borkmann printf("Failed to create prog array '%s'!\n", strerror(errno)); 532b33eb735SDaniel Borkmann return -1; 533b33eb735SDaniel Borkmann } 5345aa5bd14SDaniel Borkmann 5353123d801SDaniel Borkmann p1fd = create_prog_dummy_simple(prog_type, 42); 5363123d801SDaniel Borkmann p2fd = create_prog_dummy_loop(prog_type, mfd, p2key, 41); 5373123d801SDaniel Borkmann p3fd = create_prog_dummy_simple(prog_type, 24); 5383123d801SDaniel Borkmann if (p1fd < 0 || p2fd < 0 || p3fd < 0) 5393123d801SDaniel Borkmann goto err; 540b33eb735SDaniel Borkmann if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0) 5413123d801SDaniel Borkmann goto err; 542b33eb735SDaniel Borkmann if (bpf_map_update_elem(mfd, &p2key, &p2fd, BPF_ANY) < 0) 5433123d801SDaniel Borkmann goto err; 5443123d801SDaniel Borkmann if (bpf_map_update_elem(mfd, &p3key, &p3fd, BPF_ANY) < 0) { 5453123d801SDaniel Borkmann err: 546b33eb735SDaniel Borkmann close(mfd); 5473123d801SDaniel Borkmann mfd = -1; 5483123d801SDaniel Borkmann } 5493123d801SDaniel Borkmann close(p3fd); 5503123d801SDaniel Borkmann close(p2fd); 5513123d801SDaniel Borkmann close(p1fd); 5523123d801SDaniel Borkmann return mfd; 5535aa5bd14SDaniel Borkmann } 5545aa5bd14SDaniel Borkmann 555fb30d4b7SMartin KaFai Lau static int create_map_in_map(void) 556fb30d4b7SMartin KaFai Lau { 557fb30d4b7SMartin KaFai Lau int inner_map_fd, outer_map_fd; 558fb30d4b7SMartin KaFai Lau 559fb30d4b7SMartin KaFai Lau inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), 560fb30d4b7SMartin KaFai Lau sizeof(int), 1, 0); 561fb30d4b7SMartin KaFai Lau if (inner_map_fd < 0) { 5629acea337SStanislav Fomichev if (skip_unsupported_map(BPF_MAP_TYPE_ARRAY)) 5639acea337SStanislav Fomichev return -1; 564fb30d4b7SMartin KaFai Lau printf("Failed to create array '%s'!\n", strerror(errno)); 565fb30d4b7SMartin KaFai Lau return inner_map_fd; 566fb30d4b7SMartin KaFai Lau } 567fb30d4b7SMartin KaFai Lau 56888cda1c9SMartin KaFai Lau outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL, 569fb30d4b7SMartin KaFai Lau sizeof(int), inner_map_fd, 1, 0); 5709acea337SStanislav Fomichev if (outer_map_fd < 0) { 5719acea337SStanislav Fomichev if (skip_unsupported_map(BPF_MAP_TYPE_ARRAY_OF_MAPS)) 5729acea337SStanislav Fomichev return -1; 573fb30d4b7SMartin KaFai Lau printf("Failed to create array of maps '%s'!\n", 574fb30d4b7SMartin KaFai Lau strerror(errno)); 5759acea337SStanislav Fomichev } 576fb30d4b7SMartin KaFai Lau 577fb30d4b7SMartin KaFai Lau close(inner_map_fd); 578fb30d4b7SMartin KaFai Lau 579fb30d4b7SMartin KaFai Lau return outer_map_fd; 580fb30d4b7SMartin KaFai Lau } 581fb30d4b7SMartin KaFai Lau 582a3c6054fSRoman Gushchin static int create_cgroup_storage(bool percpu) 583d4c9f573SRoman Gushchin { 584a3c6054fSRoman Gushchin enum bpf_map_type type = percpu ? BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE : 585a3c6054fSRoman Gushchin BPF_MAP_TYPE_CGROUP_STORAGE; 586d4c9f573SRoman Gushchin int fd; 587d4c9f573SRoman Gushchin 588a3c6054fSRoman Gushchin fd = bpf_create_map(type, sizeof(struct bpf_cgroup_storage_key), 589d4c9f573SRoman Gushchin TEST_DATA_LEN, 0, 0); 5909acea337SStanislav Fomichev if (fd < 0) { 5919acea337SStanislav Fomichev if (skip_unsupported_map(type)) 5929acea337SStanislav Fomichev return -1; 593a3c6054fSRoman Gushchin printf("Failed to create cgroup storage '%s'!\n", 594a3c6054fSRoman Gushchin strerror(errno)); 5959acea337SStanislav Fomichev } 596d4c9f573SRoman Gushchin 597d4c9f573SRoman Gushchin return fd; 598d4c9f573SRoman Gushchin } 599d4c9f573SRoman Gushchin 600b4d4556cSAlexei Starovoitov /* struct bpf_spin_lock { 601b4d4556cSAlexei Starovoitov * int val; 602b4d4556cSAlexei Starovoitov * }; 603b4d4556cSAlexei Starovoitov * struct val { 604b4d4556cSAlexei Starovoitov * int cnt; 605b4d4556cSAlexei Starovoitov * struct bpf_spin_lock l; 606b4d4556cSAlexei Starovoitov * }; 607b4d4556cSAlexei Starovoitov */ 608b4d4556cSAlexei Starovoitov static const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l"; 609b4d4556cSAlexei Starovoitov static __u32 btf_raw_types[] = { 610b4d4556cSAlexei Starovoitov /* int */ 611b4d4556cSAlexei Starovoitov BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 612b4d4556cSAlexei Starovoitov /* struct bpf_spin_lock */ /* [2] */ 613b4d4556cSAlexei Starovoitov BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4), 614b4d4556cSAlexei Starovoitov BTF_MEMBER_ENC(15, 1, 0), /* int val; */ 615b4d4556cSAlexei Starovoitov /* struct val */ /* [3] */ 616b4d4556cSAlexei Starovoitov BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8), 617b4d4556cSAlexei Starovoitov BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */ 618b4d4556cSAlexei Starovoitov BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */ 619b4d4556cSAlexei Starovoitov }; 620b4d4556cSAlexei Starovoitov 621b4d4556cSAlexei Starovoitov static int load_btf(void) 622b4d4556cSAlexei Starovoitov { 623b4d4556cSAlexei Starovoitov struct btf_header hdr = { 624b4d4556cSAlexei Starovoitov .magic = BTF_MAGIC, 625b4d4556cSAlexei Starovoitov .version = BTF_VERSION, 626b4d4556cSAlexei Starovoitov .hdr_len = sizeof(struct btf_header), 627b4d4556cSAlexei Starovoitov .type_len = sizeof(btf_raw_types), 628b4d4556cSAlexei Starovoitov .str_off = sizeof(btf_raw_types), 629b4d4556cSAlexei Starovoitov .str_len = sizeof(btf_str_sec), 630b4d4556cSAlexei Starovoitov }; 631b4d4556cSAlexei Starovoitov void *ptr, *raw_btf; 632b4d4556cSAlexei Starovoitov int btf_fd; 633b4d4556cSAlexei Starovoitov 634b4d4556cSAlexei Starovoitov ptr = raw_btf = malloc(sizeof(hdr) + sizeof(btf_raw_types) + 635b4d4556cSAlexei Starovoitov sizeof(btf_str_sec)); 636b4d4556cSAlexei Starovoitov 637b4d4556cSAlexei Starovoitov memcpy(ptr, &hdr, sizeof(hdr)); 638b4d4556cSAlexei Starovoitov ptr += sizeof(hdr); 639b4d4556cSAlexei Starovoitov memcpy(ptr, btf_raw_types, hdr.type_len); 640b4d4556cSAlexei Starovoitov ptr += hdr.type_len; 641b4d4556cSAlexei Starovoitov memcpy(ptr, btf_str_sec, hdr.str_len); 642b4d4556cSAlexei Starovoitov ptr += hdr.str_len; 643b4d4556cSAlexei Starovoitov 644b4d4556cSAlexei Starovoitov btf_fd = bpf_load_btf(raw_btf, ptr - raw_btf, 0, 0, 0); 645b4d4556cSAlexei Starovoitov free(raw_btf); 646b4d4556cSAlexei Starovoitov if (btf_fd < 0) 647b4d4556cSAlexei Starovoitov return -1; 648b4d4556cSAlexei Starovoitov return btf_fd; 649b4d4556cSAlexei Starovoitov } 650b4d4556cSAlexei Starovoitov 651b4d4556cSAlexei Starovoitov static int create_map_spin_lock(void) 652b4d4556cSAlexei Starovoitov { 653b4d4556cSAlexei Starovoitov struct bpf_create_map_attr attr = { 654b4d4556cSAlexei Starovoitov .name = "test_map", 655b4d4556cSAlexei Starovoitov .map_type = BPF_MAP_TYPE_ARRAY, 656b4d4556cSAlexei Starovoitov .key_size = 4, 657b4d4556cSAlexei Starovoitov .value_size = 8, 658b4d4556cSAlexei Starovoitov .max_entries = 1, 659b4d4556cSAlexei Starovoitov .btf_key_type_id = 1, 660b4d4556cSAlexei Starovoitov .btf_value_type_id = 3, 661b4d4556cSAlexei Starovoitov }; 662b4d4556cSAlexei Starovoitov int fd, btf_fd; 663b4d4556cSAlexei Starovoitov 664b4d4556cSAlexei Starovoitov btf_fd = load_btf(); 665b4d4556cSAlexei Starovoitov if (btf_fd < 0) 666b4d4556cSAlexei Starovoitov return -1; 667b4d4556cSAlexei Starovoitov attr.btf_fd = btf_fd; 668b4d4556cSAlexei Starovoitov fd = bpf_create_map_xattr(&attr); 669b4d4556cSAlexei Starovoitov if (fd < 0) 670b4d4556cSAlexei Starovoitov printf("Failed to create map with spin_lock\n"); 671b4d4556cSAlexei Starovoitov return fd; 672b4d4556cSAlexei Starovoitov } 673b4d4556cSAlexei Starovoitov 6747a9bb976SMartin KaFai Lau static int create_sk_storage_map(void) 6757a9bb976SMartin KaFai Lau { 6767a9bb976SMartin KaFai Lau struct bpf_create_map_attr attr = { 6777a9bb976SMartin KaFai Lau .name = "test_map", 6787a9bb976SMartin KaFai Lau .map_type = BPF_MAP_TYPE_SK_STORAGE, 6797a9bb976SMartin KaFai Lau .key_size = 4, 6807a9bb976SMartin KaFai Lau .value_size = 8, 6817a9bb976SMartin KaFai Lau .max_entries = 0, 6827a9bb976SMartin KaFai Lau .map_flags = BPF_F_NO_PREALLOC, 6837a9bb976SMartin KaFai Lau .btf_key_type_id = 1, 6847a9bb976SMartin KaFai Lau .btf_value_type_id = 3, 6857a9bb976SMartin KaFai Lau }; 6867a9bb976SMartin KaFai Lau int fd, btf_fd; 6877a9bb976SMartin KaFai Lau 6887a9bb976SMartin KaFai Lau btf_fd = load_btf(); 6897a9bb976SMartin KaFai Lau if (btf_fd < 0) 6907a9bb976SMartin KaFai Lau return -1; 6917a9bb976SMartin KaFai Lau attr.btf_fd = btf_fd; 6927a9bb976SMartin KaFai Lau fd = bpf_create_map_xattr(&attr); 6937a9bb976SMartin KaFai Lau close(attr.btf_fd); 6947a9bb976SMartin KaFai Lau if (fd < 0) 6957a9bb976SMartin KaFai Lau printf("Failed to create sk_storage_map\n"); 6967a9bb976SMartin KaFai Lau return fd; 6977a9bb976SMartin KaFai Lau } 6987a9bb976SMartin KaFai Lau 69993731ef0SDaniel Borkmann static char bpf_vlog[UINT_MAX >> 8]; 7005aa5bd14SDaniel Borkmann 701aca1a80eSStanislav Fomichev static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, 7020c586079SJoe Stringer struct bpf_insn *prog, int *map_fds) 7035aa5bd14SDaniel Borkmann { 704908142e6SPrashant Bhole int *fixup_map_hash_8b = test->fixup_map_hash_8b; 705908142e6SPrashant Bhole int *fixup_map_hash_48b = test->fixup_map_hash_48b; 706908142e6SPrashant Bhole int *fixup_map_hash_16b = test->fixup_map_hash_16b; 707908142e6SPrashant Bhole int *fixup_map_array_48b = test->fixup_map_array_48b; 7087c85c448SPrashant Bhole int *fixup_map_sockmap = test->fixup_map_sockmap; 7097c85c448SPrashant Bhole int *fixup_map_sockhash = test->fixup_map_sockhash; 7107c85c448SPrashant Bhole int *fixup_map_xskmap = test->fixup_map_xskmap; 7117c85c448SPrashant Bhole int *fixup_map_stacktrace = test->fixup_map_stacktrace; 71206be0864SDaniel Borkmann int *fixup_prog1 = test->fixup_prog1; 71306be0864SDaniel Borkmann int *fixup_prog2 = test->fixup_prog2; 714fb30d4b7SMartin KaFai Lau int *fixup_map_in_map = test->fixup_map_in_map; 715d4c9f573SRoman Gushchin int *fixup_cgroup_storage = test->fixup_cgroup_storage; 716a3c6054fSRoman Gushchin int *fixup_percpu_cgroup_storage = test->fixup_percpu_cgroup_storage; 717b4d4556cSAlexei Starovoitov int *fixup_map_spin_lock = test->fixup_map_spin_lock; 718fb2abb73SDaniel Borkmann int *fixup_map_array_ro = test->fixup_map_array_ro; 719fb2abb73SDaniel Borkmann int *fixup_map_array_wo = test->fixup_map_array_wo; 720fb2abb73SDaniel Borkmann int *fixup_map_array_small = test->fixup_map_array_small; 7217a9bb976SMartin KaFai Lau int *fixup_sk_storage_map = test->fixup_sk_storage_map; 72203cd1d1aSAllan Zhang int *fixup_map_event_output = test->fixup_map_event_output; 723c3210222SJakub Sitnicki int *fixup_map_reuseport_array = test->fixup_map_reuseport_array; 7244237e9f4SGilad Reti int *fixup_map_ringbuf = test->fixup_map_ringbuf; 7255aa5bd14SDaniel Borkmann 7268aa2d4b4SAlexei Starovoitov if (test->fill_helper) { 7278aa2d4b4SAlexei Starovoitov test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn)); 72893731ef0SDaniel Borkmann test->fill_helper(test); 7298aa2d4b4SAlexei Starovoitov } 73093731ef0SDaniel Borkmann 7315aa5bd14SDaniel Borkmann /* Allocating HTs with 1 elem is fine here, since we only test 7325aa5bd14SDaniel Borkmann * for verifier and not do a runtime lookup, so the only thing 7335aa5bd14SDaniel Borkmann * that really matters is value size in this case. 7345aa5bd14SDaniel Borkmann */ 735908142e6SPrashant Bhole if (*fixup_map_hash_8b) { 73606be0864SDaniel Borkmann map_fds[0] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), 73706be0864SDaniel Borkmann sizeof(long long), 1); 7385aa5bd14SDaniel Borkmann do { 739908142e6SPrashant Bhole prog[*fixup_map_hash_8b].imm = map_fds[0]; 740908142e6SPrashant Bhole fixup_map_hash_8b++; 741908142e6SPrashant Bhole } while (*fixup_map_hash_8b); 7425aa5bd14SDaniel Borkmann } 7435aa5bd14SDaniel Borkmann 744908142e6SPrashant Bhole if (*fixup_map_hash_48b) { 74506be0864SDaniel Borkmann map_fds[1] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), 74606be0864SDaniel Borkmann sizeof(struct test_val), 1); 7475aa5bd14SDaniel Borkmann do { 748908142e6SPrashant Bhole prog[*fixup_map_hash_48b].imm = map_fds[1]; 749908142e6SPrashant Bhole fixup_map_hash_48b++; 750908142e6SPrashant Bhole } while (*fixup_map_hash_48b); 7515aa5bd14SDaniel Borkmann } 7525aa5bd14SDaniel Borkmann 753908142e6SPrashant Bhole if (*fixup_map_hash_16b) { 75406be0864SDaniel Borkmann map_fds[2] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), 75506be0864SDaniel Borkmann sizeof(struct other_val), 1); 7565f90dd6aSPaul Chaignon do { 757908142e6SPrashant Bhole prog[*fixup_map_hash_16b].imm = map_fds[2]; 758908142e6SPrashant Bhole fixup_map_hash_16b++; 759908142e6SPrashant Bhole } while (*fixup_map_hash_16b); 7605f90dd6aSPaul Chaignon } 7615f90dd6aSPaul Chaignon 762908142e6SPrashant Bhole if (*fixup_map_array_48b) { 76306be0864SDaniel Borkmann map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), 76406be0864SDaniel Borkmann sizeof(struct test_val), 1); 76580c9b2faSDaniel Borkmann update_map(map_fds[3], 0); 7665aa5bd14SDaniel Borkmann do { 767908142e6SPrashant Bhole prog[*fixup_map_array_48b].imm = map_fds[3]; 768908142e6SPrashant Bhole fixup_map_array_48b++; 769908142e6SPrashant Bhole } while (*fixup_map_array_48b); 77006be0864SDaniel Borkmann } 77106be0864SDaniel Borkmann 77206be0864SDaniel Borkmann if (*fixup_prog1) { 7733123d801SDaniel Borkmann map_fds[4] = create_prog_array(prog_type, 4, 0, 1, 2); 77406be0864SDaniel Borkmann do { 77506be0864SDaniel Borkmann prog[*fixup_prog1].imm = map_fds[4]; 77606be0864SDaniel Borkmann fixup_prog1++; 77706be0864SDaniel Borkmann } while (*fixup_prog1); 77806be0864SDaniel Borkmann } 77906be0864SDaniel Borkmann 78006be0864SDaniel Borkmann if (*fixup_prog2) { 7813123d801SDaniel Borkmann map_fds[5] = create_prog_array(prog_type, 8, 7, 1, 2); 78206be0864SDaniel Borkmann do { 78306be0864SDaniel Borkmann prog[*fixup_prog2].imm = map_fds[5]; 78406be0864SDaniel Borkmann fixup_prog2++; 78506be0864SDaniel Borkmann } while (*fixup_prog2); 7865aa5bd14SDaniel Borkmann } 787fb30d4b7SMartin KaFai Lau 788fb30d4b7SMartin KaFai Lau if (*fixup_map_in_map) { 78906be0864SDaniel Borkmann map_fds[6] = create_map_in_map(); 790fb30d4b7SMartin KaFai Lau do { 79106be0864SDaniel Borkmann prog[*fixup_map_in_map].imm = map_fds[6]; 792fb30d4b7SMartin KaFai Lau fixup_map_in_map++; 793fb30d4b7SMartin KaFai Lau } while (*fixup_map_in_map); 794fb30d4b7SMartin KaFai Lau } 795d4c9f573SRoman Gushchin 796d4c9f573SRoman Gushchin if (*fixup_cgroup_storage) { 797a3c6054fSRoman Gushchin map_fds[7] = create_cgroup_storage(false); 798d4c9f573SRoman Gushchin do { 799d4c9f573SRoman Gushchin prog[*fixup_cgroup_storage].imm = map_fds[7]; 800d4c9f573SRoman Gushchin fixup_cgroup_storage++; 801d4c9f573SRoman Gushchin } while (*fixup_cgroup_storage); 802d4c9f573SRoman Gushchin } 803a3c6054fSRoman Gushchin 804a3c6054fSRoman Gushchin if (*fixup_percpu_cgroup_storage) { 805a3c6054fSRoman Gushchin map_fds[8] = create_cgroup_storage(true); 806a3c6054fSRoman Gushchin do { 807a3c6054fSRoman Gushchin prog[*fixup_percpu_cgroup_storage].imm = map_fds[8]; 808a3c6054fSRoman Gushchin fixup_percpu_cgroup_storage++; 809a3c6054fSRoman Gushchin } while (*fixup_percpu_cgroup_storage); 810a3c6054fSRoman Gushchin } 8117c85c448SPrashant Bhole if (*fixup_map_sockmap) { 8127c85c448SPrashant Bhole map_fds[9] = create_map(BPF_MAP_TYPE_SOCKMAP, sizeof(int), 8137c85c448SPrashant Bhole sizeof(int), 1); 8147c85c448SPrashant Bhole do { 8157c85c448SPrashant Bhole prog[*fixup_map_sockmap].imm = map_fds[9]; 8167c85c448SPrashant Bhole fixup_map_sockmap++; 8177c85c448SPrashant Bhole } while (*fixup_map_sockmap); 8187c85c448SPrashant Bhole } 8197c85c448SPrashant Bhole if (*fixup_map_sockhash) { 8207c85c448SPrashant Bhole map_fds[10] = create_map(BPF_MAP_TYPE_SOCKHASH, sizeof(int), 8217c85c448SPrashant Bhole sizeof(int), 1); 8227c85c448SPrashant Bhole do { 8237c85c448SPrashant Bhole prog[*fixup_map_sockhash].imm = map_fds[10]; 8247c85c448SPrashant Bhole fixup_map_sockhash++; 8257c85c448SPrashant Bhole } while (*fixup_map_sockhash); 8267c85c448SPrashant Bhole } 8277c85c448SPrashant Bhole if (*fixup_map_xskmap) { 8287c85c448SPrashant Bhole map_fds[11] = create_map(BPF_MAP_TYPE_XSKMAP, sizeof(int), 8297c85c448SPrashant Bhole sizeof(int), 1); 8307c85c448SPrashant Bhole do { 8317c85c448SPrashant Bhole prog[*fixup_map_xskmap].imm = map_fds[11]; 8327c85c448SPrashant Bhole fixup_map_xskmap++; 8337c85c448SPrashant Bhole } while (*fixup_map_xskmap); 8347c85c448SPrashant Bhole } 8357c85c448SPrashant Bhole if (*fixup_map_stacktrace) { 8367c85c448SPrashant Bhole map_fds[12] = create_map(BPF_MAP_TYPE_STACK_TRACE, sizeof(u32), 8377c85c448SPrashant Bhole sizeof(u64), 1); 8387c85c448SPrashant Bhole do { 8397c85c448SPrashant Bhole prog[*fixup_map_stacktrace].imm = map_fds[12]; 8407c85c448SPrashant Bhole fixup_map_stacktrace++; 841c2a20a27SStanislav Fomichev } while (*fixup_map_stacktrace); 8427c85c448SPrashant Bhole } 843b4d4556cSAlexei Starovoitov if (*fixup_map_spin_lock) { 844b4d4556cSAlexei Starovoitov map_fds[13] = create_map_spin_lock(); 845b4d4556cSAlexei Starovoitov do { 846b4d4556cSAlexei Starovoitov prog[*fixup_map_spin_lock].imm = map_fds[13]; 847b4d4556cSAlexei Starovoitov fixup_map_spin_lock++; 848b4d4556cSAlexei Starovoitov } while (*fixup_map_spin_lock); 849b4d4556cSAlexei Starovoitov } 850fb2abb73SDaniel Borkmann if (*fixup_map_array_ro) { 851fb2abb73SDaniel Borkmann map_fds[14] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), 852fb2abb73SDaniel Borkmann sizeof(struct test_val), 1, 853fb2abb73SDaniel Borkmann BPF_F_RDONLY_PROG); 854fb2abb73SDaniel Borkmann update_map(map_fds[14], 0); 855fb2abb73SDaniel Borkmann do { 856fb2abb73SDaniel Borkmann prog[*fixup_map_array_ro].imm = map_fds[14]; 857fb2abb73SDaniel Borkmann fixup_map_array_ro++; 858fb2abb73SDaniel Borkmann } while (*fixup_map_array_ro); 859fb2abb73SDaniel Borkmann } 860fb2abb73SDaniel Borkmann if (*fixup_map_array_wo) { 861fb2abb73SDaniel Borkmann map_fds[15] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), 862fb2abb73SDaniel Borkmann sizeof(struct test_val), 1, 863fb2abb73SDaniel Borkmann BPF_F_WRONLY_PROG); 864fb2abb73SDaniel Borkmann update_map(map_fds[15], 0); 865fb2abb73SDaniel Borkmann do { 866fb2abb73SDaniel Borkmann prog[*fixup_map_array_wo].imm = map_fds[15]; 867fb2abb73SDaniel Borkmann fixup_map_array_wo++; 868fb2abb73SDaniel Borkmann } while (*fixup_map_array_wo); 869fb2abb73SDaniel Borkmann } 870fb2abb73SDaniel Borkmann if (*fixup_map_array_small) { 871fb2abb73SDaniel Borkmann map_fds[16] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), 872fb2abb73SDaniel Borkmann 1, 1, 0); 873fb2abb73SDaniel Borkmann update_map(map_fds[16], 0); 874fb2abb73SDaniel Borkmann do { 875fb2abb73SDaniel Borkmann prog[*fixup_map_array_small].imm = map_fds[16]; 876fb2abb73SDaniel Borkmann fixup_map_array_small++; 877fb2abb73SDaniel Borkmann } while (*fixup_map_array_small); 878fb2abb73SDaniel Borkmann } 8797a9bb976SMartin KaFai Lau if (*fixup_sk_storage_map) { 8807a9bb976SMartin KaFai Lau map_fds[17] = create_sk_storage_map(); 8817a9bb976SMartin KaFai Lau do { 8827a9bb976SMartin KaFai Lau prog[*fixup_sk_storage_map].imm = map_fds[17]; 8837a9bb976SMartin KaFai Lau fixup_sk_storage_map++; 8847a9bb976SMartin KaFai Lau } while (*fixup_sk_storage_map); 8857a9bb976SMartin KaFai Lau } 88603cd1d1aSAllan Zhang if (*fixup_map_event_output) { 88703cd1d1aSAllan Zhang map_fds[18] = __create_map(BPF_MAP_TYPE_PERF_EVENT_ARRAY, 88803cd1d1aSAllan Zhang sizeof(int), sizeof(int), 1, 0); 88903cd1d1aSAllan Zhang do { 89003cd1d1aSAllan Zhang prog[*fixup_map_event_output].imm = map_fds[18]; 89103cd1d1aSAllan Zhang fixup_map_event_output++; 89203cd1d1aSAllan Zhang } while (*fixup_map_event_output); 89303cd1d1aSAllan Zhang } 894c3210222SJakub Sitnicki if (*fixup_map_reuseport_array) { 895c3210222SJakub Sitnicki map_fds[19] = __create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, 896c3210222SJakub Sitnicki sizeof(u32), sizeof(u64), 1, 0); 897c3210222SJakub Sitnicki do { 898c3210222SJakub Sitnicki prog[*fixup_map_reuseport_array].imm = map_fds[19]; 899c3210222SJakub Sitnicki fixup_map_reuseport_array++; 900c3210222SJakub Sitnicki } while (*fixup_map_reuseport_array); 901c3210222SJakub Sitnicki } 9024237e9f4SGilad Reti if (*fixup_map_ringbuf) { 9034237e9f4SGilad Reti map_fds[20] = create_map(BPF_MAP_TYPE_RINGBUF, 0, 9044237e9f4SGilad Reti 0, 4096); 9054237e9f4SGilad Reti do { 9064237e9f4SGilad Reti prog[*fixup_map_ringbuf].imm = map_fds[20]; 9074237e9f4SGilad Reti fixup_map_ringbuf++; 9084237e9f4SGilad Reti } while (*fixup_map_ringbuf); 9094237e9f4SGilad Reti } 9105aa5bd14SDaniel Borkmann } 9115aa5bd14SDaniel Borkmann 91281626001SAlexei Starovoitov struct libcap { 91381626001SAlexei Starovoitov struct __user_cap_header_struct hdr; 91481626001SAlexei Starovoitov struct __user_cap_data_struct data[2]; 91581626001SAlexei Starovoitov }; 91681626001SAlexei Starovoitov 917832c6f2cSDaniel Borkmann static int set_admin(bool admin) 918832c6f2cSDaniel Borkmann { 919832c6f2cSDaniel Borkmann cap_t caps; 92081626001SAlexei Starovoitov /* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */ 92181626001SAlexei Starovoitov const cap_value_t cap_net_admin = CAP_NET_ADMIN; 92281626001SAlexei Starovoitov const cap_value_t cap_sys_admin = CAP_SYS_ADMIN; 92381626001SAlexei Starovoitov struct libcap *cap; 924832c6f2cSDaniel Borkmann int ret = -1; 925832c6f2cSDaniel Borkmann 926832c6f2cSDaniel Borkmann caps = cap_get_proc(); 927832c6f2cSDaniel Borkmann if (!caps) { 928832c6f2cSDaniel Borkmann perror("cap_get_proc"); 929832c6f2cSDaniel Borkmann return -1; 930832c6f2cSDaniel Borkmann } 93181626001SAlexei Starovoitov cap = (struct libcap *)caps; 93281626001SAlexei Starovoitov if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_sys_admin, CAP_CLEAR)) { 93381626001SAlexei Starovoitov perror("cap_set_flag clear admin"); 934832c6f2cSDaniel Borkmann goto out; 935832c6f2cSDaniel Borkmann } 93681626001SAlexei Starovoitov if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_admin, 93781626001SAlexei Starovoitov admin ? CAP_SET : CAP_CLEAR)) { 93881626001SAlexei Starovoitov perror("cap_set_flag set_or_clear net"); 93981626001SAlexei Starovoitov goto out; 94081626001SAlexei Starovoitov } 94181626001SAlexei Starovoitov /* libcap is likely old and simply ignores CAP_BPF and CAP_PERFMON, 94281626001SAlexei Starovoitov * so update effective bits manually 94381626001SAlexei Starovoitov */ 94481626001SAlexei Starovoitov if (admin) { 94581626001SAlexei Starovoitov cap->data[1].effective |= 1 << (38 /* CAP_PERFMON */ - 32); 94681626001SAlexei Starovoitov cap->data[1].effective |= 1 << (39 /* CAP_BPF */ - 32); 94781626001SAlexei Starovoitov } else { 94881626001SAlexei Starovoitov cap->data[1].effective &= ~(1 << (38 - 32)); 94981626001SAlexei Starovoitov cap->data[1].effective &= ~(1 << (39 - 32)); 95081626001SAlexei Starovoitov } 951832c6f2cSDaniel Borkmann if (cap_set_proc(caps)) { 952832c6f2cSDaniel Borkmann perror("cap_set_proc"); 953832c6f2cSDaniel Borkmann goto out; 954832c6f2cSDaniel Borkmann } 955832c6f2cSDaniel Borkmann ret = 0; 956832c6f2cSDaniel Borkmann out: 957832c6f2cSDaniel Borkmann if (cap_free(caps)) 958832c6f2cSDaniel Borkmann perror("cap_free"); 959832c6f2cSDaniel Borkmann return ret; 960832c6f2cSDaniel Borkmann } 961832c6f2cSDaniel Borkmann 9625a8d5209SJakub Kicinski static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val, 9635a8d5209SJakub Kicinski void *data, size_t size_data) 9645a8d5209SJakub Kicinski { 9655a8d5209SJakub Kicinski __u8 tmp[TEST_DATA_LEN << 2]; 9665a8d5209SJakub Kicinski __u32 size_tmp = sizeof(tmp); 9675a8d5209SJakub Kicinski uint32_t retval; 9685f61b7c6SFlorian Lehner int err, saved_errno; 9695a8d5209SJakub Kicinski 9705a8d5209SJakub Kicinski if (unpriv) 9715a8d5209SJakub Kicinski set_admin(true); 9725a8d5209SJakub Kicinski err = bpf_prog_test_run(fd_prog, 1, data, size_data, 9735a8d5209SJakub Kicinski tmp, &size_tmp, &retval, NULL); 9745f61b7c6SFlorian Lehner saved_errno = errno; 9755f61b7c6SFlorian Lehner 9765a8d5209SJakub Kicinski if (unpriv) 9775a8d5209SJakub Kicinski set_admin(false); 9785f61b7c6SFlorian Lehner 9795f61b7c6SFlorian Lehner if (err) { 9805f61b7c6SFlorian Lehner switch (saved_errno) { 981*5319255bSIlya Leoshkevich case ENOTSUPP: 9825f61b7c6SFlorian Lehner printf("Did not run the program (not supported) "); 9835f61b7c6SFlorian Lehner return 0; 9845f61b7c6SFlorian Lehner case EPERM: 9855f61b7c6SFlorian Lehner if (unpriv) { 9865f61b7c6SFlorian Lehner printf("Did not run the program (no permission) "); 9875f61b7c6SFlorian Lehner return 0; 9885f61b7c6SFlorian Lehner } 9895f61b7c6SFlorian Lehner /* fallthrough; */ 9905f61b7c6SFlorian Lehner default: 9915f61b7c6SFlorian Lehner printf("FAIL: Unexpected bpf_prog_test_run error (%s) ", 9925f61b7c6SFlorian Lehner strerror(saved_errno)); 9935a8d5209SJakub Kicinski return err; 9945a8d5209SJakub Kicinski } 9955f61b7c6SFlorian Lehner } 9965f61b7c6SFlorian Lehner 9975f61b7c6SFlorian Lehner if (retval != expected_val && 9985a8d5209SJakub Kicinski expected_val != POINTER_VALUE) { 9995a8d5209SJakub Kicinski printf("FAIL retval %d != %d ", retval, expected_val); 10005a8d5209SJakub Kicinski return 1; 10015a8d5209SJakub Kicinski } 10025a8d5209SJakub Kicinski 10035a8d5209SJakub Kicinski return 0; 10045a8d5209SJakub Kicinski } 10055a8d5209SJakub Kicinski 1006060fd103SAndrei Matei /* Returns true if every part of exp (tab-separated) appears in log, in order. 1007060fd103SAndrei Matei * 1008060fd103SAndrei Matei * If exp is an empty string, returns true. 1009060fd103SAndrei Matei */ 1010e8c13c4dSAlexei Starovoitov static bool cmp_str_seq(const char *log, const char *exp) 1011e8c13c4dSAlexei Starovoitov { 1012060fd103SAndrei Matei char needle[200]; 1013e8c13c4dSAlexei Starovoitov const char *p, *q; 1014e8c13c4dSAlexei Starovoitov int len; 1015e8c13c4dSAlexei Starovoitov 1016e8c13c4dSAlexei Starovoitov do { 1017060fd103SAndrei Matei if (!strlen(exp)) 1018060fd103SAndrei Matei break; 1019e8c13c4dSAlexei Starovoitov p = strchr(exp, '\t'); 1020e8c13c4dSAlexei Starovoitov if (!p) 1021e8c13c4dSAlexei Starovoitov p = exp + strlen(exp); 1022e8c13c4dSAlexei Starovoitov 1023e8c13c4dSAlexei Starovoitov len = p - exp; 1024e8c13c4dSAlexei Starovoitov if (len >= sizeof(needle) || !len) { 1025e8c13c4dSAlexei Starovoitov printf("FAIL\nTestcase bug\n"); 1026e8c13c4dSAlexei Starovoitov return false; 1027e8c13c4dSAlexei Starovoitov } 1028e8c13c4dSAlexei Starovoitov strncpy(needle, exp, len); 1029e8c13c4dSAlexei Starovoitov needle[len] = 0; 1030e8c13c4dSAlexei Starovoitov q = strstr(log, needle); 1031e8c13c4dSAlexei Starovoitov if (!q) { 1032060fd103SAndrei Matei printf("FAIL\nUnexpected verifier log!\n" 1033e8c13c4dSAlexei Starovoitov "EXP: %s\nRES:\n", needle); 1034e8c13c4dSAlexei Starovoitov return false; 1035e8c13c4dSAlexei Starovoitov } 1036e8c13c4dSAlexei Starovoitov log = q + len; 1037e8c13c4dSAlexei Starovoitov exp = p + 1; 1038e8c13c4dSAlexei Starovoitov } while (*p); 1039e8c13c4dSAlexei Starovoitov return true; 1040e8c13c4dSAlexei Starovoitov } 1041e8c13c4dSAlexei Starovoitov 10425aa5bd14SDaniel Borkmann static void do_test_single(struct bpf_test *test, bool unpriv, 10435aa5bd14SDaniel Borkmann int *passes, int *errors) 10445aa5bd14SDaniel Borkmann { 1045c7665702SDavid Miller int fd_prog, expected_ret, alignment_prevented_execution; 104693731ef0SDaniel Borkmann int prog_len, prog_type = test->prog_type; 10475aa5bd14SDaniel Borkmann struct bpf_insn *prog = test->insns; 104876d95077SStanislav Fomichev struct bpf_load_program_attr attr; 10495a8d5209SJakub Kicinski int run_errs, run_successes; 1050fb30d4b7SMartin KaFai Lau int map_fds[MAX_NR_MAPS]; 10515aa5bd14SDaniel Borkmann const char *expected_err; 10527d171672SFlorian Lehner int saved_errno; 10539acea337SStanislav Fomichev int fixup_skips; 1054c7665702SDavid Miller __u32 pflags; 1055111e6b45SAlexei Starovoitov int i, err; 10565aa5bd14SDaniel Borkmann 1057fb30d4b7SMartin KaFai Lau for (i = 0; i < MAX_NR_MAPS; i++) 1058fb30d4b7SMartin KaFai Lau map_fds[i] = -1; 1059fb30d4b7SMartin KaFai Lau 10600c586079SJoe Stringer if (!prog_type) 10610c586079SJoe Stringer prog_type = BPF_PROG_TYPE_SOCKET_FILTER; 10629acea337SStanislav Fomichev fixup_skips = skips; 10630c586079SJoe Stringer do_test_fixup(test, prog_type, prog, map_fds); 10648aa2d4b4SAlexei Starovoitov if (test->fill_insns) { 10658aa2d4b4SAlexei Starovoitov prog = test->fill_insns; 10668aa2d4b4SAlexei Starovoitov prog_len = test->prog_len; 10678aa2d4b4SAlexei Starovoitov } else { 10688aa2d4b4SAlexei Starovoitov prog_len = probe_filter_length(prog); 10698aa2d4b4SAlexei Starovoitov } 10709acea337SStanislav Fomichev /* If there were some map skips during fixup due to missing bpf 10719acea337SStanislav Fomichev * features, skip this test. 10729acea337SStanislav Fomichev */ 10739acea337SStanislav Fomichev if (fixup_skips != skips) 10749acea337SStanislav Fomichev return; 10755aa5bd14SDaniel Borkmann 10769d120b41SJiong Wang pflags = BPF_F_TEST_RND_HI32; 1077c7665702SDavid Miller if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT) 1078c7665702SDavid Miller pflags |= BPF_F_STRICT_ALIGNMENT; 1079c7665702SDavid Miller if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) 1080c7665702SDavid Miller pflags |= BPF_F_ANY_ALIGNMENT; 1081e8c13c4dSAlexei Starovoitov if (test->flags & ~3) 1082e8c13c4dSAlexei Starovoitov pflags |= test->flags; 108376d95077SStanislav Fomichev 1084e8c13c4dSAlexei Starovoitov expected_ret = unpriv && test->result_unpriv != UNDEF ? 1085e8c13c4dSAlexei Starovoitov test->result_unpriv : test->result; 1086e8c13c4dSAlexei Starovoitov expected_err = unpriv && test->errstr_unpriv ? 1087e8c13c4dSAlexei Starovoitov test->errstr_unpriv : test->errstr; 108876d95077SStanislav Fomichev memset(&attr, 0, sizeof(attr)); 108976d95077SStanislav Fomichev attr.prog_type = prog_type; 109076d95077SStanislav Fomichev attr.expected_attach_type = test->expected_attach_type; 109176d95077SStanislav Fomichev attr.insns = prog; 109276d95077SStanislav Fomichev attr.insns_cnt = prog_len; 109376d95077SStanislav Fomichev attr.license = "GPL"; 10946f8a57ccSAndrii Nakryiko if (verbose) 10956f8a57ccSAndrii Nakryiko attr.log_level = 1; 10966f8a57ccSAndrii Nakryiko else if (expected_ret == VERBOSE_ACCEPT) 10976f8a57ccSAndrii Nakryiko attr.log_level = 2; 10986f8a57ccSAndrii Nakryiko else 10996f8a57ccSAndrii Nakryiko attr.log_level = 4; 110076d95077SStanislav Fomichev attr.prog_flags = pflags; 110176d95077SStanislav Fomichev 1102762f8515SJiri Olsa if (prog_type == BPF_PROG_TYPE_TRACING && test->kfunc) { 1103762f8515SJiri Olsa attr.attach_btf_id = libbpf_find_vmlinux_btf_id(test->kfunc, 1104762f8515SJiri Olsa attr.expected_attach_type); 1105762f8515SJiri Olsa if (attr.attach_btf_id < 0) { 1106762f8515SJiri Olsa printf("FAIL\nFailed to find BTF ID for '%s'!\n", 1107762f8515SJiri Olsa test->kfunc); 1108762f8515SJiri Olsa (*errors)++; 1109762f8515SJiri Olsa return; 1110762f8515SJiri Olsa } 1111762f8515SJiri Olsa } 1112762f8515SJiri Olsa 111376d95077SStanislav Fomichev fd_prog = bpf_load_program_xattr(&attr, bpf_vlog, sizeof(bpf_vlog)); 11147d171672SFlorian Lehner saved_errno = errno; 1115762f8515SJiri Olsa 1116762f8515SJiri Olsa /* BPF_PROG_TYPE_TRACING requires more setup and 1117762f8515SJiri Olsa * bpf_probe_prog_type won't give correct answer 1118762f8515SJiri Olsa */ 1119762f8515SJiri Olsa if (fd_prog < 0 && prog_type != BPF_PROG_TYPE_TRACING && 1120762f8515SJiri Olsa !bpf_probe_prog_type(prog_type, 0)) { 11218184d44cSStanislav Fomichev printf("SKIP (unsupported program type %d)\n", prog_type); 11228184d44cSStanislav Fomichev skips++; 11238184d44cSStanislav Fomichev goto close_fds; 11248184d44cSStanislav Fomichev } 11255aa5bd14SDaniel Borkmann 1126*5319255bSIlya Leoshkevich if (fd_prog < 0 && saved_errno == ENOTSUPP) { 1127*5319255bSIlya Leoshkevich printf("SKIP (program uses an unsupported feature)\n"); 1128*5319255bSIlya Leoshkevich skips++; 1129*5319255bSIlya Leoshkevich goto close_fds; 1130*5319255bSIlya Leoshkevich } 1131*5319255bSIlya Leoshkevich 1132c7665702SDavid Miller alignment_prevented_execution = 0; 1133c7665702SDavid Miller 1134e8c13c4dSAlexei Starovoitov if (expected_ret == ACCEPT || expected_ret == VERBOSE_ACCEPT) { 1135c7665702SDavid Miller if (fd_prog < 0) { 11365aa5bd14SDaniel Borkmann printf("FAIL\nFailed to load prog '%s'!\n", 11377d171672SFlorian Lehner strerror(saved_errno)); 11385aa5bd14SDaniel Borkmann goto fail_log; 11395aa5bd14SDaniel Borkmann } 1140c7665702SDavid Miller #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1141c7665702SDavid Miller if (fd_prog >= 0 && 11425a8d5209SJakub Kicinski (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)) 1143c7665702SDavid Miller alignment_prevented_execution = 1; 1144c7665702SDavid Miller #endif 1145e8c13c4dSAlexei Starovoitov if (expected_ret == VERBOSE_ACCEPT && !cmp_str_seq(bpf_vlog, expected_err)) { 1146e8c13c4dSAlexei Starovoitov goto fail_log; 1147e8c13c4dSAlexei Starovoitov } 11485aa5bd14SDaniel Borkmann } else { 11495aa5bd14SDaniel Borkmann if (fd_prog >= 0) { 11505aa5bd14SDaniel Borkmann printf("FAIL\nUnexpected success to load!\n"); 11515aa5bd14SDaniel Borkmann goto fail_log; 11525aa5bd14SDaniel Borkmann } 1153060fd103SAndrei Matei if (!expected_err || !cmp_str_seq(bpf_vlog, expected_err)) { 115495f87a97SJoe Stringer printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n", 115595f87a97SJoe Stringer expected_err, bpf_vlog); 11565aa5bd14SDaniel Borkmann goto fail_log; 11575aa5bd14SDaniel Borkmann } 11585aa5bd14SDaniel Borkmann } 11595aa5bd14SDaniel Borkmann 1160973377ffSDaniel Borkmann if (!unpriv && test->insn_processed) { 1161730ff40fSAlexei Starovoitov uint32_t insn_processed; 1162730ff40fSAlexei Starovoitov char *proc; 11636e6fddc7SDaniel Borkmann 1164730ff40fSAlexei Starovoitov proc = strstr(bpf_vlog, "processed "); 1165730ff40fSAlexei Starovoitov insn_processed = atoi(proc + 10); 1166730ff40fSAlexei Starovoitov if (test->insn_processed != insn_processed) { 1167730ff40fSAlexei Starovoitov printf("FAIL\nUnexpected insn_processed %u vs %u\n", 1168730ff40fSAlexei Starovoitov insn_processed, test->insn_processed); 1169111e6b45SAlexei Starovoitov goto fail_log; 1170111e6b45SAlexei Starovoitov } 1171111e6b45SAlexei Starovoitov } 1172730ff40fSAlexei Starovoitov 1173e8c13c4dSAlexei Starovoitov if (verbose) 1174e8c13c4dSAlexei Starovoitov printf(", verifier log:\n%s", bpf_vlog); 1175e8c13c4dSAlexei Starovoitov 11765a8d5209SJakub Kicinski run_errs = 0; 11775a8d5209SJakub Kicinski run_successes = 0; 1178b4f89463SLorenz Bauer if (!alignment_prevented_execution && fd_prog >= 0 && test->runs >= 0) { 11795a8d5209SJakub Kicinski uint32_t expected_val; 11805a8d5209SJakub Kicinski int i; 11815aa5bd14SDaniel Borkmann 1182d5e1db99SAndrii Nakryiko if (!test->runs) 1183d5e1db99SAndrii Nakryiko test->runs = 1; 11845a8d5209SJakub Kicinski 11855a8d5209SJakub Kicinski for (i = 0; i < test->runs; i++) { 11865a8d5209SJakub Kicinski if (unpriv && test->retvals[i].retval_unpriv) 11875a8d5209SJakub Kicinski expected_val = test->retvals[i].retval_unpriv; 11885a8d5209SJakub Kicinski else 11895a8d5209SJakub Kicinski expected_val = test->retvals[i].retval; 11905a8d5209SJakub Kicinski 11915a8d5209SJakub Kicinski err = do_prog_test_run(fd_prog, unpriv, expected_val, 11925a8d5209SJakub Kicinski test->retvals[i].data, 11935a8d5209SJakub Kicinski sizeof(test->retvals[i].data)); 11945a8d5209SJakub Kicinski if (err) { 11955a8d5209SJakub Kicinski printf("(run %d/%d) ", i + 1, test->runs); 11965a8d5209SJakub Kicinski run_errs++; 11975a8d5209SJakub Kicinski } else { 11985a8d5209SJakub Kicinski run_successes++; 11995aa5bd14SDaniel Borkmann } 12005aa5bd14SDaniel Borkmann } 12015a8d5209SJakub Kicinski } 12025a8d5209SJakub Kicinski 12035a8d5209SJakub Kicinski if (!run_errs) { 12045aa5bd14SDaniel Borkmann (*passes)++; 12055a8d5209SJakub Kicinski if (run_successes > 1) 12065a8d5209SJakub Kicinski printf("%d cases ", run_successes); 12075a8d5209SJakub Kicinski printf("OK"); 12085a8d5209SJakub Kicinski if (alignment_prevented_execution) 12095a8d5209SJakub Kicinski printf(" (NOTE: not executed due to unknown alignment)"); 12105a8d5209SJakub Kicinski printf("\n"); 12115a8d5209SJakub Kicinski } else { 12125a8d5209SJakub Kicinski printf("\n"); 12135a8d5209SJakub Kicinski goto fail_log; 12145a8d5209SJakub Kicinski } 12155aa5bd14SDaniel Borkmann close_fds: 12168aa2d4b4SAlexei Starovoitov if (test->fill_insns) 12178aa2d4b4SAlexei Starovoitov free(test->fill_insns); 12185aa5bd14SDaniel Borkmann close(fd_prog); 12195aa5bd14SDaniel Borkmann for (i = 0; i < MAX_NR_MAPS; i++) 12205aa5bd14SDaniel Borkmann close(map_fds[i]); 12215aa5bd14SDaniel Borkmann sched_yield(); 12225aa5bd14SDaniel Borkmann return; 12235aa5bd14SDaniel Borkmann fail_log: 12245aa5bd14SDaniel Borkmann (*errors)++; 12255aa5bd14SDaniel Borkmann printf("%s", bpf_vlog); 12265aa5bd14SDaniel Borkmann goto close_fds; 12275aa5bd14SDaniel Borkmann } 12285aa5bd14SDaniel Borkmann 12295aa5bd14SDaniel Borkmann static bool is_admin(void) 12305aa5bd14SDaniel Borkmann { 123181626001SAlexei Starovoitov cap_flag_value_t net_priv = CAP_CLEAR; 123281626001SAlexei Starovoitov bool perfmon_priv = false; 123381626001SAlexei Starovoitov bool bpf_priv = false; 123481626001SAlexei Starovoitov struct libcap *cap; 12355aa5bd14SDaniel Borkmann cap_t caps; 12365aa5bd14SDaniel Borkmann 12375aa5bd14SDaniel Borkmann #ifdef CAP_IS_SUPPORTED 12385aa5bd14SDaniel Borkmann if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) { 12395aa5bd14SDaniel Borkmann perror("cap_get_flag"); 12405aa5bd14SDaniel Borkmann return false; 12415aa5bd14SDaniel Borkmann } 12425aa5bd14SDaniel Borkmann #endif 12435aa5bd14SDaniel Borkmann caps = cap_get_proc(); 12445aa5bd14SDaniel Borkmann if (!caps) { 12455aa5bd14SDaniel Borkmann perror("cap_get_proc"); 12465aa5bd14SDaniel Borkmann return false; 12475aa5bd14SDaniel Borkmann } 124881626001SAlexei Starovoitov cap = (struct libcap *)caps; 124981626001SAlexei Starovoitov bpf_priv = cap->data[1].effective & (1 << (39/* CAP_BPF */ - 32)); 125081626001SAlexei Starovoitov perfmon_priv = cap->data[1].effective & (1 << (38/* CAP_PERFMON */ - 32)); 125181626001SAlexei Starovoitov if (cap_get_flag(caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_priv)) 125281626001SAlexei Starovoitov perror("cap_get_flag NET"); 12535aa5bd14SDaniel Borkmann if (cap_free(caps)) 12545aa5bd14SDaniel Borkmann perror("cap_free"); 125581626001SAlexei Starovoitov return bpf_priv && perfmon_priv && net_priv == CAP_SET; 12565aa5bd14SDaniel Borkmann } 12575aa5bd14SDaniel Borkmann 12580a674874SJoe Stringer static void get_unpriv_disabled() 12590a674874SJoe Stringer { 12600a674874SJoe Stringer char buf[2]; 12610a674874SJoe Stringer FILE *fd; 12620a674874SJoe Stringer 12630a674874SJoe Stringer fd = fopen("/proc/sys/"UNPRIV_SYSCTL, "r"); 1264deea8122SJesper Dangaard Brouer if (!fd) { 1265deea8122SJesper Dangaard Brouer perror("fopen /proc/sys/"UNPRIV_SYSCTL); 1266deea8122SJesper Dangaard Brouer unpriv_disabled = true; 1267deea8122SJesper Dangaard Brouer return; 1268deea8122SJesper Dangaard Brouer } 12690a674874SJoe Stringer if (fgets(buf, 2, fd) == buf && atoi(buf)) 12700a674874SJoe Stringer unpriv_disabled = true; 12710a674874SJoe Stringer fclose(fd); 12720a674874SJoe Stringer } 12730a674874SJoe Stringer 127436641ad6SDaniel Borkmann static bool test_as_unpriv(struct bpf_test *test) 127536641ad6SDaniel Borkmann { 1276c77b0589SBjörn Töpel #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1277c77b0589SBjörn Töpel /* Some architectures have strict alignment requirements. In 1278c77b0589SBjörn Töpel * that case, the BPF verifier detects if a program has 1279c77b0589SBjörn Töpel * unaligned accesses and rejects them. A user can pass 1280c77b0589SBjörn Töpel * BPF_F_ANY_ALIGNMENT to a program to override this 1281c77b0589SBjörn Töpel * check. That, however, will only work when a privileged user 1282c77b0589SBjörn Töpel * loads a program. An unprivileged user loading a program 1283c77b0589SBjörn Töpel * with this flag will be rejected prior entering the 1284c77b0589SBjörn Töpel * verifier. 1285c77b0589SBjörn Töpel */ 1286c77b0589SBjörn Töpel if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) 1287c77b0589SBjörn Töpel return false; 1288c77b0589SBjörn Töpel #endif 128936641ad6SDaniel Borkmann return !test->prog_type || 129036641ad6SDaniel Borkmann test->prog_type == BPF_PROG_TYPE_SOCKET_FILTER || 129136641ad6SDaniel Borkmann test->prog_type == BPF_PROG_TYPE_CGROUP_SKB; 129236641ad6SDaniel Borkmann } 129336641ad6SDaniel Borkmann 12945aa5bd14SDaniel Borkmann static int do_test(bool unpriv, unsigned int from, unsigned int to) 12955aa5bd14SDaniel Borkmann { 12968184d44cSStanislav Fomichev int i, passes = 0, errors = 0; 12975aa5bd14SDaniel Borkmann 12985aa5bd14SDaniel Borkmann for (i = from; i < to; i++) { 12995aa5bd14SDaniel Borkmann struct bpf_test *test = &tests[i]; 13005aa5bd14SDaniel Borkmann 13015aa5bd14SDaniel Borkmann /* Program types that are not supported by non-root we 13025aa5bd14SDaniel Borkmann * skip right away. 13035aa5bd14SDaniel Borkmann */ 130436641ad6SDaniel Borkmann if (test_as_unpriv(test) && unpriv_disabled) { 13050a674874SJoe Stringer printf("#%d/u %s SKIP\n", i, test->descr); 13060a674874SJoe Stringer skips++; 130736641ad6SDaniel Borkmann } else if (test_as_unpriv(test)) { 13085aa5bd14SDaniel Borkmann if (!unpriv) 13095aa5bd14SDaniel Borkmann set_admin(false); 13105aa5bd14SDaniel Borkmann printf("#%d/u %s ", i, test->descr); 13115aa5bd14SDaniel Borkmann do_test_single(test, true, &passes, &errors); 13125aa5bd14SDaniel Borkmann if (!unpriv) 13135aa5bd14SDaniel Borkmann set_admin(true); 13145aa5bd14SDaniel Borkmann } 13155aa5bd14SDaniel Borkmann 1316d0a0e495SJoe Stringer if (unpriv) { 1317d0a0e495SJoe Stringer printf("#%d/p %s SKIP\n", i, test->descr); 1318d0a0e495SJoe Stringer skips++; 1319d0a0e495SJoe Stringer } else { 13205aa5bd14SDaniel Borkmann printf("#%d/p %s ", i, test->descr); 13215aa5bd14SDaniel Borkmann do_test_single(test, false, &passes, &errors); 13225aa5bd14SDaniel Borkmann } 13235aa5bd14SDaniel Borkmann } 13245aa5bd14SDaniel Borkmann 1325d0a0e495SJoe Stringer printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, 1326d0a0e495SJoe Stringer skips, errors); 13275aa5bd14SDaniel Borkmann return errors ? EXIT_FAILURE : EXIT_SUCCESS; 13285aa5bd14SDaniel Borkmann } 13295aa5bd14SDaniel Borkmann 13305aa5bd14SDaniel Borkmann int main(int argc, char **argv) 13315aa5bd14SDaniel Borkmann { 13325aa5bd14SDaniel Borkmann unsigned int from = 0, to = ARRAY_SIZE(tests); 13335aa5bd14SDaniel Borkmann bool unpriv = !is_admin(); 1334e8c13c4dSAlexei Starovoitov int arg = 1; 1335e8c13c4dSAlexei Starovoitov 1336e8c13c4dSAlexei Starovoitov if (argc > 1 && strcmp(argv[1], "-v") == 0) { 1337e8c13c4dSAlexei Starovoitov arg++; 1338e8c13c4dSAlexei Starovoitov verbose = true; 1339e8c13c4dSAlexei Starovoitov argc--; 1340e8c13c4dSAlexei Starovoitov } 13415aa5bd14SDaniel Borkmann 13425aa5bd14SDaniel Borkmann if (argc == 3) { 1343e8c13c4dSAlexei Starovoitov unsigned int l = atoi(argv[arg]); 1344e8c13c4dSAlexei Starovoitov unsigned int u = atoi(argv[arg + 1]); 13455aa5bd14SDaniel Borkmann 13465aa5bd14SDaniel Borkmann if (l < to && u < to) { 13475aa5bd14SDaniel Borkmann from = l; 13485aa5bd14SDaniel Borkmann to = u + 1; 13495aa5bd14SDaniel Borkmann } 13505aa5bd14SDaniel Borkmann } else if (argc == 2) { 1351e8c13c4dSAlexei Starovoitov unsigned int t = atoi(argv[arg]); 13525aa5bd14SDaniel Borkmann 13535aa5bd14SDaniel Borkmann if (t < to) { 13545aa5bd14SDaniel Borkmann from = t; 13555aa5bd14SDaniel Borkmann to = t + 1; 13565aa5bd14SDaniel Borkmann } 13575aa5bd14SDaniel Borkmann } 13585aa5bd14SDaniel Borkmann 13590a674874SJoe Stringer get_unpriv_disabled(); 13600a674874SJoe Stringer if (unpriv && unpriv_disabled) { 13610a674874SJoe Stringer printf("Cannot run as unprivileged user with sysctl %s.\n", 13620a674874SJoe Stringer UNPRIV_SYSCTL); 13630a674874SJoe Stringer return EXIT_FAILURE; 13640a674874SJoe Stringer } 13650a674874SJoe Stringer 1366a82d8cd3SDaniel Borkmann bpf_semi_rand_init(); 13675aa5bd14SDaniel Borkmann return do_test(unpriv, from, to); 13685aa5bd14SDaniel Borkmann } 1369