forked from mirrors/linux
		
	netns: Add a limit on the number of net namespaces
Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
		
							parent
							
								
									d08311dd6f
								
							
						
					
					
						commit
						703286608a
					
				
					 4 changed files with 24 additions and 1 deletions
				
			
		|  | @ -29,6 +29,7 @@ enum ucount_type { | ||||||
| 	UCOUNT_PID_NAMESPACES, | 	UCOUNT_PID_NAMESPACES, | ||||||
| 	UCOUNT_UTS_NAMESPACES, | 	UCOUNT_UTS_NAMESPACES, | ||||||
| 	UCOUNT_IPC_NAMESPACES, | 	UCOUNT_IPC_NAMESPACES, | ||||||
|  | 	UCOUNT_NET_NAMESPACES, | ||||||
| 	UCOUNT_CGROUP_NAMESPACES, | 	UCOUNT_CGROUP_NAMESPACES, | ||||||
| 	UCOUNT_COUNTS, | 	UCOUNT_COUNTS, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -60,6 +60,7 @@ struct net { | ||||||
| 	struct list_head	exit_list;	/* Use only net_mutex */ | 	struct list_head	exit_list;	/* Use only net_mutex */ | ||||||
| 
 | 
 | ||||||
| 	struct user_namespace   *user_ns;	/* Owning user namespace */ | 	struct user_namespace   *user_ns;	/* Owning user namespace */ | ||||||
|  | 	struct ucounts		*ucounts; | ||||||
| 	spinlock_t		nsid_lock; | 	spinlock_t		nsid_lock; | ||||||
| 	struct idr		netns_ids; | 	struct idr		netns_ids; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -71,6 +71,7 @@ static struct ctl_table user_table[] = { | ||||||
| 	UCOUNT_ENTRY("max_pid_namespaces"), | 	UCOUNT_ENTRY("max_pid_namespaces"), | ||||||
| 	UCOUNT_ENTRY("max_uts_namespaces"), | 	UCOUNT_ENTRY("max_uts_namespaces"), | ||||||
| 	UCOUNT_ENTRY("max_ipc_namespaces"), | 	UCOUNT_ENTRY("max_ipc_namespaces"), | ||||||
|  | 	UCOUNT_ENTRY("max_net_namespaces"), | ||||||
| 	UCOUNT_ENTRY("max_cgroup_namespaces"), | 	UCOUNT_ENTRY("max_cgroup_namespaces"), | ||||||
| 	{ } | 	{ } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -266,6 +266,16 @@ struct net *get_net_ns_by_id(struct net *net, int id) | ||||||
| 	return peer; | 	return peer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct ucounts *inc_net_namespaces(struct user_namespace *ns) | ||||||
|  | { | ||||||
|  | 	return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void dec_net_namespaces(struct ucounts *ucounts) | ||||||
|  | { | ||||||
|  | 	dec_ucount(ucounts, UCOUNT_NET_NAMESPACES); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * setup_net runs the initializers for the network namespace object. |  * setup_net runs the initializers for the network namespace object. | ||||||
|  */ |  */ | ||||||
|  | @ -351,19 +361,27 @@ void net_drop_ns(void *p) | ||||||
| struct net *copy_net_ns(unsigned long flags, | struct net *copy_net_ns(unsigned long flags, | ||||||
| 			struct user_namespace *user_ns, struct net *old_net) | 			struct user_namespace *user_ns, struct net *old_net) | ||||||
| { | { | ||||||
|  | 	struct ucounts *ucounts; | ||||||
| 	struct net *net; | 	struct net *net; | ||||||
| 	int rv; | 	int rv; | ||||||
| 
 | 
 | ||||||
| 	if (!(flags & CLONE_NEWNET)) | 	if (!(flags & CLONE_NEWNET)) | ||||||
| 		return get_net(old_net); | 		return get_net(old_net); | ||||||
| 
 | 
 | ||||||
|  | 	ucounts = inc_net_namespaces(user_ns); | ||||||
|  | 	if (!ucounts) | ||||||
|  | 		return ERR_PTR(-ENFILE); | ||||||
|  | 
 | ||||||
| 	net = net_alloc(); | 	net = net_alloc(); | ||||||
| 	if (!net) | 	if (!net) { | ||||||
|  | 		dec_net_namespaces(ucounts); | ||||||
| 		return ERR_PTR(-ENOMEM); | 		return ERR_PTR(-ENOMEM); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	get_user_ns(user_ns); | 	get_user_ns(user_ns); | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&net_mutex); | 	mutex_lock(&net_mutex); | ||||||
|  | 	net->ucounts = ucounts; | ||||||
| 	rv = setup_net(net, user_ns); | 	rv = setup_net(net, user_ns); | ||||||
| 	if (rv == 0) { | 	if (rv == 0) { | ||||||
| 		rtnl_lock(); | 		rtnl_lock(); | ||||||
|  | @ -372,6 +390,7 @@ struct net *copy_net_ns(unsigned long flags, | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&net_mutex); | 	mutex_unlock(&net_mutex); | ||||||
| 	if (rv < 0) { | 	if (rv < 0) { | ||||||
|  | 		dec_net_namespaces(ucounts); | ||||||
| 		put_user_ns(user_ns); | 		put_user_ns(user_ns); | ||||||
| 		net_drop_ns(net); | 		net_drop_ns(net); | ||||||
| 		return ERR_PTR(rv); | 		return ERR_PTR(rv); | ||||||
|  | @ -444,6 +463,7 @@ static void cleanup_net(struct work_struct *work) | ||||||
| 	/* Finally it is safe to free my network namespace structure */ | 	/* Finally it is safe to free my network namespace structure */ | ||||||
| 	list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { | 	list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { | ||||||
| 		list_del_init(&net->exit_list); | 		list_del_init(&net->exit_list); | ||||||
|  | 		dec_net_namespaces(net->ucounts); | ||||||
| 		put_user_ns(net->user_ns); | 		put_user_ns(net->user_ns); | ||||||
| 		net_drop_ns(net); | 		net_drop_ns(net); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric W. Biederman
						Eric W. Biederman