diff options
author | David S. Miller <davem@davemloft.net> | 2019-09-06 17:49:17 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-09-06 17:49:17 +0300 |
commit | 1e46c09ec10049a9e366153b32e41cc557383fdb (patch) | |
tree | b2f86d40fd1ddf32522b5dd1792158daeab72e21 /tools/testing | |
parent | f9bcfe214b00c37a6a8e21cab030503fdfd29aca (diff) | |
parent | 593f191a8005110e20302039834c116676d69be1 (diff) | |
download | linux-1e46c09ec10049a9e366153b32e41cc557383fdb.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says:
====================
The following pull-request contains BPF updates for your *net-next* tree.
The main changes are:
1) Add the ability to use unaligned chunks in the AF_XDP umem. By
relaxing where the chunks can be placed, it allows to use an
arbitrary buffer size and place whenever there is a free
address in the umem. Helps more seamless DPDK AF_XDP driver
integration. Support for i40e, ixgbe and mlx5e, from Kevin and
Maxim.
2) Addition of a wakeup flag for AF_XDP tx and fill rings so the
application can wake up the kernel for rx/tx processing which
avoids busy-spinning of the latter, useful when app and driver
is located on the same core. Support for i40e, ixgbe and mlx5e,
from Magnus and Maxim.
3) bpftool fixes for printf()-like functions so compiler can actually
enforce checks, bpftool build system improvements for custom output
directories, and addition of 'bpftool map freeze' command, from Quentin.
4) Support attaching/detaching XDP programs from 'bpftool net' command,
from Daniel.
5) Automatic xskmap cleanup when AF_XDP socket is released, and several
barrier/{read,write}_once fixes in AF_XDP code, from Björn.
6) Relicense of bpf_helpers.h/bpf_endian.h for future libbpf
inclusion as well as libbpf versioning improvements, from Andrii.
7) Several new BPF kselftests for verifier precision tracking, from Alexei.
8) Several BPF kselftest fixes wrt endianess to run on s390x, from Ilya.
9) And more BPF kselftest improvements all over the place, from Stanislav.
10) Add simple BPF map op cache for nfp driver to batch dumps, from Jakub.
11) AF_XDP socket umem mapping improvements for 32bit archs, from Ivan.
12) Add BPF-to-BPF call and BTF line info support for s390x JIT, from Yauheni.
13) Small optimization in arm64 JIT to spare 1 insns for BPF_MOD, from Jerin.
14) Fix an error check in bpf_tcp_gen_syncookie() helper, from Petar.
15) Various minor fixes and cleanups, from Nathan, Masahiro, Masanari,
Peter, Wei, Yue.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/testing')
39 files changed, 1029 insertions, 250 deletions
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 90f70d2c7c22..60c9338cd9b4 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -42,4 +42,5 @@ xdping test_sockopt test_sockopt_sk test_sockopt_multi +test_sockopt_inherit test_tcp_rtt diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index d69c541e2039..9eef5edf17be 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -29,7 +29,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ test_btf_dump test_cgroup_attach xdping test_sockopt test_sockopt_sk \ - test_sockopt_multi test_tcp_rtt + test_sockopt_multi test_sockopt_inherit test_tcp_rtt BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) @@ -66,7 +66,8 @@ TEST_PROGS := test_kmod.sh \ test_tcp_check_syncookie.sh \ test_tc_tunnel.sh \ test_tc_edt.sh \ - test_xdping.sh + test_xdping.sh \ + test_bpftool_build.sh TEST_PROGS_EXTENDED := with_addr.sh \ with_tunnels.sh \ @@ -115,6 +116,7 @@ $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c $(OUTPUT)/test_sockopt: cgroup_helpers.c $(OUTPUT)/test_sockopt_sk: cgroup_helpers.c $(OUTPUT)/test_sockopt_multi: cgroup_helpers.c +$(OUTPUT)/test_sockopt_inherit: cgroup_helpers.c $(OUTPUT)/test_tcp_rtt: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h index 05f036df8a4c..fbe28008450f 100644 --- a/tools/testing/selftests/bpf/bpf_endian.h +++ b/tools/testing/selftests/bpf/bpf_endian.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ #ifndef __BPF_ENDIAN__ #define __BPF_ENDIAN__ @@ -29,6 +29,10 @@ # define __bpf_htonl(x) __builtin_bswap32(x) # define __bpf_constant_ntohl(x) ___constant_swab32(x) # define __bpf_constant_htonl(x) ___constant_swab32(x) +# define __bpf_be64_to_cpu(x) __builtin_bswap64(x) +# define __bpf_cpu_to_be64(x) __builtin_bswap64(x) +# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x) +# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x) #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define __bpf_ntohs(x) (x) # define __bpf_htons(x) (x) @@ -38,6 +42,10 @@ # define __bpf_htonl(x) (x) # define __bpf_constant_ntohl(x) (x) # define __bpf_constant_htonl(x) (x) +# define __bpf_be64_to_cpu(x) (x) +# define __bpf_cpu_to_be64(x) (x) +# define __bpf_constant_be64_to_cpu(x) (x) +# define __bpf_constant_cpu_to_be64(x) (x) #else # error "Fix your compiler's __BYTE_ORDER__?!" #endif @@ -54,5 +62,11 @@ #define bpf_ntohl(x) \ (__builtin_constant_p(x) ? \ __bpf_constant_ntohl(x) : __bpf_ntohl(x)) +#define bpf_cpu_to_be64(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x)) +#define bpf_be64_to_cpu(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x)) #endif /* __BPF_ENDIAN__ */ diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 8b503ea142f0..6c4930bc6e2e 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ #ifndef __BPF_HELPERS_H #define __BPF_HELPERS_H diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c index fb5840a62548..f10029821e16 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c @@ -48,16 +48,17 @@ void test_bpf_obj_id(void) /* test_obj_id.o is a dumb prog. It should never fail * to load. */ - if (err) - error_cnt++; - assert(!err); + if (CHECK_FAIL(err)) + continue; /* Insert a magic value to the map */ map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); - assert(map_fds[i] >= 0); + if (CHECK_FAIL(map_fds[i] < 0)) + goto done; err = bpf_map_update_elem(map_fds[i], &array_key, &array_magic_value, 0); - assert(!err); + if (CHECK_FAIL(err)) + goto done; /* Check getting map info */ info_len = sizeof(struct bpf_map_info) * 2; @@ -96,9 +97,11 @@ void test_bpf_obj_id(void) prog_infos[i].map_ids = ptr_to_u64(map_ids + i); prog_infos[i].nr_map_ids = 2; err = clock_gettime(CLOCK_REALTIME, &real_time_ts); - assert(!err); + if (CHECK_FAIL(err)) + goto done; err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts); - assert(!err); + if (CHECK_FAIL(err)) + goto done; err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i], &info_len); load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec) @@ -224,7 +227,8 @@ void test_bpf_obj_id(void) nr_id_found++; err = bpf_map_lookup_elem(map_fd, &array_key, &array_value); - assert(!err); + if (CHECK_FAIL(err)) + goto done; err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len); CHECK(err || info_len != sizeof(struct bpf_map_info) || diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c index 1a1eae356f81..1c01ee2600a9 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c @@ -28,8 +28,6 @@ static int check_load(const char *file, enum bpf_prog_type type) attr.prog_flags = BPF_F_TEST_RND_HI32; err = bpf_prog_load_xattr(&attr, &obj, &prog_fd); bpf_object__close(obj); - if (err) - error_cnt++; return err; } @@ -105,12 +103,7 @@ void test_bpf_verif_scale(void) continue; err = check_load(test->file, test->attach_type); - if (test->fails) { /* expected to fail */ - if (err) - error_cnt--; - else - error_cnt++; - } + CHECK_FAIL(err && !test->fails); } if (env.verifier_stats) diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c index 6892b88ae065..92563898867c 100644 --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c @@ -344,7 +344,6 @@ struct test tests[] = { .tcp.dest = 8080, }, .keys = { - .nhoff = 0, .nhoff = ETH_HLEN, .thoff = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct iphdr), @@ -452,10 +451,8 @@ void test_flow_dissector(void) err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector", "jmp_table", "last_dissection", &prog_fd, &keys_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } for (i = 0; i < ARRAY_SIZE(tests); i++) { struct bpf_flow_keys flow_keys; diff --git a/tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c b/tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c index 3d59b3c841fe..eba9a970703b 100644 --- a/tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c +++ b/tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c @@ -135,10 +135,7 @@ void test_get_stack_raw_tp(void) exp_cnt -= err; } - goto close_prog_noerr; close_prog: - error_cnt++; -close_prog_noerr: if (!IS_ERR_OR_NULL(link)) bpf_link__destroy(link); if (!IS_ERR_OR_NULL(pb)) diff --git a/tools/testing/selftests/bpf/prog_tests/global_data.c b/tools/testing/selftests/bpf/prog_tests/global_data.c index d011079fb0bf..c680926fce73 100644 --- a/tools/testing/selftests/bpf/prog_tests/global_data.c +++ b/tools/testing/selftests/bpf/prog_tests/global_data.c @@ -7,10 +7,8 @@ static void test_global_data_number(struct bpf_object *obj, __u32 duration) uint64_t num; map_fd = bpf_find_map(__func__, obj, "result_number"); - if (map_fd < 0) { - error_cnt++; + if (CHECK_FAIL(map_fd < 0)) return; - } struct { char *name; @@ -44,10 +42,8 @@ static void test_global_data_string(struct bpf_object *obj, __u32 duration) char str[32]; map_fd = bpf_find_map(__func__, obj, "result_string"); - if (map_fd < 0) { - error_cnt++; + if (CHECK_FAIL(map_fd < 0)) return; - } struct { char *name; @@ -81,10 +77,8 @@ static void test_global_data_struct(struct bpf_object *obj, __u32 duration) struct foo val; map_fd = bpf_find_map(__func__, obj, "result_struct"); - if (map_fd < 0) { - error_cnt++; + if (CHECK_FAIL(map_fd < 0)) return; - } struct { char *name; @@ -112,16 +106,12 @@ static void test_global_data_rdonly(struct bpf_object *obj, __u32 duration) __u8 *buff; map = bpf_object__find_map_by_name(obj, "test_glo.rodata"); - if (!map || !bpf_map__is_internal(map)) { - error_cnt++; + if (CHECK_FAIL(!map || !bpf_map__is_internal(map))) return; - } map_fd = bpf_map__fd(map); - if (map_fd < 0) { - error_cnt++; + if (CHECK_FAIL(map_fd < 0)) return; - } buff = malloc(bpf_map__def(map)->value_size); if (buff) diff --git a/tools/testing/selftests/bpf/prog_tests/l4lb_all.c b/tools/testing/selftests/bpf/prog_tests/l4lb_all.c index 20ddca830e68..eaf64595be88 100644 --- a/tools/testing/selftests/bpf/prog_tests/l4lb_all.c +++ b/tools/testing/selftests/bpf/prog_tests/l4lb_all.c @@ -30,10 +30,8 @@ static void test_l4lb(const char *file) u32 *magic = (u32 *)buf; err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } map_fd = bpf_find_map(__func__, obj, "vip_map"); if (map_fd < 0) @@ -72,10 +70,9 @@ static void test_l4lb(const char *file) bytes += stats[i].bytes; pkts += stats[i].pkts; } - if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) { - error_cnt++; + if (CHECK_FAIL(bytes != MAGIC_BYTES * NUM_ITER * 2 || + pkts != NUM_ITER * 2)) printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts); - } out: bpf_object__close(obj); } diff --git a/tools/testing/selftests/bpf/prog_tests/map_lock.c b/tools/testing/selftests/bpf/prog_tests/map_lock.c index ee99368c595c..8f91f1881d11 100644 --- a/tools/testing/selftests/bpf/prog_tests/map_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/map_lock.c @@ -8,14 +8,12 @@ static void *parallel_map_access(void *arg) for (i = 0; i < 10000; i++) { err = bpf_map_lookup_elem_flags(map_fd, &key, vars, BPF_F_LOCK); - if (err) { + if (CHECK_FAIL(err)) { printf("lookup failed\n"); - error_cnt++; goto out; } - if (vars[0] != 0) { + if (CHECK_FAIL(vars[0] != 0)) { printf("lookup #%d var[0]=%d\n", i, vars[0]); - error_cnt++; goto out; } rnd = vars[1]; @@ -24,7 +22,7 @@ static void *parallel_map_access(void *arg) continue; printf("lookup #%d var[1]=%d var[%d]=%d\n", i, rnd, j, vars[j]); - error_cnt++; + CHECK_FAIL(vars[j] != rnd); goto out; } } @@ -42,34 +40,36 @@ void test_map_lock(void) void *ret; err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd); - if (err) { + if (CHECK_FAIL(err)) { printf("test_map_lock:bpf_prog_load errno %d\n", errno); goto close_prog; } map_fd[0] = bpf_find_map(__func__, obj, "hash_map"); - if (map_fd[0] < 0) + if (CHECK_FAIL(map_fd[0] < 0)) goto close_prog; map_fd[1] = bpf_find_map(__func__, obj, "array_map"); - if (map_fd[1] < 0) + if (CHECK_FAIL(map_fd[1] < 0)) goto close_prog; bpf_map_update_elem(map_fd[0], &key, vars, BPF_F_LOCK); for (i = 0; i < 4; i++) - assert(pthread_create(&thread_id[i], NULL, - &spin_lock_thread, &prog_fd) == 0); + if (CHECK_FAIL(pthread_create(&thread_id[i], NULL, + &spin_lock_thread, &prog_fd))) + goto close_prog; for (i = 4; i < 6; i++) - assert(pthread_create(&thread_id[i], NULL, - ¶llel_map_access, &map_fd[i - 4]) == 0); + if (CHECK_FAIL(pthread_create(&thread_id[i], NULL, + ¶llel_map_access, + &map_fd[i - 4]))) + goto close_prog; for (i = 0; i < 4; i++) - assert(pthread_join(thread_id[i], &ret) == 0 && - ret == (void *)&prog_fd); + if (CHECK_FAIL(pthread_join(thread_id[i], &ret) || + ret != (void *)&prog_fd)) + goto close_prog; for (i = 4; i < 6; i++) - assert(pthread_join(thread_id[i], &ret) == 0 && - ret == (void *)&map_fd[i - 4]); - goto close_prog_noerr; + if (CHECK_FAIL(pthread_join(thread_id[i], &ret) || + ret != (void *)&map_fd[i - 4])) + goto close_prog; close_prog: - error_cnt++; -close_prog_noerr: bpf_object__close(obj); } diff --git a/tools/testing/selftests/bpf/prog_tests/pkt_access.c b/tools/testing/selftests/bpf/prog_tests/pkt_access.c index 4ecfd721a044..a2537dfa899c 100644 --- a/tools/testing/selftests/bpf/prog_tests/pkt_access.c +++ b/tools/testing/selftests/bpf/prog_tests/pkt_access.c @@ -9,10 +9,8 @@ void test_pkt_access(void) int err, prog_fd; err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4), NULL, NULL, &retval, &duration); diff --git a/tools/testing/selftests/bpf/prog_tests/pkt_md_access.c b/tools/testing/selftests/bpf/prog_tests/pkt_md_access.c index ac0d43435806..5f7aea605019 100644 --- a/tools/testing/selftests/bpf/prog_tests/pkt_md_access.c +++ b/tools/testing/selftests/bpf/prog_tests/pkt_md_access.c @@ -9,10 +9,8 @@ void test_pkt_md_access(void) int err, prog_fd; err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4), NULL, NULL, &retval, &duration); diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c index e60cd5ff1f55..faccc66f4e39 100644 --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c @@ -27,10 +27,8 @@ static void test_queue_stack_map_by_type(int type) return; err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } map_in_fd = bpf_find_map(__func__, obj, "map_in"); if (map_in_fd < 0) @@ -43,10 +41,8 @@ static void test_queue_stack_map_by_type(int type) /* Push 32 elements to the input map */ for (i = 0; i < MAP_SIZE; i++) { err = bpf_map_update_elem(map_in_fd, NULL, &vals[i], 0); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) goto out; - } } /* The eBPF program pushes iph.saddr in the output map, diff --git a/tools/testing/selftests/bpf/prog_tests/reference_tracking.c b/tools/testing/selftests/bpf/prog_tests/reference_tracking.c index 4a4f428d1a78..5c78e2b5a917 100644 --- a/tools/testing/selftests/bpf/prog_tests/reference_tracking.c +++ b/tools/testing/selftests/bpf/prog_tests/reference_tracking.c @@ -10,10 +10,8 @@ void test_reference_tracking(void) int err = 0; obj = bpf_object__open(file); - if (IS_ERR(obj)) { - error_cnt++; + if (CHECK_FAIL(IS_ERR(obj))) return; - } bpf_object__for_each_program(prog, obj) { const char *title; diff --git a/tools/testing/selftests/bpf/prog_tests/send_signal.c b/tools/testing/selftests/bpf/prog_tests/send_signal.c index 1575f0a1f586..b607112c64e7 100644 --- a/tools/testing/selftests/bpf/prog_tests/send_signal.c +++ b/tools/testing/selftests/bpf/prog_tests/send_signal.c @@ -8,7 +8,7 @@ static void sigusr1_handler(int signum) sigusr1_received++; } -static int test_send_signal_common(struct perf_event_attr *attr, +static void test_send_signal_common(struct perf_event_attr *attr, int prog_type, const char *test_name) { @@ -23,13 +23,13 @@ static int test_send_signal_common(struct perf_event_attr *attr, if (CHECK(pipe(pipe_c2p), test_name, "pipe pipe_c2p error: %s\n", strerror(errno))) - goto no_fork_done; + return; if (CHECK(pipe(pipe_p2c), test_name, "pipe pipe_p2c error: %s\n", strerror(errno))) { close(pipe_c2p[0]); close(pipe_c2p[1]); - goto no_fork_done; + return; } pid = fork(); @@ -38,7 +38,7 @@ static int test_send_signal_common(struct perf_event_attr *attr, close(pipe_c2p[1]); close(pipe_p2c[0]); close(pipe_p2c[1]); - goto no_fork_done; + return; } if (pid == 0) { @@ -125,7 +125,7 @@ static int test_send_signal_common(struct perf_event_attr *attr, goto disable_pmu; } - err = CHECK(buf[0] != '2', test_name, "incorrect result\n"); + CHECK(buf[0] != '2', test_name, "incorrect result\n"); /* notify child safe to exit */ write(pipe_p2c[1], buf, 1); @@ -138,11 +138,9 @@ prog_load_failure: close(pipe_c2p[0]); close(pipe_p2c[1]); wait(NULL); -no_fork_done: - return err; } -static int test_send_signal_tracepoint(void) +static void test_send_signal_tracepoint(void) { const char *id_path = "/sys/kernel/debug/tracing/events/syscalls/sys_enter_nanosleep/id"; struct perf_event_attr attr = { @@ -159,21 +157,21 @@ static int test_send_signal_tracepoint(void) if (CHECK(efd < 0, "tracepoint", "open syscalls/sys_enter_nanosleep/id failure: %s\n", strerror(errno))) - return -1; + return; bytes = read(efd, buf, sizeof(buf)); close(efd); if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "tracepoint", "read syscalls/sys_enter_nanosleep/id failure: %s\n", strerror(errno))) - return -1; + return; attr.config = strtol(buf, NULL, 0); - return test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint"); + test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint"); } -static int test_send_signal_perf(void) +static void test_send_signal_perf(void) { struct perf_event_attr attr = { .sample_period = 1, @@ -181,11 +179,11 @@ static int test_send_signal_perf(void) .config = PERF_COUNT_SW_CPU_CLOCK, }; - return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, - "perf_sw_event"); + test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, + "perf_sw_event"); } -static int test_send_signal_nmi(void) +static void test_send_signal_nmi(void) { struct perf_event_attr attr = { .sample_freq = 50, @@ -204,25 +202,24 @@ static int test_send_signal_nmi(void) if (errno == ENOENT) { printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n", __func__); - return 0; + test__skip(); + return; } /* Let the test fail with a more informative message */ } else { close(pmu_fd); } - return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, - "perf_hw_event"); + test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, + "perf_hw_event"); } void test_send_signal(void) { - int ret = 0; - if (test__start_subtest("send_signal_tracepoint")) - ret |= test_send_signal_tracepoint(); + test_send_signal_tracepoint(); if (test__start_subtest("send_signal_perf")) - ret |= test_send_signal_perf(); + test_send_signal_perf(); if (test__start_subtest("send_signal_nmi")) - ret |= test_send_signal_nmi(); + test_send_signal_nmi(); } diff --git a/tools/testing/selftests/bpf/prog_tests/spinlock.c b/tools/testing/selftests/bpf/prog_tests/spinlock.c index 114ebe6a438e..1ae00cd3174e 100644 --- a/tools/testing/selftests/bpf/prog_tests/spinlock.c +++ b/tools/testing/selftests/bpf/prog_tests/spinlock.c @@ -11,19 +11,19 @@ void test_spinlock(void) void *ret; err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd); - if (err) { + if (CHECK_FAIL(err)) { printf("test_spin_lock:bpf_prog_load errno %d\n", errno); goto close_prog; } for (i = 0; i < 4; i++) - assert(pthread_create(&thread_id[i], NULL, - &spin_lock_thread, &prog_fd) == 0); + if (CHECK_FAIL(pthread_create(&thread_id[i], NULL, + &spin_lock_thread, &prog_fd))) + goto close_prog; + for (i = 0; i < 4; i++) - assert(pthread_join(thread_id[i], &ret) == 0 && - ret == (void *)&prog_fd); - goto close_prog_noerr; + if (CHECK_FAIL(pthread_join(thread_id[i], &ret) || + ret != (void *)&prog_fd)) + goto close_prog; close_prog: - error_cnt++; -close_prog_noerr: bpf_object__close(obj); } diff --git a/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id.c b/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id.c index ac44fda84833..d841dced971f 100644 --- a/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id.c +++ b/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id.c @@ -51,9 +51,10 @@ retry: "err %d errno %d\n", err, errno)) goto disable_pmu; - assert(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null") - == 0); - assert(system("./urandom_read") == 0); + if (CHECK_FAIL(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null"))) + goto disable_pmu; + if (CHECK_FAIL(system("./urandom_read"))) + goto disable_pmu; /* disable stack trace collection */ key = 0; val = 1; diff --git a/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id_nmi.c b/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id_nmi.c index 9557b7dfb782..f62aa0eb959b 100644 --- a/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id_nmi.c +++ b/tools/testing/selftests/bpf/prog_tests/stacktrace_build_id_nmi.c @@ -82,9 +82,10 @@ retry: "err %d errno %d\n", err, errno)) goto disable_pmu; - assert(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null") - == 0); - assert(system("taskset 0x1 ./urandom_read 100000") == 0); + if (CHECK_FAIL(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null"))) + goto disable_pmu; + if (CHECK_FAIL(system("taskset 0x1 ./urandom_read 100000"))) + goto disable_pmu; /* disable stack trace collection */ key = 0; val = 1; diff --git a/tools/testing/selftests/bpf/prog_tests/stacktrace_map.c b/tools/testing/selftests/bpf/prog_tests/stacktrace_map.c index fc539335c5b3..37269d23df93 100644 --- a/tools/testing/selftests/bpf/prog_tests/stacktrace_map.c +++ b/tools/testing/selftests/bpf/prog_tests/stacktrace_map.c @@ -26,19 +26,19 @@ void test_stacktrace_map(void) /* find map fds */ control_map_fd = bpf_find_map(__func__, obj, "control_map"); - if (control_map_fd < 0) + if (CHECK_FAIL(control_map_fd < 0)) goto disable_pmu; stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); - if (stackid_hmap_fd < 0) + if (CHECK_FAIL(stackid_hmap_fd < 0)) goto disable_pmu; stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); - if (stackmap_fd < 0) + if (CHECK_FAIL(stackmap_fd < 0)) goto disable_pmu; stack_amap_fd = bpf_find_map(__func__, obj, "stack_amap"); - if (stack_amap_fd < 0) + if (CHECK_FAIL(stack_amap_fd < 0)) goto disable_pmu; /* give some time for bpf program run */ @@ -55,23 +55,20 @@ void test_stacktrace_map(void) err = compare_map_keys(stackid_hmap_fd, stackmap_fd); if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", "err %d errno %d\n", err, errno)) - goto disable_pmu_noerr; + goto disable_pmu; err = compare_map_keys(stackmap_fd, stackid_hmap_fd); if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", "err %d errno %d\n", err, errno)) - goto disable_pmu_noerr; + goto disable_pmu; stack_trace_len = PERF_MAX_STACK_DEPTH * sizeof(__u64); err = compare_stack_ips(stackmap_fd, stack_amap_fd, stack_trace_len); if (CHECK(err, "compare_stack_ips stackmap vs. stack_amap", "err %d errno %d\n", err, errno)) - goto disable_pmu_noerr; + goto disable_pmu; - goto disable_pmu_noerr; disable_pmu: - error_cnt++; -disable_pmu_noerr: bpf_link__destroy(link); close_prog: bpf_object__close(obj); diff --git a/tools/testing/selftests/bpf/prog_tests/stacktrace_map_raw_tp.c b/tools/testing/selftests/bpf/prog_tests/stacktrace_map_raw_tp.c index fbfa8e76cf63..404a5498e1a3 100644 --- a/tools/testing/selftests/bpf/prog_tests/stacktrace_map_raw_tp.c +++ b/tools/testing/selftests/bpf/prog_tests/stacktrace_map_raw_tp.c @@ -26,15 +26,15 @@ void test_stacktrace_map_raw_tp(void) /* find map fds */ control_map_fd = bpf_find_map(__func__, obj, "control_map"); - if (control_map_fd < 0) + if (CHECK_FAIL(control_map_fd < 0)) goto close_prog; stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); - if (stackid_hmap_fd < 0) + if (CHECK_FAIL(stackid_hmap_fd < 0)) goto close_prog; stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); - if (stackmap_fd < 0) + if (CHECK_FAIL(stackmap_fd < 0)) goto close_prog; /* give some time for bpf program run */ @@ -58,10 +58,7 @@ void test_stacktrace_map_raw_tp(void) "err %d errno %d\n", err, errno)) goto close_prog; - goto close_prog_noerr; close_prog: - error_cnt++; -close_prog_noerr: if (!IS_ERR_OR_NULL(link)) bpf_link__destroy(link); bpf_object__close(obj); diff --git a/tools/testing/selftests/bpf/prog_tests/task_fd_query_rawtp.c b/tools/testing/selftests/bpf/prog_tests/task_fd_query_rawtp.c index 958a3d88de99..1bdc1d86a50c 100644 --- a/tools/testing/selftests/bpf/prog_tests/task_fd_query_rawtp.c +++ b/tools/testing/selftests/bpf/prog_tests/task_fd_query_rawtp.c @@ -70,9 +70,6 @@ void test_task_fd_query_rawtp(void) if (CHECK(!err, "check_results", "fd_type %d len %u\n", fd_type, len)) goto close_prog; - goto close_prog_noerr; close_prog: - error_cnt++; -close_prog_noerr: bpf_object__close(obj); } diff --git a/tools/testing/selftests/bpf/prog_tests/task_fd_query_tp.c b/tools/testing/selftests/bpf/prog_tests/task_fd_query_tp.c index f9b70e81682b..3f131b8fe328 100644 --- a/tools/testing/selftests/bpf/prog_tests/task_fd_query_tp.c +++ b/tools/testing/selftests/bpf/prog_tests/task_fd_query_tp.c @@ -62,14 +62,9 @@ static void test_task_fd_query_tp_core(const char *probe_name, fd_type, buf)) goto close_pmu; - close(pmu_fd); - goto close_prog_noerr; - close_pmu: close(pmu_fd); close_prog: - error_cnt++; -close_prog_noerr: bpf_object__close(obj); } diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_estats.c b/tools/testing/selftests/bpf/prog_tests/tcp_estats.c index bb8759d69099..594307dffd13 100644 --- a/tools/testing/selftests/bpf/prog_tests/tcp_estats.c +++ b/tools/testing/selftests/bpf/prog_tests/tcp_estats.c @@ -10,10 +10,8 @@ void test_tcp_estats(void) err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); CHECK(err, "", "err %d errno %d\n", err, errno); - if (err) { - error_cnt++; + if (err) return; - } bpf_object__close(obj); } diff --git a/tools/testing/selftests/bpf/prog_tests/xdp.c b/tools/testing/selftests/bpf/prog_tests/xdp.c index a74167289545..dcb5ecac778e 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp.c @@ -16,10 +16,8 @@ void test_xdp(void) int err, prog_fd, map_fd; err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } map_fd = bpf_find_map(__func__, obj, "vip2tnl"); if (map_fd < 0) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c index 922aa0a19764..3744196d7cba 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c @@ -10,10 +10,8 @@ void test_xdp_adjust_tail(void) int err, prog_fd; err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), buf, &size, &retval, &duration); diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_noinline.c b/tools/testing/selftests/bpf/prog_tests/xdp_noinline.c index 15f7c272edb0..c9404e6b226e 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_noinline.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_noinline.c @@ -31,10 +31,8 @@ void test_xdp_noinline(void) u32 *magic = (u32 *)buf; err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); - if (err) { - error_cnt++; + if (CHECK_FAIL(err)) return; - } map_fd = bpf_find_map(__func__, obj, "vip_map"); if (map_fd < 0) @@ -73,8 +71,8 @@ void test_xdp_noinline(void) bytes += stats[i].bytes; pkts += stats[i].pkts; } - if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) { - error_cnt++; + if (CHECK_FAIL(bytes != MAGIC_BYTES * NUM_ITER * 2 || + pkts != NUM_ITER * 2)) { printf("test_xdp_noinline:FAIL:stats %lld %lld\n", bytes, pkts); } diff --git a/tools/testing/selftests/bpf/progs/sockopt_inherit.c b/tools/testing/selftests/bpf/progs/sockopt_inherit.c new file mode 100644 index 000000000000..dede0fcd6102 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sockopt_inherit.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/bpf.h> +#include "bpf_helpers.h" + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; + +#define SOL_CUSTOM 0xdeadbeef +#define CUSTOM_INHERIT1 0 +#define CUSTOM_INHERIT2 1 +#define CUSTOM_LISTENER 2 + +struct sockopt_inherit { + __u8 val; +}; + +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE); + __type(key, int); + __type(value, struct sockopt_inherit); +} cloned1_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE); + __type(key, int); + __type(value, struct sockopt_inherit); +} cloned2_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct sockopt_inherit); +} listener_only_map SEC(".maps"); + +static __inline struct sockopt_inherit *get_storage(struct bpf_sockopt *ctx) +{ + if (ctx->optname == CUSTOM_INHERIT1) + return bpf_sk_storage_get(&cloned1_map, ctx->sk, 0, + BPF_SK_STORAGE_GET_F_CREATE); + else if (ctx->optname == CUSTOM_INHERIT2) + return bpf_sk_storage_get(&cloned2_map, ctx->sk, 0, + BPF_SK_STORAGE_GET_F_CREATE); + else + return bpf_sk_storage_get(&listener_only_map, ctx->sk, 0, + BPF_SK_STORAGE_GET_F_CREATE); +} + +SEC("cgroup/getsockopt") +int _getsockopt(struct bpf_sockopt *ctx) +{ + __u8 *optval_end = ctx->optval_end; + struct sockopt_inherit *storage; + __u8 *optval = ctx->optval; + + if (ctx->level != SOL_CUSTOM) + return 1; /* only interested in SOL_CUSTOM */ + + if (optval + 1 > optval_end) + return 0; /* EPERM, bounds check */ + + storage = get_storage(ctx); + if (!storage) + return 0; /* EPERM, couldn't get sk storage */ + + ctx->retval = 0; /* Reset system call return value to zero */ + + optval[0] = storage->val; + ctx->optlen = 1; + + return 1; +} + +SEC("cgroup/setsockopt") +int _setsockopt(struct bpf_sockopt *ctx) +{ + __u8 *optval_end = ctx->optval_end; + struct sockopt_inherit *storage; + __u8 *optval = ctx->optval; + + if (ctx->level != SOL_CUSTOM) + return 1; /* only interested in SOL_CUSTOM */ + + if (optval + 1 > optval_end) + return 0; /* EPERM, bounds check */ + + storage = get_storage(ctx); + if (!storage) + return 0; /* EPERM, couldn't get sk storage */ + + storage->val = optval[0]; + ctx->optlen = -1; + + return 1; +} diff --git a/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c b/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c index a334a0e882e4..41a3ebcd593d 100644 --- a/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c +++ b/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c @@ -12,10 +12,6 @@ #define SR6_FLAG_ALERT (1 << 4) -#define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \ - 0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32)) -#define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \ - 0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32)) #define BPF_PACKET_HEADER __attribute__((packed)) struct ip6_t { @@ -276,8 +272,8 @@ int has_egr_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh) return 0; // check if egress TLV value is correct - if (ntohll(egr_addr.hi) == 0xfd00000000000000 && - ntohll(egr_addr.lo) == 0x4) + if (bpf_be64_to_cpu(egr_addr.hi) == 0xfd00000000000000 && + bpf_be64_to_cpu(egr_addr.lo) == 0x4) return 1; } @@ -308,8 +304,8 @@ int __encap_srh(struct __sk_buff *skb) #pragma clang loop unroll(full) for (unsigned long long lo = 0; lo < 4; lo++) { - seg->lo = htonll(4 - lo); - seg->hi = htonll(hi); + seg->lo = bpf_cpu_to_be64(4 - lo); + seg->hi = bpf_cpu_to_be64(hi); seg = (struct ip6_addr_t *)((char *)seg + sizeof(*seg)); } @@ -349,8 +345,8 @@ int __add_egr_x(struct __sk_buff *skb) if (err) return BPF_DROP; - addr.lo = htonll(lo); - addr.hi = htonll(hi); + addr.lo = bpf_cpu_to_be64(lo); + addr.hi = bpf_cpu_to_be64(hi); err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X, (void *)&addr, sizeof(addr)); if (err) diff --git a/tools/testing/selftests/bpf/progs/test_seg6_loop.c b/tools/testing/selftests/bpf/progs/test_seg6_loop.c index 1dbe1d4d467e..c4d104428643 100644 --- a/tools/testing/selftests/bpf/progs/test_seg6_loop.c +++ b/tools/testing/selftests/bpf/progs/test_seg6_loop.c @@ -12,10 +12,6 @@ #define SR6_FLAG_ALERT (1 << 4) -#define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \ - 0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32)) -#define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \ - 0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32)) #define BPF_PACKET_HEADER __attribute__((packed)) struct ip6_t { @@ -251,8 +247,8 @@ int __add_egr_x(struct __sk_buff *skb) if (err) return BPF_DROP; - addr.lo = htonll(lo); - addr.hi = htonll(hi); + addr.lo = bpf_cpu_to_be64(lo); + addr.hi = bpf_cpu_to_be64(hi); err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X, (void *)&addr, sizeof(addr)); if (err) diff --git a/tools/testing/selftests/bpf/test_bpftool_build.sh b/tools/testing/selftests/bpf/test_bpftool_build.sh new file mode 100755 index 000000000000..4ba5a34bff56 --- /dev/null +++ b/tools/testing/selftests/bpf/test_bpftool_build.sh @@ -0,0 +1,143 @@ +#!/bin/bash +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +ERROR=0 +TMPDIR= + +# If one build fails, continue but return non-0 on exit. +return_value() { + if [ -d "$TMPDIR" ] ; then + rm -rf -- $TMPDIR + fi + exit $ERROR +} +trap return_value EXIT + +case $1 in + -h|--help) + echo -e "$0 [-j <n>]" + echo -e "\tTest the different ways of building bpftool." + echo -e "" + echo -e "\tOptions:" + echo -e "\t\t-j <n>:\tPass -j flag to 'make'." + exit + ;; +esac + +J=$* + +# Assume script is located under tools/testing/selftests/bpf/. We want to start +# build attempts from the top of kernel repository. +SCRIPT_REL_PATH=$(realpath --relative-to=$PWD $0) +SCRIPT_REL_DIR=$(dirname $SCRIPT_REL_PATH) +KDIR_ROOT_DIR=$(realpath $PWD/$SCRIPT_REL_DIR/../../../../) +cd $KDIR_ROOT_DIR + +check() { + local dir=$(realpath $1) + + echo -n "binary: " + # Returns non-null if file is found (and "false" is run) + find $dir -type f -executable -name bpftool -print -exec false {} + && \ + ERROR=1 && printf "FAILURE: Did not find bpftool\n" +} + +make_and_clean() { + echo -e "\$PWD: $PWD" + echo -e "command: make -s $* >/dev/null" + make $J -s $* >/dev/null + if [ $? -ne 0 ] ; then + ERROR=1 + fi + if [ $# -ge 1 ] ; then + check ${@: -1} + else + check . + fi + ( + if [ $# -ge 1 ] ; then + cd ${@: -1} + fi + make -s clean + ) + echo +} + +make_with_tmpdir() { + local ARGS + + TMPDIR=$(mktemp -d) + if [ $# -ge 2 ] ; then + ARGS=${@:1:(($# - 1))} + fi + echo -e "\$PWD: $PWD" + echo -e "command: make -s $ARGS ${@: -1}=$TMPDIR/ >/dev/null" + make $J -s $ARGS ${@: -1}=$TMPDIR/ >/dev/null + if [ $? -ne 0 ] ; then + ERROR=1 + fi + check $TMPDIR + rm -rf -- $TMPDIR + echo +} + +echo "Trying to build bpftool" +echo -e "... through kbuild\n" + +if [ -f ".config" ] ; then + make_and_clean tools/bpf + + ## $OUTPUT is overwritten in kbuild Makefile, and thus cannot be passed + ## down from toplevel Makefile to bpftool's Makefile. + + # make_with_tmpdir tools/bpf OUTPUT + echo -e "skip: make tools/bpf OUTPUT=<dir> (not supported)\n" + + make_with_tmpdir tools/bpf O +else + echo -e "skip: make tools/bpf (no .config found)\n" + echo -e "skip: make tools/bpf OUTPUT=<dir> (not supported)\n" + echo -e "skip: make tools/bpf O=<dir> (no .config found)\n" +fi + +echo -e "... from kernel source tree\n" + +make_and_clean -C tools/bpf/bpftool + +make_with_tmpdir -C tools/bpf/bpftool OUTPUT + +make_with_tmpdir -C tools/bpf/bpftool O + +echo -e "... from tools/\n" +cd tools/ + +make_and_clean bpf + +## In tools/bpf/Makefile, function "descend" is called and passes $(O) and +## $(OUTPUT). We would like $(OUTPUT) to have "bpf/bpftool/" appended before +## calling bpftool's Makefile, but this is not the case as the "descend" +## function focuses on $(O)/$(subdir). However, in the present case, updating +## $(O) to have $(OUTPUT) recomputed from it in bpftool's Makefile does not +## work, because $(O) is not defined from command line and $(OUTPUT) is not +## updated in tools/scripts/Makefile.include. +## +## Workarounds would require to a) edit "descend" or use an alternative way to +## call bpftool's Makefile, b) modify the conditions to update $(OUTPUT) and +## other variables in tools/scripts/Makefile.include (at the risk of breaking +## the build of other tools), or c) append manually the "bpf/bpftool" suffix to +## $(OUTPUT) in bpf's Makefile, which may break if targets for other directories +## use "descend" in the future. + +# make_with_tmpdir bpf OUTPUT +echo -e "skip: make bpf OUTPUT=<dir> (not supported)\n" + +make_with_tmpdir bpf O + +echo -e "... from bpftool's dir\n" +cd bpf/bpftool + +make_and_clean + +make_with_tmpdir OUTPUT + +make_with_tmpdir O diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py index 425f9ed27c3b..15a666329a34 100755 --- a/tools/testing/selftests/bpf/test_offload.py +++ b/tools/testing/selftests/bpf/test_offload.py @@ -1353,7 +1353,7 @@ try: bpftool_prog_list_wait(expected=1) ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] - fail(ifnameB != simB1['ifname'], "program not bound to originial device") + fail(ifnameB != simB1['ifname'], "program not bound to original device") simB1.remove() bpftool_prog_list_wait(expected=1) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 12895d03d58b..e8616e778cb5 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -8,22 +8,20 @@ /* defined in test_progs.h */ struct test_env env; -int error_cnt, pass_cnt; struct prog_test_def { const char *test_name; int test_num; void (*run_test)(void); bool force_log; - int pass_cnt; int error_cnt; + int skip_cnt; bool tested; const char *subtest_name; int subtest_num; /* store counts before subtest started */ - int old_pass_cnt; int old_error_cnt; }; @@ -47,6 +45,7 @@ static void dump_test_log(const struct prog_test_def *test, bool failed) if (env.verbose || test->force_log || failed) { if (env.log_cnt) { + env.log_buf[env.log_cnt] = '\0'; fprintf(env.stdout, "%s", env.log_buf); if (env.log_buf[env.log_cnt - 1] != '\n') fprintf(env.stdout, "\n"); @@ -56,15 +55,24 @@ static void dump_test_log(const struct prog_test_def *test, bool failed) fseeko(stdout, 0, SEEK_SET); /* rewind */ } +static void skip_account(void) +{ + if (env.test->skip_cnt) { + env.skip_cnt++; + env.test->skip_cnt = 0; + } +} + void test__end_subtest() { struct prog_test_def *test = env.test; - int sub_error_cnt = error_cnt - test->old_error_cnt; + int sub_error_cnt = test->error_cnt - test->old_error_cnt; if (sub_error_cnt) env.fail_cnt++; else env.sub_succ_cnt++; + skip_account(); dump_test_log(test, sub_error_cnt); @@ -95,8 +103,7 @@ bool test__start_subtest(const char *name) return false; test->subtest_name = name; - env.test->old_pass_cnt = pass_cnt; - env.test->old_error_cnt = error_cnt; + env.test->old_error_cnt = env.test->error_cnt; return true; } @@ -105,6 +112,16 @@ void test__force_log() { env.test->force_log = true; } +void test__skip(void) +{ + env.test->skip_cnt++; +} + +void test__fail(void) +{ + env.test->error_cnt++; +} + struct ipv4_packet pkt_v4 = { .eth.h_proto = __bpf_constant_htons(ETH_P_IP), .iph.ihl = 5, @@ -129,7 +146,7 @@ int bpf_find_map(const char *test, struct bpf_object *obj, const char *name) map = bpf_object__find_map_by_name(obj, name); if (!map) { printf("%s:FAIL:map '%s' not found\n", test, name); - error_cnt++; + test__fail(); return -1; } return bpf_map__fd(map); @@ -488,8 +505,6 @@ int main(int argc, char **argv) stdio_hijack(); for (i = 0; i < prog_test_cnt; i++) { struct prog_test_def *test = &prog_test_defs[i]; - int old_pass_cnt = pass_cnt; - int old_error_cnt = error_cnt; env.test = test; test->test_num = i + 1; @@ -504,12 +519,11 @@ int main(int argc, char **argv) test__end_subtest(); test->tested = true; - test->pass_cnt = pass_cnt - old_pass_cnt; - test->error_cnt = error_cnt - old_error_cnt; if (test->error_cnt) env.fail_cnt++; else env.succ_cnt++; + skip_account(); dump_test_log(test, test->error_cnt); @@ -518,11 +532,11 @@ int main(int argc, char **argv) test->error_cnt ? "FAIL" : "OK"); } stdio_restore(); - printf("Summary: %d/%d PASSED, %d FAILED\n", - env.succ_cnt, env.sub_succ_cnt, env.fail_cnt); + printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", + env.succ_cnt, env.sub_succ_cnt, env.skip_cnt, env.fail_cnt); free(env.test_selector.num_set); free(env.subtest_selector.num_set); - return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; + return env.fail_cnt ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index 37d427f5a1e5..c8edb9464ba6 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -38,8 +38,6 @@ typedef __u16 __sum16; #include "trace_helpers.h" #include "flow_dissector_load.h" -struct prog_test_def; - struct test_selector { const char *name; bool *num_set; @@ -64,14 +62,15 @@ struct test_env { int succ_cnt; /* successful tests */ int sub_succ_cnt; /* successful sub-tests */ int fail_cnt; /* total failed tests + sub-tests */ + int skip_cnt; /* skipped tests */ }; -extern int error_cnt; -extern int pass_cnt; extern struct test_env env; extern void test__force_log(); extern bool test__start_subtest(const char *name); +extern void test__skip(void); +extern void test__fail(void); #define MAGIC_BYTES 123 @@ -94,17 +93,25 @@ extern struct ipv6_packet pkt_v6; #define _CHECK(condition, tag, duration, format...) ({ \ int __ret = !!(condition); \ if (__ret) { \ - error_cnt++; \ + test__fail(); \ printf("%s:FAIL:%s ", __func__, tag); \ printf(format); \ } else { \ - pass_cnt++; \ printf("%s:PASS:%s %d nsec\n", \ __func__, tag, duration); \ } \ __ret; \ }) +#define CHECK_FAIL(condition) ({ \ + int __ret = !!(condition); \ + if (__ret) { \ + test__fail(); \ + printf("%s:FAIL:%d\n", __func__, __LINE__); \ + } \ + __ret; \ +}) + #define CHECK(condition, tag, format...) \ _CHECK(condition, tag, duration, format) #define CHECK_ATTR(condition, tag, format...) \ diff --git a/tools/testing/selftests/bpf/test_sockopt_inherit.c b/tools/testing/selftests/bpf/test_sockopt_inherit.c new file mode 100644 index 000000000000..1bf699815b9b --- /dev/null +++ b/tools/testing/selftests/bpf/test_sockopt_inherit.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <error.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <pthread.h> + +#include <linux/filter.h> +#include <bpf/bpf.h> +#include <bpf/libbpf.h> + +#include "bpf_rlimit.h" +#include "bpf_util.h" +#include "cgroup_helpers.h" + +#define CG_PATH "/sockopt_inherit" +#define SOL_CUSTOM 0xdeadbeef +#define CUSTOM_INHERIT1 0 +#define CUSTOM_INHERIT2 1 +#define CUSTOM_LISTENER 2 + +static int connect_to_server(int server_fd) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create client socket"); + return -1; + } + + if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { + log_err("Failed to get server addr"); + goto out; + } + + if (connect(fd, (const struct sockaddr *)&addr, len) < 0) { + log_err("Fail to connect to server"); + goto out; + } + + return fd; + +out: + close(fd); + return -1; +} + +static int verify_sockopt(int fd, int optname, const char *msg, char expected) +{ + socklen_t optlen = 1; + char buf = 0; + int err; + + err = getsockopt(fd, SOL_CUSTOM, optname, &buf, &optlen); + if (err) { + log_err("%s: failed to call getsockopt", msg); + return 1; + } + + printf("%s %d: got=0x%x ? expected=0x%x\n", msg, optname, buf, expected); + + if (buf != expected) { + log_err("%s: unexpected getsockopt value %d != %d", msg, + buf, expected); + return 1; + } + + return 0; +} + +static void *server_thread(void *arg) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd = *(int *)arg; + int client_fd; + int err = 0; + + if (listen(fd, 1) < 0) + error(1, errno, "Failed to listed on socket"); + + err += verify_sockopt(fd, CUSTOM_INHERIT1, "listen", 1); + err += verify_sockopt(fd, CUSTOM_INHERIT2, "listen", 1); + err += verify_sockopt(fd, CUSTOM_LISTENER, "listen", 1); + + client_fd = accept(fd, (struct sockaddr *)&addr, &len); + if (client_fd < 0) + error(1, errno, "Failed to accept client"); + + err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "accept", 1); + err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "accept", 1); + err += verify_sockopt(client_fd, CUSTOM_LISTENER, "accept", 0); + + close(client_fd); + + return (void *)(long)err; +} + +static int start_server(void) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; + char buf; + int err; + int fd; + int i; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create server socket"); + return -1; + } + + for (i = CUSTOM_INHERIT1; i <= CUSTOM_LISTENER; i++) { + buf = 0x01; + err = setsockopt(fd, SOL_CUSTOM, i, &buf, 1); + if (err) { + log_err("Failed to call setsockopt(%d)", i); + close(fd); + return -1; + } + } + + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { + log_err("Failed to bind socket"); + close(fd); + return -1; + } + + return fd; +} + +static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) +{ + enum bpf_attach_type attach_type; + enum bpf_prog_type prog_type; + struct bpf_program *prog; + int err; + + err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); + if (err) { + log_err("Failed to deduct types for %s BPF program", title); + return -1; + } + + prog = bpf_object__find_program_by_title(obj, title); + if (!prog) { + log_err("Failed to find %s BPF program", title); + return -1; + } + + err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, + attach_type, 0); + if (err) { + log_err("Failed to attach %s BPF program", title); + return -1; + } + + return 0; +} + +static int run_test(int cgroup_fd) +{ + struct bpf_prog_load_attr attr = { + .file = "./sockopt_inherit.o", + }; + int server_fd = -1, client_fd; + struct bpf_object *obj; + void *server_err; + pthread_t tid; + int ignored; + int err; + + err = bpf_prog_load_xattr(&attr, &obj, &ignored); + if (err) { + log_err("Failed to load BPF object"); + return -1; + } + + err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt"); + if (err) + goto close_bpf_object; + + err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt"); + if (err) + goto close_bpf_object; + + server_fd = start_server(); + if (server_fd < 0) { + err = -1; + goto close_bpf_object; + } + + pthread_create(&tid, NULL, server_thread, (void *)&server_fd); + + client_fd = connect_to_server(server_fd); + if (client_fd < 0) { + err = -1; + goto close_server_fd; + } + + err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "connect", 0); + err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "connect", 0); + err += verify_sockopt(client_fd, CUSTOM_LISTENER, "connect", 0); + + pthread_join(tid, &server_err); + + err += (int)(long)server_err; + + close(client_fd); + +close_server_fd: + close(server_fd); +close_bpf_object: + bpf_object__close(obj); + return err; +} + +int main(int args, char **argv) +{ + int cgroup_fd; + int err = EXIT_SUCCESS; + + if (setup_cgroup_environment()) + return err; + + cgroup_fd = create_and_get_cgroup(CG_PATH); + if (cgroup_fd < 0) + goto cleanup_cgroup_env; + + if (join_cgroup(CG_PATH)) + goto cleanup_cgroup; + + if (run_test(cgroup_fd)) + err = EXIT_FAILURE; + + printf("test_sockopt_inherit: %s\n", + err == EXIT_SUCCESS ? "PASSED" : "FAILED"); + +cleanup_cgroup: + close(cgroup_fd); +cleanup_cgroup_env: + cleanup_cgroup_environment(); + return err; +} diff --git a/tools/testing/selftests/bpf/test_sysctl.c b/tools/testing/selftests/bpf/test_sysctl.c index a3bebd7c68dd..fc33ae36b760 100644 --- a/tools/testing/selftests/bpf/test_sysctl.c +++ b/tools/testing/selftests/bpf/test_sysctl.c @@ -13,6 +13,7 @@ #include <bpf/bpf.h> #include <bpf/libbpf.h> +#include "bpf_endian.h" #include "bpf_rlimit.h" #include "bpf_util.h" #include "cgroup_helpers.h" @@ -100,7 +101,7 @@ static struct sysctl_test tests[] = { .descr = "ctx:write sysctl:write read ok", .insns = { /* If (write) */ - BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_1, + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, offsetof(struct bpf_sysctl, write)), BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 1, 2), @@ -214,7 +215,8 @@ static struct sysctl_test tests[] = { /* if (ret == expected && */ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, sizeof("tcp_mem") - 1, 6), /* buf == "tcp_mem\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x006d656d5f706374ULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x7463705f6d656d00ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -255,7 +257,8 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 6), /* buf[0:7] == "tcp_me\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x00656d5f706374ULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x7463705f6d650000ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -298,12 +301,14 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 16, 14), /* buf[0:8] == "net/ipv4" && */ - BPF_LD_IMM64(BPF_REG_8, 0x347670692f74656eULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x6e65742f69707634ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 10), /* buf[8:16] == "/tcp_mem" && */ - BPF_LD_IMM64(BPF_REG_8, 0x6d656d5f7063742fULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x2f7463705f6d656dULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 8), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 6), @@ -350,12 +355,14 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 10), /* buf[0:8] == "net/ipv4" && */ - BPF_LD_IMM64(BPF_REG_8, 0x347670692f74656eULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x6e65742f69707634ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 6), /* buf[8:16] == "/tcp_me\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x00656d5f7063742fULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x2f7463705f6d6500ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 8), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -396,7 +403,8 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 6), /* buf[0:8] == "net/ip\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x000070692f74656eULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x6e65742f69700000ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -431,7 +439,8 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 6, 6), /* buf[0:6] == "Linux\n\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x000a78756e694cULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x4c696e75780a0000ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -469,7 +478,8 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 6, 6), /* buf[0:6] == "Linux\n\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x000a78756e694cULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x4c696e75780a0000ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -507,7 +517,8 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 6), /* buf[0:6] == "Linux\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x000078756e694cULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x4c696e7578000000ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -650,7 +661,8 @@ static struct sysctl_test tests[] = { /* buf[0:4] == "606\0") */ BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_7, 0), - BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0x00363036, 2), + BPF_JMP_IMM(BPF_JNE, BPF_REG_9, + bpf_ntohl(0x36303600), 2), /* return DENY; */ BPF_MOV64_IMM(BPF_REG_0, 0), @@ -685,17 +697,20 @@ static struct sysctl_test tests[] = { BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 23, 14), /* buf[0:8] == "3000000 " && */ - BPF_LD_IMM64(BPF_REG_8, 0x2030303030303033ULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x3330303030303020ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 10), /* buf[8:16] == "4000000 " && */ - BPF_LD_IMM64(BPF_REG_8, 0x2030303030303034ULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x3430303030303020ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 8), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 6), /* buf[16:24] == "6000000\0") */ - BPF_LD_IMM64(BPF_REG_8, 0x0030303030303036ULL), + BPF_LD_IMM64(BPF_REG_8, + bpf_be64_to_cpu(0x3630303030303000ULL)), BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 16), BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), @@ -735,7 +750,8 @@ static struct sysctl_test tests[] = { /* buf[0:3] == "60\0") */ BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_7, 0), - BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0x003036, 2), + BPF_JMP_IMM(BPF_JNE, BPF_REG_9, + bpf_ntohl(0x36300000), 2), /* return DENY; */ BPF_MOV64_IMM(BPF_REG_0, 0), @@ -757,7 +773,8 @@ static struct sysctl_test tests[] = { /* sysctl_set_new_value arg2 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00303036), + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x36303000)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), @@ -791,7 +808,7 @@ static struct sysctl_test tests[] = { /* sysctl_set_new_value arg2 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, FIXUP_SYSCTL_VALUE), + BPF_LD_IMM64(BPF_REG_0, FIXUP_SYSCTL_VALUE), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), @@ -825,8 +842,9 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00303036), - BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x36303000)), + BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -869,7 +887,8 @@ static struct sysctl_test tests[] = { BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), /* "600 602\0" */ - BPF_LD_IMM64(BPF_REG_0, 0x0032303620303036ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3630302036303200ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -937,7 +956,8 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00303036), + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x36303000)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -969,8 +989,9 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00373730), - BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x30373700)), + BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1012,7 +1033,8 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00303036), + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x36303000)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1052,7 +1074,8 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x090a0c0d), + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x0d0c0a09)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1092,7 +1115,9 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00362d0a), /* " -6\0" */ + /* " -6\0" */ + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x0a2d3600)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1132,8 +1157,10 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x00362d0a), /* " -6\0" */ - BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), + /* " -6\0" */ + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x0a2d3600)), + BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1175,8 +1202,10 @@ static struct sysctl_test tests[] = { /* arg1 (buf) */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), - BPF_MOV64_IMM(BPF_REG_0, 0x65667830), /* "0xfe" */ - BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), + /* "0xfe" */ + BPF_MOV64_IMM(BPF_REG_0, + bpf_ntohl(0x30786665)), + BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1218,11 +1247,14 @@ static struct sysctl_test tests[] = { /* arg1 (buf) 9223372036854775807 */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -24), - BPF_LD_IMM64(BPF_REG_0, 0x3032373333323239ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3932323333373230ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), - BPF_LD_IMM64(BPF_REG_0, 0x3537373435383633ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3336383534373735ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 8), - BPF_LD_IMM64(BPF_REG_0, 0x0000000000373038ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3830370000000000ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 16), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1266,11 +1298,14 @@ static struct sysctl_test tests[] = { /* arg1 (buf) 9223372036854775808 */ BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -24), - BPF_LD_IMM64(BPF_REG_0, 0x3032373333323239ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3932323333373230ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), - BPF_LD_IMM64(BPF_REG_0, 0x3537373435383633ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3336383534373735ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 8), - BPF_LD_IMM64(BPF_REG_0, 0x0000000000383038ULL), + BPF_LD_IMM64(BPF_REG_0, + bpf_be64_to_cpu(0x3830380000000000ULL)), BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 16), BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), @@ -1344,20 +1379,24 @@ static size_t probe_prog_length(const struct bpf_insn *fp) static int fixup_sysctl_value(const char *buf, size_t buf_len, struct bpf_insn *prog, size_t insn_num) { - uint32_t value_num = 0; + union { + uint8_t raw[sizeof(uint64_t)]; + uint64_t num; + } value = {}; uint8_t c, i; - if (buf_len > sizeof(value_num)) { + if (buf_len > sizeof(value)) { log_err("Value is too big (%zd) to use in fixup", buf_len); return -1; } - - for (i = 0; i < buf_len; ++i) { - c = buf[i]; - value_num |= (c << i * 8); + if (prog[insn_num].code != (BPF_LD | BPF_DW | BPF_IMM)) { + log_err("Can fixup only BPF_LD_IMM64 insns"); + return -1; } - prog[insn_num].imm = value_num; + memcpy(value.raw, buf, buf_len); + prog[insn_num].imm = (uint32_t)value.num; + prog[insn_num + 1].imm = (uint32_t)(value.num >> 32); return 0; } @@ -1499,6 +1538,7 @@ static int run_test_case(int cgfd, struct sysctl_test *test) goto err; } + errno = 0; if (access_sysctl(sysctl_path, test) == -1) { if (test->result == OP_EPERM && errno == EPERM) goto out; @@ -1507,7 +1547,7 @@ static int run_test_case(int cgfd, struct sysctl_test *test) } if (test->result != SUCCESS) { - log_err("Unexpected failure"); + log_err("Unexpected success"); goto err; } diff --git a/tools/testing/selftests/bpf/test_tcp_rtt.c b/tools/testing/selftests/bpf/test_tcp_rtt.c index 90c3862f74a8..93916a69823e 100644 --- a/tools/testing/selftests/bpf/test_tcp_rtt.c +++ b/tools/testing/selftests/bpf/test_tcp_rtt.c @@ -6,6 +6,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> +#include <netinet/tcp.h> #include <pthread.h> #include <linux/filter.h> @@ -34,6 +35,30 @@ static void send_byte(int fd) error(1, errno, "Failed to send single byte"); } +static int wait_for_ack(int fd, int retries) +{ + struct tcp_info info; + socklen_t optlen; + int i, err; + + for (i = 0; i < retries; i++) { + optlen = sizeof(info); + err = getsockopt(fd, SOL_TCP, TCP_INFO, &info, &optlen); + if (err < 0) { + log_err("Failed to lookup TCP stats"); + return err; + } + + if (info.tcpi_unacked == 0) + return 0; + + usleep(10); + } + + log_err("Did not receive ACK"); + return -1; +} + static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked, __u32 dsack_dups, __u32 delivered, __u32 delivered_ce, __u32 icsk_retransmits) @@ -149,6 +174,11 @@ static int run_test(int cgroup_fd, int server_fd) /*icsk_retransmits=*/0); send_byte(client_fd); + if (wait_for_ack(client_fd, 100) < 0) { + err = -1; + goto close_client_fd; + } + err += verify_sk(map_fd, client_fd, "first payload byte", /*invoked=*/2, @@ -157,6 +187,7 @@ static int run_test(int cgroup_fd, int server_fd) /*delivered_ce=*/0, /*icsk_retransmits=*/0); +close_client_fd: close(client_fd); close_bpf_object: diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 44e2d640b088..d27fd929abb9 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -61,6 +61,7 @@ #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" static bool unpriv_disabled = false; static int skips; +static bool verbose = false; struct bpf_test { const char *descr; @@ -92,7 +93,8 @@ struct bpf_test { enum { UNDEF, ACCEPT, - REJECT + REJECT, + VERBOSE_ACCEPT, } result, result_unpriv; enum bpf_prog_type prog_type; uint8_t flags; @@ -859,6 +861,36 @@ static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val, return 0; } +static bool cmp_str_seq(const char *log, const char *exp) +{ + char needle[80]; + const char *p, *q; + int len; + + do { + p = strchr(exp, '\t'); + if (!p) + p = exp + strlen(exp); + + len = p - exp; + if (len >= sizeof(needle) || !len) { + printf("FAIL\nTestcase bug\n"); + return false; + } + strncpy(needle, exp, len); + needle[len] = 0; + q = strstr(log, needle); + if (!q) { + printf("FAIL\nUnexpected verifier log in successful load!\n" + "EXP: %s\nRES:\n", needle); + return false; + } + log = q + len; + exp = p + 1; + } while (*p); + return true; +} + static void do_test_single(struct bpf_test *test, bool unpriv, int *passes, int *errors) { @@ -897,14 +929,20 @@ static void do_test_single(struct bpf_test *test, bool unpriv, 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; + expected_ret = unpriv && test->result_unpriv != UNDEF ? + test->result_unpriv : test->result; + expected_err = unpriv && test->errstr_unpriv ? + test->errstr_unpriv : test->errstr; memset(&attr, 0, sizeof(attr)); attr.prog_type = prog_type; attr.expected_attach_type = test->expected_attach_type; attr.insns = prog; attr.insns_cnt = prog_len; attr.license = "GPL"; - attr.log_level = 4; + attr.log_level = verbose || expected_ret == VERBOSE_ACCEPT ? 1 : 4; attr.prog_flags = pflags; fd_prog = bpf_load_program_xattr(&attr, bpf_vlog, sizeof(bpf_vlog)); @@ -914,14 +952,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv, goto close_fds; } - expected_ret = unpriv && test->result_unpriv != UNDEF ? - test->result_unpriv : test->result; - expected_err = unpriv && test->errstr_unpriv ? - test->errstr_unpriv : test->errstr; - alignment_prevented_execution = 0; - if (expected_ret == ACCEPT) { + if (expected_ret == ACCEPT || expected_ret == VERBOSE_ACCEPT) { if (fd_prog < 0) { printf("FAIL\nFailed to load prog '%s'!\n", strerror(errno)); @@ -932,6 +965,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv, (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)) alignment_prevented_execution = 1; #endif + if (expected_ret == VERBOSE_ACCEPT && !cmp_str_seq(bpf_vlog, expected_err)) { + goto fail_log; + } } else { if (fd_prog >= 0) { printf("FAIL\nUnexpected success to load!\n"); @@ -957,6 +993,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv, } } + if (verbose) + printf(", verifier log:\n%s", bpf_vlog); + run_errs = 0; run_successes = 0; if (!alignment_prevented_execution && fd_prog >= 0) { @@ -1097,17 +1136,24 @@ int main(int argc, char **argv) { unsigned int from = 0, to = ARRAY_SIZE(tests); bool unpriv = !is_admin(); + int arg = 1; + + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + arg++; + verbose = true; + argc--; + } if (argc == 3) { - unsigned int l = atoi(argv[argc - 2]); - unsigned int u = atoi(argv[argc - 1]); + unsigned int l = atoi(argv[arg]); + unsigned int u = atoi(argv[arg + 1]); if (l < to && u < to) { from = l; to = u + 1; } } else if (argc == 2) { - unsigned int t = atoi(argv[argc - 1]); + unsigned int t = atoi(argv[arg]); if (t < to) { from = t; diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c new file mode 100644 index 000000000000..02151f8c940f --- /dev/null +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -0,0 +1,194 @@ +{ + "precise: test 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_MAP_FD(BPF_REG_6, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + + BPF_MOV64_REG(BPF_REG_9, BPF_REG_0), + + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + + BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), + + BPF_ALU64_REG(BPF_SUB, BPF_REG_9, BPF_REG_8), /* map_value_ptr -= map_value_ptr */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_9), + BPF_JMP_IMM(BPF_JLT, BPF_REG_2, 8, 1), + BPF_EXIT_INSN(), + + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), /* R2=inv(umin=1, umax=8) */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_EMIT_CALL(BPF_FUNC_probe_read), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .fixup_map_array_48b = { 1 }, + .result = VERBOSE_ACCEPT, + .errstr = + "26: (85) call bpf_probe_read#4\ + last_idx 26 first_idx 20\ + regs=4 stack=0 before 25\ + regs=4 stack=0 before 24\ + regs=4 stack=0 before 23\ + regs=4 stack=0 before 22\ + regs=4 stack=0 before 20\ + parent didn't have regs=4 stack=0 marks\ + last_idx 19 first_idx 10\ + regs=4 stack=0 before 19\ + regs=200 stack=0 before 18\ + regs=300 stack=0 before 17\ + regs=201 stack=0 before 15\ + regs=201 stack=0 before 14\ + regs=200 stack=0 before 13\ + regs=200 stack=0 before 12\ + regs=200 stack=0 before 11\ + regs=200 stack=0 before 10\ + parent already had regs=0 stack=0 marks", +}, +{ + "precise: test 2", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_MAP_FD(BPF_REG_6, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + + BPF_MOV64_REG(BPF_REG_9, BPF_REG_0), + + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + + BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), + + BPF_ALU64_REG(BPF_SUB, BPF_REG_9, BPF_REG_8), /* map_value_ptr -= map_value_ptr */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_9), + BPF_JMP_IMM(BPF_JLT, BPF_REG_2, 8, 1), + BPF_EXIT_INSN(), + + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), /* R2=inv(umin=1, umax=8) */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_EMIT_CALL(BPF_FUNC_probe_read), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .fixup_map_array_48b = { 1 }, + .result = VERBOSE_ACCEPT, + .flags = BPF_F_TEST_STATE_FREQ, + .errstr = + "26: (85) call bpf_probe_read#4\ + last_idx 26 first_idx 22\ + regs=4 stack=0 before 25\ + regs=4 stack=0 before 24\ + regs=4 stack=0 before 23\ + regs=4 stack=0 before 22\ + parent didn't have regs=4 stack=0 marks\ + last_idx 20 first_idx 20\ + regs=4 stack=0 before 20\ + parent didn't have regs=4 stack=0 marks\ + last_idx 19 first_idx 17\ + regs=4 stack=0 before 19\ + regs=200 stack=0 before 18\ + regs=300 stack=0 before 17\ + parent already had regs=0 stack=0 marks", +}, +{ + "precise: cross frame pruning", + .insns = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), + BPF_MOV64_IMM(BPF_REG_8, 0), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_MOV64_IMM(BPF_REG_8, 1), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), + BPF_MOV64_IMM(BPF_REG_9, 0), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_MOV64_IMM(BPF_REG_9, 1), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 1, 1), + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_XDP, + .flags = BPF_F_TEST_STATE_FREQ, + .errstr = "!read_ok", + .result = REJECT, +}, +{ + "precise: ST insn causing spi > allocated_stack", + .insns = { + BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), + BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0), + BPF_ST_MEM(BPF_DW, BPF_REG_3, -8, 0), + BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), + BPF_MOV64_IMM(BPF_REG_0, -1), + BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_XDP, + .flags = BPF_F_TEST_STATE_FREQ, + .errstr = "5: (2d) if r4 > r0 goto pc+0\ + last_idx 5 first_idx 5\ + parent didn't have regs=10 stack=0 marks\ + last_idx 4 first_idx 2\ + regs=10 stack=0 before 4\ + regs=10 stack=0 before 3\ + regs=0 stack=1 before 2\ + last_idx 5 first_idx 5\ + parent didn't have regs=1 stack=0 marks", + .result = VERBOSE_ACCEPT, + .retval = -1, +}, +{ + "precise: STX insn causing spi > allocated_stack", + .insns = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), + BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), + BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0), + BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, -8), + BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), + BPF_MOV64_IMM(BPF_REG_0, -1), + BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_XDP, + .flags = BPF_F_TEST_STATE_FREQ, + .errstr = "last_idx 6 first_idx 6\ + parent didn't have regs=10 stack=0 marks\ + last_idx 5 first_idx 3\ + regs=10 stack=0 before 5\ + regs=10 stack=0 before 4\ + regs=0 stack=1 before 3\ + last_idx 6 first_idx 6\ + parent didn't have regs=1 stack=0 marks\ + last_idx 5 first_idx 3\ + regs=1 stack=0 before 5", + .result = VERBOSE_ACCEPT, + .retval = -1, +}, |