diff options
Diffstat (limited to 'kernel/nsproxy.c')
| -rw-r--r-- | kernel/nsproxy.c | 36 | 
1 files changed, 19 insertions, 17 deletions
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 7e1c3de1ce4..78e2ecb2016 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -57,7 +57,8 @@ static inline struct nsproxy *create_nsproxy(void)   * leave it to the caller to do proper locking and attach it to task.   */  static struct nsproxy *create_new_namespaces(unsigned long flags, -			struct task_struct *tsk, struct fs_struct *new_fs) +	struct task_struct *tsk, struct user_namespace *user_ns, +	struct fs_struct *new_fs)  {  	struct nsproxy *new_nsp;  	int err; @@ -66,31 +67,31 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,  	if (!new_nsp)  		return ERR_PTR(-ENOMEM); -	new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs); +	new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);  	if (IS_ERR(new_nsp->mnt_ns)) {  		err = PTR_ERR(new_nsp->mnt_ns);  		goto out_ns;  	} -	new_nsp->uts_ns = copy_utsname(flags, tsk); +	new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);  	if (IS_ERR(new_nsp->uts_ns)) {  		err = PTR_ERR(new_nsp->uts_ns);  		goto out_uts;  	} -	new_nsp->ipc_ns = copy_ipcs(flags, tsk); +	new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);  	if (IS_ERR(new_nsp->ipc_ns)) {  		err = PTR_ERR(new_nsp->ipc_ns);  		goto out_ipc;  	} -	new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); +	new_nsp->pid_ns = copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns);  	if (IS_ERR(new_nsp->pid_ns)) {  		err = PTR_ERR(new_nsp->pid_ns);  		goto out_pid;  	} -	new_nsp->net_ns = copy_net_ns(flags, task_cred_xxx(tsk, user_ns), tsk->nsproxy->net_ns); +	new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);  	if (IS_ERR(new_nsp->net_ns)) {  		err = PTR_ERR(new_nsp->net_ns);  		goto out_net; @@ -122,6 +123,7 @@ out_ns:  int copy_namespaces(unsigned long flags, struct task_struct *tsk)  {  	struct nsproxy *old_ns = tsk->nsproxy; +	struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);  	struct nsproxy *new_ns;  	int err = 0; @@ -134,7 +136,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)  				CLONE_NEWPID | CLONE_NEWNET)))  		return 0; -	if (!capable(CAP_SYS_ADMIN)) { +	if (!ns_capable(user_ns, CAP_SYS_ADMIN)) {  		err = -EPERM;  		goto out;  	} @@ -151,7 +153,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)  		goto out;  	} -	new_ns = create_new_namespaces(flags, tsk, tsk->fs); +	new_ns = create_new_namespaces(flags, tsk, +				       task_cred_xxx(tsk, user_ns), tsk->fs);  	if (IS_ERR(new_ns)) {  		err = PTR_ERR(new_ns);  		goto out; @@ -183,19 +186,21 @@ void free_nsproxy(struct nsproxy *ns)   * On success, returns the new nsproxy.   */  int unshare_nsproxy_namespaces(unsigned long unshare_flags, -		struct nsproxy **new_nsp, struct fs_struct *new_fs) +	struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)  { +	struct user_namespace *user_ns;  	int err = 0;  	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | -			       CLONE_NEWNET))) +			       CLONE_NEWNET | CLONE_NEWPID)))  		return 0; -	if (!capable(CAP_SYS_ADMIN)) +	user_ns = new_cred ? new_cred->user_ns : current_user_ns(); +	if (!ns_capable(user_ns, CAP_SYS_ADMIN))  		return -EPERM; -	*new_nsp = create_new_namespaces(unshare_flags, current, -				new_fs ? new_fs : current->fs); +	*new_nsp = create_new_namespaces(unshare_flags, current, user_ns, +					 new_fs ? new_fs : current->fs);  	if (IS_ERR(*new_nsp)) {  		err = PTR_ERR(*new_nsp);  		goto out; @@ -241,9 +246,6 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)  	struct file *file;  	int err; -	if (!capable(CAP_SYS_ADMIN)) -		return -EPERM; -  	file = proc_ns_fget(fd);  	if (IS_ERR(file))  		return PTR_ERR(file); @@ -254,7 +256,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)  	if (nstype && (ops->type != nstype))  		goto out; -	new_nsproxy = create_new_namespaces(0, tsk, tsk->fs); +	new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);  	if (IS_ERR(new_nsproxy)) {  		err = PTR_ERR(new_nsproxy);  		goto out;  |