net: filter: cleanup invocation of internal BPF
Subsystems (7)
PATCH 1/1 net: filter: cleanup invocation of internal BPF
Kernel API for classic BPF socket filters is:
sk_unattached_filter_create() - validate classic BPF, convert, JIT SK_RUN_FILTER() - run itsk_unattached_filter_destroy() - destroy socket filter
Cleanup internal BPF kernel API as following:
sk_filter_select_runtime() - final step of internal BPF creation.
Try to JIT internal BPF program, if JIT is not available select interpreterSK_RUN_FILTER() - run itsk_filter_free() - free internal BPF program
Disallow direct calls to BPF interpreter. Execution of the BPF program should be done with SK_RUN_FILTER() macro.
Example of internal BPF create, run, destroy:
struct sk_filter *fp;
fp = kzalloc(sk_filter_size(prog_len), GFP_KERNEL); memcpy(fp->insni, prog, prog_len * sizeof(fp->insni[0])); fp->len = prog_len; sk_filter_select_runtime(fp); SK_RUN_FILTER(fp, ctx); sk_filter_free(fp);
Sockets, seccomp, testsuite, tracing are using different ways to populate sk_filter, so first steps of program creation are not common.
---
This patch blurs the line between BPF program running in interpeter and JITed program. The 'jited' flag in 'struct sk_filter' indicates to the caller whether program was JITed or not, but that shouldn't matter to the caller. JITed program must be equivalent.
Another alternative is to export bpf_int_jit_compile()/bpf_jit_free() and let the users decide whether to use interpreter or JIT, but that seems ugly. We already have net.core.bpf_jit_enable for that.
include/linux/filter.h | 6 ++---- kernel/seccomp.c | 6 ++---- lib/test_bpf.c | 4 ++-- net/core/filter.c | 44 ++++++++++++++++++++++++++++---------------- 4 files changed, 34 insertions(+), 26 deletions(-)
include/linux/filter.h +2 -4
@@ -184,10 +184,8 @@ static inline unsigned int sk_filter_size(unsigned int proglen)int sk_filter (struct sock *sk,struct sk_buff *skb); -u32 sk_run_filter_int_seccomp (const struct seccomp_data *ctx, -const struct sock_filter_int *insni); -u32 sk_run_filter_int_skb (const struct sk_buff *ctx, -const struct sock_filter_int *insni); +void sk_filter_select_runtime (struct sk_filter *fp); +void sk_filter_free (struct sk_filter *fp);int sk_convert_filter (struct sock_filter *prog,int len,struct sock_filter_int *new_prog,int *new_len);
kernel/seccomp.c +2 -4
@@ -273,10 +273,8 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)atomic_set (&filter->usage,1 ); filter->prog->len = new_len; - filter->prog->bpf_func = (void *)sk_run_filter_int_seccomp; -/* JIT internal BPF into native HW instructions */ -bpf_int_jit_compile (filter->prog); +sk_filter_select_runtime (filter->prog);/* * If there is an existing filter, make it the prev and don't drop its
@@ -340,7 +338,7 @@ void put_seccomp_filter(struct task_struct *tsk)while (orig &&atomic_dec_and_test (&orig->usage)) {struct seccomp_filter *freeme = orig; orig = orig->prev; -bpf_jit_free (freeme->prog); +sk_filter_free (freeme->prog);kfree (freeme); } }
lib/test_bpf.c +2 -2
@@ -1489,7 +1489,7 @@ static __init int test_bpf(void)memcpy (fp_ext->insns, tests[i].insns_int, fprog.len *8 ); fp->len = fprog.len; - fp->bpf_func = sk_run_filter_int_skb; +sk_filter_select_runtime (fp); }else { err =sk_unattached_filter_create (&fp, &fprog);if (tests[i].data_type ==EXPECTED_FAIL ) {
@@ -1516,7 +1516,7 @@ static __init int test_bpf(void)if (tests[i].data_type !=SKB_INT )sk_unattached_filter_destroy (fp);else -kfree (fp); +sk_filter_free (fp);if (err) {pr_cont ("FAIL %d\n" , err);
net/core/filter.c +28 -16
88 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Quoted 30 lines · Alexei Starovoitov
Kernel API for classic BPF socket filters is:
sk_unattached_filter_create()- validate classic BPF, convert, JITSK_RUN_FILTER()- run itsk_unattached_filter_destroy()- destroy socket filterCleanup internal BPF kernel API as following:
sk_filter_select_runtime()- final step of internal BPF creation.
Try to JIT internal BPF program, if JIT is not available select interpreterSK_RUN_FILTER()- run itsk_filter_free()- free internal BPF programDisallow direct calls to BPF interpreter. Execution of the BPF program should be done with
SK_RUN_FILTER()macro.Example of internal BPF create, run, destroy:
struct sk_filter *fp; fp = kzalloc(sk_filter_size(prog_len), GFP_KERNEL); memcpy(fp->insni, prog, prog_len * sizeof(fp->insni[0])); fp->len = prog_len; sk_filter_select_runtime(fp); SK_RUN_FILTER(fp, ctx); sk_filter_free(fp);
Quoted 4 lines
Sockets, seccomp, testsuite, tracing are using different ways to populate
sk_filter, so first steps of program creation are not common.Signed-off-by Alexei Starovoitov <[email protected]>
I think it makes sense and we can avoid directly exposing the symbol __sk_run_filter() resp. its aliases.
From: Alexei Starovoitov <[email protected]>
Date: Mon, 19 May 2014 14:56:14 -0700
Quoted 30 lines
Kernel API for classic BPF socket filters is:
sk_unattached_filter_create()- validate classic BPF, convert, JITSK_RUN_FILTER()- run itsk_unattached_filter_destroy()- destroy socket filterCleanup internal BPF kernel API as following:
sk_filter_select_runtime()- final step of internal BPF creation.
Try to JIT internal BPF program, if JIT is not available select interpreterSK_RUN_FILTER()- run itsk_filter_free()- free internal BPF programDisallow direct calls to BPF interpreter. Execution of the BPF program should be done with
SK_RUN_FILTER()macro.Example of internal BPF create, run, destroy:
struct
sk_filter*fp;fp = kzalloc(sk_filter_size(prog_len), GFP_KERNEL); memcpy(fp->insni, prog, prog_len * sizeof(fp->insni[0])); fp->len = prog_len; sk_filter_select_runtime(fp); SK_RUN_FILTER(fp, ctx); sk_filter_free(fp);
Quoted 4 lines
Sockets, seccomp, testsuite, tracing are using different ways to populate
sk_filter, so first steps of program creation are not common.Signed-off-by Alexei Starovoitov <[email protected]>
Applied, thank you.