[PATCH 2/4] seccomp: rework seccomp_prepare_filter().

From: Nicolas Schichan
Date: Wed Apr 29 2015 - 09:38:11 EST


- Try to use the classic BPF JIT via bpf_jit_compile().

- Use bpf_migrate_filter() from NET filter code instead of the double
bpf_convert_filter() followed by bpf_prog_select_runtime() if
classic bpf_jit_compile() did not succeed in producing native code.

Signed-off-by: Nicolas Schichan <nschichan@xxxxxxxxxx>
---
kernel/seccomp.c | 47 ++++++++++++++++++++---------------------------
1 file changed, 20 insertions(+), 27 deletions(-)

diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 4f44028..4f9fea7 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -348,8 +348,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
{
struct seccomp_filter *filter;
unsigned long fp_size;
- struct sock_filter *fp;
- int new_len;
+ struct bpf_prog *fp;
long ret;

if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
@@ -368,29 +367,38 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
CAP_SYS_ADMIN) != 0)
return ERR_PTR(-EACCES);

- fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
+ fp = bpf_prog_alloc(bpf_prog_size(fprog->len), __GFP_NOWARN);
if (!fp)
return ERR_PTR(-ENOMEM);

/* Copy the instructions from fprog. */
ret = -EFAULT;
- if (copy_from_user(fp, fprog->filter, fp_size))
+ if (copy_from_user(fp->insns, fprog->filter, fp_size))
goto free_prog;
+ fp->len = fprog->len;

/* Check and rewrite the fprog via the skb checker */
- ret = bpf_check_classic(fp, fprog->len);
+ ret = bpf_check_classic(fp->insns, fp->len);
if (ret)
goto free_prog;

/* Check and rewrite the fprog for seccomp use */
- ret = seccomp_check_filter(fp, fprog->len);
+ ret = seccomp_check_filter(fp->insns, fp->len);
if (ret)
goto free_prog;

- /* Convert 'sock_filter' insns to 'bpf_insn' insns */
- ret = bpf_convert_filter(fp, fprog->len, NULL, &new_len);
- if (ret)
- goto free_prog;
+ /* try to use the classic JIT */
+ bpf_jit_compile(fp);
+
+ if (!fp->jited) {
+ /*
+ * if classic JIT has failed, try to convert it to an
+ * internal filter
+ */
+ fp = bpf_migrate_filter(fp);
+ if (IS_ERR(fp))
+ return fp;
+ }

/* Allocate a new seccomp_filter */
ret = -ENOMEM;
@@ -399,28 +407,13 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
if (!filter)
goto free_prog;

- filter->prog = bpf_prog_alloc(bpf_prog_size(new_len), __GFP_NOWARN);
- if (!filter->prog)
- goto free_filter;
-
- ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len);
- if (ret)
- goto free_filter_prog;
-
- kfree(fp);
+ filter->prog = fp;
atomic_set(&filter->usage, 1);
- filter->prog->len = new_len;
-
- bpf_prog_select_runtime(filter->prog);

return filter;

-free_filter_prog:
- __bpf_prog_free(filter->prog);
-free_filter:
- kfree(filter);
free_prog:
- kfree(fp);
+ bpf_prog_destroy(fp);
return ERR_PTR(ret);
}

--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/