diff options
Diffstat (limited to 'kernel/nsproxy.c')
| -rw-r--r-- | kernel/nsproxy.c | 41 | 
1 files changed, 34 insertions, 7 deletions
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index c815f58e6bc0..ed9882108cd2 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -18,6 +18,7 @@  #include <linux/pid_namespace.h>  #include <net/net_namespace.h>  #include <linux/ipc_namespace.h> +#include <linux/time_namespace.h>  #include <linux/proc_ns.h>  #include <linux/file.h>  #include <linux/syscalls.h> @@ -40,6 +41,10 @@ struct nsproxy init_nsproxy = {  #ifdef CONFIG_CGROUPS  	.cgroup_ns		= &init_cgroup_ns,  #endif +#ifdef CONFIG_TIME_NS +	.time_ns		= &init_time_ns, +	.time_ns_for_children	= &init_time_ns, +#endif  };  static inline struct nsproxy *create_nsproxy(void) @@ -106,8 +111,18 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,  		goto out_net;  	} +	new_nsp->time_ns_for_children = copy_time_ns(flags, user_ns, +					tsk->nsproxy->time_ns_for_children); +	if (IS_ERR(new_nsp->time_ns_for_children)) { +		err = PTR_ERR(new_nsp->time_ns_for_children); +		goto out_time; +	} +	new_nsp->time_ns = get_time_ns(tsk->nsproxy->time_ns); +  	return new_nsp; +out_time: +	put_net(new_nsp->net_ns);  out_net:  	put_cgroup_ns(new_nsp->cgroup_ns);  out_cgroup: @@ -136,15 +151,16 @@ 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 ret;  	if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |  			      CLONE_NEWPID | CLONE_NEWNET | -			      CLONE_NEWCGROUP)))) { -		get_nsproxy(old_ns); -		return 0; -	} - -	if (!ns_capable(user_ns, CAP_SYS_ADMIN)) +			      CLONE_NEWCGROUP | CLONE_NEWTIME)))) { +		if (likely(old_ns->time_ns_for_children == old_ns->time_ns)) { +			get_nsproxy(old_ns); +			return 0; +		} +	} else if (!ns_capable(user_ns, CAP_SYS_ADMIN))  		return -EPERM;  	/* @@ -162,6 +178,12 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)  	if (IS_ERR(new_ns))  		return  PTR_ERR(new_ns); +	ret = timens_on_fork(new_ns, tsk); +	if (ret) { +		free_nsproxy(new_ns); +		return ret; +	} +  	tsk->nsproxy = new_ns;  	return 0;  } @@ -176,6 +198,10 @@ void free_nsproxy(struct nsproxy *ns)  		put_ipc_ns(ns->ipc_ns);  	if (ns->pid_ns_for_children)  		put_pid_ns(ns->pid_ns_for_children); +	if (ns->time_ns) +		put_time_ns(ns->time_ns); +	if (ns->time_ns_for_children) +		put_time_ns(ns->time_ns_for_children);  	put_cgroup_ns(ns->cgroup_ns);  	put_net(ns->net_ns);  	kmem_cache_free(nsproxy_cachep, ns); @@ -192,7 +218,8 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,  	int err = 0;  	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | -			       CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP))) +			       CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP | +			       CLONE_NEWTIME)))  		return 0;  	user_ns = new_cred ? new_cred->user_ns : current_user_ns();  |