diff options
Diffstat (limited to 'kernel/fork.c')
| -rw-r--r-- | kernel/fork.c | 25 | 
1 files changed, 22 insertions, 3 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 8c29abb1901..38e53b87402 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1687,7 +1687,7 @@ static int check_unshare_flags(unsigned long unshare_flags)  	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|  				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|  				CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET| -				CLONE_NEWPID)) +				CLONE_NEWUSER|CLONE_NEWPID))  		return -EINVAL;  	/*  	 * Not implemented, but pretend it works if there is nothing to @@ -1754,11 +1754,17 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)  {  	struct fs_struct *fs, *new_fs = NULL;  	struct files_struct *fd, *new_fd = NULL; +	struct cred *new_cred = NULL;  	struct nsproxy *new_nsproxy = NULL;  	int do_sysvsem = 0;  	int err;  	/* +	 * If unsharing a user namespace must also unshare the thread. +	 */ +	if (unshare_flags & CLONE_NEWUSER) +		unshare_flags |= CLONE_THREAD; +	/*  	 * If unsharing a pid namespace must also unshare the thread.  	 */  	if (unshare_flags & CLONE_NEWPID) @@ -1795,11 +1801,15 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)  	err = unshare_fd(unshare_flags, &new_fd);  	if (err)  		goto bad_unshare_cleanup_fs; -	err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, new_fs); +	err = unshare_userns(unshare_flags, &new_cred);  	if (err)  		goto bad_unshare_cleanup_fd; +	err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, +					 new_cred, new_fs); +	if (err) +		goto bad_unshare_cleanup_cred; -	if (new_fs || new_fd || do_sysvsem || new_nsproxy) { +	if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {  		if (do_sysvsem) {  			/*  			 * CLONE_SYSVSEM is equivalent to sys_exit(). @@ -1832,11 +1842,20 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)  		}  		task_unlock(current); + +		if (new_cred) { +			/* Install the new user namespace */ +			commit_creds(new_cred); +			new_cred = NULL; +		}  	}  	if (new_nsproxy)  		put_nsproxy(new_nsproxy); +bad_unshare_cleanup_cred: +	if (new_cred) +		put_cred(new_cred);  bad_unshare_cleanup_fd:  	if (new_fd)  		put_files_struct(new_fd);  |