From: "Indan Zupancic" <indan@nul.nu>
To: "Will Drewry" <wad@chromium.org>
Cc: linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-doc@vger.kernel.org, kernel-hardening@lists.openwall.com,
netdev@vger.kernel.org, x86@kernel.org, arnd@arndb.de,
davem@davemloft.net, hpa@zytor.com, mingo@redhat.com,
oleg@redhat.com, peterz@infradead.org, rdunlap@xenotime.net,
mcgrathr@chromium.org, tglx@linutronix.de, luto@mit.edu,
eparis@redhat.com, serge.hallyn@canonical.com, djm@mindrot.org,
scarybeasts@gmail.com, pmoore@redhat.com,
akpm@linux-foundation.org, corbet@lwn.net,
eric.dumazet@gmail.com, markus@chromium.org,
coreyb@linux.vnet.ibm.com, keescook@chromium.org,
"Will Drewry" <wad@chromium.org>
Subject: Re: [PATCH v14 01/13] sk_run_filter: add BPF_S_ANC_SECCOMP_LD_W
Date: Tue, 13 Mar 2012 11:04:42 +0100 [thread overview]
Message-ID: <0c55cb258e0b5bbd615923ee2a9f06b9.squirrel@webmail.greenhost.nl> (raw)
In-Reply-To: <1331587715-26069-1-git-send-email-wad@chromium.org>
Hello,
I made a quick pseudo-patch for BPF JIT support. As far as I can tell,
the actual code itself is very simple, just:
case BPF_S_ANC_SECCOMP_LD_W:
/* SECCOMP doesn't use SKB, no need to preserve %rdi. */
t_offset = seccomp_bpf_load - (image + addrs[i]);
EMIT1_off32(0xbf, K); /* mov imm32,%rdi */
EMIT1_off32(0xe8, t_offset); /* call */
break;
EAX is set directly as it's the return register, EBX is preserved by the
callee, RDI and other registers are unused by seccomp, so no need for
trampoline code AFAIK.
The rest of the patch just makes the JIT code suitable for sharing.
Only real change is that after this patch unused insns memory is freed.
The code is untested and even uncompiled, as I've only access to my 32-bit
laptop at the moment.
Would be interesting to know if this actually works and what the performance
difference is for seccomp.
Greetings,
Indan
arch/x86/net/bpf_jit_comp.c | 47 ++++++++++++++++++++----------------------
include/linux/filter.h | 14 +++++++-----
net/core/filter.c | 27 ++++++++++++++++++++++--
3 files changed, 54 insertions(+), 34 deletions(-)
---
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 7c1b765..3cd6626 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -118,7 +118,7 @@ static inline void bpf_flush_icache(void *start, void *end)
}
-void bpf_jit_compile(struct sk_filter *fp)
+bpf_func_t bpf_jit_compile(const struct sock_filter* filter, int flen, int use_skb)
{
u8 temp[64];
u8 *prog;
@@ -131,15 +131,13 @@ void bpf_jit_compile(struct sk_filter *fp)
int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */
unsigned int cleanup_addr; /* epilogue code offset */
unsigned int *addrs;
- const struct sock_filter *filter = fp->insns;
- int flen = fp->len;
if (!bpf_jit_enable)
- return;
+ return NULL;
addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL);
if (addrs == NULL)
- return;
+ return NULL;
/* Before first pass, make a rough estimation of addrs[]
* each bpf instruction is translated to less than 64 bytes
@@ -151,11 +149,16 @@ void bpf_jit_compile(struct sk_filter *fp)
cleanup_addr = proglen; /* epilogue address */
for (pass = 0; pass < 10; pass++) {
- u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen;
+ u8 seen_or_pass0 = seen;
/* no prologue/epilogue for trivial filters (RET something) */
proglen = 0;
prog = temp;
+ if (pass == 0) {
+ seen_or_pass0 = SEEN_XREG | SEEN_MEM;
+ if (use_skb)
+ seen_or_pass0 |= SEEN_DATAREF;
+ }
if (seen_or_pass0) {
EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */
EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */
@@ -472,6 +475,14 @@ void bpf_jit_compile(struct sk_filter *fp)
CLEAR_A();
#endif
break;
+#ifdef CONFIG_SECCOMP_FILTER
+ case BPF_S_ANC_SECCOMP_LD_W:
+ /* SECCOMP doesn't use SKB, no need to preserve %rdi. */
+ t_offset = seccomp_bpf_load - (image + addrs[i]);
+ EMIT1_off32(0xbf, K); /* mov imm32,%rdi */
+ EMIT1_off32(0xe8, t_offset); /* call */
+ break;
+#endif
case BPF_S_LD_W_ABS:
func = sk_load_word;
common_load: seen |= SEEN_DATAREF;
@@ -588,13 +599,14 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
/* hmm, too complex filter, give up with jit compiler */
goto out;
}
+ BUG_ON(!use_skb && (seen & SEEN_DATAREF));
ilen = prog - temp;
if (image) {
if (unlikely(proglen + ilen > oldproglen)) {
pr_err("bpb_jit_compile fatal error\n");
kfree(addrs);
module_free(NULL, image);
- return;
+ return NULL;
}
memcpy(image + proglen, temp, ilen);
}
@@ -635,28 +647,13 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
16, 1, image, proglen, false);
bpf_flush_icache(image, image + proglen);
-
- fp->bpf_func = (void *)image;
}
out:
kfree(addrs);
- return;
+ return (void *)image;
}
-static void jit_free_defer(struct work_struct *arg)
+void bpf_jit_free(bpf_func_t image)
{
- module_free(NULL, arg);
-}
-
-/* run from softirq, we must use a work_struct to call
- * module_free() from process context
- */
-void bpf_jit_free(struct sk_filter *fp)
-{
- if (fp->bpf_func != sk_run_filter) {
- struct work_struct *work = (struct work_struct *)fp->bpf_func;
-
- INIT_WORK(work, jit_free_defer);
- schedule_work(work);
- }
+ module_free(NULL, image);
}
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 8eeb205..292ccca 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -135,12 +135,13 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
struct sk_buff;
struct sock;
+typedef unsigned int (*bpf_func_t)(const struct sk_buff*, const struct sock_filter*);
+
struct sk_filter
{
atomic_t refcnt;
unsigned int len; /* Number of filter blocks */
- unsigned int (*bpf_func)(const struct sk_buff *skb,
- const struct sock_filter *filter);
+ bpf_func_t bpf_func;
struct rcu_head rcu;
struct sock_filter insns[0];
};
@@ -158,14 +159,15 @@ extern int sk_detach_filter(struct sock *sk);
extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
#ifdef CONFIG_BPF_JIT
-extern void bpf_jit_compile(struct sk_filter *fp);
-extern void bpf_jit_free(struct sk_filter *fp);
+extern bpf_func_t bpf_jit_compile(const struct sock_filter*, int flen, int use_skb);
+extern void bpf_jit_free(bpf_funct_t);
#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
#else
-static inline void bpf_jit_compile(struct sk_filter *fp)
+static inline bpf_func_t bpf_jit_compile(const struct sock_filter*, int flen, int use_skb)
{
+ return NULL;
}
-static inline void bpf_jit_free(struct sk_filter *fp)
+static inline void bpf_jit_free(bpf_func_t)
{
}
#define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns)
diff --git a/net/core/filter.c b/net/core/filter.c
index 5dea452..03e3ea3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -574,6 +574,14 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
}
EXPORT_SYMBOL(sk_chk_filter);
+/* run from softirq, we must use a work_struct to call
+ * bpf_jit_free() from process context
+ */
+static void jit_free_defer(struct work_struct *arg)
+{
+ bpf_jit_free((bpf_func_t)arg);
+}
+
/**
* sk_filter_release_rcu - Release a socket filter by rcu_head
* @rcu: rcu_head that contains the sk_filter to free
@@ -582,7 +590,12 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
{
struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
- bpf_jit_free(fp);
+ if (fp->bpf_func != sk_run_filter) {
+ struct work_struct *work = (struct work_struct *)fp->bpf_func;
+
+ INIT_WORK(work, jit_free_defer);
+ schedule_work(work);
+ }
kfree(fp);
}
EXPORT_SYMBOL(sk_filter_release_rcu);
@@ -599,9 +612,10 @@ EXPORT_SYMBOL(sk_filter_release_rcu);
*/
int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
{
- struct sk_filter *fp, *old_fp;
+ struct sk_filter *fp, *old_fp, *new_fp;
unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
int err;
+ bpf_func_t jit;
/* Make sure new filter is there and in the right amounts. */
if (fprog->filter == NULL)
@@ -625,7 +639,14 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
return err;
}
- bpf_jit_compile(fp);
+ jit = bpf_jit_compile(fp->insns, fp->len, 1);
+ if (jit) {
+ fp->bpf_func = jit;
+ /* Free unused insns memory */
+ newfp = krealloc(fp, sizeof(*fp), GFP_KERNEL);
+ if (newfp)
+ fp = newfp;
+ }
old_fp = rcu_dereference_protected(sk->sk_filter,
sock_owned_by_user(sk));
next prev parent reply other threads:[~2012-03-13 10:05 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-12 21:28 Will Drewry
2012-03-12 21:28 ` [PATCH v14 02/13] net/compat.c,linux/filter.h: share compat_sock_fprog Will Drewry
2012-03-12 21:28 ` [PATCH v14 03/13] seccomp: kill the seccomp_t typedef Will Drewry
2012-03-12 21:28 ` [PATCH v14 04/13] arch/x86: add syscall_get_arch to syscall.h Will Drewry
2012-03-12 21:28 ` [PATCH v14 05/13] asm/syscall.h: add syscall_get_arch Will Drewry
2012-03-12 21:28 ` [PATCH v14 06/13] seccomp: add system call filtering using BPF Will Drewry
2012-03-13 3:33 ` Indan Zupancic
2012-03-13 15:57 ` [kernel-hardening] " Will Drewry
2012-03-12 21:28 ` [PATCH v14 07/13] signal, x86: add SIGSYS info and make it synchronous Will Drewry
2012-03-12 21:28 ` [PATCH v14 08/13] seccomp: add SECCOMP_RET_ERRNO Will Drewry
2012-03-12 21:28 ` [PATCH v14 09/13] seccomp: Add SECCOMP_RET_TRAP Will Drewry
2012-03-12 21:28 ` [PATCH v14 10/13] ptrace,seccomp: Add PTRACE_SECCOMP support Will Drewry
2012-03-14 7:31 ` Indan Zupancic
2012-03-14 15:03 ` [kernel-hardening] " Will Drewry
2012-03-14 15:52 ` Will Drewry
2012-03-15 20:31 ` [PATCH v16 11/13] " Will Drewry
2012-03-12 21:28 ` [PATCH v14 11/13] x86: Enable HAVE_ARCH_SECCOMP_FILTER Will Drewry
2012-03-12 21:28 ` [PATCH v14 12/13] Documentation: prctl/seccomp_filter Will Drewry
2012-03-12 21:28 ` [PATCH v14 13/13] seccomp: remove duplicated failure logging Will Drewry
2012-03-13 3:40 ` [PATCH v14 01/13] sk_run_filter: add BPF_S_ANC_SECCOMP_LD_W Indan Zupancic
2012-03-13 15:40 ` Will Drewry
2012-03-13 10:04 ` Indan Zupancic [this message]
2012-03-13 15:43 ` Will Drewry
2012-03-13 17:13 ` Eric Dumazet
2012-03-14 5:12 ` Indan Zupancic
2012-03-14 5:55 ` Eric Dumazet
2012-03-14 7:59 ` Indan Zupancic
2012-03-14 8:05 ` Eric Dumazet
2012-03-17 10:14 ` Indan Zupancic
2012-03-17 13:49 ` Eric Dumazet
2012-03-18 8:35 ` Indan Zupancic
2012-03-18 12:40 ` [PATCH] net: bpf_jit: fix BPF_S_LDX_B_MSH compilation Eric Dumazet
2012-03-19 21:42 ` David Miller
2012-03-20 0:16 ` [PATCH] net: bpf_jit: Document evilness of negative indirect loads Indan Zupancic
2012-03-18 12:52 ` [PATCH v14 01/13] sk_run_filter: add BPF_S_ANC_SECCOMP_LD_W Eric Dumazet
2012-03-20 2:24 ` [PATCH] net: bpf_jit: Simplify code by always using offset8 or offset32 Indan Zupancic
2012-03-20 2:59 ` Eric Dumazet
2012-03-20 11:33 ` Indan Zupancic
2012-03-20 11:41 ` David Laight
2012-03-20 13:56 ` Eric Dumazet
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0c55cb258e0b5bbd615923ee2a9f06b9.squirrel@webmail.greenhost.nl \
--to=indan@nul.nu \
--cc=akpm@linux-foundation.org \
--cc=arnd@arndb.de \
--cc=corbet@lwn.net \
--cc=coreyb@linux.vnet.ibm.com \
--cc=davem@davemloft.net \
--cc=djm@mindrot.org \
--cc=eparis@redhat.com \
--cc=eric.dumazet@gmail.com \
--cc=hpa@zytor.com \
--cc=keescook@chromium.org \
--cc=kernel-hardening@lists.openwall.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@mit.edu \
--cc=markus@chromium.org \
--cc=mcgrathr@chromium.org \
--cc=mingo@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=pmoore@redhat.com \
--cc=rdunlap@xenotime.net \
--cc=scarybeasts@gmail.com \
--cc=serge.hallyn@canonical.com \
--cc=tglx@linutronix.de \
--cc=wad@chromium.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®