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(¤t->sighand->siglock);
+
+ err = seccomp_attach_filter(flags, sfilter);
+ if (err)
+ goto unlock;
+
+ seccomp_assign_mode(current, seccomp_mode);
+
+ spin_unlock_irq(¤t->sighand->siglock);
+
+ return err;
+unlock:
+ spin_unlock_irq(¤t->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.