Message ID | 20160914072415.26021-17-mic@digikod.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Sep 14, 2016 at 12:24 AM, Mickaël Salaün <mic@digikod.net> wrote: > This allows to add new eBPF programs to Landlock hooks dedicated to a > cgroup thanks to the BPF_PROG_ATTACH command. Like for socket eBPF > programs, the Landlock hooks attached to a cgroup are propagated to the > nested cgroups. However, when a new Landlock program is attached to one > of this nested cgroup, this cgroup hierarchy fork the Landlock hooks. > This design is simple and match the current CONFIG_BPF_CGROUP > inheritance. The difference lie in the fact that Landlock programs can > only be stacked but not removed. This match the append-only seccomp > behavior. Userland is free to handle Landlock hooks attached to a cgroup > in more complicated ways (e.g. continuous inheritance), but care should > be taken to properly handle error cases (e.g. memory allocation errors). > > Changes since v2: > * new design based on BPF_PROG_ATTACH (suggested by Alexei Starovoitov) > > Signed-off-by: Mickaël Salaün <mic@digikod.net> > Cc: Alexei Starovoitov <ast@kernel.org> > Cc: Andy Lutomirski <luto@amacapital.net> > Cc: Daniel Borkmann <daniel@iogearbox.net> > Cc: Daniel Mack <daniel@zonque.org> > Cc: David S. Miller <davem@davemloft.net> > Cc: Kees Cook <keescook@chromium.org> > Cc: Tejun Heo <tj@kernel.org> > Link: https://lkml.kernel.org/r/20160826021432.GA8291@ast-mbp.thefacebook.com > Link: https://lkml.kernel.org/r/20160827204307.GA43714@ast-mbp.thefacebook.com > --- > include/linux/bpf-cgroup.h | 7 +++++++ > include/linux/cgroup-defs.h | 2 ++ > include/linux/landlock.h | 9 +++++++++ > include/uapi/linux/bpf.h | 1 + > kernel/bpf/cgroup.c | 33 ++++++++++++++++++++++++++++++--- > kernel/bpf/syscall.c | 11 +++++++++++ > security/landlock/lsm.c | 40 +++++++++++++++++++++++++++++++++++++++- > security/landlock/manager.c | 32 ++++++++++++++++++++++++++++++++ > 8 files changed, 131 insertions(+), 4 deletions(-) > > [...] > diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c > index 7b75fa692617..1c18fe46958a 100644 > --- a/kernel/bpf/cgroup.c > +++ b/kernel/bpf/cgroup.c > @@ -15,6 +15,7 @@ > #include <linux/bpf.h> > #include <linux/bpf-cgroup.h> > #include <net/sock.h> > +#include <linux/landlock.h> > > DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key); > EXPORT_SYMBOL(cgroup_bpf_enabled_key); > @@ -31,7 +32,15 @@ void cgroup_bpf_put(struct cgroup *cgrp) > union bpf_object pinned = cgrp->bpf.pinned[type]; > > if (pinned.prog) { > - bpf_prog_put(pinned.prog); > + switch (type) { > + case BPF_CGROUP_LANDLOCK: > +#ifdef CONFIG_SECURITY_LANDLOCK > + put_landlock_hooks(pinned.hooks); > + break; > +#endif /* CONFIG_SECURITY_LANDLOCK */ > + default: > + bpf_prog_put(pinned.prog); > + } > static_branch_dec(&cgroup_bpf_enabled_key); > } > } I get creeped out by type-controlled unions of pointers. :P I don't have a suggestion to improve this, but I don't like seeing a pointer type managed separately from the pointer itself as it tends to bypass a lot of both static and dynamic checking. A union is better than a cast of void *, but it still worries me. :) -Kees
On 04/10/2016 01:43, Kees Cook wrote: > On Wed, Sep 14, 2016 at 12:24 AM, Mickaël Salaün <mic@digikod.net> wrote: >> This allows to add new eBPF programs to Landlock hooks dedicated to a >> cgroup thanks to the BPF_PROG_ATTACH command. Like for socket eBPF >> programs, the Landlock hooks attached to a cgroup are propagated to the >> nested cgroups. However, when a new Landlock program is attached to one >> of this nested cgroup, this cgroup hierarchy fork the Landlock hooks. >> This design is simple and match the current CONFIG_BPF_CGROUP >> inheritance. The difference lie in the fact that Landlock programs can >> only be stacked but not removed. This match the append-only seccomp >> behavior. Userland is free to handle Landlock hooks attached to a cgroup >> in more complicated ways (e.g. continuous inheritance), but care should >> be taken to properly handle error cases (e.g. memory allocation errors). >> >> Changes since v2: >> * new design based on BPF_PROG_ATTACH (suggested by Alexei Starovoitov) >> >> Signed-off-by: Mickaël Salaün <mic@digikod.net> >> Cc: Alexei Starovoitov <ast@kernel.org> >> Cc: Andy Lutomirski <luto@amacapital.net> >> Cc: Daniel Borkmann <daniel@iogearbox.net> >> Cc: Daniel Mack <daniel@zonque.org> >> Cc: David S. Miller <davem@davemloft.net> >> Cc: Kees Cook <keescook@chromium.org> >> Cc: Tejun Heo <tj@kernel.org> >> Link: https://lkml.kernel.org/r/20160826021432.GA8291@ast-mbp.thefacebook.com >> Link: https://lkml.kernel.org/r/20160827204307.GA43714@ast-mbp.thefacebook.com >> --- >> include/linux/bpf-cgroup.h | 7 +++++++ >> include/linux/cgroup-defs.h | 2 ++ >> include/linux/landlock.h | 9 +++++++++ >> include/uapi/linux/bpf.h | 1 + >> kernel/bpf/cgroup.c | 33 ++++++++++++++++++++++++++++++--- >> kernel/bpf/syscall.c | 11 +++++++++++ >> security/landlock/lsm.c | 40 +++++++++++++++++++++++++++++++++++++++- >> security/landlock/manager.c | 32 ++++++++++++++++++++++++++++++++ >> 8 files changed, 131 insertions(+), 4 deletions(-) >> >> [...] >> diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c >> index 7b75fa692617..1c18fe46958a 100644 >> --- a/kernel/bpf/cgroup.c >> +++ b/kernel/bpf/cgroup.c >> @@ -15,6 +15,7 @@ >> #include <linux/bpf.h> >> #include <linux/bpf-cgroup.h> >> #include <net/sock.h> >> +#include <linux/landlock.h> >> >> DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key); >> EXPORT_SYMBOL(cgroup_bpf_enabled_key); >> @@ -31,7 +32,15 @@ void cgroup_bpf_put(struct cgroup *cgrp) >> union bpf_object pinned = cgrp->bpf.pinned[type]; >> >> if (pinned.prog) { >> - bpf_prog_put(pinned.prog); >> + switch (type) { >> + case BPF_CGROUP_LANDLOCK: >> +#ifdef CONFIG_SECURITY_LANDLOCK >> + put_landlock_hooks(pinned.hooks); >> + break; >> +#endif /* CONFIG_SECURITY_LANDLOCK */ >> + default: >> + bpf_prog_put(pinned.prog); >> + } >> static_branch_dec(&cgroup_bpf_enabled_key); >> } >> } > > I get creeped out by type-controlled unions of pointers. :P I don't > have a suggestion to improve this, but I don't like seeing a pointer > type managed separately from the pointer itself as it tends to bypass > a lot of both static and dynamic checking. A union is better than a > cast of void *, but it still worries me. :) This is not fully satisfactory for me neither but the other approach is to use two distinct struct fields instead of a union. Do you prefer if there is a "type" field in the "pinned" struct to select the union? Mickaël
On Wed, Oct 5, 2016 at 1:58 PM, Mickaël Salaün <mic@digikod.net> wrote: > > > On 04/10/2016 01:43, Kees Cook wrote: >> On Wed, Sep 14, 2016 at 12:24 AM, Mickaël Salaün <mic@digikod.net> wrote: >>> This allows to add new eBPF programs to Landlock hooks dedicated to a >>> cgroup thanks to the BPF_PROG_ATTACH command. Like for socket eBPF >>> programs, the Landlock hooks attached to a cgroup are propagated to the >>> nested cgroups. However, when a new Landlock program is attached to one >>> of this nested cgroup, this cgroup hierarchy fork the Landlock hooks. >>> This design is simple and match the current CONFIG_BPF_CGROUP >>> inheritance. The difference lie in the fact that Landlock programs can >>> only be stacked but not removed. This match the append-only seccomp >>> behavior. Userland is free to handle Landlock hooks attached to a cgroup >>> in more complicated ways (e.g. continuous inheritance), but care should >>> be taken to properly handle error cases (e.g. memory allocation errors). >>> >>> Changes since v2: >>> * new design based on BPF_PROG_ATTACH (suggested by Alexei Starovoitov) >>> >>> Signed-off-by: Mickaël Salaün <mic@digikod.net> >>> Cc: Alexei Starovoitov <ast@kernel.org> >>> Cc: Andy Lutomirski <luto@amacapital.net> >>> Cc: Daniel Borkmann <daniel@iogearbox.net> >>> Cc: Daniel Mack <daniel@zonque.org> >>> Cc: David S. Miller <davem@davemloft.net> >>> Cc: Kees Cook <keescook@chromium.org> >>> Cc: Tejun Heo <tj@kernel.org> >>> Link: https://lkml.kernel.org/r/20160826021432.GA8291@ast-mbp.thefacebook.com >>> Link: https://lkml.kernel.org/r/20160827204307.GA43714@ast-mbp.thefacebook.com >>> --- >>> include/linux/bpf-cgroup.h | 7 +++++++ >>> include/linux/cgroup-defs.h | 2 ++ >>> include/linux/landlock.h | 9 +++++++++ >>> include/uapi/linux/bpf.h | 1 + >>> kernel/bpf/cgroup.c | 33 ++++++++++++++++++++++++++++++--- >>> kernel/bpf/syscall.c | 11 +++++++++++ >>> security/landlock/lsm.c | 40 +++++++++++++++++++++++++++++++++++++++- >>> security/landlock/manager.c | 32 ++++++++++++++++++++++++++++++++ >>> 8 files changed, 131 insertions(+), 4 deletions(-) >>> >>> [...] >>> diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c >>> index 7b75fa692617..1c18fe46958a 100644 >>> --- a/kernel/bpf/cgroup.c >>> +++ b/kernel/bpf/cgroup.c >>> @@ -15,6 +15,7 @@ >>> #include <linux/bpf.h> >>> #include <linux/bpf-cgroup.h> >>> #include <net/sock.h> >>> +#include <linux/landlock.h> >>> >>> DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key); >>> EXPORT_SYMBOL(cgroup_bpf_enabled_key); >>> @@ -31,7 +32,15 @@ void cgroup_bpf_put(struct cgroup *cgrp) >>> union bpf_object pinned = cgrp->bpf.pinned[type]; >>> >>> if (pinned.prog) { >>> - bpf_prog_put(pinned.prog); >>> + switch (type) { >>> + case BPF_CGROUP_LANDLOCK: >>> +#ifdef CONFIG_SECURITY_LANDLOCK >>> + put_landlock_hooks(pinned.hooks); >>> + break; >>> +#endif /* CONFIG_SECURITY_LANDLOCK */ >>> + default: >>> + bpf_prog_put(pinned.prog); >>> + } >>> static_branch_dec(&cgroup_bpf_enabled_key); >>> } >>> } >> >> I get creeped out by type-controlled unions of pointers. :P I don't >> have a suggestion to improve this, but I don't like seeing a pointer >> type managed separately from the pointer itself as it tends to bypass >> a lot of both static and dynamic checking. A union is better than a >> cast of void *, but it still worries me. :) > > This is not fully satisfactory for me neither but the other approach is > to use two distinct struct fields instead of a union. > Do you prefer if there is a "type" field in the "pinned" struct to > select the union? Since memory usage isn't a huge deal for this, I'd actually prefer there just be no union at all. Have a type field, and a distinct pointer field for each type you're expecting to use. That way there can never be confusion between types and you could even validate that only a single field type has been populated, etc. -Kees
diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index 6cca7924ee17..439c681159e2 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -14,8 +14,15 @@ struct sk_buff; extern struct static_key_false cgroup_bpf_enabled_key; #define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key) +#ifdef CONFIG_SECURITY_LANDLOCK +struct landlock_hooks; +#endif /* CONFIG_SECURITY_LANDLOCK */ + union bpf_object { struct bpf_prog *prog; +#ifdef CONFIG_SECURITY_LANDLOCK + struct landlock_hooks *hooks; +#endif /* CONFIG_SECURITY_LANDLOCK */ }; struct cgroup_bpf { diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 861b4677fc5b..fe1023bf7b9d 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -301,8 +301,10 @@ struct cgroup { /* used to schedule release agent */ struct work_struct release_agent_work; +#ifdef CONFIG_CGROUP_BPF /* used to store eBPF programs */ struct cgroup_bpf bpf; +#endif /* CONFIG_CGROUP_BPF */ /* ids of the ancestors at each level including self */ int ancestor_ids[]; diff --git a/include/linux/landlock.h b/include/linux/landlock.h index 932ae57fa70e..179a848110f3 100644 --- a/include/linux/landlock.h +++ b/include/linux/landlock.h @@ -19,6 +19,9 @@ #include <linux/seccomp.h> /* struct seccomp_filter */ #endif /* CONFIG_SECCOMP_FILTER */ +#ifdef CONFIG_CGROUP_BPF +#include <linux/cgroup-defs.h> /* struct cgroup */ +#endif /* CONFIG_CGROUP_BPF */ #ifdef CONFIG_SECCOMP_FILTER struct landlock_seccomp_ret { @@ -65,6 +68,7 @@ struct landlock_hooks { struct landlock_hooks *new_landlock_hooks(void); +void get_landlock_hooks(struct landlock_hooks *hooks); void put_landlock_hooks(struct landlock_hooks *hooks); #ifdef CONFIG_SECCOMP_FILTER @@ -73,5 +77,10 @@ int landlock_seccomp_set_hook(unsigned int flags, const char __user *user_bpf_fd); #endif /* CONFIG_SECCOMP_FILTER */ +#ifdef CONFIG_CGROUP_BPF +struct landlock_hooks *landlock_cgroup_set_hook(struct cgroup *cgrp, + struct bpf_prog *prog); +#endif /* CONFIG_CGROUP_BPF */ + #endif /* CONFIG_SECURITY_LANDLOCK */ #endif /* _LINUX_LANDLOCK_H */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 905dcace7255..12e61508f879 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -124,6 +124,7 @@ enum bpf_prog_type { enum bpf_attach_type { BPF_CGROUP_INET_INGRESS, BPF_CGROUP_INET_EGRESS, + BPF_CGROUP_LANDLOCK, __MAX_BPF_ATTACH_TYPE }; diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 7b75fa692617..1c18fe46958a 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -15,6 +15,7 @@ #include <linux/bpf.h> #include <linux/bpf-cgroup.h> #include <net/sock.h> +#include <linux/landlock.h> DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key); EXPORT_SYMBOL(cgroup_bpf_enabled_key); @@ -31,7 +32,15 @@ void cgroup_bpf_put(struct cgroup *cgrp) union bpf_object pinned = cgrp->bpf.pinned[type]; if (pinned.prog) { - bpf_prog_put(pinned.prog); + switch (type) { + case BPF_CGROUP_LANDLOCK: +#ifdef CONFIG_SECURITY_LANDLOCK + put_landlock_hooks(pinned.hooks); + break; +#endif /* CONFIG_SECURITY_LANDLOCK */ + default: + bpf_prog_put(pinned.prog); + } static_branch_dec(&cgroup_bpf_enabled_key); } } @@ -53,6 +62,10 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent) parent->bpf.effective[type].prog, lockdep_is_held(&cgroup_mutex)); rcu_assign_pointer(cgrp->bpf.effective[type].prog, e.prog); +#ifdef CONFIG_SECURITY_LANDLOCK + if (type == BPF_CGROUP_LANDLOCK) + get_landlock_hooks(e.hooks); +#endif /* CONFIG_SECURITY_LANDLOCK */ } } @@ -91,7 +104,18 @@ int __cgroup_bpf_update(struct cgroup *cgrp, union bpf_object obj, old_pinned, effective; struct cgroup_subsys_state *pos; - obj.prog = prog; + switch (type) { + case BPF_CGROUP_LANDLOCK: +#ifdef CONFIG_SECURITY_LANDLOCK + /* append hook */ + obj.hooks = landlock_cgroup_set_hook(cgrp, prog); + if (IS_ERR(obj.hooks)) + return PTR_ERR(obj.hooks); + break; +#endif /* CONFIG_SECURITY_LANDLOCK */ + default: + obj.prog = prog; + } old_pinned = xchg(cgrp->bpf.pinned + type, obj); effective.prog = (!obj.prog && parent) ? @@ -114,7 +138,10 @@ int __cgroup_bpf_update(struct cgroup *cgrp, static_branch_inc(&cgroup_bpf_enabled_key); if (old_pinned.prog) { - bpf_prog_put(old_pinned.prog); +#ifdef CONFIG_SECURITY_LANDLOCK + if (type != BPF_CGROUP_LANDLOCK) + bpf_prog_put(old_pinned.prog); +#endif /* CONFIG_SECURITY_LANDLOCK */ static_branch_dec(&cgroup_bpf_enabled_key); } return 0; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8599596fd6cf..e9c5add327e6 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -846,6 +846,16 @@ static int bpf_prog_attach(const union bpf_attr *attr) BPF_PROG_TYPE_CGROUP_SOCKET); break; + case BPF_CGROUP_LANDLOCK: +#ifdef CONFIG_SECURITY_LANDLOCK + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + prog = bpf_prog_get_type(attr->attach_bpf_fd, + BPF_PROG_TYPE_LANDLOCK); + break; +#endif /* CONFIG_SECURITY_LANDLOCK */ + default: return -EINVAL; } @@ -889,6 +899,7 @@ static int bpf_prog_detach(const union bpf_attr *attr) cgroup_put(cgrp); break; + case BPF_CGROUP_LANDLOCK: default: return -EINVAL; } diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c index b6e0bace683d..000dd0c7ec3d 100644 --- a/security/landlock/lsm.c +++ b/security/landlock/lsm.c @@ -9,6 +9,7 @@ */ #include <asm/current.h> +#include <linux/bpf-cgroup.h> /* cgroup_bpf_enabled */ #include <linux/bpf.h> /* enum bpf_reg_type, struct landlock_data */ #include <linux/cred.h> #include <linux/err.h> /* MAX_ERRNO */ @@ -19,6 +20,10 @@ #include <linux/seccomp.h> /* struct seccomp_* */ #include <linux/types.h> /* uintptr_t */ +#ifdef CONFIG_CGROUP_BPF +#include <linux/cgroup-defs.h> /* struct cgroup */ +#endif /* CONFIG_CGROUP_BPF */ + #include "checker_fs.h" #include "common.h" @@ -99,6 +104,9 @@ static int landlock_run_prog(enum landlock_hook_id hook_id, __u64 args[6]) #ifdef CONFIG_SECCOMP_FILTER struct landlock_seccomp_ret *lr; #endif /* CONFIG_SECCOMP_FILTER */ +#ifdef CONFIG_CGROUP_BPF + struct cgroup *cgrp; +#endif /* CONFIG_CGROUP_BPF */ struct landlock_rule *rule; u32 hook_idx = get_index(hook_id); @@ -115,6 +123,11 @@ static int landlock_run_prog(enum landlock_hook_id hook_id, __u64 args[6]) /* TODO: use lockless_dereference()? */ + /* + * Run the seccomp-based triggers before the cgroup-based triggers to + * prioritize fine-grained policies (i.e. per thread), and return early. + */ + #ifdef CONFIG_SECCOMP_FILTER /* seccomp triggers and landlock_ret cleanup */ ctx.origin = LANDLOCK_FLAG_ORIGIN_SECCOMP; @@ -155,8 +168,21 @@ static int landlock_run_prog(enum landlock_hook_id hook_id, __u64 args[6]) ctx.origin = LANDLOCK_FLAG_ORIGIN_SYSCALL; ret = landlock_run_prog_for_syscall(hook_idx, &ctx, current->seccomp.landlock_hooks); + if (ret) + return -ret; #endif /* CONFIG_SECCOMP_FILTER */ +#ifdef CONFIG_CGROUP_BPF + /* syscall trigger */ + if (cgroup_bpf_enabled) { + ctx.origin = LANDLOCK_FLAG_ORIGIN_SYSCALL; + /* get the default cgroup associated with the current thread */ + cgrp = task_css_set(current)->dfl_cgrp; + ret = landlock_run_prog_for_syscall(hook_idx, &ctx, + cgrp->bpf.effective[BPF_CGROUP_LANDLOCK].hooks); + } +#endif /* CONFIG_CGROUP_BPF */ + return -ret; } @@ -242,9 +268,21 @@ static struct security_hook_list landlock_hooks[] = { LANDLOCK_HOOK_INIT(mmap_file), }; +#ifdef CONFIG_SECCOMP_FILTER +#ifdef CONFIG_CGROUP_BPF +#define LANDLOCK_MANAGERS "seccomp and cgroups" +#else /* CONFIG_CGROUP_BPF */ +#define LANDLOCK_MANAGERS "seccomp" +#endif /* CONFIG_CGROUP_BPF */ +#elif define(CONFIG_CGROUP_BPF) +#define LANDLOCK_MANAGERS "cgroups" +#else +#error "Need CONFIG_SECCOMP_FILTER or CONFIG_CGROUP_BPF" +#endif /* CONFIG_SECCOMP_FILTER */ + void __init landlock_add_hooks(void) { - pr_info("landlock: Becoming ready to sandbox with seccomp\n"); + pr_info("landlock: Becoming ready to sandbox with " LANDLOCK_MANAGERS "\n"); security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks)); } diff --git a/security/landlock/manager.c b/security/landlock/manager.c index e9f3f1092023..50aa1305d0d1 100644 --- a/security/landlock/manager.c +++ b/security/landlock/manager.c @@ -24,6 +24,11 @@ #include <linux/seccomp.h> /* struct seccomp_filter */ #endif /* CONFIG_SECCOMP_FILTER */ +#ifdef CONFIG_CGROUP_BPF +#include <linux/bpf-cgroup.h> /* struct cgroup_bpf */ +#include <linux/cgroup-defs.h> /* struct cgroup */ +#endif /* CONFIG_CGROUP_BPF */ + #include "common.h" static void put_landlock_rule(struct landlock_rule *rule) @@ -84,6 +89,12 @@ struct landlock_hooks *new_landlock_hooks(void) return ret; } +inline void get_landlock_hooks(struct landlock_hooks *hooks) +{ + if (hooks) + atomic_inc(&hooks->usage); +} + /* Limit Landlock hooks to 256KB. */ #define LANDLOCK_HOOKS_MAX_PAGES (1 << 6) @@ -240,3 +251,24 @@ int landlock_seccomp_set_hook(unsigned int flags, const char __user *user_bpf_fd return 0; } #endif /* CONFIG_SECCOMP_FILTER */ + +/** + * landlock_cgroup_set_hook - attach a Landlock program to a cgroup + * + * Must be called with cgroup_mutex held. + * + * @crgp: non-NULL cgroup pointer to attach to + * @prog: Landlock program pointer + */ +#ifdef CONFIG_CGROUP_BPF +struct landlock_hooks *landlock_cgroup_set_hook(struct cgroup *cgrp, + struct bpf_prog *prog) +{ + if (!prog) + return ERR_PTR(-EINVAL); + + /* copy the inherited hooks and append a new one */ + return landlock_set_hook(cgrp->bpf.effective[BPF_CGROUP_LANDLOCK].hooks, + prog, NULL); +} +#endif /* CONFIG_CGROUP_BPF */
This allows to add new eBPF programs to Landlock hooks dedicated to a cgroup thanks to the BPF_PROG_ATTACH command. Like for socket eBPF programs, the Landlock hooks attached to a cgroup are propagated to the nested cgroups. However, when a new Landlock program is attached to one of this nested cgroup, this cgroup hierarchy fork the Landlock hooks. This design is simple and match the current CONFIG_BPF_CGROUP inheritance. The difference lie in the fact that Landlock programs can only be stacked but not removed. This match the append-only seccomp behavior. Userland is free to handle Landlock hooks attached to a cgroup in more complicated ways (e.g. continuous inheritance), but care should be taken to properly handle error cases (e.g. memory allocation errors). Changes since v2: * new design based on BPF_PROG_ATTACH (suggested by Alexei Starovoitov) Signed-off-by: Mickaël Salaün <mic@digikod.net> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Daniel Mack <daniel@zonque.org> Cc: David S. Miller <davem@davemloft.net> Cc: Kees Cook <keescook@chromium.org> Cc: Tejun Heo <tj@kernel.org> Link: https://lkml.kernel.org/r/20160826021432.GA8291@ast-mbp.thefacebook.com Link: https://lkml.kernel.org/r/20160827204307.GA43714@ast-mbp.thefacebook.com --- include/linux/bpf-cgroup.h | 7 +++++++ include/linux/cgroup-defs.h | 2 ++ include/linux/landlock.h | 9 +++++++++ include/uapi/linux/bpf.h | 1 + kernel/bpf/cgroup.c | 33 ++++++++++++++++++++++++++++++--- kernel/bpf/syscall.c | 11 +++++++++++ security/landlock/lsm.c | 40 +++++++++++++++++++++++++++++++++++++++- security/landlock/manager.c | 32 ++++++++++++++++++++++++++++++++ 8 files changed, 131 insertions(+), 4 deletions(-)