add sysctl to disallow unprivileged CLONE_NEWUSER by default
authorSerge Hallyn <serge.hallyn@canonical.com>
Fri, 31 May 2013 18:12:12 +0000 (19:12 +0100)
committerSalvatore Bonaccorso <carnil@debian.org>
Sat, 20 Dec 2025 09:15:48 +0000 (10:15 +0100)
Origin: http://kernel.ubuntu.com/git?p=serge%2Fubuntu-saucy.git;a=commit;h=5c847404dcb2e3195ad0057877e1422ae90892b8

add sysctl to disallow unprivileged CLONE_NEWUSER by default

This is a short-term patch.  Unprivileged use of CLONE_NEWUSER
is certainly an intended feature of user namespaces.  However
for at least saucy we want to make sure that, if any security
issues are found, we have a fail-safe.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
[bwh: Remove unneeded binary sysctl bits]
[bwh: Keep this sysctl, but change the default to enabled]

Gbp-Pq: Topic debian
Gbp-Pq: Name add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by-default.patch

kernel/fork.c
kernel/sysctl.c
kernel/user_namespace.c

index bb86c57cc0d987587c102533fcd347b00a1bf769..324e2aee27cb4f6bfe5de41351294dafef41da52 100644 (file)
 
 #include <kunit/visibility.h>
 
+#ifdef CONFIG_USER_NS
+extern int unprivileged_userns_clone;
+#else
+#define unprivileged_userns_clone 0
+#endif
+
 /*
  * Minimum number of threads to boot the kernel
  */
@@ -1938,6 +1944,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.
@@ -3105,6 +3115,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;
index cb6196e3fa993daa21704d190baf366084e014f7..c955e49a4b7a304d3ea3dd870c7ad42f378b9b14 100644 (file)
@@ -36,6 +36,10 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals);
 static const int ngroups_max = NGROUPS_MAX;
 static const int cap_last_cap = CAP_LAST_CAP;
 
+#ifdef CONFIG_USER_NS
+extern int unprivileged_userns_clone;
+#endif
+
 #ifdef CONFIG_PROC_SYSCTL
 
 /**
@@ -1455,6 +1459,15 @@ int proc_do_static_key(const struct ctl_table *table, int write,
 }
 
 static const struct ctl_table sysctl_subsys_table[] = {
+#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       = "sysctl_writes_strict",
index 682f40d5632d44b983f8b2322fdfd1f7d1d47d2c..bf265ad528f9ea3de8f31b770c07319814163028 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/bsearch.h>
 #include <linux/sort.h>
 
+/* sysctl */
+int unprivileged_userns_clone = 1;
+
 static struct kmem_cache *user_ns_cachep __ro_after_init;
 static DEFINE_MUTEX(userns_state_mutex);