Skip to content

bpf: Allow fall back to interpreter for programs with stack size <= 512 #9473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: bpf_base
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions kernel/bpf/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

/**
Expand All @@ -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;
Expand All @@ -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
Expand Down
124 changes: 124 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/socket_filter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0

#include <test_progs.h>
#include <sys/utsname.h>
#include <uapi/linux/filter.h>
#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);
}
16 changes: 16 additions & 0 deletions tools/testing/selftests/bpf/progs/socket_filter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

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;
}
Loading