On 02/07/2018 02:27 PM, Tom Hromatka wrote:

This patch adds support for EBPF hash maps to seccomp.


The prototype seccomp/EBPF changes to the kernel are attached
below.  They are definitely a work in progress.

bpf_prog_seccomp_prepare() is loosely based upon bpf_prog_load(),
and seccomp_set_mode_ebpf_filter() is loosely based upon
seccomp_set_mode_filter().



commit bf655771e7c108ab76100f4e9af189f8f6b9bf67
Author: Tom Hromatka <[email protected]>
Date:   Tue Jan 30 17:19:53 2018 -0700

    seccomp: add ebpf support

    This commit adds ebpf support to seccomp.  Prior to this commit
    seccomp only supported classic bpf.

    Signed-off-by: Tom Hromatka <[email protected]>

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0b25cf8..508e83d 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -430,6 +430,7 @@ static inline int bpf_map_attr_numa_node(const union bpf_attr *attr)
 }

 struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type type); +int bpf_prog_seccomp_prepare(union bpf_attr *attr, struct bpf_prog **prog);

 #else /* !CONFIG_BPF_SYSCALL */
 static inline struct bpf_prog *bpf_prog_get(u32 ufd)
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 2a0bd9d..c71053f 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -10,11 +10,13 @@
 #define SECCOMP_MODE_DISABLED  0 /* seccomp is not in use. */
 #define SECCOMP_MODE_STRICT    1 /* uses hard-coded filter. */
 #define SECCOMP_MODE_FILTER    2 /* uses user-supplied filter. */
+#define SECCOMP_MODE_EBPF_FILTER        3 /* uses user-supplied EBPF. */

 /* Valid operations for seccomp syscall. */
 #define SECCOMP_SET_MODE_STRICT                0
 #define SECCOMP_SET_MODE_FILTER                1
 #define SECCOMP_GET_ACTION_AVAIL       2
+#define SECCOMP_SET_MODE_EBPF_FILTER    3

 /* Valid flags for SECCOMP_SET_MODE_FILTER */
 #define SECCOMP_FILTER_FLAG_TSYNC      1
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 5cb783f..e33344c 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1229,6 +1229,89 @@ static int bpf_prog_load(union bpf_attr *attr)
        return err;
 }

+int bpf_prog_seccomp_prepare(union bpf_attr *attr, struct bpf_prog **prog)
+{
+       int err;
+
+       if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
+               return -EINVAL;
+
+       if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS)
+               return -E2BIG;
+
+/// TODO
+#if 0
+       if (attr->_prog_type != BPF_PROG_TYPE_SECCOMP)
+               return -EINVAL;
+#endif
+
+       /* plain bpf_prog allocation */
+       *prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
+       if (!prog)
+               return -ENOMEM;
+
+       err = security_bpf_prog_alloc((*prog)->aux);
+       if (err)
+               goto free_prog_nouncharge;
+
+       err = bpf_prog_charge_memlock(*prog);
+       if (err)
+               goto free_prog_sec;
+
+       (*prog)->len = attr->insn_cnt;
+
+       err = -EFAULT;
+       if (copy_from_user((*prog)->insns, u64_to_user_ptr(attr->insns),
+                          bpf_prog_insn_size(*prog)) != 0)
+               goto free_prog;
+
+       (*prog)->orig_prog = NULL;
+       (*prog)->jited = 0;
+
+       atomic_set(&(*prog)->aux->refcnt, 1);
+       (*prog)->gpl_compatible = 1;
+
+       if (attr->prog_ifindex) {
+               err = bpf_prog_offload_init(*prog, attr);
+               if (err)
+                       goto free_prog;
+       }
+
+/// TODO
+       /* find program type */
+#if 0
+       err = find_prog_type(type, prog);
+       if (err < 0)
+               goto free_prog;
+#else
+       (*prog)->type = attr->prog_type;
+#endif
+
+       (*prog)->aux->load_time = ktime_get_boot_ns();
+
+       /* run eBPF verifier */
+       err = bpf_check(prog, attr);
+       if (err < 0)
+               goto free_used_maps;
+
+       /* eBPF program is ready to be JITed */
+       *prog = bpf_prog_select_runtime(*prog, &err);
+       if (err < 0)
+               goto free_used_maps;
+
+       return err;
+
+free_used_maps:
+       free_used_maps((*prog)->aux);
+free_prog:
+       bpf_prog_uncharge_memlock(*prog);
+free_prog_sec:
+       security_bpf_prog_free((*prog)->aux);
+free_prog_nouncharge:
+       bpf_prog_free(*prog);
+       return err;
+}
+
 #define BPF_OBJ_LAST_FIELD file_flags

 static int bpf_obj_pin(const union bpf_attr *attr)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 5f0dfb2ab..ab3895e 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -16,6 +16,7 @@

 #include <linux/refcount.h>
 #include <linux/audit.h>
+#include <linux/bpf.h>
 #include <linux/compat.h>
 #include <linux/coredump.h>
 #include <linux/kmemleak.h>
@@ -205,6 +206,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
         * All filters in the list are evaluated and the lowest BPF return
         * value always takes priority (ignoring the DATA).
         */
+       rcu_read_lock();
        for (; f; f = f->prev) {
                u32 cur_ret = BPF_PROG_RUN(f->prog, sd);

@@ -213,6 +215,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
                        *match = f;
                }
        }
+       rcu_read_unlock();
        return ret;
 }
 #endif /* CONFIG_SECCOMP_FILTER */
@@ -786,6 +789,7 @@ int __secure_computing(const struct seccomp_data *sd)
                __secure_computing_strict(this_syscall);  /* may call do_exit */
                return 0;
        case SECCOMP_MODE_FILTER:
+       case SECCOMP_MODE_EBPF_FILTER:
                return __seccomp_filter(this_syscall, sd, false);
        default:
                BUG();
@@ -893,6 +897,48 @@ static inline long seccomp_set_mode_filter(unsigned int flags,
 }
 #endif

+static long seccomp_set_mode_ebpf_filter(unsigned int flags,
+                                        const char __user *uattr)
+{
+       union bpf_attr attr = {};
+       struct bpf_prog *prog;
+       struct seccomp_filter *sfilter = NULL;
+       const unsigned long seccomp_mode = SECCOMP_MODE_EBPF_FILTER;
+       int err;
+
+       if (copy_from_user(&attr, uattr, sizeof(attr)) != 0)
+               return -EFAULT;
+
+       err = bpf_prog_seccomp_prepare(&attr, &prog);
+       if (err)
+               return err;
+
+       sfilter = kzalloc(sizeof(*sfilter), GFP_KERNEL | __GFP_NOWARN);
+       if (!sfilter)
+               goto free_prog;
+
+       sfilter->prog = prog;
+       refcount_set(&sfilter->usage, 1);
+
+       spin_lock_irq(&current->sighand->siglock);
+
+       err = seccomp_attach_filter(flags, sfilter);
+       if (err)
+               goto unlock;
+
+       seccomp_assign_mode(current, seccomp_mode);
+
+       spin_unlock_irq(&current->sighand->siglock);
+
+       return err;
+unlock:
+       spin_unlock_irq(&current->sighand->siglock);
+       kfree(sfilter);
+free_prog:
+       bpf_prog_free(prog);
+       return err;
+}
+
 static long seccomp_get_action_avail(const char __user *uaction)
 {
        u32 action;
@@ -927,6 +973,8 @@ static long do_seccomp(unsigned int op, unsigned int flags,
                return seccomp_set_mode_strict();
        case SECCOMP_SET_MODE_FILTER:
                return seccomp_set_mode_filter(flags, uargs);
+       case SECCOMP_SET_MODE_EBPF_FILTER:
+               return seccomp_set_mode_ebpf_filter(flags, uargs);
        case SECCOMP_GET_ACTION_AVAIL:
                if (flags != 0)
                        return -EINVAL;
@@ -969,6 +1017,10 @@ long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
                op = SECCOMP_SET_MODE_FILTER;
                uargs = filter;
                break;
+       case SECCOMP_MODE_EBPF_FILTER:
+               op = SECCOMP_SET_MODE_EBPF_FILTER;
+               uargs = filter;
+               break;
        default:
                return -EINVAL;
        }


--
You received this message because you are subscribed to the Google Groups 
"libseccomp" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to