Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions include/linux/bpf_lsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
#include <linux/bpf_verifier.h>
#include <linux/lsm_hooks.h>

struct cgroup;
struct cgroup_namespace;
struct ns_common;
struct nsset;
struct super_block;

#ifdef CONFIG_BPF_LSM

#define LSM_HOOK(RET, DEFAULT, NAME, ...) \
Expand Down Expand Up @@ -48,6 +54,14 @@ void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, bpf_func_t *bpf_func)

int bpf_lsm_get_retval_range(const struct bpf_prog *prog,
struct bpf_retval_range *range);

int bpf_lsm_namespace_alloc(struct ns_common *ns);
void bpf_lsm_namespace_free(struct ns_common *ns);
int bpf_lsm_namespace_install(struct nsset *nsset, struct ns_common *ns);
int bpf_lsm_cgroup_attach(struct task_struct *task, struct cgroup *src_cgrp,
struct cgroup *dst_cgrp, struct super_block *sb,
bool threadgroup, struct cgroup_namespace *ns);

int bpf_set_dentry_xattr_locked(struct dentry *dentry, const char *name__str,
const struct bpf_dynptr *value_p, int flags);
int bpf_remove_dentry_xattr_locked(struct dentry *dentry, const char *name__str);
Expand Down Expand Up @@ -104,6 +118,28 @@ static inline bool bpf_lsm_has_d_inode_locked(const struct bpf_prog *prog)
{
return false;
}

static inline int bpf_lsm_namespace_alloc(struct ns_common *ns)
{
return 0;
}
static inline void bpf_lsm_namespace_free(struct ns_common *ns)
{
}
static inline int bpf_lsm_namespace_install(struct nsset *nsset,
struct ns_common *ns)
{
return 0;
}
static inline int bpf_lsm_cgroup_attach(struct task_struct *task,
struct cgroup *src_cgrp,
struct cgroup *dst_cgrp,
struct super_block *sb,
bool threadgroup,
struct cgroup_namespace *ns)
{
return 0;
}
#endif /* CONFIG_BPF_LSM */

#endif /* _LINUX_BPF_LSM_H */
37 changes: 37 additions & 0 deletions kernel/bpf/bpf_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,43 @@ __weak noinline RET bpf_lsm_##NAME(__VA_ARGS__) \
#include <linux/lsm_hook_defs.h>
#undef LSM_HOOK

__bpf_hook_start();

__weak noinline int bpf_lsm_namespace_alloc(struct ns_common *ns)
{
return 0;
}

__weak noinline void bpf_lsm_namespace_free(struct ns_common *ns)
{
}

__weak noinline int bpf_lsm_namespace_install(struct nsset *nsset,
struct ns_common *ns)
{
return 0;
}

__weak noinline int bpf_lsm_cgroup_attach(struct task_struct *task,
struct cgroup *src_cgrp,
struct cgroup *dst_cgrp,
struct super_block *sb,
bool threadgroup,
struct cgroup_namespace *ns)
{
return 0;
}

__bpf_hook_end();

#define LSM_HOOK(RET, DEFAULT, NAME, ...) BTF_ID(func, bpf_lsm_##NAME)
BTF_SET_START(bpf_lsm_hooks)
#include <linux/lsm_hook_defs.h>
#undef LSM_HOOK
BTF_ID(func, bpf_lsm_namespace_alloc)
BTF_ID(func, bpf_lsm_namespace_free)
BTF_ID(func, bpf_lsm_namespace_install)
BTF_ID(func, bpf_lsm_cgroup_attach)
BTF_SET_END(bpf_lsm_hooks)

BTF_SET_START(bpf_lsm_disabled_hooks)
Expand Down Expand Up @@ -383,6 +416,9 @@ BTF_ID(func, bpf_lsm_task_prctl)
BTF_ID(func, bpf_lsm_task_setscheduler)
BTF_ID(func, bpf_lsm_task_to_inode)
BTF_ID(func, bpf_lsm_userns_create)
BTF_ID(func, bpf_lsm_namespace_alloc)
BTF_ID(func, bpf_lsm_namespace_install)
BTF_ID(func, bpf_lsm_cgroup_attach)
BTF_SET_END(sleepable_lsm_hooks)

BTF_SET_START(untrusted_lsm_hooks)
Expand All @@ -395,6 +431,7 @@ BTF_ID(func, bpf_lsm_sk_alloc_security)
BTF_ID(func, bpf_lsm_sk_free_security)
#endif /* CONFIG_SECURITY_NETWORK */
BTF_ID(func, bpf_lsm_task_free)
BTF_ID(func, bpf_lsm_namespace_free)
BTF_SET_END(untrusted_lsm_hooks)

bool bpf_lsm_is_sleepable_hook(u32 btf_id)
Expand Down
18 changes: 11 additions & 7 deletions kernel/cgroup/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "cgroup-internal.h"

#include <linux/bpf-cgroup.h>
#include <linux/bpf_lsm.h>
#include <linux/cred.h>
#include <linux/errno.h>
#include <linux/init_task.h>
Expand Down Expand Up @@ -5334,7 +5335,8 @@ static int cgroup_procs_write_permission(struct cgroup *src_cgrp,
return 0;
}

static int cgroup_attach_permissions(struct cgroup *src_cgrp,
static int cgroup_attach_permissions(struct task_struct *task,
struct cgroup *src_cgrp,
struct cgroup *dst_cgrp,
struct super_block *sb, bool threadgroup,
struct cgroup_namespace *ns)
Expand All @@ -5350,9 +5352,9 @@ static int cgroup_attach_permissions(struct cgroup *src_cgrp,
return ret;

if (!threadgroup && (src_cgrp->dom_cgrp != dst_cgrp->dom_cgrp))
ret = -EOPNOTSUPP;
return -EOPNOTSUPP;

return ret;
return bpf_lsm_cgroup_attach(task, src_cgrp, dst_cgrp, sb, threadgroup, ns);
}

static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
Expand Down Expand Up @@ -5384,7 +5386,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
* inherited fd attacks.
*/
scoped_with_creds(of->file->f_cred)
ret = cgroup_attach_permissions(src_cgrp, dst_cgrp,
ret = cgroup_attach_permissions(task, src_cgrp, dst_cgrp,
of->file->f_path.dentry->d_sb,
threadgroup, ctx->ns);
if (ret)
Expand Down Expand Up @@ -6669,6 +6671,7 @@ static struct cgroup *cgroup_get_from_file(struct file *f)

/**
* cgroup_css_set_fork - find or create a css_set for a child process
* @task: the task to be attached
* @kargs: the arguments passed to create the child process
*
* This functions finds or creates a new css_set which the child
Expand All @@ -6683,7 +6686,8 @@ static struct cgroup *cgroup_get_from_file(struct file *f)
* before grabbing cgroup_threadgroup_rwsem and will hold a reference
* to the target cgroup.
*/
static int cgroup_css_set_fork(struct kernel_clone_args *kargs)
static int cgroup_css_set_fork(struct task_struct *task,
struct kernel_clone_args *kargs)
__acquires(&cgroup_mutex) __acquires(&cgroup_threadgroup_rwsem)
{
int ret;
Expand Down Expand Up @@ -6752,7 +6756,7 @@ static int cgroup_css_set_fork(struct kernel_clone_args *kargs)
* cgroup.procs of the cgroup indicated by @dfd_cgroup. This allows us
* to always use the caller's credentials.
*/
ret = cgroup_attach_permissions(cset->dfl_cgrp, dst_cgrp, sb,
ret = cgroup_attach_permissions(task, cset->dfl_cgrp, dst_cgrp, sb,
!(kargs->flags & CLONE_THREAD),
current->nsproxy->cgroup_ns);
if (ret)
Expand Down Expand Up @@ -6824,7 +6828,7 @@ int cgroup_can_fork(struct task_struct *child, struct kernel_clone_args *kargs)
struct cgroup_subsys *ss;
int i, j, ret;

ret = cgroup_css_set_fork(kargs);
ret = cgroup_css_set_fork(child, kargs);
if (ret)
return ret;

Expand Down
9 changes: 8 additions & 1 deletion kernel/nscommon.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2025 Christian Brauner <brauner@kernel.org> */

#include <linux/bpf_lsm.h>
#include <linux/ns_common.h>
#include <linux/nstree.h>
#include <linux/proc_ns.h>
Expand Down Expand Up @@ -77,6 +78,7 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
ret = proc_alloc_inum(&ns->inum);
if (ret)
return ret;

/*
* Tree ref starts at 0. It's incremented when namespace enters
* active use (installed in nsproxy) and decremented when all
Expand All @@ -86,11 +88,16 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
atomic_set(&ns->__ns_ref_active, 1);
else
atomic_set(&ns->__ns_ref_active, 0);
return 0;

ret = bpf_lsm_namespace_alloc(ns);
if (ret && !inum)
proc_free_inum(ns->inum);
return ret;
}

void __ns_common_free(struct ns_common *ns)
{
bpf_lsm_namespace_free(ns);
proc_free_inum(ns->inum);
}

Expand Down
7 changes: 7 additions & 0 deletions kernel/nsproxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Pavel Emelianov <xemul@openvz.org>
*/

#include <linux/bpf_lsm.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/nsproxy.h>
Expand Down Expand Up @@ -379,6 +380,12 @@ static int prepare_nsset(unsigned flags, struct nsset *nsset)

static inline int validate_ns(struct nsset *nsset, struct ns_common *ns)
{
int ret;

ret = bpf_lsm_namespace_install(nsset, ns);
if (ret)
return ret;

return ns->ops->install(nsset, ns);
}

Expand Down
Loading
Loading