While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Links: 1. https://lore.kernel.org/all/20220608150942.776446-1-fred@cloudflare.com/ 2. https://lore.kernel.org/all/87y1xzyhub.fsf@email.froward.int.ebiederm.org/ 3. https://lore.kernel.org/all/9fe9cd9f-1ded-a179-8ded-5fde8960a586@cloudflare....
Changes since v1: - Add selftests/bpf: Add tests verifying bpf lsm create_user_ns hook patch - Add selinux: Implement create_user_ns hook patch - Change function signature of security_create_user_ns() to only take struct cred - Move security_create_user_ns() call after id mapping check in create_user_ns() - Update documentation to reflect changes
Frederick Lawler (4): security, lsm: Introduce security_create_user_ns() bpf-lsm: Make bpf_lsm_create_user_ns() sleepable selftests/bpf: Add tests verifying bpf lsm create_user_ns hook selinux: Implement create_user_ns hook
include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 + include/linux/security.h | 6 ++ kernel/bpf/bpf_lsm.c | 1 + kernel/user_namespace.c | 5 ++ security/security.c | 5 ++ security/selinux/hooks.c | 9 ++ security/selinux/include/classmap.h | 2 + .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 10 files changed, 160 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
Preventing user namespace (privileged or otherwise) creation comes in a few of forms in order of granularity:
1. /proc/sys/user/max_user_namespaces sysctl 2. OS specific patch(es) 3. CONFIG_USER_NS
To block a task based on its attributes, the LSM hook cred_prepare is a good candidate for use because it provides more granular control, and it is called before create_user_ns():
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
Since security_prepare_creds() is meant for LSMs to copy and prepare credentials, access control is an unintended use of the hook. Therefore introduce a new function security_create_user_ns() with an accompanying create_user_ns LSM hook.
This hook takes the prepared creds for LSM authors to write policy against. On success, the new namespace is applied to credentials, otherwise an error is returned.
Signed-off-by: Frederick Lawler fred@cloudflare.com
--- Changes since v1: - Changed commit wording - Moved execution to be after id mapping check - Changed signature to only accept a const struct cred * --- include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 ++++ include/linux/security.h | 6 ++++++ kernel/user_namespace.c | 5 +++++ security/security.c | 5 +++++ 5 files changed, 21 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index eafa1d2489fd..3eabd6b10776 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -223,6 +223,7 @@ LSM_HOOK(int, -ENOSYS, task_prctl, int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) LSM_HOOK(void, LSM_RET_VOID, task_to_inode, struct task_struct *p, struct inode *inode) +LSM_HOOK(int, 0, create_user_ns, const struct cred *cred) LSM_HOOK(int, 0, ipc_permission, struct kern_ipc_perm *ipcp, short flag) LSM_HOOK(void, LSM_RET_VOID, ipc_getsecid, struct kern_ipc_perm *ipcp, u32 *secid) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 91c8146649f5..07f833da0bbf 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -799,6 +799,10 @@ * security attributes, e.g. for /proc/pid inodes. * @p contains the task_struct for the task. * @inode contains the inode structure for the inode. + * @create_user_ns: + * Check permission prior to creating a new user namespace. + * @cred points to prepared creds. + * Return 0 if successful, otherwise < 0 error code. * * Security hooks for Netlink messaging. * diff --git a/include/linux/security.h b/include/linux/security.h index 7fc4e9f49f54..a195bf33246a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -435,6 +435,7 @@ int security_task_kill(struct task_struct *p, struct kernel_siginfo *info, int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); void security_task_to_inode(struct task_struct *p, struct inode *inode); +int security_create_user_ns(const struct cred *cred); int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid); int security_msg_msg_alloc(struct msg_msg *msg); @@ -1185,6 +1186,11 @@ static inline int security_task_prctl(int option, unsigned long arg2, static inline void security_task_to_inode(struct task_struct *p, struct inode *inode) { }
+static inline int security_create_user_ns(const struct cred *cred) +{ + return 0; +} + static inline int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 5481ba44a8d6..3f464bbda0e9 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -9,6 +9,7 @@ #include <linux/highuid.h> #include <linux/cred.h> #include <linux/securebits.h> +#include <linux/security.h> #include <linux/keyctl.h> #include <linux/key-type.h> #include <keys/user-type.h> @@ -113,6 +114,10 @@ int create_user_ns(struct cred *new) !kgid_has_mapping(parent_ns, group)) goto fail_dec;
+ ret = security_create_user_ns(new); + if (ret < 0) + goto fail_dec; + ret = -ENOMEM; ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL); if (!ns) diff --git a/security/security.c b/security/security.c index 188b8f782220..c700dbdc14fe 100644 --- a/security/security.c +++ b/security/security.c @@ -1903,6 +1903,11 @@ void security_task_to_inode(struct task_struct *p, struct inode *inode) call_void_hook(task_to_inode, p, inode); }
+int security_create_user_ns(const struct cred *cred) +{ + return call_int_hook(create_user_ns, 0, cred); +} + int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { return call_int_hook(ipc_permission, 0, ipcp, flag);
Users may want to audit calls to security_create_user_ns() and access user space memory. Also create_user_ns() runs without pagefault_disabled(). Therefore, make bpf_lsm_create_user_ns() sleepable for mandatory access control policies.
Signed-off-by: Frederick Lawler fred@cloudflare.com
--- Changes since v1: - None --- kernel/bpf/bpf_lsm.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index c1351df9f7ee..75853965e7b0 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -250,6 +250,7 @@ BTF_ID(func, bpf_lsm_task_getsecid_obj) 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_create_user_ns) BTF_SET_END(sleepable_lsm_hooks)
bool bpf_lsm_is_sleepable_hook(u32 btf_id)
The LSM hook create_user_ns was introduced to provide LSM's an opportunity to block or allow unprivileged user namespace creation. This test serves two purposes: it provides a test eBPF implementation, and tests the hook successfully blocks or allows user namespace creation.
This tests 4 cases:
1. Unattached bpf program does not block unpriv user namespace creation. 2. Attached bpf program allows user namespace creation given CAP_SYS_ADMIN privileges. 3. Attached bpf program denies user namespace creation for a user without CAP_SYS_ADMIN. 4. The sleepable implementation loads
Signed-off-by: Frederick Lawler fred@cloudflare.com
--- The generic deny_namespace file name is used for future namespace expansion. I didn't want to limit these files to just the create_user_ns hook.
Changes since v1: - Introduce this patch --- .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 2 files changed, 127 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
diff --git a/tools/testing/selftests/bpf/prog_tests/deny_namespace.c b/tools/testing/selftests/bpf/prog_tests/deny_namespace.c new file mode 100644 index 000000000000..a1fb07038dd5 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/deny_namespace.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <test_progs.h> +#include "test_deny_namespace.skel.h" +#include <sched.h> +#include "cap_helpers.h" + +#define STACK_SIZE (1024 * 1024) +static char child_stack[STACK_SIZE]; + +int clone_callback(void *arg) +{ + return 0; +} + +static int create_new_user_ns(void) +{ + int status; + pid_t cpid; + + cpid = clone(clone_callback, child_stack + STACK_SIZE, + CLONE_NEWUSER | SIGCHLD, NULL); + + if (cpid == -1) + return errno; + + if (cpid == 0) + return 0; + + waitpid(cpid, &status, 0); + if (WIFEXITED(status)) + return WEXITSTATUS(status); + + return -1; +} + +static void test_create_user_ns_bpf(void) +{ + __u32 cap_mask = 1ULL << CAP_SYS_ADMIN; + __u64 old_caps = 0; + + ASSERT_OK(create_new_user_ns(), "priv new user ns"); + + cap_disable_effective(cap_mask, &old_caps); + + ASSERT_EQ(create_new_user_ns(), EPERM, "unpriv new user ns"); + + if (cap_mask & old_caps) + cap_enable_effective(cap_mask, NULL); +} + +static void test_unpriv_create_user_ns_no_bpf(void) +{ + __u32 cap_mask = 1ULL << CAP_SYS_ADMIN; + __u64 old_caps = 0; + + cap_disable_effective(cap_mask, &old_caps); + + ASSERT_OK(create_new_user_ns(), "no-bpf unpriv new user ns"); + + if (cap_mask & old_caps) + cap_enable_effective(cap_mask, NULL); +} + +void test_deny_namespace(void) +{ + struct test_deny_namespace *skel = NULL; + int err; + + if (test__start_subtest("unpriv_create_user_ns_no_bpf")) + test_unpriv_create_user_ns_no_bpf(); + + skel = test_deny_namespace__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel load")) + goto close_prog; + + err = test_deny_namespace__attach(skel); + if (!ASSERT_OK(err, "attach")) + goto close_prog; + + if (test__start_subtest("create_user_ns_bpf")) + test_create_user_ns_bpf(); + + test_deny_namespace__detach(skel); + +close_prog: + test_deny_namespace__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_deny_namespace.c b/tools/testing/selftests/bpf/progs/test_deny_namespace.c new file mode 100644 index 000000000000..eedede891431 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_deny_namespace.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <errno.h> +#include <linux/capability.h> + +struct kernel_cap_struct { + __u32 cap[_LINUX_CAPABILITY_U32S_3]; +} __attribute__((preserve_access_index)); + +struct cred { + struct kernel_cap_struct cap_effective; +} __attribute__((preserve_access_index)); + +char _license[] SEC("license") = "GPL"; + +SEC("lsm/create_user_ns") +int BPF_PROG(test_create_user_ns, const struct cred *cred, int ret) +{ + struct kernel_cap_struct caps = cred->cap_effective; + int cap_index = CAP_TO_INDEX(CAP_SYS_ADMIN); + __u32 cap_mask = CAP_TO_MASK(CAP_SYS_ADMIN); + + if (ret) + return 0; + + ret = -EPERM; + if (caps.cap[cap_index] & cap_mask) + return 0; + + return -EPERM; +} + +SEC("lsm.s/create_user_ns") +int BPF_PROG(test_sleepable_create_user_ns, const struct cred *cred, int ret) +{ + return 0; +}
Unprivileged user namespace creation is an intended feature to enable sandboxing, however this feature is often used to as an initial step to perform a privilege escalation attack.
This patch implements a new namespace { userns_create } access control permission to restrict which domains allow or deny user namespace creation. This is necessary for system administrators to quickly protect their systems while waiting for vulnerability patches to be applied.
This permission can be used in the following way:
allow domA_t domB_t : namespace { userns_create };
Signed-off-by: Frederick Lawler fred@cloudflare.com
--- Changes since v1: - Introduce this patch --- security/selinux/hooks.c | 9 +++++++++ security/selinux/include/classmap.h | 2 ++ 2 files changed, 11 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index beceb89f68d9..73fbcb434fe0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4227,6 +4227,14 @@ static void selinux_task_to_inode(struct task_struct *p, spin_unlock(&isec->lock); }
+static int selinux_userns_create(const struct cred *cred) +{ + u32 sid = current_sid(); + + return avc_has_perm(&selinux_state, sid, sid, SECCLASS_NAMESPACE, + NAMESPACE__USERNS_CREATE, NULL); +} + /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct common_audit_data *ad, u8 *proto) @@ -7117,6 +7125,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(task_movememory, selinux_task_movememory), LSM_HOOK_INIT(task_kill, selinux_task_kill), LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode), + LSM_HOOK_INIT(create_user_ns, selinux_userns_create),
LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission), LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid), diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index ff757ae5f253..9943e85c6b3e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -254,6 +254,8 @@ const struct security_class_mapping secclass_map[] = { { COMMON_FILE_PERMS, NULL } }, { "io_uring", { "override_creds", "sqpoll", NULL } }, + { "namespace", + { "userns_create", NULL } }, { NULL } };
On Thu, Jul 7, 2022 at 6:32 PM Frederick Lawler fred@cloudflare.com wrote:
Unprivileged user namespace creation is an intended feature to enable sandboxing, however this feature is often used to as an initial step to perform a privilege escalation attack.
This patch implements a new namespace { userns_create } access control permission to restrict which domains allow or deny user namespace creation. This is necessary for system administrators to quickly protect their systems while waiting for vulnerability patches to be applied.
This permission can be used in the following way:
allow domA_t domB_t : namespace { userns_create };
Signed-off-by: Frederick Lawler fred@cloudflare.com
Changes since v1:
- Introduce this patch
security/selinux/hooks.c | 9 +++++++++ security/selinux/include/classmap.h | 2 ++ 2 files changed, 11 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index beceb89f68d9..73fbcb434fe0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4227,6 +4227,14 @@ static void selinux_task_to_inode(struct task_struct *p, spin_unlock(&isec->lock); }
+static int selinux_userns_create(const struct cred *cred) +{
u32 sid = current_sid();
return avc_has_perm(&selinux_state, sid, sid, SECCLASS_NAMESPACE,
NAMESPACE__USERNS_CREATE, NULL);
+}
As we continue to discuss this, I'm beginning to think that having a dedicated object class for the userns might be a good idea. I believe I was the one who gave you these code snippets, so feel free to blame me for the respin ;)
This is what I'm thinking:
static int selinux_userns_create(const struct cred *cred) { u32 sid = current_sid();
return avc_has_perm(&selinux_state, sid, sid, SECCLASS_USER_NAMESPACE, USER_NAMESPACE__CREATE, NULL); }
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index ff757ae5f253..9943e85c6b3e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -254,6 +254,8 @@ const struct security_class_mapping secclass_map[] = { { COMMON_FILE_PERMS, NULL } }, { "io_uring", { "override_creds", "sqpoll", NULL } },
{ "namespace",
{ "userns_create", NULL } },
The above would need to change to:
{ "user_namespace", { "create", NULL } }
On 7/19/22 8:32 PM, Paul Moore wrote:
On Thu, Jul 7, 2022 at 6:32 PM Frederick Lawler fred@cloudflare.com wrote:
Unprivileged user namespace creation is an intended feature to enable sandboxing, however this feature is often used to as an initial step to perform a privilege escalation attack.
This patch implements a new namespace { userns_create } access control permission to restrict which domains allow or deny user namespace creation. This is necessary for system administrators to quickly protect their systems while waiting for vulnerability patches to be applied.
This permission can be used in the following way:
allow domA_t domB_t : namespace { userns_create };
Signed-off-by: Frederick Lawler fred@cloudflare.com
Changes since v1:
- Introduce this patch
security/selinux/hooks.c | 9 +++++++++ security/selinux/include/classmap.h | 2 ++ 2 files changed, 11 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index beceb89f68d9..73fbcb434fe0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4227,6 +4227,14 @@ static void selinux_task_to_inode(struct task_struct *p, spin_unlock(&isec->lock); }
+static int selinux_userns_create(const struct cred *cred) +{
u32 sid = current_sid();
return avc_has_perm(&selinux_state, sid, sid, SECCLASS_NAMESPACE,
NAMESPACE__USERNS_CREATE, NULL);
+}
As we continue to discuss this, I'm beginning to think that having a dedicated object class for the userns might be a good idea. I believe I was the one who gave you these code snippets, so feel free to blame me for the respin ;)
No worries, I'll make this change for v3.
This is what I'm thinking:
static int selinux_userns_create(const struct cred *cred) { u32 sid = current_sid();
return avc_has_perm(&selinux_state, sid, sid, SECCLASS_USER_NAMESPACE, USER_NAMESPACE__CREATE, NULL);
}
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index ff757ae5f253..9943e85c6b3e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -254,6 +254,8 @@ const struct security_class_mapping secclass_map[] = { { COMMON_FILE_PERMS, NULL } }, { "io_uring", { "override_creds", "sqpoll", NULL } },
{ "namespace",
{ "userns_create", NULL } },
The above would need to change to:
{ "user_namespace", { "create", NULL } }
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Some thoughts:
I.
Why not make the hook more generic, e.g. support all other existing and potential future namespaces? Also I think the naming scheme is <object>_<verb>.
LSM_HOOK(int, 0, namespace_create, const struct cred *cred, unsigned int flags)
where flags is a bitmap of CLONE flags from include/uapi/linux/sched.h (like CLONE_NEWUSER).
II.
While adding policing for namespaces maybe also add a new hook for setns(2)
LSM_HOOK(int, 0, namespace_join, const struct cred *subj, const struct cred *obj, unsigned int flags)
III.
Maybe even attach a security context to namespaces so they can be further governed? SELinux example:
type domainA_userns_t; type_transition domainA_t domainA_t : namespace domainA_userns_t "user"; allow domainA_t domainA_userns_t:namespace create;
# domainB calling setns(2) with domainA as target allow domainB_t domainA_userns_t:namespace join;
Links:
- https://lore.kernel.org/all/20220608150942.776446-1-fred@cloudflare.com/
- https://lore.kernel.org/all/87y1xzyhub.fsf@email.froward.int.ebiederm.org/
- https://lore.kernel.org/all/9fe9cd9f-1ded-a179-8ded-5fde8960a586@cloudflare....
Changes since v1:
- Add selftests/bpf: Add tests verifying bpf lsm create_user_ns hook patch
- Add selinux: Implement create_user_ns hook patch
- Change function signature of security_create_user_ns() to only take struct cred
- Move security_create_user_ns() call after id mapping check in create_user_ns()
- Update documentation to reflect changes
Frederick Lawler (4): security, lsm: Introduce security_create_user_ns() bpf-lsm: Make bpf_lsm_create_user_ns() sleepable selftests/bpf: Add tests verifying bpf lsm create_user_ns hook selinux: Implement create_user_ns hook
include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 + include/linux/security.h | 6 ++ kernel/bpf/bpf_lsm.c | 1 + kernel/user_namespace.c | 5 ++ security/security.c | 5 ++ security/selinux/hooks.c | 9 ++ security/selinux/include/classmap.h | 2 + .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 10 files changed, 160 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
-- 2.30.2
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Some thoughts:
I.
Why not make the hook more generic, e.g. support all other existing and potential future namespaces?
The main issue with a generic hook is that different namespaces have different calling contexts. We decided in a previous discussion to opt-out of a generic hook for this reason. [1]
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
LSM_HOOK(int, 0, namespace_create, const struct cred *cred,
unsigned int flags)
where flags is a bitmap of CLONE flags from include/uapi/linux/sched.h (like CLONE_NEWUSER).
II.
While adding policing for namespaces maybe also add a new hook for setns(2)
LSM_HOOK(int, 0, namespace_join, const struct cred *subj, const
struct cred *obj, unsigned int flags)
IIUC, setns() will create a new namespace for the other namespaces except for user namespace. If we add a security hook for the other create_*_ns() functions, then we can catch setns() at that point.
III.
Maybe even attach a security context to namespaces so they can be further governed? SELinux example:
type domainA_userns_t; type_transition domainA_t domainA_t : namespace domainA_userns_t "user"; allow domainA_t domainA_userns_t:namespace create; # domainB calling setns(2) with domainA as target allow domainB_t domainA_userns_t:namespace join;
Links: 1. https://lore.kernel.org/all/CAHC9VhSTkEMT90Tk+=iTyp3npWEm+3imrkFVX2qb=XsOPp9...
Links:
- https://lore.kernel.org/all/20220608150942.776446-1-fred@cloudflare.com/
- https://lore.kernel.org/all/87y1xzyhub.fsf@email.froward.int.ebiederm.org/
- https://lore.kernel.org/all/9fe9cd9f-1ded-a179-8ded-5fde8960a586@cloudflare....
Changes since v1:
- Add selftests/bpf: Add tests verifying bpf lsm create_user_ns hook patch
- Add selinux: Implement create_user_ns hook patch
- Change function signature of security_create_user_ns() to only take struct cred
- Move security_create_user_ns() call after id mapping check in create_user_ns()
- Update documentation to reflect changes
Frederick Lawler (4): security, lsm: Introduce security_create_user_ns() bpf-lsm: Make bpf_lsm_create_user_ns() sleepable selftests/bpf: Add tests verifying bpf lsm create_user_ns hook selinux: Implement create_user_ns hook
include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 + include/linux/security.h | 6 ++ kernel/bpf/bpf_lsm.c | 1 + kernel/user_namespace.c | 5 ++ security/security.c | 5 ++ security/selinux/hooks.c | 9 ++ security/selinux/include/classmap.h | 2 + .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 10 files changed, 160 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
-- 2.30.2
On Fri, Jul 08, 2022 at 09:01:32AM -0500, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Some thoughts:
I.
Why not make the hook more generic, e.g. support all other existing and potential future namespaces?
The main issue with a generic hook is that different namespaces have different calling contexts. We decided in a previous discussion to opt-out of a generic hook for this reason. [1]
Agreed.
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
LSM_HOOK(int, 0, namespace_create, const struct cred *cred,
unsigned int flags)
where flags is a bitmap of CLONE flags from include/uapi/linux/sched.h (like CLONE_NEWUSER).
II.
While adding policing for namespaces maybe also add a new hook for setns(2)
LSM_HOOK(int, 0, namespace_join, const struct cred *subj, const
struct cred *obj, unsigned int flags)
IIUC, setns() will create a new namespace for the other namespaces except for user namespace. If we add a security hook for the other create_*_ns()
setns() doesn't create new namespaces. It just switches to already existing ones:
setns(<pidfd>, <flags>) -> prepare_nsset() /* * Notice the 0 passed as flags which means all namespaces will * just take a reference. */ -> create_new_namespaces(0, ...)
you're thinking about unshare() and unshare() will be caught in create_user_ns().
functions, then we can catch setns() at that point.
If you block the creation of user namespaces by unprivileged users in create_user_ns() you can only create user namespaces as a privileged user. Consequently only a privileged users can setns() to a user namespace. So either the caller has CAP_SYS_ADMIN in the parent userns or they are located in the parent userns and are the owner of the userns they are attaching to. So if you lock create_user_ns() to capable(CAP_SYS_ADMIN) you should be done.
On 7/8/2022 7:01 AM, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Some thoughts:
I.
Why not make the hook more generic, e.g. support all other existing and potential future namespaces?
The main issue with a generic hook is that different namespaces have different calling contexts. We decided in a previous discussion to opt-out of a generic hook for this reason. [1]
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
LSM_HOOK(int, 0, namespace_create, const struct cred *cred, unsigned int flags)
where flags is a bitmap of CLONE flags from include/uapi/linux/sched.h (like CLONE_NEWUSER).
II.
While adding policing for namespaces maybe also add a new hook for setns(2)
LSM_HOOK(int, 0, namespace_join, const struct cred *subj, const struct cred *obj, unsigned int flags)
IIUC, setns() will create a new namespace for the other namespaces except for user namespace. If we add a security hook for the other create_*_ns() functions, then we can catch setns() at that point.
III.
Maybe even attach a security context to namespaces so they can be further governed?
That would likely add confusion to the existing security module namespace efforts. SELinux, Smack and AppArmor have all developed namespace models. That, or it could replace the various independent efforts with a single, unified security module namespace effort. There's more work to that than adding a context to a namespace. Treating namespaces as objects is almost, but not quite, solidifying containers as a kernel construct. We know we can't do that.
SELinux example:
type domainA_userns_t; type_transition domainA_t domainA_t : namespace domainA_userns_t "user"; allow domainA_t domainA_userns_t:namespace create;
# domainB calling setns(2) with domainA as target allow domainB_t domainA_userns_t:namespace join;
While I'm not an expert on SELinux policy, I'd bet a refreshing beverage that there's already a way to achieve this with existing constructs. Smack, which is subject+object MAC couldn't care less about the user namespace configuration. User namespaces are DAC constructs.
Links:
https://lore.kernel.org/all/CAHC9VhSTkEMT90Tk+=iTyp3npWEm+3imrkFVX2qb=XsOPp9...
Links:
https://lore.kernel.org/all/20220608150942.776446-1-fred@cloudflare.com/
https://lore.kernel.org/all/87y1xzyhub.fsf@email.froward.int.ebiederm.org/ 3. https://lore.kernel.org/all/9fe9cd9f-1ded-a179-8ded-5fde8960a586@cloudflare....
Changes since v1:
- Add selftests/bpf: Add tests verifying bpf lsm create_user_ns hook
patch
- Add selinux: Implement create_user_ns hook patch
- Change function signature of security_create_user_ns() to only take
struct cred
- Move security_create_user_ns() call after id mapping check in
create_user_ns()
- Update documentation to reflect changes
Frederick Lawler (4): security, lsm: Introduce security_create_user_ns() bpf-lsm: Make bpf_lsm_create_user_ns() sleepable selftests/bpf: Add tests verifying bpf lsm create_user_ns hook selinux: Implement create_user_ns hook
include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 + include/linux/security.h | 6 ++ kernel/bpf/bpf_lsm.c | 1 + kernel/user_namespace.c | 5 ++ security/security.c | 5 ++ security/selinux/hooks.c | 9 ++ security/selinux/include/classmap.h | 2 + .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 10 files changed, 160 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
-- 2.30.2
On Fri, Jul 08, 2022 at 09:11:15AM -0700, Casey Schaufler wrote:
On 7/8/2022 7:01 AM, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Some thoughts:
I.
Why not make the hook more generic, e.g. support all other existing and potential future namespaces?
The main issue with a generic hook is that different namespaces have different calling contexts. We decided in a previous discussion to opt-out of a generic hook for this reason. [1]
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
LSM_HOOK(int, 0, namespace_create, const struct cred *cred, unsigned int flags)
where flags is a bitmap of CLONE flags from include/uapi/linux/sched.h (like CLONE_NEWUSER).
II.
While adding policing for namespaces maybe also add a new hook for setns(2)
LSM_HOOK(int, 0, namespace_join, const struct cred *subj, const struct cred *obj, unsigned int flags)
IIUC, setns() will create a new namespace for the other namespaces except for user namespace. If we add a security hook for the other create_*_ns() functions, then we can catch setns() at that point.
III.
Maybe even attach a security context to namespaces so they can be further governed?
That would likely add confusion to the existing security module namespace efforts. SELinux, Smack and AppArmor have all developed namespace models. That, or it could replace the various independent efforts with a single,
I feel like you're attaching more meaning to this than there needs to be. I *think* he's just talking about a user_namespace->u_security void*. So that for instance while deciding whether to allow some transition, selinux could check whether the caller's user namespace was created by a task in an selinux context authorized to create user namespaces.
The "user namespaces are DAC and orthogonal to MAC" is of course true (where the LSM does not itself tie them together), except that we all know that a process running as root in a user namespace gains access to often-less-trustworthy code gated under CAP_SYS_ADMIN.
unified security module namespace effort. There's more work to that than adding a context to a namespace. Treating namespaces as objects is almost, but not quite, solidifying containers as a kernel construct. We know we can't do that.
What we "can't do" (imo) is to create a "full container" construct which ties together the various namespaces and other concepts in a restrictive way.
SELinux example:
type domainA_userns_t; type_transition domainA_t domainA_t : namespace domainA_userns_t "user"; allow domainA_t domainA_userns_t:namespace create;
# domainB calling setns(2) with domainA as target allow domainB_t domainA_userns_t:namespace join;
While I'm not an expert on SELinux policy, I'd bet a refreshing beverage that there's already a way to achieve this with existing constructs. Smack, which is subject+object MAC couldn't care less about the user namespace configuration. User namespaces are DAC constructs.
Links:
https://lore.kernel.org/all/CAHC9VhSTkEMT90Tk+=iTyp3npWEm+3imrkFVX2qb=XsOPp9...
Links:
https://lore.kernel.org/all/20220608150942.776446-1-fred@cloudflare.com/
https://lore.kernel.org/all/87y1xzyhub.fsf@email.froward.int.ebiederm.org/ 3. https://lore.kernel.org/all/9fe9cd9f-1ded-a179-8ded-5fde8960a586@cloudflare....
Changes since v1:
- Add selftests/bpf: Add tests verifying bpf lsm create_user_ns hook
patch
- Add selinux: Implement create_user_ns hook patch
- Change function signature of security_create_user_ns() to only take
struct cred
- Move security_create_user_ns() call after id mapping check in
create_user_ns()
- Update documentation to reflect changes
Frederick Lawler (4): security, lsm: Introduce security_create_user_ns() bpf-lsm: Make bpf_lsm_create_user_ns() sleepable selftests/bpf: Add tests verifying bpf lsm create_user_ns hook selinux: Implement create_user_ns hook
include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 + include/linux/security.h | 6 ++ kernel/bpf/bpf_lsm.c | 1 + kernel/user_namespace.c | 5 ++ security/security.c | 5 ++ security/selinux/hooks.c | 9 ++ security/selinux/include/classmap.h | 2 + .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 10 files changed, 160 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
-- 2.30.2
On 7/14/22 9:27 AM, Serge E. Hallyn wrote:
On Fri, Jul 08, 2022 at 09:11:15AM -0700, Casey Schaufler wrote:
On 7/8/2022 7:01 AM, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
While creating a LSM BPF MAC policy to block user namespace creation, we used the LSM cred_prepare hook because that is the closest hook to prevent a call to create_user_ns().
The calls look something like this:
cred = prepare_creds() security_prepare_creds() call_int_hook(cred_prepare, ... if (cred) create_user_ns(cred)
We noticed that error codes were not propagated from this hook and introduced a patch [1] to propagate those errors.
The discussion notes that security_prepare_creds() is not appropriate for MAC policies, and instead the hook is meant for LSM authors to prepare credentials for mutation. [2]
Ultimately, we concluded that a better course of action is to introduce a new security hook for LSM authors. [3]
This patch set first introduces a new security_create_user_ns() function and create_user_ns LSM hook, then marks the hook as sleepable in BPF.
Some thoughts:
I.
Why not make the hook more generic, e.g. support all other existing and potential future namespaces?
The main issue with a generic hook is that different namespaces have different calling contexts. We decided in a previous discussion to opt-out of a generic hook for this reason. [1]
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
LSM_HOOK(int, 0, namespace_create, const struct cred *cred, unsigned int flags)
where flags is a bitmap of CLONE flags from include/uapi/linux/sched.h (like CLONE_NEWUSER).
II.
While adding policing for namespaces maybe also add a new hook for setns(2)
LSM_HOOK(int, 0, namespace_join, const struct cred *subj, const struct cred *obj, unsigned int flags)
IIUC, setns() will create a new namespace for the other namespaces except for user namespace. If we add a security hook for the other create_*_ns() functions, then we can catch setns() at that point.
III.
Maybe even attach a security context to namespaces so they can be further governed?
That would likely add confusion to the existing security module namespace efforts. SELinux, Smack and AppArmor have all developed namespace models. That, or it could replace the various independent efforts with a single,
I feel like you're attaching more meaning to this than there needs to be. I *think* he's just talking about a user_namespace->u_security void*. So that for instance while deciding whether to allow some transition, selinux could check whether the caller's user namespace was created by a task in an selinux context authorized to create user namespaces.
The "user namespaces are DAC and orthogonal to MAC" is of course true (where the LSM does not itself tie them together), except that we all know that a process running as root in a user namespace gains access to often-less-trustworthy code gated under CAP_SYS_ADMIN.
unified security module namespace effort. There's more work to that than adding a context to a namespace. Treating namespaces as objects is almost, but not quite, solidifying containers as a kernel construct. We know we can't do that.
What we "can't do" (imo) is to create a "full container" construct which ties together the various namespaces and other concepts in a restrictive way.
Is this the direction we want to go with the SELinux implementation? If so, where can I find a similar implementation to make the userns_create work with this? If not, I have a v3 with the hook name change ready to post.
SELinux example:
type domainA_userns_t; type_transition domainA_t domainA_t : namespace domainA_userns_t "user"; allow domainA_t domainA_userns_t:namespace create;
# domainB calling setns(2) with domainA as target allow domainB_t domainA_userns_t:namespace join;
While I'm not an expert on SELinux policy, I'd bet a refreshing beverage that there's already a way to achieve this with existing constructs. Smack, which is subject+object MAC couldn't care less about the user namespace configuration. User namespaces are DAC constructs.
Links:
https://lore.kernel.org/all/CAHC9VhSTkEMT90Tk+=iTyp3npWEm+3imrkFVX2qb=XsOPp9...
Links:
https://lore.kernel.org/all/20220608150942.776446-1-fred@cloudflare.com/
https://lore.kernel.org/all/87y1xzyhub.fsf@email.froward.int.ebiederm.org/ 3. https://lore.kernel.org/all/9fe9cd9f-1ded-a179-8ded-5fde8960a586@cloudflare....
Changes since v1:
- Add selftests/bpf: Add tests verifying bpf lsm create_user_ns hook
patch
- Add selinux: Implement create_user_ns hook patch
- Change function signature of security_create_user_ns() to only take
struct cred
- Move security_create_user_ns() call after id mapping check in
create_user_ns()
- Update documentation to reflect changes
Frederick Lawler (4): security, lsm: Introduce security_create_user_ns() bpf-lsm: Make bpf_lsm_create_user_ns() sleepable selftests/bpf: Add tests verifying bpf lsm create_user_ns hook selinux: Implement create_user_ns hook
include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 + include/linux/security.h | 6 ++ kernel/bpf/bpf_lsm.c | 1 + kernel/user_namespace.c | 5 ++ security/security.c | 5 ++ security/selinux/hooks.c | 9 ++ security/selinux/include/classmap.h | 2 + .../selftests/bpf/prog_tests/deny_namespace.c | 88 +++++++++++++++++++ .../selftests/bpf/progs/test_deny_namespace.c | 39 ++++++++ 10 files changed, 160 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/deny_namespace.c create mode 100644 tools/testing/selftests/bpf/progs/test_deny_namespace.c
-- 2.30.2
On Fri, Jul 8, 2022 at 12:11 PM Casey Schaufler casey@schaufler-ca.com wrote:
On 7/8/2022 7:01 AM, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
...
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
No objection from me.
[Sorry for the delay, the last week or two has been pretty busy.]
III.
Maybe even attach a security context to namespaces so they can be further governed?
That would likely add confusion to the existing security module namespace efforts. SELinux, Smack and AppArmor have all developed namespace models.
I'm not sure I fully understand what Casey is saying here as SELinux does not yet have an established namespace model to the best of my understanding, but perhaps we are talking about different concepts for the word "namespace"?
From a SELinux perspective, if we are going to control access to a namespace beyond simple creation, we would need to assign the namespace a label (inherited from the creating process). Although that would need some discussion among the SELinux folks as this would mean treating a userns as a proper system entity from a policy perspective which is ... interesting.
That, or it could replace the various independent efforts with a single, unified security module namespace effort.
We've talked about this before and I just don't see how that could ever work, the LSM implementations are just too different to do namespacing at the LSM layer. If a LSM is going to namespace themselves, they need the ability to define what that means without having to worry about what other LSMs want to do.
-- paul-moore.com
On 7/19/2022 6:32 PM, Paul Moore wrote:
On Fri, Jul 8, 2022 at 12:11 PM Casey Schaufler casey@schaufler-ca.com wrote:
On 7/8/2022 7:01 AM, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
..
Also I think the naming scheme is <object>_<verb>.
That's a good call out. I was originally hoping to keep the security_*() match with the hook name matched with the caller function to keep things all aligned. If no one objects to renaming the hook, I can rename the hook for v3.
No objection from me.
[Sorry for the delay, the last week or two has been pretty busy.]
III.
Maybe even attach a security context to namespaces so they can be further governed?
That would likely add confusion to the existing security module namespace efforts. SELinux, Smack and AppArmor have all developed namespace models.
I'm not sure I fully understand what Casey is saying here as SELinux does not yet have an established namespace model to the best of my understanding, but perhaps we are talking about different concepts for the word "namespace"?
Stephen Smalley proposed a SELinux namespace model, with patches, some time back. It hasn't been adopted, but I've seen at least one attempt to revive it. You're right that there isn't an established model. The model proposed for Smack wasn't adopted either. My point is that models have been developed and refinements and/or alternatives are likely to be suggested.
From a SELinux perspective, if we are going to control access to a
namespace beyond simple creation, we would need to assign the namespace a label (inherited from the creating process). Although that would need some discussion among the SELinux folks as this would mean treating a userns as a proper system entity from a policy perspective which is ... interesting.
That, or it could replace the various independent efforts with a single, unified security module namespace effort.
We've talked about this before and I just don't see how that could ever work, the LSM implementations are just too different to do namespacing at the LSM layer.
It's possible that fresh eyes might see options that those who have been staring at the current state and historical proposals may have missed.
If a LSM is going to namespace themselves, they need the ability to define what that means without having to worry about what other LSMs want to do.
Possibly. On the other hand, if someone came up with a rational scheme for general xattr namespacing I don't see that anyone would pass it up.
On Wed, Jul 20, 2022 at 5:42 PM Casey Schaufler casey@schaufler-ca.com wrote:
On 7/19/2022 6:32 PM, Paul Moore wrote:
On Fri, Jul 8, 2022 at 12:11 PM Casey Schaufler casey@schaufler-ca.com wrote:
On 7/8/2022 7:01 AM, Frederick Lawler wrote:
On 7/8/22 7:10 AM, Christian Göttsche wrote:
,On Fri, 8 Jul 2022 at 00:32, Frederick Lawler fred@cloudflare.com wrote:
...
III.
Maybe even attach a security context to namespaces so they can be further governed?
That would likely add confusion to the existing security module namespace efforts. SELinux, Smack and AppArmor have all developed namespace models.
I'm not sure I fully understand what Casey is saying here as SELinux does not yet have an established namespace model to the best of my understanding, but perhaps we are talking about different concepts for the word "namespace"?
Stephen Smalley proposed a SELinux namespace model, with patches, some time back. It hasn't been adopted, but I've seen at least one attempt to revive it. You're right that there isn't an established model.
If it isn't in the mainline kernel, it isn't an established namespace model.
I ported Stephen's initial namespace patches to new kernels for quite some time, look at the working-selinuxns branch in the main SELinux repository, but that doesn't mean they are ready for upstreaming. Aside from some pretty critical implementation holes, there is the much larger conceptual issue of how to deal with persistent filesystem objects. We've discussed that quite a bit among the SELinux developers but have yet to arrive at a good-enough solution. I have some thoughts on how we might be able to make forward progress on that, but it's wildly off-topic for this patchset discussion. I mostly wanted to make sure I was understanding what you were referencing when you talked about a "SELinux namespace model", and it is what I suspected ... which I believe is unrelated to the patches being discussed here.
That, or it could replace the various independent efforts with a single, unified security module namespace effort.
We've talked about this before and I just don't see how that could ever work, the LSM implementations are just too different to do namespacing at the LSM layer.
It's possible that fresh eyes might see options that those who have been staring at the current state and historical proposals may have missed.
That's always a possibility, and I'm definitely open to a clever approach that would resolve all the current issues and not paint us into a corner in the future, but I haven't seen anything close (or any serious effort for that matter).
... and this still remains way off-topic for a discussion around adding a hook to allow LSMs to enforce access controls on user namespace creation.
If a LSM is going to namespace themselves, they need the ability to define what that means without having to worry about what other LSMs want to do.
Possibly. On the other hand, if someone came up with a rational scheme for general xattr namespacing I don't see that anyone would pass it up.
Oh geez ...
Namespacing xattrs is not the same thing as namespacing LSMs. LSMs may make use of xattrs, and namespacing xattrs may make it easier to namespace a given LSM, but I'm not aware of an in-tree LSM that would be magically namespaced if xattrs were namespaced.
This patchset has nothing to do with xattrs, it deals with adding a LSM hook to implement LSM-based access controls for user namespace creation.
linux-kselftest-mirror@lists.linaro.org