mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	pidns: Add a limit on the number of pid namespaces
Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
		
							parent
							
								
									25f9c0817c
								
							
						
					
					
						commit
						f333c700c6
					
				
					 4 changed files with 24 additions and 4 deletions
				
			
		|  | @ -40,6 +40,7 @@ struct pid_namespace { | ||||||
| 	struct fs_pin *bacct; | 	struct fs_pin *bacct; | ||||||
| #endif | #endif | ||||||
| 	struct user_namespace *user_ns; | 	struct user_namespace *user_ns; | ||||||
|  | 	struct ucounts *ucounts; | ||||||
| 	struct work_struct proc_work; | 	struct work_struct proc_work; | ||||||
| 	kgid_t pid_gid; | 	kgid_t pid_gid; | ||||||
| 	int hide_pid; | 	int hide_pid; | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ struct ucounts; | ||||||
| 
 | 
 | ||||||
| enum ucount_type { | enum ucount_type { | ||||||
| 	UCOUNT_USER_NAMESPACES, | 	UCOUNT_USER_NAMESPACES, | ||||||
|  | 	UCOUNT_PID_NAMESPACES, | ||||||
| 	UCOUNT_COUNTS, | 	UCOUNT_COUNTS, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -79,23 +79,36 @@ static void proc_cleanup_work(struct work_struct *work) | ||||||
| /* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */ | /* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */ | ||||||
| #define MAX_PID_NS_LEVEL 32 | #define MAX_PID_NS_LEVEL 32 | ||||||
| 
 | 
 | ||||||
|  | static struct ucounts *inc_pid_namespaces(struct user_namespace *ns) | ||||||
|  | { | ||||||
|  | 	return inc_ucount(ns, current_euid(), UCOUNT_PID_NAMESPACES); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void dec_pid_namespaces(struct ucounts *ucounts) | ||||||
|  | { | ||||||
|  | 	dec_ucount(ucounts, UCOUNT_PID_NAMESPACES); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns, | static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns, | ||||||
| 	struct pid_namespace *parent_pid_ns) | 	struct pid_namespace *parent_pid_ns) | ||||||
| { | { | ||||||
| 	struct pid_namespace *ns; | 	struct pid_namespace *ns; | ||||||
| 	unsigned int level = parent_pid_ns->level + 1; | 	unsigned int level = parent_pid_ns->level + 1; | ||||||
|  | 	struct ucounts *ucounts; | ||||||
| 	int i; | 	int i; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	if (level > MAX_PID_NS_LEVEL) { | 	err = -EINVAL; | ||||||
| 		err = -EINVAL; | 	if (level > MAX_PID_NS_LEVEL) | ||||||
|  | 		goto out; | ||||||
|  | 	ucounts = inc_pid_namespaces(user_ns); | ||||||
|  | 	if (!ucounts) | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	err = -ENOMEM; | 	err = -ENOMEM; | ||||||
| 	ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL); | 	ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL); | ||||||
| 	if (ns == NULL) | 	if (ns == NULL) | ||||||
| 		goto out; | 		goto out_dec; | ||||||
| 
 | 
 | ||||||
| 	ns->pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); | 	ns->pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||||||
| 	if (!ns->pidmap[0].page) | 	if (!ns->pidmap[0].page) | ||||||
|  | @ -114,6 +127,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns | ||||||
| 	ns->level = level; | 	ns->level = level; | ||||||
| 	ns->parent = get_pid_ns(parent_pid_ns); | 	ns->parent = get_pid_ns(parent_pid_ns); | ||||||
| 	ns->user_ns = get_user_ns(user_ns); | 	ns->user_ns = get_user_ns(user_ns); | ||||||
|  | 	ns->ucounts = ucounts; | ||||||
| 	ns->nr_hashed = PIDNS_HASH_ADDING; | 	ns->nr_hashed = PIDNS_HASH_ADDING; | ||||||
| 	INIT_WORK(&ns->proc_work, proc_cleanup_work); | 	INIT_WORK(&ns->proc_work, proc_cleanup_work); | ||||||
| 
 | 
 | ||||||
|  | @ -129,6 +143,8 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns | ||||||
| 	kfree(ns->pidmap[0].page); | 	kfree(ns->pidmap[0].page); | ||||||
| out_free: | out_free: | ||||||
| 	kmem_cache_free(pid_ns_cachep, ns); | 	kmem_cache_free(pid_ns_cachep, ns); | ||||||
|  | out_dec: | ||||||
|  | 	dec_pid_namespaces(ucounts); | ||||||
| out: | out: | ||||||
| 	return ERR_PTR(err); | 	return ERR_PTR(err); | ||||||
| } | } | ||||||
|  | @ -146,6 +162,7 @@ static void destroy_pid_namespace(struct pid_namespace *ns) | ||||||
| 	ns_free_inum(&ns->ns); | 	ns_free_inum(&ns->ns); | ||||||
| 	for (i = 0; i < PIDMAP_ENTRIES; i++) | 	for (i = 0; i < PIDMAP_ENTRIES; i++) | ||||||
| 		kfree(ns->pidmap[i].page); | 		kfree(ns->pidmap[i].page); | ||||||
|  | 	dec_pid_namespaces(ns->ucounts); | ||||||
| 	put_user_ns(ns->user_ns); | 	put_user_ns(ns->user_ns); | ||||||
| 	call_rcu(&ns->rcu, delayed_free_pidns); | 	call_rcu(&ns->rcu, delayed_free_pidns); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -68,6 +68,7 @@ static int int_max = INT_MAX; | ||||||
| 	} | 	} | ||||||
| static struct ctl_table user_table[] = { | static struct ctl_table user_table[] = { | ||||||
| 	UCOUNT_ENTRY("max_user_namespaces"), | 	UCOUNT_ENTRY("max_user_namespaces"), | ||||||
|  | 	UCOUNT_ENTRY("max_pid_namespaces"), | ||||||
| 	{ } | 	{ } | ||||||
| }; | }; | ||||||
| #endif /* CONFIG_SYSCTL */ | #endif /* CONFIG_SYSCTL */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric W. Biederman
						Eric W. Biederman