diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index f8ac77d08ca72..e4568d44e8279 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2366,8 +2366,7 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx, const struct bpf_insn *insn) { /* If this handler ever gets executed, then BPF_JIT_ALWAYS_ON - * is not working properly, or interpreter is being used when - * prog->jit_requested is not 0, so warn about it! + * is not working properly, so warn about it! */ WARN_ON_ONCE(1); return 0; @@ -2468,8 +2467,9 @@ static int bpf_check_tail_call(const struct bpf_prog *fp) return ret; } -static void bpf_prog_select_func(struct bpf_prog *fp) +static bool bpf_prog_select_interpreter(struct bpf_prog *fp) { + bool select_interpreter = false; #ifndef CONFIG_BPF_JIT_ALWAYS_ON u32 stack_depth = max_t(u32, fp->aux->stack_depth, 1); u32 idx = (round_up(stack_depth, 32) / 32) - 1; @@ -2478,15 +2478,16 @@ static void bpf_prog_select_func(struct bpf_prog *fp) * But for non-JITed programs, we don't need bpf_func, so no bounds * check needed. */ - if (!fp->jit_requested && - !WARN_ON_ONCE(idx >= ARRAY_SIZE(interpreters))) { + if (idx < ARRAY_SIZE(interpreters)) { fp->bpf_func = interpreters[idx]; + select_interpreter = true; } else { fp->bpf_func = __bpf_prog_ret0_warn; } #else fp->bpf_func = __bpf_prog_ret0_warn; #endif + return select_interpreter; } /** @@ -2505,7 +2506,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) /* In case of BPF to BPF calls, verifier did all the prep * work with regards to JITing, etc. */ - bool jit_needed = fp->jit_requested; + bool jit_needed = false; if (fp->bpf_func) goto finalize; @@ -2514,7 +2515,8 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) bpf_prog_has_kfunc_call(fp)) jit_needed = true; - bpf_prog_select_func(fp); + if (!bpf_prog_select_interpreter(fp)) + jit_needed = true; /* eBPF JITs can rewrite the program in case constant * blinding is active. However, in case of error during diff --git a/tools/testing/selftests/bpf/prog_tests/socket_filter.c b/tools/testing/selftests/bpf/prog_tests/socket_filter.c new file mode 100644 index 0000000000000..ee3a4cc1a992d --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/socket_filter.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include "socket_filter.skel.h" + +static int duration; + +void do_test(void) +{ + /* the filter below is the tcpdump filter: + * tcpdump "not ether host 3c37121a2b3c and not ether host 184ecbca2a3a \ + * and not ether host 14130b4d3f47 and not ether host f0f61cf440b7 \ + * and not ether host a84b4dedf471 and not ether host d022be17e1d7 \ + * and not ether host 5c497967208b and not ether host 706655784d5b" + */ + struct sock_filter code[] = { + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0x121a2b3c }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 60, 0, 0x00003c37 }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0x121a2b3c }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 56, 0, 0x00003c37 }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0xcbca2a3a }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 52, 0, 0x0000184e }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0xcbca2a3a }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 48, 0, 0x0000184e }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0x0b4d3f47 }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 44, 0, 0x00001413 }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0x0b4d3f47 }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 40, 0, 0x00001413 }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0x1cf440b7 }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 36, 0, 0x0000f0f6 }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0x1cf440b7 }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 32, 0, 0x0000f0f6 }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0x4dedf471 }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 28, 0, 0x0000a84b }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0x4dedf471 }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 24, 0, 0x0000a84b }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0xbe17e1d7 }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 20, 0, 0x0000d022 }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0xbe17e1d7 }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 16, 0, 0x0000d022 }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0x7967208b }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 12, 0, 0x00005c49 }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 2, 0x7967208b }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 8, 0, 0x00005c49 }, + { 0x20, 0, 0, 0x00000008 }, + { 0x15, 0, 2, 0x55784d5b }, + { 0x28, 0, 0, 0x00000006 }, + { 0x15, 4, 0, 0x00007066 }, + { 0x20, 0, 0, 0x00000002 }, + { 0x15, 0, 3, 0x55784d5b }, + { 0x28, 0, 0, 0x00000000 }, + { 0x15, 0, 1, 0x00007066 }, + { 0x06, 0, 0, 0x00000000 }, + { 0x06, 0, 0, 0x00040000 }, + }; + struct sock_fprog bpf = { + .len = ARRAY_SIZE(code), + .filter = code, + }; + int ret, sock = 0; + + sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (CHECK(sock < 0, "create socket", "errno %d\n", errno)) + return; + + ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); + CHECK(ret < 0, "attach filter", "errno %d\n", errno); + + close(sock); +} + +void test_socket_filter(void) +{ + struct socket_filter *skel; + struct utsname uts; + int err; + + err = uname(&uts); + if (err < 0) + return; + + skel = socket_filter__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + /* The filter JIT fails on armv6 */ + if (strncmp(uts.machine, "armv6", strlen("armv6")) == 0 && + skel->kconfig->CONFIG_BPF_JIT_ALWAYS_ON) + test__skip(); + else + do_test(); + + socket_filter__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/socket_filter.c b/tools/testing/selftests/bpf/progs/socket_filter.c new file mode 100644 index 0000000000000..f93623ec7ec0f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/socket_filter.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include + +char _license[] SEC("license") = "GPL"; + +extern bool CONFIG_BPF_JIT_ALWAYS_ON __kconfig __weak; + +/* This function is here to have CONFIG_BPF_JIT_ALWAYS_ON + * used and added to object BTF. + */ +int unused(void) +{ + return CONFIG_BPF_JIT_ALWAYS_ON ? 0 : 1; +}