From 7170d7853fa363999a80733111e78d8f8b40825d Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Tue, 5 Jan 2016 20:12:21 +0000 Subject: [PATCH] UBUNTU: SAUCE: add a sysctl to disable unprivileged user namespace unsharing It is turned on by default, but can be turned off if admins prefer or, more importantly, if a security vulnerability is found. The intent is to use this as mitigation so long as Ubuntu is on the cutting edge of enablement for things like unprivileged filesystem mounting. (This patch is tweaked from the one currently still in Debian sid, which in turn came from the patch we had in saucy) Signed-off-by: Serge Hallyn [bwh: Remove unneeded binary sysctl bits] [ saf: move extern unprivileged_userns_clone declaration to include/linux/user_namespace.h to conform with 2374c09b1c8a "sysctl: remove all extern declaration from sysctl.c" ] Signed-off-by: Tim Gardner [ arighi: adjust context for v6.7 ] Signed-off-by: Andrea Righi --- include/linux/user_namespace.h | 2 ++ kernel/fork.c | 15 +++++++++++++++ kernel/sysctl.c | 10 ++++++++++ kernel/user_namespace.c | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 6030a8235617..eeb7cd94bca0 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -187,6 +187,8 @@ extern bool in_userns(const struct user_namespace *ancestor, const struct user_namespace *child); extern bool current_in_userns(const struct user_namespace *target_ns); struct ns_common *ns_get_owner(struct ns_common *ns); + +extern int unprivileged_userns_clone; #else static inline struct user_namespace *get_user_ns(struct user_namespace *ns) diff --git a/kernel/fork.c b/kernel/fork.c index 0d944e92a43f..172fc8c09973 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -112,6 +112,11 @@ #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_USER_NS +extern int unprivileged_userns_clone; +#else +#define unprivileged_userns_clone 0 +#endif /* * Minimum number of threads to boot the kernel @@ -2260,6 +2265,10 @@ __latent_entropy struct task_struct *copy_process( if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) return ERR_PTR(-EINVAL); + if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) + if (!capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. @@ -3406,6 +3415,12 @@ int ksys_unshare(unsigned long unshare_flags) if (unshare_flags & CLONE_NEWNS) unshare_flags |= CLONE_FS; + if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { + err = -EPERM; + if (!capable(CAP_SYS_ADMIN)) + goto bad_unshare_out; + } + err = check_unshare_flags(unshare_flags); if (err) goto bad_unshare_out; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 157f7ce2942d..9d198d7f482b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "../lib/kstrtox.h" @@ -1766,6 +1767,15 @@ static struct ctl_table kern_table[] = { .proc_handler = sysrq_sysctl_handler, }, #endif +#ifdef CONFIG_USER_NS + { + .procname = "unprivileged_userns_clone", + .data = &unprivileged_userns_clone, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif #ifdef CONFIG_PROC_SYSCTL { .procname = "cad_pid", diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index ce4d99df5f0e..eb7406b5d4d0 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -22,6 +22,12 @@ #include #include +/* + * sysctl determining whether unprivileged users may unshare a new + * userns. Allowed by default + */ +int unprivileged_userns_clone = 1; + static struct kmem_cache *user_ns_cachep __ro_after_init; static DEFINE_MUTEX(userns_state_mutex);