diff --git a/kernel/fork.c b/kernel/fork.c index f0e2e131a9a5..7b611da9a27a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -127,6 +127,12 @@ #include +#ifdef CONFIG_USER_NS +static int unprivileged_userns_clone = 1; +#else +#define unprivileged_userns_clone 1 +#endif + /* * Minimum number of threads to boot the kernel */ @@ -2093,6 +2099,11 @@ __latent_entropy struct task_struct *copy_process( return ERR_PTR(-EPERM); } + if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { + if (!capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + } + /* * Force any signals received before this point to be delivered * before the fork happens. Collect up signals sent to multiple @@ -3163,6 +3174,10 @@ static int check_unshare_flags(unsigned long unshare_flags) if (!current_is_single_threaded()) return -EINVAL; } + if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + } return 0; } @@ -3398,6 +3413,15 @@ static const struct ctl_table fork_sysctl_table[] = { .mode = 0644, .proc_handler = sysctl_max_threads, }, +#ifdef CONFIG_USER_NS + { + .procname = "unprivileged_userns_clone", + .data = &unprivileged_userns_clone, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif }; static int __init init_fork_sysctl(void)