|
@@ -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,10 +1754,16 @@ 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.
|
|
|
*/
|
|
@@ -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);
|