Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: selftest: Ensure the return value of the bpf_per_cpu_ptr() must be checked

This patch tests all pointers returned by bpf_per_cpu_ptr() must be
tested for NULL first before it can be accessed.

This patch adds a subtest "null_check", so it moves the ".data..percpu"
existence check to the very beginning and before doing any subtest.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20201019194225.1051596-1-kafai@fb.com

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
8568c3ce e710bcc6

+70 -18
+39 -18
tools/testing/selftests/bpf/prog_tests/ksyms_btf.c
··· 5 5 #include <bpf/libbpf.h> 6 6 #include <bpf/btf.h> 7 7 #include "test_ksyms_btf.skel.h" 8 + #include "test_ksyms_btf_null_check.skel.h" 8 9 9 10 static int duration; 10 11 11 - void test_ksyms_btf(void) 12 + static void test_basic(void) 12 13 { 13 14 __u64 runqueues_addr, bpf_prog_active_addr; 14 15 __u32 this_rq_cpu; 15 16 int this_bpf_prog_active; 16 17 struct test_ksyms_btf *skel = NULL; 17 18 struct test_ksyms_btf__data *data; 18 - struct btf *btf; 19 - int percpu_datasec; 20 19 int err; 21 20 22 21 err = kallsyms_find("runqueues", &runqueues_addr); ··· 29 30 return; 30 31 if (CHECK(err == -ENOENT, "ksym_find", "symbol 'bpf_prog_active' not found\n")) 31 32 return; 32 - 33 - btf = libbpf_find_kernel_btf(); 34 - if (CHECK(IS_ERR(btf), "btf_exists", "failed to load kernel BTF: %ld\n", 35 - PTR_ERR(btf))) 36 - return; 37 - 38 - percpu_datasec = btf__find_by_name_kind(btf, ".data..percpu", 39 - BTF_KIND_DATASEC); 40 - if (percpu_datasec < 0) { 41 - printf("%s:SKIP:no PERCPU DATASEC in kernel btf\n", 42 - __func__); 43 - test__skip(); 44 - goto cleanup; 45 - } 46 33 47 34 skel = test_ksyms_btf__open_and_load(); 48 35 if (CHECK(!skel, "skel_open", "failed to open and load skeleton\n")) ··· 68 83 data->out__bpf_prog_active); 69 84 70 85 cleanup: 71 - btf__free(btf); 72 86 test_ksyms_btf__destroy(skel); 87 + } 88 + 89 + static void test_null_check(void) 90 + { 91 + struct test_ksyms_btf_null_check *skel; 92 + 93 + skel = test_ksyms_btf_null_check__open_and_load(); 94 + CHECK(skel, "skel_open", "unexpected load of a prog missing null check\n"); 95 + 96 + test_ksyms_btf_null_check__destroy(skel); 97 + } 98 + 99 + void test_ksyms_btf(void) 100 + { 101 + int percpu_datasec; 102 + struct btf *btf; 103 + 104 + btf = libbpf_find_kernel_btf(); 105 + if (CHECK(IS_ERR(btf), "btf_exists", "failed to load kernel BTF: %ld\n", 106 + PTR_ERR(btf))) 107 + return; 108 + 109 + percpu_datasec = btf__find_by_name_kind(btf, ".data..percpu", 110 + BTF_KIND_DATASEC); 111 + btf__free(btf); 112 + if (percpu_datasec < 0) { 113 + printf("%s:SKIP:no PERCPU DATASEC in kernel btf\n", 114 + __func__); 115 + test__skip(); 116 + return; 117 + } 118 + 119 + if (test__start_subtest("basic")) 120 + test_basic(); 121 + 122 + if (test__start_subtest("null_check")) 123 + test_null_check(); 73 124 }
+31
tools/testing/selftests/bpf/progs/test_ksyms_btf_null_check.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2020 Facebook */ 3 + 4 + #include "vmlinux.h" 5 + 6 + #include <bpf/bpf_helpers.h> 7 + 8 + extern const struct rq runqueues __ksym; /* struct type global var. */ 9 + extern const int bpf_prog_active __ksym; /* int type global var. */ 10 + 11 + SEC("raw_tp/sys_enter") 12 + int handler(const void *ctx) 13 + { 14 + struct rq *rq; 15 + int *active; 16 + __u32 cpu; 17 + 18 + cpu = bpf_get_smp_processor_id(); 19 + rq = (struct rq *)bpf_per_cpu_ptr(&runqueues, cpu); 20 + active = (int *)bpf_per_cpu_ptr(&bpf_prog_active, cpu); 21 + if (active) { 22 + /* READ_ONCE */ 23 + *(volatile int *)active; 24 + /* !rq has not been tested, so verifier should reject. */ 25 + *(volatile int *)(&rq->cpu); 26 + } 27 + 28 + return 0; 29 + } 30 + 31 + char _license[] SEC("license") = "GPL";