xref: /linux-6.15/kernel/user_namespace.c (revision 784ed435)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2acce292cSCedric Le Goater 
39984de1aSPaul Gortmaker #include <linux/export.h>
4acce292cSCedric Le Goater #include <linux/nsproxy.h>
51aeb272cSRobert P. J. Day #include <linux/slab.h>
63f07c014SIngo Molnar #include <linux/sched/signal.h>
7acce292cSCedric Le Goater #include <linux/user_namespace.h>
80bb80f24SDavid Howells #include <linux/proc_ns.h>
95c1469deSEric W. Biederman #include <linux/highuid.h>
1018b6e041SSerge Hallyn #include <linux/cred.h>
11973c5914SEric W. Biederman #include <linux/securebits.h>
127cd4c5c2SFrederick Lawler #include <linux/security.h>
1322d917d8SEric W. Biederman #include <linux/keyctl.h>
1422d917d8SEric W. Biederman #include <linux/key-type.h>
1522d917d8SEric W. Biederman #include <keys/user-type.h>
1622d917d8SEric W. Biederman #include <linux/seq_file.h>
1722d917d8SEric W. Biederman #include <linux/fs.h>
1822d917d8SEric W. Biederman #include <linux/uaccess.h>
1922d917d8SEric W. Biederman #include <linux/ctype.h>
20f76d207aSEric W. Biederman #include <linux/projid.h>
21e66eded8SEric W. Biederman #include <linux/fs_struct.h>
226397fac4SChristian Brauner #include <linux/bsearch.h>
236397fac4SChristian Brauner #include <linux/sort.h>
24acce292cSCedric Le Goater 
2568279f9cSAlexey Dobriyan static struct kmem_cache *user_ns_cachep __ro_after_init;
26f0d62aecSEric W. Biederman static DEFINE_MUTEX(userns_state_mutex);
276164281aSPavel Emelyanov 
286708075fSEric W. Biederman static bool new_idmap_permitted(const struct file *file,
296708075fSEric W. Biederman 				struct user_namespace *ns, int cap_setid,
3022d917d8SEric W. Biederman 				struct uid_gid_map *map);
31b032132cSEric W. Biederman static void free_user_ns(struct work_struct *work);
3222d917d8SEric W. Biederman 
inc_user_namespaces(struct user_namespace * ns,kuid_t uid)3325f9c081SEric W. Biederman static struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid)
3425f9c081SEric W. Biederman {
3525f9c081SEric W. Biederman 	return inc_ucount(ns, uid, UCOUNT_USER_NAMESPACES);
3625f9c081SEric W. Biederman }
3725f9c081SEric W. Biederman 
dec_user_namespaces(struct ucounts * ucounts)3825f9c081SEric W. Biederman static void dec_user_namespaces(struct ucounts *ucounts)
3925f9c081SEric W. Biederman {
4025f9c081SEric W. Biederman 	return dec_ucount(ucounts, UCOUNT_USER_NAMESPACES);
4125f9c081SEric W. Biederman }
4225f9c081SEric W. Biederman 
set_cred_user_ns(struct cred * cred,struct user_namespace * user_ns)43cde1975bSEric W. Biederman static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
44cde1975bSEric W. Biederman {
45cde1975bSEric W. Biederman 	/* Start with the same capabilities as init but useless for doing
46cde1975bSEric W. Biederman 	 * anything as the capabilities are bound to the new user namespace.
47cde1975bSEric W. Biederman 	 */
48cde1975bSEric W. Biederman 	cred->securebits = SECUREBITS_DEFAULT;
49cde1975bSEric W. Biederman 	cred->cap_inheritable = CAP_EMPTY_SET;
50cde1975bSEric W. Biederman 	cred->cap_permitted = CAP_FULL_SET;
51cde1975bSEric W. Biederman 	cred->cap_effective = CAP_FULL_SET;
5258319057SAndy Lutomirski 	cred->cap_ambient = CAP_EMPTY_SET;
53cde1975bSEric W. Biederman 	cred->cap_bset = CAP_FULL_SET;
54cde1975bSEric W. Biederman #ifdef CONFIG_KEYS
55cde1975bSEric W. Biederman 	key_put(cred->request_key_auth);
56cde1975bSEric W. Biederman 	cred->request_key_auth = NULL;
57cde1975bSEric W. Biederman #endif
58cde1975bSEric W. Biederman 	/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
59cde1975bSEric W. Biederman 	cred->user_ns = user_ns;
60cde1975bSEric W. Biederman }
61cde1975bSEric W. Biederman 
enforced_nproc_rlimit(void)620ac983f5SEric W. Biederman static unsigned long enforced_nproc_rlimit(void)
630ac983f5SEric W. Biederman {
640ac983f5SEric W. Biederman 	unsigned long limit = RLIM_INFINITY;
650ac983f5SEric W. Biederman 
660ac983f5SEric W. Biederman 	/* Is RLIMIT_NPROC currently enforced? */
670ac983f5SEric W. Biederman 	if (!uid_eq(current_uid(), GLOBAL_ROOT_UID) ||
680ac983f5SEric W. Biederman 	    (current_user_ns() != &init_user_ns))
690ac983f5SEric W. Biederman 		limit = rlimit(RLIMIT_NPROC);
700ac983f5SEric W. Biederman 
710ac983f5SEric W. Biederman 	return limit;
720ac983f5SEric W. Biederman }
730ac983f5SEric W. Biederman 
7477ec739dSSerge E. Hallyn /*
7518b6e041SSerge Hallyn  * Create a new user namespace, deriving the creator from the user in the
7618b6e041SSerge Hallyn  * passed credentials, and replacing that user with the new root user for the
7718b6e041SSerge Hallyn  * new namespace.
7818b6e041SSerge Hallyn  *
7918b6e041SSerge Hallyn  * This is called by copy_creds(), which will finish setting the target task's
8018b6e041SSerge Hallyn  * credentials.
8177ec739dSSerge E. Hallyn  */
create_user_ns(struct cred * new)8218b6e041SSerge Hallyn int create_user_ns(struct cred *new)
8377ec739dSSerge E. Hallyn {
840093ccb6SEric W. Biederman 	struct user_namespace *ns, *parent_ns = new->user_ns;
85078de5f7SEric W. Biederman 	kuid_t owner = new->euid;
86078de5f7SEric W. Biederman 	kgid_t group = new->egid;
87f6b2db1aSEric W. Biederman 	struct ucounts *ucounts;
8825f9c081SEric W. Biederman 	int ret, i;
89783291e6SEric W. Biederman 
90df75e774SEric W. Biederman 	ret = -ENOSPC;
918742f229SOleg Nesterov 	if (parent_ns->level > 32)
92b376c3e1SEric W. Biederman 		goto fail;
93b376c3e1SEric W. Biederman 
94f6b2db1aSEric W. Biederman 	ucounts = inc_user_namespaces(parent_ns, owner);
95f6b2db1aSEric W. Biederman 	if (!ucounts)
96b376c3e1SEric W. Biederman 		goto fail;
978742f229SOleg Nesterov 
983151527eSEric W. Biederman 	/*
993151527eSEric W. Biederman 	 * Verify that we can not violate the policy of which files
1003151527eSEric W. Biederman 	 * may be accessed that is specified by the root directory,
101a12f4f85SXiaofeng Cao 	 * by verifying that the root directory is at the root of the
1023151527eSEric W. Biederman 	 * mount namespace which allows all files to be accessed.
1033151527eSEric W. Biederman 	 */
104b376c3e1SEric W. Biederman 	ret = -EPERM;
1053151527eSEric W. Biederman 	if (current_chrooted())
106b376c3e1SEric W. Biederman 		goto fail_dec;
1073151527eSEric W. Biederman 
108783291e6SEric W. Biederman 	/* The creator needs a mapping in the parent user namespace
109783291e6SEric W. Biederman 	 * or else we won't be able to reasonably tell userspace who
110783291e6SEric W. Biederman 	 * created a user_namespace.
111783291e6SEric W. Biederman 	 */
112b376c3e1SEric W. Biederman 	ret = -EPERM;
113783291e6SEric W. Biederman 	if (!kuid_has_mapping(parent_ns, owner) ||
114783291e6SEric W. Biederman 	    !kgid_has_mapping(parent_ns, group))
115b376c3e1SEric W. Biederman 		goto fail_dec;
11677ec739dSSerge E. Hallyn 
1177cd4c5c2SFrederick Lawler 	ret = security_create_user_ns(new);
1187cd4c5c2SFrederick Lawler 	if (ret < 0)
1197cd4c5c2SFrederick Lawler 		goto fail_dec;
1207cd4c5c2SFrederick Lawler 
121b376c3e1SEric W. Biederman 	ret = -ENOMEM;
12222d917d8SEric W. Biederman 	ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL);
12377ec739dSSerge E. Hallyn 	if (!ns)
124b376c3e1SEric W. Biederman 		goto fail_dec;
12577ec739dSSerge E. Hallyn 
126db2e718aSSerge E. Hallyn 	ns->parent_could_setfcap = cap_raised(new->cap_effective, CAP_SETFCAP);
1276344c433SAl Viro 	ret = ns_alloc_inum(&ns->ns);
128b376c3e1SEric W. Biederman 	if (ret)
129b376c3e1SEric W. Biederman 		goto fail_free;
13033c42940SAl Viro 	ns->ns.ops = &userns_operations;
13198f842e6SEric W. Biederman 
132265cbd62SKirill Tkhai 	refcount_set(&ns->ns.count, 1);
133cde1975bSEric W. Biederman 	/* Leave the new->user_ns reference with the new user namespace. */
134aeb3ae9dSEric W. Biederman 	ns->parent = parent_ns;
1358742f229SOleg Nesterov 	ns->level = parent_ns->level + 1;
136783291e6SEric W. Biederman 	ns->owner = owner;
137783291e6SEric W. Biederman 	ns->group = group;
138b032132cSEric W. Biederman 	INIT_WORK(&ns->work, free_user_ns);
139de399236SAlexey Gladkov 	for (i = 0; i < UCOUNT_COUNTS; i++) {
14025f9c081SEric W. Biederman 		ns->ucount_max[i] = INT_MAX;
14125f9c081SEric W. Biederman 	}
142de399236SAlexey Gladkov 	set_userns_rlimit_max(ns, UCOUNT_RLIMIT_NPROC, enforced_nproc_rlimit());
143de399236SAlexey Gladkov 	set_userns_rlimit_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
144de399236SAlexey Gladkov 	set_userns_rlimit_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
145de399236SAlexey Gladkov 	set_userns_rlimit_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));
146f6b2db1aSEric W. Biederman 	ns->ucounts = ucounts;
14722d917d8SEric W. Biederman 
1489cc46516SEric W. Biederman 	/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
1499cc46516SEric W. Biederman 	mutex_lock(&userns_state_mutex);
1509cc46516SEric W. Biederman 	ns->flags = parent_ns->flags;
1519cc46516SEric W. Biederman 	mutex_unlock(&userns_state_mutex);
1529cc46516SEric W. Biederman 
153b206f281SDavid Howells #ifdef CONFIG_KEYS
154b206f281SDavid Howells 	INIT_LIST_HEAD(&ns->keyring_name_list);
1550f44e4d9SDavid Howells 	init_rwsem(&ns->keyring_sem);
156f36f8c75SDavid Howells #endif
157dbec2846SEric W. Biederman 	ret = -ENOMEM;
158dbec2846SEric W. Biederman 	if (!setup_userns_sysctls(ns))
159dbec2846SEric W. Biederman 		goto fail_keyring;
160dbec2846SEric W. Biederman 
161dbec2846SEric W. Biederman 	set_cred_user_ns(new, ns);
16218b6e041SSerge Hallyn 	return 0;
163dbec2846SEric W. Biederman fail_keyring:
164dbec2846SEric W. Biederman #ifdef CONFIG_PERSISTENT_KEYRINGS
165dbec2846SEric W. Biederman 	key_put(ns->persistent_keyring_register);
166dbec2846SEric W. Biederman #endif
167dbec2846SEric W. Biederman 	ns_free_inum(&ns->ns);
168b376c3e1SEric W. Biederman fail_free:
169dbec2846SEric W. Biederman 	kmem_cache_free(user_ns_cachep, ns);
170b376c3e1SEric W. Biederman fail_dec:
171f6b2db1aSEric W. Biederman 	dec_user_namespaces(ucounts);
172b376c3e1SEric W. Biederman fail:
173dbec2846SEric W. Biederman 	return ret;
174acce292cSCedric Le Goater }
175acce292cSCedric Le Goater 
unshare_userns(unsigned long unshare_flags,struct cred ** new_cred)176b2e0d987SEric W. Biederman int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
177b2e0d987SEric W. Biederman {
178b2e0d987SEric W. Biederman 	struct cred *cred;
1796160968cSOleg Nesterov 	int err = -ENOMEM;
180b2e0d987SEric W. Biederman 
181b2e0d987SEric W. Biederman 	if (!(unshare_flags & CLONE_NEWUSER))
182b2e0d987SEric W. Biederman 		return 0;
183b2e0d987SEric W. Biederman 
184b2e0d987SEric W. Biederman 	cred = prepare_creds();
1856160968cSOleg Nesterov 	if (cred) {
1866160968cSOleg Nesterov 		err = create_user_ns(cred);
1876160968cSOleg Nesterov 		if (err)
1886160968cSOleg Nesterov 			put_cred(cred);
1896160968cSOleg Nesterov 		else
190b2e0d987SEric W. Biederman 			*new_cred = cred;
1916160968cSOleg Nesterov 	}
1926160968cSOleg Nesterov 
1936160968cSOleg Nesterov 	return err;
194b2e0d987SEric W. Biederman }
195b2e0d987SEric W. Biederman 
free_user_ns(struct work_struct * work)196b032132cSEric W. Biederman static void free_user_ns(struct work_struct *work)
19751708366SDavid Howells {
198b032132cSEric W. Biederman 	struct user_namespace *parent, *ns =
199b032132cSEric W. Biederman 		container_of(work, struct user_namespace, work);
20051708366SDavid Howells 
201c61a2810SEric W. Biederman 	do {
202f6b2db1aSEric W. Biederman 		struct ucounts *ucounts = ns->ucounts;
203783291e6SEric W. Biederman 		parent = ns->parent;
2046397fac4SChristian Brauner 		if (ns->gid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) {
2056397fac4SChristian Brauner 			kfree(ns->gid_map.forward);
2066397fac4SChristian Brauner 			kfree(ns->gid_map.reverse);
2076397fac4SChristian Brauner 		}
2086397fac4SChristian Brauner 		if (ns->uid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) {
2096397fac4SChristian Brauner 			kfree(ns->uid_map.forward);
2106397fac4SChristian Brauner 			kfree(ns->uid_map.reverse);
2116397fac4SChristian Brauner 		}
2126397fac4SChristian Brauner 		if (ns->projid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) {
2136397fac4SChristian Brauner 			kfree(ns->projid_map.forward);
2146397fac4SChristian Brauner 			kfree(ns->projid_map.reverse);
2156397fac4SChristian Brauner 		}
21621ca59b3SChristian Brauner #if IS_ENABLED(CONFIG_BINFMT_MISC)
21721ca59b3SChristian Brauner 		kfree(ns->binfmt_misc);
21821ca59b3SChristian Brauner #endif
219dbec2846SEric W. Biederman 		retire_userns_sysctls(ns);
220b206f281SDavid Howells 		key_free_user_ns(ns);
2216344c433SAl Viro 		ns_free_inum(&ns->ns);
222783291e6SEric W. Biederman 		kmem_cache_free(user_ns_cachep, ns);
223f6b2db1aSEric W. Biederman 		dec_user_namespaces(ucounts);
224c61a2810SEric W. Biederman 		ns = parent;
225265cbd62SKirill Tkhai 	} while (refcount_dec_and_test(&parent->ns.count));
22651708366SDavid Howells }
227b032132cSEric W. Biederman 
__put_user_ns(struct user_namespace * ns)228b032132cSEric W. Biederman void __put_user_ns(struct user_namespace *ns)
229b032132cSEric W. Biederman {
230b032132cSEric W. Biederman 	schedule_work(&ns->work);
231b032132cSEric W. Biederman }
232b032132cSEric W. Biederman EXPORT_SYMBOL(__put_user_ns);
2335c1469deSEric W. Biederman 
234f73f6181SRandy Dunlap /*
235e227db4dSRandy Dunlap  * struct idmap_key - holds the information necessary to find an idmapping in a
2366397fac4SChristian Brauner  * sorted idmap array. It is passed to cmp_map_id() as first argument.
2376397fac4SChristian Brauner  */
2386397fac4SChristian Brauner struct idmap_key {
2396397fac4SChristian Brauner 	bool map_up; /* true  -> id from kid; false -> kid from id */
2406397fac4SChristian Brauner 	u32 id; /* id to find */
241*784ed435SChristian Brauner 	u32 count;
2426397fac4SChristian Brauner };
2436397fac4SChristian Brauner 
244f73f6181SRandy Dunlap /*
2456397fac4SChristian Brauner  * cmp_map_id - Function to be passed to bsearch() to find the requested
2466397fac4SChristian Brauner  * idmapping. Expects struct idmap_key to be passed via @k.
2476397fac4SChristian Brauner  */
cmp_map_id(const void * k,const void * e)2486397fac4SChristian Brauner static int cmp_map_id(const void *k, const void *e)
2495c1469deSEric W. Biederman {
2506397fac4SChristian Brauner 	u32 first, last, id2;
2516397fac4SChristian Brauner 	const struct idmap_key *key = k;
2526397fac4SChristian Brauner 	const struct uid_gid_extent *el = e;
2536397fac4SChristian Brauner 
2546397fac4SChristian Brauner 	id2 = key->id + key->count - 1;
2556397fac4SChristian Brauner 
2566397fac4SChristian Brauner 	/* handle map_id_{down,up}() */
2576397fac4SChristian Brauner 	if (key->map_up)
2586397fac4SChristian Brauner 		first = el->lower_first;
2596397fac4SChristian Brauner 	else
2606397fac4SChristian Brauner 		first = el->first;
2616397fac4SChristian Brauner 
2626397fac4SChristian Brauner 	last = first + el->count - 1;
2636397fac4SChristian Brauner 
2646397fac4SChristian Brauner 	if (key->id >= first && key->id <= last &&
2656397fac4SChristian Brauner 	    (id2 >= first && id2 <= last))
2666397fac4SChristian Brauner 		return 0;
2676397fac4SChristian Brauner 
2686397fac4SChristian Brauner 	if (key->id < first || id2 < first)
2696397fac4SChristian Brauner 		return -1;
2706397fac4SChristian Brauner 
2716397fac4SChristian Brauner 	return 1;
2726397fac4SChristian Brauner }
2736397fac4SChristian Brauner 
274f73f6181SRandy Dunlap /*
2756397fac4SChristian Brauner  * map_id_range_down_max - Find idmap via binary search in ordered idmap array.
2766397fac4SChristian Brauner  * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS.
2776397fac4SChristian Brauner  */
2783edf652fSEric W. Biederman static struct uid_gid_extent *
map_id_range_down_max(unsigned extents,struct uid_gid_map * map,u32 id,u32 count)2793edf652fSEric W. Biederman map_id_range_down_max(unsigned extents, struct uid_gid_map *map, u32 id, u32 count)
2806397fac4SChristian Brauner {
2816397fac4SChristian Brauner 	struct idmap_key key;
2826397fac4SChristian Brauner 
2836397fac4SChristian Brauner 	key.map_up = false;
2846397fac4SChristian Brauner 	key.count = count;
2856397fac4SChristian Brauner 	key.id = id;
2866397fac4SChristian Brauner 
2873edf652fSEric W. Biederman 	return bsearch(&key, map->forward, extents,
2883edf652fSEric W. Biederman 		       sizeof(struct uid_gid_extent), cmp_map_id);
2893edf652fSEric W. Biederman }
2903edf652fSEric W. Biederman 
291f73f6181SRandy Dunlap /*
2923edf652fSEric W. Biederman  * map_id_range_down_base - Find idmap via binary search in static extent array.
2933edf652fSEric W. Biederman  * Can only be called if number of mappings is equal or less than
2943edf652fSEric W. Biederman  * UID_GID_MAP_MAX_BASE_EXTENTS.
2953edf652fSEric W. Biederman  */
2963edf652fSEric W. Biederman static struct uid_gid_extent *
map_id_range_down_base(unsigned extents,struct uid_gid_map * map,u32 id,u32 count)2973edf652fSEric W. Biederman map_id_range_down_base(unsigned extents, struct uid_gid_map *map, u32 id, u32 count)
2983edf652fSEric W. Biederman {
2993edf652fSEric W. Biederman 	unsigned idx;
30022d917d8SEric W. Biederman 	u32 first, last, id2;
3015c1469deSEric W. Biederman 
30222d917d8SEric W. Biederman 	id2 = id + count - 1;
30322d917d8SEric W. Biederman 
30422d917d8SEric W. Biederman 	/* Find the matching extent */
30522d917d8SEric W. Biederman 	for (idx = 0; idx < extents; idx++) {
30622d917d8SEric W. Biederman 		first = map->extent[idx].first;
30722d917d8SEric W. Biederman 		last = first + map->extent[idx].count - 1;
30822d917d8SEric W. Biederman 		if (id >= first && id <= last &&
30922d917d8SEric W. Biederman 		    (id2 >= first && id2 <= last))
3103edf652fSEric W. Biederman 			return &map->extent[idx];
31122d917d8SEric W. Biederman 	}
3123edf652fSEric W. Biederman 	return NULL;
3133edf652fSEric W. Biederman }
3143edf652fSEric W. Biederman 
map_id_range_down(struct uid_gid_map * map,u32 id,u32 count)3153edf652fSEric W. Biederman static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
3163edf652fSEric W. Biederman {
3173edf652fSEric W. Biederman 	struct uid_gid_extent *extent;
3183edf652fSEric W. Biederman 	unsigned extents = map->nr_extents;
3196397fac4SChristian Brauner 	smp_rmb();
3206397fac4SChristian Brauner 
3213edf652fSEric W. Biederman 	if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
3223edf652fSEric W. Biederman 		extent = map_id_range_down_base(extents, map, id, count);
3233edf652fSEric W. Biederman 	else
3243edf652fSEric W. Biederman 		extent = map_id_range_down_max(extents, map, id, count);
3253edf652fSEric W. Biederman 
32622d917d8SEric W. Biederman 	/* Map the id or note failure */
3276397fac4SChristian Brauner 	if (extent)
3286397fac4SChristian Brauner 		id = (id - extent->first) + extent->lower_first;
32922d917d8SEric W. Biederman 	else
33022d917d8SEric W. Biederman 		id = (u32) -1;
33122d917d8SEric W. Biederman 
33222d917d8SEric W. Biederman 	return id;
33322d917d8SEric W. Biederman }
33422d917d8SEric W. Biederman 
map_id_down(struct uid_gid_map * map,u32 id)335783822e4SChristian Brauner u32 map_id_down(struct uid_gid_map *map, u32 id)
33622d917d8SEric W. Biederman {
337ece66133SEric W. Biederman 	return map_id_range_down(map, id, 1);
33822d917d8SEric W. Biederman }
33922d917d8SEric W. Biederman 
340f73f6181SRandy Dunlap /*
3416397fac4SChristian Brauner  * map_id_up_base - Find idmap via binary search in static extent array.
3426397fac4SChristian Brauner  * Can only be called if number of mappings is equal or less than
3436397fac4SChristian Brauner  * UID_GID_MAP_MAX_BASE_EXTENTS.
3446397fac4SChristian Brauner  */
3453edf652fSEric W. Biederman static struct uid_gid_extent *
map_id_range_up_base(unsigned extents,struct uid_gid_map * map,u32 id,u32 count)346*784ed435SChristian Brauner map_id_range_up_base(unsigned extents, struct uid_gid_map *map, u32 id, u32 count)
34722d917d8SEric W. Biederman {
3483edf652fSEric W. Biederman 	unsigned idx;
349*784ed435SChristian Brauner 	u32 first, last, id2;
350*784ed435SChristian Brauner 
351*784ed435SChristian Brauner 	id2 = id + count - 1;
35222d917d8SEric W. Biederman 
35322d917d8SEric W. Biederman 	/* Find the matching extent */
35422d917d8SEric W. Biederman 	for (idx = 0; idx < extents; idx++) {
35522d917d8SEric W. Biederman 		first = map->extent[idx].lower_first;
35622d917d8SEric W. Biederman 		last = first + map->extent[idx].count - 1;
357*784ed435SChristian Brauner 		if (id >= first && id <= last &&
358*784ed435SChristian Brauner 		    (id2 >= first && id2 <= last))
3593edf652fSEric W. Biederman 			return &map->extent[idx];
36022d917d8SEric W. Biederman 	}
3613edf652fSEric W. Biederman 	return NULL;
36222d917d8SEric W. Biederman }
36322d917d8SEric W. Biederman 
364f73f6181SRandy Dunlap /*
3656397fac4SChristian Brauner  * map_id_up_max - Find idmap via binary search in ordered idmap array.
3666397fac4SChristian Brauner  * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS.
3676397fac4SChristian Brauner  */
3683edf652fSEric W. Biederman static struct uid_gid_extent *
map_id_range_up_max(unsigned extents,struct uid_gid_map * map,u32 id,u32 count)369*784ed435SChristian Brauner map_id_range_up_max(unsigned extents, struct uid_gid_map *map, u32 id, u32 count)
3706397fac4SChristian Brauner {
3716397fac4SChristian Brauner 	struct idmap_key key;
3726397fac4SChristian Brauner 
3736397fac4SChristian Brauner 	key.map_up = true;
374*784ed435SChristian Brauner 	key.count = count;
3756397fac4SChristian Brauner 	key.id = id;
3766397fac4SChristian Brauner 
3773edf652fSEric W. Biederman 	return bsearch(&key, map->reverse, extents,
3783edf652fSEric W. Biederman 		       sizeof(struct uid_gid_extent), cmp_map_id);
3793edf652fSEric W. Biederman }
3803edf652fSEric W. Biederman 
map_id_range_up(struct uid_gid_map * map,u32 id,u32 count)381*784ed435SChristian Brauner u32 map_id_range_up(struct uid_gid_map *map, u32 id, u32 count)
3823edf652fSEric W. Biederman {
3833edf652fSEric W. Biederman 	struct uid_gid_extent *extent;
3843edf652fSEric W. Biederman 	unsigned extents = map->nr_extents;
3856397fac4SChristian Brauner 	smp_rmb();
3866397fac4SChristian Brauner 
3873edf652fSEric W. Biederman 	if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
388*784ed435SChristian Brauner 		extent = map_id_range_up_base(extents, map, id, count);
3893edf652fSEric W. Biederman 	else
390*784ed435SChristian Brauner 		extent = map_id_range_up_max(extents, map, id, count);
3913edf652fSEric W. Biederman 
39222d917d8SEric W. Biederman 	/* Map the id or note failure */
3936397fac4SChristian Brauner 	if (extent)
3946397fac4SChristian Brauner 		id = (id - extent->lower_first) + extent->first;
39522d917d8SEric W. Biederman 	else
39622d917d8SEric W. Biederman 		id = (u32) -1;
39722d917d8SEric W. Biederman 
39822d917d8SEric W. Biederman 	return id;
39922d917d8SEric W. Biederman }
40022d917d8SEric W. Biederman 
map_id_up(struct uid_gid_map * map,u32 id)401*784ed435SChristian Brauner u32 map_id_up(struct uid_gid_map *map, u32 id)
402*784ed435SChristian Brauner {
403*784ed435SChristian Brauner 	return map_id_range_up(map, id, 1);
404*784ed435SChristian Brauner }
405*784ed435SChristian Brauner 
40622d917d8SEric W. Biederman /**
40722d917d8SEric W. Biederman  *	make_kuid - Map a user-namespace uid pair into a kuid.
40822d917d8SEric W. Biederman  *	@ns:  User namespace that the uid is in
40922d917d8SEric W. Biederman  *	@uid: User identifier
41022d917d8SEric W. Biederman  *
41122d917d8SEric W. Biederman  *	Maps a user-namespace uid pair into a kernel internal kuid,
41222d917d8SEric W. Biederman  *	and returns that kuid.
41322d917d8SEric W. Biederman  *
41422d917d8SEric W. Biederman  *	When there is no mapping defined for the user-namespace uid
41522d917d8SEric W. Biederman  *	pair INVALID_UID is returned.  Callers are expected to test
416b080e047SBrian Campbell  *	for and handle INVALID_UID being returned.  INVALID_UID
41722d917d8SEric W. Biederman  *	may be tested for using uid_valid().
41822d917d8SEric W. Biederman  */
make_kuid(struct user_namespace * ns,uid_t uid)41922d917d8SEric W. Biederman kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
42022d917d8SEric W. Biederman {
42122d917d8SEric W. Biederman 	/* Map the uid to a global kernel uid */
42222d917d8SEric W. Biederman 	return KUIDT_INIT(map_id_down(&ns->uid_map, uid));
42322d917d8SEric W. Biederman }
42422d917d8SEric W. Biederman EXPORT_SYMBOL(make_kuid);
42522d917d8SEric W. Biederman 
42622d917d8SEric W. Biederman /**
42722d917d8SEric W. Biederman  *	from_kuid - Create a uid from a kuid user-namespace pair.
42822d917d8SEric W. Biederman  *	@targ: The user namespace we want a uid in.
42922d917d8SEric W. Biederman  *	@kuid: The kernel internal uid to start with.
43022d917d8SEric W. Biederman  *
43122d917d8SEric W. Biederman  *	Map @kuid into the user-namespace specified by @targ and
43222d917d8SEric W. Biederman  *	return the resulting uid.
43322d917d8SEric W. Biederman  *
43422d917d8SEric W. Biederman  *	There is always a mapping into the initial user_namespace.
43522d917d8SEric W. Biederman  *
43622d917d8SEric W. Biederman  *	If @kuid has no mapping in @targ (uid_t)-1 is returned.
43722d917d8SEric W. Biederman  */
from_kuid(struct user_namespace * targ,kuid_t kuid)43822d917d8SEric W. Biederman uid_t from_kuid(struct user_namespace *targ, kuid_t kuid)
43922d917d8SEric W. Biederman {
44022d917d8SEric W. Biederman 	/* Map the uid from a global kernel uid */
44122d917d8SEric W. Biederman 	return map_id_up(&targ->uid_map, __kuid_val(kuid));
44222d917d8SEric W. Biederman }
44322d917d8SEric W. Biederman EXPORT_SYMBOL(from_kuid);
44422d917d8SEric W. Biederman 
44522d917d8SEric W. Biederman /**
44622d917d8SEric W. Biederman  *	from_kuid_munged - Create a uid from a kuid user-namespace pair.
44722d917d8SEric W. Biederman  *	@targ: The user namespace we want a uid in.
44822d917d8SEric W. Biederman  *	@kuid: The kernel internal uid to start with.
44922d917d8SEric W. Biederman  *
45022d917d8SEric W. Biederman  *	Map @kuid into the user-namespace specified by @targ and
45122d917d8SEric W. Biederman  *	return the resulting uid.
45222d917d8SEric W. Biederman  *
45322d917d8SEric W. Biederman  *	There is always a mapping into the initial user_namespace.
45422d917d8SEric W. Biederman  *
45522d917d8SEric W. Biederman  *	Unlike from_kuid from_kuid_munged never fails and always
45622d917d8SEric W. Biederman  *	returns a valid uid.  This makes from_kuid_munged appropriate
45722d917d8SEric W. Biederman  *	for use in syscalls like stat and getuid where failing the
45822d917d8SEric W. Biederman  *	system call and failing to provide a valid uid are not an
45922d917d8SEric W. Biederman  *	options.
46022d917d8SEric W. Biederman  *
46122d917d8SEric W. Biederman  *	If @kuid has no mapping in @targ overflowuid is returned.
46222d917d8SEric W. Biederman  */
from_kuid_munged(struct user_namespace * targ,kuid_t kuid)46322d917d8SEric W. Biederman uid_t from_kuid_munged(struct user_namespace *targ, kuid_t kuid)
46422d917d8SEric W. Biederman {
46522d917d8SEric W. Biederman 	uid_t uid;
46622d917d8SEric W. Biederman 	uid = from_kuid(targ, kuid);
46722d917d8SEric W. Biederman 
46822d917d8SEric W. Biederman 	if (uid == (uid_t) -1)
46922d917d8SEric W. Biederman 		uid = overflowuid;
4705c1469deSEric W. Biederman 	return uid;
47122d917d8SEric W. Biederman }
47222d917d8SEric W. Biederman EXPORT_SYMBOL(from_kuid_munged);
4735c1469deSEric W. Biederman 
47422d917d8SEric W. Biederman /**
47522d917d8SEric W. Biederman  *	make_kgid - Map a user-namespace gid pair into a kgid.
47622d917d8SEric W. Biederman  *	@ns:  User namespace that the gid is in
47768a9a435SFabian Frederick  *	@gid: group identifier
47822d917d8SEric W. Biederman  *
47922d917d8SEric W. Biederman  *	Maps a user-namespace gid pair into a kernel internal kgid,
48022d917d8SEric W. Biederman  *	and returns that kgid.
48122d917d8SEric W. Biederman  *
48222d917d8SEric W. Biederman  *	When there is no mapping defined for the user-namespace gid
48322d917d8SEric W. Biederman  *	pair INVALID_GID is returned.  Callers are expected to test
48422d917d8SEric W. Biederman  *	for and handle INVALID_GID being returned.  INVALID_GID may be
48522d917d8SEric W. Biederman  *	tested for using gid_valid().
4865c1469deSEric W. Biederman  */
make_kgid(struct user_namespace * ns,gid_t gid)48722d917d8SEric W. Biederman kgid_t make_kgid(struct user_namespace *ns, gid_t gid)
4885c1469deSEric W. Biederman {
48922d917d8SEric W. Biederman 	/* Map the gid to a global kernel gid */
49022d917d8SEric W. Biederman 	return KGIDT_INIT(map_id_down(&ns->gid_map, gid));
49122d917d8SEric W. Biederman }
49222d917d8SEric W. Biederman EXPORT_SYMBOL(make_kgid);
4935c1469deSEric W. Biederman 
49422d917d8SEric W. Biederman /**
49522d917d8SEric W. Biederman  *	from_kgid - Create a gid from a kgid user-namespace pair.
49622d917d8SEric W. Biederman  *	@targ: The user namespace we want a gid in.
49722d917d8SEric W. Biederman  *	@kgid: The kernel internal gid to start with.
49822d917d8SEric W. Biederman  *
49922d917d8SEric W. Biederman  *	Map @kgid into the user-namespace specified by @targ and
50022d917d8SEric W. Biederman  *	return the resulting gid.
50122d917d8SEric W. Biederman  *
50222d917d8SEric W. Biederman  *	There is always a mapping into the initial user_namespace.
50322d917d8SEric W. Biederman  *
50422d917d8SEric W. Biederman  *	If @kgid has no mapping in @targ (gid_t)-1 is returned.
5055c1469deSEric W. Biederman  */
from_kgid(struct user_namespace * targ,kgid_t kgid)50622d917d8SEric W. Biederman gid_t from_kgid(struct user_namespace *targ, kgid_t kgid)
50722d917d8SEric W. Biederman {
50822d917d8SEric W. Biederman 	/* Map the gid from a global kernel gid */
50922d917d8SEric W. Biederman 	return map_id_up(&targ->gid_map, __kgid_val(kgid));
5105c1469deSEric W. Biederman }
51122d917d8SEric W. Biederman EXPORT_SYMBOL(from_kgid);
51222d917d8SEric W. Biederman 
51322d917d8SEric W. Biederman /**
51422d917d8SEric W. Biederman  *	from_kgid_munged - Create a gid from a kgid user-namespace pair.
51522d917d8SEric W. Biederman  *	@targ: The user namespace we want a gid in.
51622d917d8SEric W. Biederman  *	@kgid: The kernel internal gid to start with.
51722d917d8SEric W. Biederman  *
51822d917d8SEric W. Biederman  *	Map @kgid into the user-namespace specified by @targ and
51922d917d8SEric W. Biederman  *	return the resulting gid.
52022d917d8SEric W. Biederman  *
52122d917d8SEric W. Biederman  *	There is always a mapping into the initial user_namespace.
52222d917d8SEric W. Biederman  *
52322d917d8SEric W. Biederman  *	Unlike from_kgid from_kgid_munged never fails and always
52422d917d8SEric W. Biederman  *	returns a valid gid.  This makes from_kgid_munged appropriate
52522d917d8SEric W. Biederman  *	for use in syscalls like stat and getgid where failing the
52622d917d8SEric W. Biederman  *	system call and failing to provide a valid gid are not options.
52722d917d8SEric W. Biederman  *
52822d917d8SEric W. Biederman  *	If @kgid has no mapping in @targ overflowgid is returned.
52922d917d8SEric W. Biederman  */
from_kgid_munged(struct user_namespace * targ,kgid_t kgid)53022d917d8SEric W. Biederman gid_t from_kgid_munged(struct user_namespace *targ, kgid_t kgid)
53122d917d8SEric W. Biederman {
53222d917d8SEric W. Biederman 	gid_t gid;
53322d917d8SEric W. Biederman 	gid = from_kgid(targ, kgid);
53422d917d8SEric W. Biederman 
53522d917d8SEric W. Biederman 	if (gid == (gid_t) -1)
53622d917d8SEric W. Biederman 		gid = overflowgid;
53722d917d8SEric W. Biederman 	return gid;
53822d917d8SEric W. Biederman }
53922d917d8SEric W. Biederman EXPORT_SYMBOL(from_kgid_munged);
54022d917d8SEric W. Biederman 
541f76d207aSEric W. Biederman /**
542f76d207aSEric W. Biederman  *	make_kprojid - Map a user-namespace projid pair into a kprojid.
543f76d207aSEric W. Biederman  *	@ns:  User namespace that the projid is in
544f76d207aSEric W. Biederman  *	@projid: Project identifier
545f76d207aSEric W. Biederman  *
546f76d207aSEric W. Biederman  *	Maps a user-namespace uid pair into a kernel internal kuid,
547f76d207aSEric W. Biederman  *	and returns that kuid.
548f76d207aSEric W. Biederman  *
549f76d207aSEric W. Biederman  *	When there is no mapping defined for the user-namespace projid
550f76d207aSEric W. Biederman  *	pair INVALID_PROJID is returned.  Callers are expected to test
5517b7b8a2cSRandy Dunlap  *	for and handle INVALID_PROJID being returned.  INVALID_PROJID
552f76d207aSEric W. Biederman  *	may be tested for using projid_valid().
553f76d207aSEric W. Biederman  */
make_kprojid(struct user_namespace * ns,projid_t projid)554f76d207aSEric W. Biederman kprojid_t make_kprojid(struct user_namespace *ns, projid_t projid)
555f76d207aSEric W. Biederman {
556f76d207aSEric W. Biederman 	/* Map the uid to a global kernel uid */
557f76d207aSEric W. Biederman 	return KPROJIDT_INIT(map_id_down(&ns->projid_map, projid));
558f76d207aSEric W. Biederman }
559f76d207aSEric W. Biederman EXPORT_SYMBOL(make_kprojid);
560f76d207aSEric W. Biederman 
561f76d207aSEric W. Biederman /**
562f76d207aSEric W. Biederman  *	from_kprojid - Create a projid from a kprojid user-namespace pair.
563f76d207aSEric W. Biederman  *	@targ: The user namespace we want a projid in.
564f76d207aSEric W. Biederman  *	@kprojid: The kernel internal project identifier to start with.
565f76d207aSEric W. Biederman  *
566f76d207aSEric W. Biederman  *	Map @kprojid into the user-namespace specified by @targ and
567f76d207aSEric W. Biederman  *	return the resulting projid.
568f76d207aSEric W. Biederman  *
569f76d207aSEric W. Biederman  *	There is always a mapping into the initial user_namespace.
570f76d207aSEric W. Biederman  *
571f76d207aSEric W. Biederman  *	If @kprojid has no mapping in @targ (projid_t)-1 is returned.
572f76d207aSEric W. Biederman  */
from_kprojid(struct user_namespace * targ,kprojid_t kprojid)573f76d207aSEric W. Biederman projid_t from_kprojid(struct user_namespace *targ, kprojid_t kprojid)
574f76d207aSEric W. Biederman {
575f76d207aSEric W. Biederman 	/* Map the uid from a global kernel uid */
576f76d207aSEric W. Biederman 	return map_id_up(&targ->projid_map, __kprojid_val(kprojid));
577f76d207aSEric W. Biederman }
578f76d207aSEric W. Biederman EXPORT_SYMBOL(from_kprojid);
579f76d207aSEric W. Biederman 
580f76d207aSEric W. Biederman /**
581f76d207aSEric W. Biederman  *	from_kprojid_munged - Create a projiid from a kprojid user-namespace pair.
582f76d207aSEric W. Biederman  *	@targ: The user namespace we want a projid in.
583f76d207aSEric W. Biederman  *	@kprojid: The kernel internal projid to start with.
584f76d207aSEric W. Biederman  *
585f76d207aSEric W. Biederman  *	Map @kprojid into the user-namespace specified by @targ and
586f76d207aSEric W. Biederman  *	return the resulting projid.
587f76d207aSEric W. Biederman  *
588f76d207aSEric W. Biederman  *	There is always a mapping into the initial user_namespace.
589f76d207aSEric W. Biederman  *
590f76d207aSEric W. Biederman  *	Unlike from_kprojid from_kprojid_munged never fails and always
591f76d207aSEric W. Biederman  *	returns a valid projid.  This makes from_kprojid_munged
592f76d207aSEric W. Biederman  *	appropriate for use in syscalls like stat and where
593f76d207aSEric W. Biederman  *	failing the system call and failing to provide a valid projid are
594f76d207aSEric W. Biederman  *	not an options.
595f76d207aSEric W. Biederman  *
596f76d207aSEric W. Biederman  *	If @kprojid has no mapping in @targ OVERFLOW_PROJID is returned.
597f76d207aSEric W. Biederman  */
from_kprojid_munged(struct user_namespace * targ,kprojid_t kprojid)598f76d207aSEric W. Biederman projid_t from_kprojid_munged(struct user_namespace *targ, kprojid_t kprojid)
599f76d207aSEric W. Biederman {
600f76d207aSEric W. Biederman 	projid_t projid;
601f76d207aSEric W. Biederman 	projid = from_kprojid(targ, kprojid);
602f76d207aSEric W. Biederman 
603f76d207aSEric W. Biederman 	if (projid == (projid_t) -1)
604f76d207aSEric W. Biederman 		projid = OVERFLOW_PROJID;
605f76d207aSEric W. Biederman 	return projid;
606f76d207aSEric W. Biederman }
607f76d207aSEric W. Biederman EXPORT_SYMBOL(from_kprojid_munged);
608f76d207aSEric W. Biederman 
609f76d207aSEric W. Biederman 
uid_m_show(struct seq_file * seq,void * v)61022d917d8SEric W. Biederman static int uid_m_show(struct seq_file *seq, void *v)
61122d917d8SEric W. Biederman {
61222d917d8SEric W. Biederman 	struct user_namespace *ns = seq->private;
61322d917d8SEric W. Biederman 	struct uid_gid_extent *extent = v;
61422d917d8SEric W. Biederman 	struct user_namespace *lower_ns;
61522d917d8SEric W. Biederman 	uid_t lower;
61622d917d8SEric W. Biederman 
617c450f371SEric W. Biederman 	lower_ns = seq_user_ns(seq);
61822d917d8SEric W. Biederman 	if ((lower_ns == ns) && lower_ns->parent)
61922d917d8SEric W. Biederman 		lower_ns = lower_ns->parent;
62022d917d8SEric W. Biederman 
62122d917d8SEric W. Biederman 	lower = from_kuid(lower_ns, KUIDT_INIT(extent->lower_first));
62222d917d8SEric W. Biederman 
62322d917d8SEric W. Biederman 	seq_printf(seq, "%10u %10u %10u\n",
62422d917d8SEric W. Biederman 		extent->first,
62522d917d8SEric W. Biederman 		lower,
62622d917d8SEric W. Biederman 		extent->count);
62722d917d8SEric W. Biederman 
62822d917d8SEric W. Biederman 	return 0;
6295c1469deSEric W. Biederman }
6305c1469deSEric W. Biederman 
gid_m_show(struct seq_file * seq,void * v)63122d917d8SEric W. Biederman static int gid_m_show(struct seq_file *seq, void *v)
63222d917d8SEric W. Biederman {
63322d917d8SEric W. Biederman 	struct user_namespace *ns = seq->private;
63422d917d8SEric W. Biederman 	struct uid_gid_extent *extent = v;
63522d917d8SEric W. Biederman 	struct user_namespace *lower_ns;
63622d917d8SEric W. Biederman 	gid_t lower;
63722d917d8SEric W. Biederman 
638c450f371SEric W. Biederman 	lower_ns = seq_user_ns(seq);
63922d917d8SEric W. Biederman 	if ((lower_ns == ns) && lower_ns->parent)
64022d917d8SEric W. Biederman 		lower_ns = lower_ns->parent;
64122d917d8SEric W. Biederman 
64222d917d8SEric W. Biederman 	lower = from_kgid(lower_ns, KGIDT_INIT(extent->lower_first));
64322d917d8SEric W. Biederman 
64422d917d8SEric W. Biederman 	seq_printf(seq, "%10u %10u %10u\n",
64522d917d8SEric W. Biederman 		extent->first,
64622d917d8SEric W. Biederman 		lower,
64722d917d8SEric W. Biederman 		extent->count);
64822d917d8SEric W. Biederman 
64922d917d8SEric W. Biederman 	return 0;
65022d917d8SEric W. Biederman }
65122d917d8SEric W. Biederman 
projid_m_show(struct seq_file * seq,void * v)652f76d207aSEric W. Biederman static int projid_m_show(struct seq_file *seq, void *v)
653f76d207aSEric W. Biederman {
654f76d207aSEric W. Biederman 	struct user_namespace *ns = seq->private;
655f76d207aSEric W. Biederman 	struct uid_gid_extent *extent = v;
656f76d207aSEric W. Biederman 	struct user_namespace *lower_ns;
657f76d207aSEric W. Biederman 	projid_t lower;
658f76d207aSEric W. Biederman 
659f76d207aSEric W. Biederman 	lower_ns = seq_user_ns(seq);
660f76d207aSEric W. Biederman 	if ((lower_ns == ns) && lower_ns->parent)
661f76d207aSEric W. Biederman 		lower_ns = lower_ns->parent;
662f76d207aSEric W. Biederman 
663f76d207aSEric W. Biederman 	lower = from_kprojid(lower_ns, KPROJIDT_INIT(extent->lower_first));
664f76d207aSEric W. Biederman 
665f76d207aSEric W. Biederman 	seq_printf(seq, "%10u %10u %10u\n",
666f76d207aSEric W. Biederman 		extent->first,
667f76d207aSEric W. Biederman 		lower,
668f76d207aSEric W. Biederman 		extent->count);
669f76d207aSEric W. Biederman 
670f76d207aSEric W. Biederman 	return 0;
671f76d207aSEric W. Biederman }
672f76d207aSEric W. Biederman 
m_start(struct seq_file * seq,loff_t * ppos,struct uid_gid_map * map)67368a9a435SFabian Frederick static void *m_start(struct seq_file *seq, loff_t *ppos,
67468a9a435SFabian Frederick 		     struct uid_gid_map *map)
67522d917d8SEric W. Biederman {
67622d917d8SEric W. Biederman 	loff_t pos = *ppos;
677d5e7b3c5SEric W. Biederman 	unsigned extents = map->nr_extents;
678d5e7b3c5SEric W. Biederman 	smp_rmb();
67922d917d8SEric W. Biederman 
680d5e7b3c5SEric W. Biederman 	if (pos >= extents)
6816397fac4SChristian Brauner 		return NULL;
68222d917d8SEric W. Biederman 
683d5e7b3c5SEric W. Biederman 	if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
6846397fac4SChristian Brauner 		return &map->extent[pos];
6856397fac4SChristian Brauner 
6866397fac4SChristian Brauner 	return &map->forward[pos];
68722d917d8SEric W. Biederman }
68822d917d8SEric W. Biederman 
uid_m_start(struct seq_file * seq,loff_t * ppos)68922d917d8SEric W. Biederman static void *uid_m_start(struct seq_file *seq, loff_t *ppos)
69022d917d8SEric W. Biederman {
69122d917d8SEric W. Biederman 	struct user_namespace *ns = seq->private;
69222d917d8SEric W. Biederman 
69322d917d8SEric W. Biederman 	return m_start(seq, ppos, &ns->uid_map);
69422d917d8SEric W. Biederman }
69522d917d8SEric W. Biederman 
gid_m_start(struct seq_file * seq,loff_t * ppos)69622d917d8SEric W. Biederman static void *gid_m_start(struct seq_file *seq, loff_t *ppos)
69722d917d8SEric W. Biederman {
69822d917d8SEric W. Biederman 	struct user_namespace *ns = seq->private;
69922d917d8SEric W. Biederman 
70022d917d8SEric W. Biederman 	return m_start(seq, ppos, &ns->gid_map);
70122d917d8SEric W. Biederman }
70222d917d8SEric W. Biederman 
projid_m_start(struct seq_file * seq,loff_t * ppos)703f76d207aSEric W. Biederman static void *projid_m_start(struct seq_file *seq, loff_t *ppos)
704f76d207aSEric W. Biederman {
705f76d207aSEric W. Biederman 	struct user_namespace *ns = seq->private;
706f76d207aSEric W. Biederman 
707f76d207aSEric W. Biederman 	return m_start(seq, ppos, &ns->projid_map);
708f76d207aSEric W. Biederman }
709f76d207aSEric W. Biederman 
m_next(struct seq_file * seq,void * v,loff_t * pos)71022d917d8SEric W. Biederman static void *m_next(struct seq_file *seq, void *v, loff_t *pos)
71122d917d8SEric W. Biederman {
71222d917d8SEric W. Biederman 	(*pos)++;
71322d917d8SEric W. Biederman 	return seq->op->start(seq, pos);
71422d917d8SEric W. Biederman }
71522d917d8SEric W. Biederman 
m_stop(struct seq_file * seq,void * v)71622d917d8SEric W. Biederman static void m_stop(struct seq_file *seq, void *v)
71722d917d8SEric W. Biederman {
71822d917d8SEric W. Biederman 	return;
71922d917d8SEric W. Biederman }
72022d917d8SEric W. Biederman 
721ccf94f1bSFabian Frederick const struct seq_operations proc_uid_seq_operations = {
72222d917d8SEric W. Biederman 	.start = uid_m_start,
72322d917d8SEric W. Biederman 	.stop = m_stop,
72422d917d8SEric W. Biederman 	.next = m_next,
72522d917d8SEric W. Biederman 	.show = uid_m_show,
72622d917d8SEric W. Biederman };
72722d917d8SEric W. Biederman 
728ccf94f1bSFabian Frederick const struct seq_operations proc_gid_seq_operations = {
72922d917d8SEric W. Biederman 	.start = gid_m_start,
73022d917d8SEric W. Biederman 	.stop = m_stop,
73122d917d8SEric W. Biederman 	.next = m_next,
73222d917d8SEric W. Biederman 	.show = gid_m_show,
73322d917d8SEric W. Biederman };
73422d917d8SEric W. Biederman 
735ccf94f1bSFabian Frederick const struct seq_operations proc_projid_seq_operations = {
736f76d207aSEric W. Biederman 	.start = projid_m_start,
737f76d207aSEric W. Biederman 	.stop = m_stop,
738f76d207aSEric W. Biederman 	.next = m_next,
739f76d207aSEric W. Biederman 	.show = projid_m_show,
740f76d207aSEric W. Biederman };
741f76d207aSEric W. Biederman 
mappings_overlap(struct uid_gid_map * new_map,struct uid_gid_extent * extent)74268a9a435SFabian Frederick static bool mappings_overlap(struct uid_gid_map *new_map,
74368a9a435SFabian Frederick 			     struct uid_gid_extent *extent)
7440bd14b4fSEric W. Biederman {
7450bd14b4fSEric W. Biederman 	u32 upper_first, lower_first, upper_last, lower_last;
7460bd14b4fSEric W. Biederman 	unsigned idx;
7470bd14b4fSEric W. Biederman 
7480bd14b4fSEric W. Biederman 	upper_first = extent->first;
7490bd14b4fSEric W. Biederman 	lower_first = extent->lower_first;
7500bd14b4fSEric W. Biederman 	upper_last = upper_first + extent->count - 1;
7510bd14b4fSEric W. Biederman 	lower_last = lower_first + extent->count - 1;
7520bd14b4fSEric W. Biederman 
7530bd14b4fSEric W. Biederman 	for (idx = 0; idx < new_map->nr_extents; idx++) {
7540bd14b4fSEric W. Biederman 		u32 prev_upper_first, prev_lower_first;
7550bd14b4fSEric W. Biederman 		u32 prev_upper_last, prev_lower_last;
7560bd14b4fSEric W. Biederman 		struct uid_gid_extent *prev;
7570bd14b4fSEric W. Biederman 
7586397fac4SChristian Brauner 		if (new_map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
7590bd14b4fSEric W. Biederman 			prev = &new_map->extent[idx];
7606397fac4SChristian Brauner 		else
7616397fac4SChristian Brauner 			prev = &new_map->forward[idx];
7620bd14b4fSEric W. Biederman 
7630bd14b4fSEric W. Biederman 		prev_upper_first = prev->first;
7640bd14b4fSEric W. Biederman 		prev_lower_first = prev->lower_first;
7650bd14b4fSEric W. Biederman 		prev_upper_last = prev_upper_first + prev->count - 1;
7660bd14b4fSEric W. Biederman 		prev_lower_last = prev_lower_first + prev->count - 1;
7670bd14b4fSEric W. Biederman 
7680bd14b4fSEric W. Biederman 		/* Does the upper range intersect a previous extent? */
7690bd14b4fSEric W. Biederman 		if ((prev_upper_first <= upper_last) &&
7700bd14b4fSEric W. Biederman 		    (prev_upper_last >= upper_first))
7710bd14b4fSEric W. Biederman 			return true;
7720bd14b4fSEric W. Biederman 
7730bd14b4fSEric W. Biederman 		/* Does the lower range intersect a previous extent? */
7740bd14b4fSEric W. Biederman 		if ((prev_lower_first <= lower_last) &&
7750bd14b4fSEric W. Biederman 		    (prev_lower_last >= lower_first))
7760bd14b4fSEric W. Biederman 			return true;
7770bd14b4fSEric W. Biederman 	}
7780bd14b4fSEric W. Biederman 	return false;
7790bd14b4fSEric W. Biederman }
7800bd14b4fSEric W. Biederman 
781f73f6181SRandy Dunlap /*
7826397fac4SChristian Brauner  * insert_extent - Safely insert a new idmap extent into struct uid_gid_map.
7836397fac4SChristian Brauner  * Takes care to allocate a 4K block of memory if the number of mappings exceeds
7846397fac4SChristian Brauner  * UID_GID_MAP_MAX_BASE_EXTENTS.
7856397fac4SChristian Brauner  */
insert_extent(struct uid_gid_map * map,struct uid_gid_extent * extent)7866397fac4SChristian Brauner static int insert_extent(struct uid_gid_map *map, struct uid_gid_extent *extent)
7876397fac4SChristian Brauner {
7883fda0e73SEric W. Biederman 	struct uid_gid_extent *dest;
7896397fac4SChristian Brauner 
7906397fac4SChristian Brauner 	if (map->nr_extents == UID_GID_MAP_MAX_BASE_EXTENTS) {
7916397fac4SChristian Brauner 		struct uid_gid_extent *forward;
7926397fac4SChristian Brauner 
7936397fac4SChristian Brauner 		/* Allocate memory for 340 mappings. */
7946da2ec56SKees Cook 		forward = kmalloc_array(UID_GID_MAP_MAX_EXTENTS,
7956da2ec56SKees Cook 					sizeof(struct uid_gid_extent),
7966da2ec56SKees Cook 					GFP_KERNEL);
7976397fac4SChristian Brauner 		if (!forward)
7986397fac4SChristian Brauner 			return -ENOMEM;
7996397fac4SChristian Brauner 
8006397fac4SChristian Brauner 		/* Copy over memory. Only set up memory for the forward pointer.
8016397fac4SChristian Brauner 		 * Defer the memory setup for the reverse pointer.
8026397fac4SChristian Brauner 		 */
8036397fac4SChristian Brauner 		memcpy(forward, map->extent,
8046397fac4SChristian Brauner 		       map->nr_extents * sizeof(map->extent[0]));
8056397fac4SChristian Brauner 
8066397fac4SChristian Brauner 		map->forward = forward;
8076397fac4SChristian Brauner 		map->reverse = NULL;
8086397fac4SChristian Brauner 	}
8096397fac4SChristian Brauner 
8103fda0e73SEric W. Biederman 	if (map->nr_extents < UID_GID_MAP_MAX_BASE_EXTENTS)
8113fda0e73SEric W. Biederman 		dest = &map->extent[map->nr_extents];
8123fda0e73SEric W. Biederman 	else
8133fda0e73SEric W. Biederman 		dest = &map->forward[map->nr_extents];
8143fda0e73SEric W. Biederman 
8153fda0e73SEric W. Biederman 	*dest = *extent;
8163fda0e73SEric W. Biederman 	map->nr_extents++;
8176397fac4SChristian Brauner 	return 0;
8186397fac4SChristian Brauner }
8196397fac4SChristian Brauner 
8206397fac4SChristian Brauner /* cmp function to sort() forward mappings */
cmp_extents_forward(const void * a,const void * b)8216397fac4SChristian Brauner static int cmp_extents_forward(const void *a, const void *b)
8226397fac4SChristian Brauner {
8236397fac4SChristian Brauner 	const struct uid_gid_extent *e1 = a;
8246397fac4SChristian Brauner 	const struct uid_gid_extent *e2 = b;
8256397fac4SChristian Brauner 
8266397fac4SChristian Brauner 	if (e1->first < e2->first)
8276397fac4SChristian Brauner 		return -1;
8286397fac4SChristian Brauner 
8296397fac4SChristian Brauner 	if (e1->first > e2->first)
8306397fac4SChristian Brauner 		return 1;
8316397fac4SChristian Brauner 
8326397fac4SChristian Brauner 	return 0;
8336397fac4SChristian Brauner }
8346397fac4SChristian Brauner 
8356397fac4SChristian Brauner /* cmp function to sort() reverse mappings */
cmp_extents_reverse(const void * a,const void * b)8366397fac4SChristian Brauner static int cmp_extents_reverse(const void *a, const void *b)
8376397fac4SChristian Brauner {
8386397fac4SChristian Brauner 	const struct uid_gid_extent *e1 = a;
8396397fac4SChristian Brauner 	const struct uid_gid_extent *e2 = b;
8406397fac4SChristian Brauner 
8416397fac4SChristian Brauner 	if (e1->lower_first < e2->lower_first)
8426397fac4SChristian Brauner 		return -1;
8436397fac4SChristian Brauner 
8446397fac4SChristian Brauner 	if (e1->lower_first > e2->lower_first)
8456397fac4SChristian Brauner 		return 1;
8466397fac4SChristian Brauner 
8476397fac4SChristian Brauner 	return 0;
8486397fac4SChristian Brauner }
8496397fac4SChristian Brauner 
850f73f6181SRandy Dunlap /*
8516397fac4SChristian Brauner  * sort_idmaps - Sorts an array of idmap entries.
8526397fac4SChristian Brauner  * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS.
8536397fac4SChristian Brauner  */
sort_idmaps(struct uid_gid_map * map)8546397fac4SChristian Brauner static int sort_idmaps(struct uid_gid_map *map)
8556397fac4SChristian Brauner {
8566397fac4SChristian Brauner 	if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
8576397fac4SChristian Brauner 		return 0;
8586397fac4SChristian Brauner 
8596397fac4SChristian Brauner 	/* Sort forward array. */
8606397fac4SChristian Brauner 	sort(map->forward, map->nr_extents, sizeof(struct uid_gid_extent),
8616397fac4SChristian Brauner 	     cmp_extents_forward, NULL);
8626397fac4SChristian Brauner 
8636397fac4SChristian Brauner 	/* Only copy the memory from forward we actually need. */
864546f0282SJinjie Ruan 	map->reverse = kmemdup_array(map->forward, map->nr_extents,
865546f0282SJinjie Ruan 				     sizeof(struct uid_gid_extent), GFP_KERNEL);
8666397fac4SChristian Brauner 	if (!map->reverse)
8676397fac4SChristian Brauner 		return -ENOMEM;
8686397fac4SChristian Brauner 
8696397fac4SChristian Brauner 	/* Sort reverse array. */
8706397fac4SChristian Brauner 	sort(map->reverse, map->nr_extents, sizeof(struct uid_gid_extent),
8716397fac4SChristian Brauner 	     cmp_extents_reverse, NULL);
8726397fac4SChristian Brauner 
8736397fac4SChristian Brauner 	return 0;
8746397fac4SChristian Brauner }
8756397fac4SChristian Brauner 
876db2e718aSSerge E. Hallyn /**
877db2e718aSSerge E. Hallyn  * verify_root_map() - check the uid 0 mapping
878db2e718aSSerge E. Hallyn  * @file: idmapping file
879db2e718aSSerge E. Hallyn  * @map_ns: user namespace of the target process
880db2e718aSSerge E. Hallyn  * @new_map: requested idmap
881db2e718aSSerge E. Hallyn  *
882db2e718aSSerge E. Hallyn  * If a process requests mapping parent uid 0 into the new ns, verify that the
883db2e718aSSerge E. Hallyn  * process writing the map had the CAP_SETFCAP capability as the target process
884db2e718aSSerge E. Hallyn  * will be able to write fscaps that are valid in ancestor user namespaces.
885db2e718aSSerge E. Hallyn  *
886db2e718aSSerge E. Hallyn  * Return: true if the mapping is allowed, false if not.
887db2e718aSSerge E. Hallyn  */
verify_root_map(const struct file * file,struct user_namespace * map_ns,struct uid_gid_map * new_map)888db2e718aSSerge E. Hallyn static bool verify_root_map(const struct file *file,
889db2e718aSSerge E. Hallyn 			    struct user_namespace *map_ns,
890db2e718aSSerge E. Hallyn 			    struct uid_gid_map *new_map)
891db2e718aSSerge E. Hallyn {
892db2e718aSSerge E. Hallyn 	int idx;
893db2e718aSSerge E. Hallyn 	const struct user_namespace *file_ns = file->f_cred->user_ns;
894db2e718aSSerge E. Hallyn 	struct uid_gid_extent *extent0 = NULL;
895db2e718aSSerge E. Hallyn 
896db2e718aSSerge E. Hallyn 	for (idx = 0; idx < new_map->nr_extents; idx++) {
897db2e718aSSerge E. Hallyn 		if (new_map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
898db2e718aSSerge E. Hallyn 			extent0 = &new_map->extent[idx];
899db2e718aSSerge E. Hallyn 		else
900db2e718aSSerge E. Hallyn 			extent0 = &new_map->forward[idx];
901db2e718aSSerge E. Hallyn 		if (extent0->lower_first == 0)
902db2e718aSSerge E. Hallyn 			break;
903db2e718aSSerge E. Hallyn 
904db2e718aSSerge E. Hallyn 		extent0 = NULL;
905db2e718aSSerge E. Hallyn 	}
906db2e718aSSerge E. Hallyn 
907db2e718aSSerge E. Hallyn 	if (!extent0)
908db2e718aSSerge E. Hallyn 		return true;
909db2e718aSSerge E. Hallyn 
910db2e718aSSerge E. Hallyn 	if (map_ns == file_ns) {
911db2e718aSSerge E. Hallyn 		/* The process unshared its ns and is writing to its own
912db2e718aSSerge E. Hallyn 		 * /proc/self/uid_map.  User already has full capabilites in
913db2e718aSSerge E. Hallyn 		 * the new namespace.  Verify that the parent had CAP_SETFCAP
914db2e718aSSerge E. Hallyn 		 * when it unshared.
915db2e718aSSerge E. Hallyn 		 * */
916db2e718aSSerge E. Hallyn 		if (!file_ns->parent_could_setfcap)
917db2e718aSSerge E. Hallyn 			return false;
918db2e718aSSerge E. Hallyn 	} else {
919db2e718aSSerge E. Hallyn 		/* Process p1 is writing to uid_map of p2, who is in a child
920db2e718aSSerge E. Hallyn 		 * user namespace to p1's.  Verify that the opener of the map
921db2e718aSSerge E. Hallyn 		 * file has CAP_SETFCAP against the parent of the new map
922db2e718aSSerge E. Hallyn 		 * namespace */
923db2e718aSSerge E. Hallyn 		if (!file_ns_capable(file, map_ns->parent, CAP_SETFCAP))
924db2e718aSSerge E. Hallyn 			return false;
925db2e718aSSerge E. Hallyn 	}
926db2e718aSSerge E. Hallyn 
927db2e718aSSerge E. Hallyn 	return true;
928db2e718aSSerge E. Hallyn }
929db2e718aSSerge E. Hallyn 
map_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos,int cap_setid,struct uid_gid_map * map,struct uid_gid_map * parent_map)93022d917d8SEric W. Biederman static ssize_t map_write(struct file *file, const char __user *buf,
93122d917d8SEric W. Biederman 			 size_t count, loff_t *ppos,
93222d917d8SEric W. Biederman 			 int cap_setid,
93322d917d8SEric W. Biederman 			 struct uid_gid_map *map,
93422d917d8SEric W. Biederman 			 struct uid_gid_map *parent_map)
93522d917d8SEric W. Biederman {
93622d917d8SEric W. Biederman 	struct seq_file *seq = file->private_data;
937db2e718aSSerge E. Hallyn 	struct user_namespace *map_ns = seq->private;
93822d917d8SEric W. Biederman 	struct uid_gid_map new_map;
93922d917d8SEric W. Biederman 	unsigned idx;
9406397fac4SChristian Brauner 	struct uid_gid_extent extent;
9416db9d317SLi zeming 	char *kbuf, *pos, *next_line;
9425820f140SJann Horn 	ssize_t ret;
9435820f140SJann Horn 
9445820f140SJann Horn 	/* Only allow < page size writes at the beginning of the file */
9455820f140SJann Horn 	if ((*ppos != 0) || (count >= PAGE_SIZE))
9465820f140SJann Horn 		return -EINVAL;
9475820f140SJann Horn 
9485820f140SJann Horn 	/* Slurp in the user data */
9495820f140SJann Horn 	kbuf = memdup_user_nul(buf, count);
9505820f140SJann Horn 	if (IS_ERR(kbuf))
9515820f140SJann Horn 		return PTR_ERR(kbuf);
95222d917d8SEric W. Biederman 
95322d917d8SEric W. Biederman 	/*
954f0d62aecSEric W. Biederman 	 * The userns_state_mutex serializes all writes to any given map.
95522d917d8SEric W. Biederman 	 *
95622d917d8SEric W. Biederman 	 * Any map is only ever written once.
95722d917d8SEric W. Biederman 	 *
95822d917d8SEric W. Biederman 	 * An id map fits within 1 cache line on most architectures.
95922d917d8SEric W. Biederman 	 *
96022d917d8SEric W. Biederman 	 * On read nothing needs to be done unless you are on an
96122d917d8SEric W. Biederman 	 * architecture with a crazy cache coherency model like alpha.
96222d917d8SEric W. Biederman 	 *
96322d917d8SEric W. Biederman 	 * There is a one time data dependency between reading the
96422d917d8SEric W. Biederman 	 * count of the extents and the values of the extents.  The
96522d917d8SEric W. Biederman 	 * desired behavior is to see the values of the extents that
96622d917d8SEric W. Biederman 	 * were written before the count of the extents.
96722d917d8SEric W. Biederman 	 *
96822d917d8SEric W. Biederman 	 * To achieve this smp_wmb() is used on guarantee the write
969e79323bdSMikulas Patocka 	 * order and smp_rmb() is guaranteed that we don't have crazy
970e79323bdSMikulas Patocka 	 * architectures returning stale data.
97122d917d8SEric W. Biederman 	 */
972f0d62aecSEric W. Biederman 	mutex_lock(&userns_state_mutex);
97322d917d8SEric W. Biederman 
9746397fac4SChristian Brauner 	memset(&new_map, 0, sizeof(struct uid_gid_map));
9756397fac4SChristian Brauner 
97622d917d8SEric W. Biederman 	ret = -EPERM;
97722d917d8SEric W. Biederman 	/* Only allow one successful write to the map */
97822d917d8SEric W. Biederman 	if (map->nr_extents != 0)
97922d917d8SEric W. Biederman 		goto out;
98022d917d8SEric W. Biederman 
98141c21e35SAndy Lutomirski 	/*
98241c21e35SAndy Lutomirski 	 * Adjusting namespace settings requires capabilities on the target.
98322d917d8SEric W. Biederman 	 */
984db2e718aSSerge E. Hallyn 	if (cap_valid(cap_setid) && !file_ns_capable(file, map_ns, CAP_SYS_ADMIN))
98522d917d8SEric W. Biederman 		goto out;
98622d917d8SEric W. Biederman 
98722d917d8SEric W. Biederman 	/* Parse the user data */
98822d917d8SEric W. Biederman 	ret = -EINVAL;
98922d917d8SEric W. Biederman 	pos = kbuf;
99022d917d8SEric W. Biederman 	for (; pos; pos = next_line) {
99122d917d8SEric W. Biederman 
99222d917d8SEric W. Biederman 		/* Find the end of line and ensure I don't look past it */
99322d917d8SEric W. Biederman 		next_line = strchr(pos, '\n');
99422d917d8SEric W. Biederman 		if (next_line) {
99522d917d8SEric W. Biederman 			*next_line = '\0';
99622d917d8SEric W. Biederman 			next_line++;
99722d917d8SEric W. Biederman 			if (*next_line == '\0')
99822d917d8SEric W. Biederman 				next_line = NULL;
99922d917d8SEric W. Biederman 		}
100022d917d8SEric W. Biederman 
100122d917d8SEric W. Biederman 		pos = skip_spaces(pos);
10026397fac4SChristian Brauner 		extent.first = simple_strtoul(pos, &pos, 10);
100322d917d8SEric W. Biederman 		if (!isspace(*pos))
100422d917d8SEric W. Biederman 			goto out;
100522d917d8SEric W. Biederman 
100622d917d8SEric W. Biederman 		pos = skip_spaces(pos);
10076397fac4SChristian Brauner 		extent.lower_first = simple_strtoul(pos, &pos, 10);
100822d917d8SEric W. Biederman 		if (!isspace(*pos))
100922d917d8SEric W. Biederman 			goto out;
101022d917d8SEric W. Biederman 
101122d917d8SEric W. Biederman 		pos = skip_spaces(pos);
10126397fac4SChristian Brauner 		extent.count = simple_strtoul(pos, &pos, 10);
101322d917d8SEric W. Biederman 		if (*pos && !isspace(*pos))
101422d917d8SEric W. Biederman 			goto out;
101522d917d8SEric W. Biederman 
101622d917d8SEric W. Biederman 		/* Verify there is not trailing junk on the line */
101722d917d8SEric W. Biederman 		pos = skip_spaces(pos);
101822d917d8SEric W. Biederman 		if (*pos != '\0')
101922d917d8SEric W. Biederman 			goto out;
102022d917d8SEric W. Biederman 
102122d917d8SEric W. Biederman 		/* Verify we have been given valid starting values */
10226397fac4SChristian Brauner 		if ((extent.first == (u32) -1) ||
10236397fac4SChristian Brauner 		    (extent.lower_first == (u32) -1))
102422d917d8SEric W. Biederman 			goto out;
102522d917d8SEric W. Biederman 
102668a9a435SFabian Frederick 		/* Verify count is not zero and does not cause the
102768a9a435SFabian Frederick 		 * extent to wrap
102868a9a435SFabian Frederick 		 */
10296397fac4SChristian Brauner 		if ((extent.first + extent.count) <= extent.first)
103022d917d8SEric W. Biederman 			goto out;
10316397fac4SChristian Brauner 		if ((extent.lower_first + extent.count) <=
10326397fac4SChristian Brauner 		     extent.lower_first)
103322d917d8SEric W. Biederman 			goto out;
103422d917d8SEric W. Biederman 
10350bd14b4fSEric W. Biederman 		/* Do the ranges in extent overlap any previous extents? */
10366397fac4SChristian Brauner 		if (mappings_overlap(&new_map, &extent))
103722d917d8SEric W. Biederman 			goto out;
103822d917d8SEric W. Biederman 
10396397fac4SChristian Brauner 		if ((new_map.nr_extents + 1) == UID_GID_MAP_MAX_EXTENTS &&
104022d917d8SEric W. Biederman 		    (next_line != NULL))
104122d917d8SEric W. Biederman 			goto out;
10426397fac4SChristian Brauner 
10436397fac4SChristian Brauner 		ret = insert_extent(&new_map, &extent);
10446397fac4SChristian Brauner 		if (ret < 0)
10456397fac4SChristian Brauner 			goto out;
10466397fac4SChristian Brauner 		ret = -EINVAL;
104722d917d8SEric W. Biederman 	}
1048a12f4f85SXiaofeng Cao 	/* Be very certain the new map actually exists */
104922d917d8SEric W. Biederman 	if (new_map.nr_extents == 0)
105022d917d8SEric W. Biederman 		goto out;
105122d917d8SEric W. Biederman 
105222d917d8SEric W. Biederman 	ret = -EPERM;
105322d917d8SEric W. Biederman 	/* Validate the user is allowed to use user id's mapped to. */
1054db2e718aSSerge E. Hallyn 	if (!new_idmap_permitted(file, map_ns, cap_setid, &new_map))
105522d917d8SEric W. Biederman 		goto out;
105622d917d8SEric W. Biederman 
10576397fac4SChristian Brauner 	ret = -EPERM;
105822d917d8SEric W. Biederman 	/* Map the lower ids from the parent user namespace to the
105922d917d8SEric W. Biederman 	 * kernel global id space.
106022d917d8SEric W. Biederman 	 */
106122d917d8SEric W. Biederman 	for (idx = 0; idx < new_map.nr_extents; idx++) {
10626397fac4SChristian Brauner 		struct uid_gid_extent *e;
106322d917d8SEric W. Biederman 		u32 lower_first;
10646397fac4SChristian Brauner 
10656397fac4SChristian Brauner 		if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
10666397fac4SChristian Brauner 			e = &new_map.extent[idx];
10676397fac4SChristian Brauner 		else
10686397fac4SChristian Brauner 			e = &new_map.forward[idx];
106922d917d8SEric W. Biederman 
107022d917d8SEric W. Biederman 		lower_first = map_id_range_down(parent_map,
10716397fac4SChristian Brauner 						e->lower_first,
10726397fac4SChristian Brauner 						e->count);
107322d917d8SEric W. Biederman 
107422d917d8SEric W. Biederman 		/* Fail if we can not map the specified extent to
107522d917d8SEric W. Biederman 		 * the kernel global id space.
107622d917d8SEric W. Biederman 		 */
107722d917d8SEric W. Biederman 		if (lower_first == (u32) -1)
107822d917d8SEric W. Biederman 			goto out;
107922d917d8SEric W. Biederman 
10806397fac4SChristian Brauner 		e->lower_first = lower_first;
108122d917d8SEric W. Biederman 	}
108222d917d8SEric W. Biederman 
1083d2f007dbSJann Horn 	/*
1084d2f007dbSJann Horn 	 * If we want to use binary search for lookup, this clones the extent
1085d2f007dbSJann Horn 	 * array and sorts both copies.
1086d2f007dbSJann Horn 	 */
1087d2f007dbSJann Horn 	ret = sort_idmaps(&new_map);
1088d2f007dbSJann Horn 	if (ret < 0)
1089d2f007dbSJann Horn 		goto out;
1090d2f007dbSJann Horn 
109122d917d8SEric W. Biederman 	/* Install the map */
10926397fac4SChristian Brauner 	if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) {
109322d917d8SEric W. Biederman 		memcpy(map->extent, new_map.extent,
109422d917d8SEric W. Biederman 		       new_map.nr_extents * sizeof(new_map.extent[0]));
10956397fac4SChristian Brauner 	} else {
10966397fac4SChristian Brauner 		map->forward = new_map.forward;
10976397fac4SChristian Brauner 		map->reverse = new_map.reverse;
10986397fac4SChristian Brauner 	}
109922d917d8SEric W. Biederman 	smp_wmb();
110022d917d8SEric W. Biederman 	map->nr_extents = new_map.nr_extents;
110122d917d8SEric W. Biederman 
110222d917d8SEric W. Biederman 	*ppos = count;
110322d917d8SEric W. Biederman 	ret = count;
110422d917d8SEric W. Biederman out:
11056397fac4SChristian Brauner 	if (ret < 0 && new_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) {
11066397fac4SChristian Brauner 		kfree(new_map.forward);
11076397fac4SChristian Brauner 		kfree(new_map.reverse);
11086397fac4SChristian Brauner 		map->forward = NULL;
11096397fac4SChristian Brauner 		map->reverse = NULL;
11106397fac4SChristian Brauner 		map->nr_extents = 0;
11116397fac4SChristian Brauner 	}
11126397fac4SChristian Brauner 
1113f0d62aecSEric W. Biederman 	mutex_unlock(&userns_state_mutex);
111470f6cbb6SAl Viro 	kfree(kbuf);
111522d917d8SEric W. Biederman 	return ret;
111622d917d8SEric W. Biederman }
111722d917d8SEric W. Biederman 
proc_uid_map_write(struct file * file,const char __user * buf,size_t size,loff_t * ppos)111868a9a435SFabian Frederick ssize_t proc_uid_map_write(struct file *file, const char __user *buf,
111968a9a435SFabian Frederick 			   size_t size, loff_t *ppos)
112022d917d8SEric W. Biederman {
112122d917d8SEric W. Biederman 	struct seq_file *seq = file->private_data;
112222d917d8SEric W. Biederman 	struct user_namespace *ns = seq->private;
1123c450f371SEric W. Biederman 	struct user_namespace *seq_ns = seq_user_ns(seq);
112422d917d8SEric W. Biederman 
112522d917d8SEric W. Biederman 	if (!ns->parent)
112622d917d8SEric W. Biederman 		return -EPERM;
112722d917d8SEric W. Biederman 
1128c450f371SEric W. Biederman 	if ((seq_ns != ns) && (seq_ns != ns->parent))
1129c450f371SEric W. Biederman 		return -EPERM;
1130c450f371SEric W. Biederman 
113122d917d8SEric W. Biederman 	return map_write(file, buf, size, ppos, CAP_SETUID,
113222d917d8SEric W. Biederman 			 &ns->uid_map, &ns->parent->uid_map);
113322d917d8SEric W. Biederman }
113422d917d8SEric W. Biederman 
proc_gid_map_write(struct file * file,const char __user * buf,size_t size,loff_t * ppos)113568a9a435SFabian Frederick ssize_t proc_gid_map_write(struct file *file, const char __user *buf,
113668a9a435SFabian Frederick 			   size_t size, loff_t *ppos)
113722d917d8SEric W. Biederman {
113822d917d8SEric W. Biederman 	struct seq_file *seq = file->private_data;
113922d917d8SEric W. Biederman 	struct user_namespace *ns = seq->private;
1140c450f371SEric W. Biederman 	struct user_namespace *seq_ns = seq_user_ns(seq);
114122d917d8SEric W. Biederman 
114222d917d8SEric W. Biederman 	if (!ns->parent)
114322d917d8SEric W. Biederman 		return -EPERM;
114422d917d8SEric W. Biederman 
1145c450f371SEric W. Biederman 	if ((seq_ns != ns) && (seq_ns != ns->parent))
1146c450f371SEric W. Biederman 		return -EPERM;
1147c450f371SEric W. Biederman 
114822d917d8SEric W. Biederman 	return map_write(file, buf, size, ppos, CAP_SETGID,
114922d917d8SEric W. Biederman 			 &ns->gid_map, &ns->parent->gid_map);
115022d917d8SEric W. Biederman }
115122d917d8SEric W. Biederman 
proc_projid_map_write(struct file * file,const char __user * buf,size_t size,loff_t * ppos)115268a9a435SFabian Frederick ssize_t proc_projid_map_write(struct file *file, const char __user *buf,
115368a9a435SFabian Frederick 			      size_t size, loff_t *ppos)
1154f76d207aSEric W. Biederman {
1155f76d207aSEric W. Biederman 	struct seq_file *seq = file->private_data;
1156f76d207aSEric W. Biederman 	struct user_namespace *ns = seq->private;
1157f76d207aSEric W. Biederman 	struct user_namespace *seq_ns = seq_user_ns(seq);
1158f76d207aSEric W. Biederman 
1159f76d207aSEric W. Biederman 	if (!ns->parent)
1160f76d207aSEric W. Biederman 		return -EPERM;
1161f76d207aSEric W. Biederman 
1162f76d207aSEric W. Biederman 	if ((seq_ns != ns) && (seq_ns != ns->parent))
1163f76d207aSEric W. Biederman 		return -EPERM;
1164f76d207aSEric W. Biederman 
1165f76d207aSEric W. Biederman 	/* Anyone can set any valid project id no capability needed */
1166f76d207aSEric W. Biederman 	return map_write(file, buf, size, ppos, -1,
1167f76d207aSEric W. Biederman 			 &ns->projid_map, &ns->parent->projid_map);
1168f76d207aSEric W. Biederman }
1169f76d207aSEric W. Biederman 
new_idmap_permitted(const struct file * file,struct user_namespace * ns,int cap_setid,struct uid_gid_map * new_map)11706708075fSEric W. Biederman static bool new_idmap_permitted(const struct file *file,
11716708075fSEric W. Biederman 				struct user_namespace *ns, int cap_setid,
117222d917d8SEric W. Biederman 				struct uid_gid_map *new_map)
117322d917d8SEric W. Biederman {
1174f95d7918SEric W. Biederman 	const struct cred *cred = file->f_cred;
1175db2e718aSSerge E. Hallyn 
1176db2e718aSSerge E. Hallyn 	if (cap_setid == CAP_SETUID && !verify_root_map(file, ns, new_map))
1177db2e718aSSerge E. Hallyn 		return false;
1178db2e718aSSerge E. Hallyn 
11790542f17bSEric W. Biederman 	/* Don't allow mappings that would allow anything that wouldn't
11800542f17bSEric W. Biederman 	 * be allowed without the establishment of unprivileged mappings.
11810542f17bSEric W. Biederman 	 */
1182f95d7918SEric W. Biederman 	if ((new_map->nr_extents == 1) && (new_map->extent[0].count == 1) &&
1183f95d7918SEric W. Biederman 	    uid_eq(ns->owner, cred->euid)) {
118437657da3SEric W. Biederman 		u32 id = new_map->extent[0].lower_first;
118537657da3SEric W. Biederman 		if (cap_setid == CAP_SETUID) {
118637657da3SEric W. Biederman 			kuid_t uid = make_kuid(ns->parent, id);
1187f95d7918SEric W. Biederman 			if (uid_eq(uid, cred->euid))
118837657da3SEric W. Biederman 				return true;
118968a9a435SFabian Frederick 		} else if (cap_setid == CAP_SETGID) {
119037657da3SEric W. Biederman 			kgid_t gid = make_kgid(ns->parent, id);
119166d2f338SEric W. Biederman 			if (!(ns->flags & USERNS_SETGROUPS_ALLOWED) &&
119266d2f338SEric W. Biederman 			    gid_eq(gid, cred->egid))
119337657da3SEric W. Biederman 				return true;
119437657da3SEric W. Biederman 		}
119537657da3SEric W. Biederman 	}
119637657da3SEric W. Biederman 
1197f76d207aSEric W. Biederman 	/* Allow anyone to set a mapping that doesn't require privilege */
1198f76d207aSEric W. Biederman 	if (!cap_valid(cap_setid))
1199f76d207aSEric W. Biederman 		return true;
1200f76d207aSEric W. Biederman 
120122d917d8SEric W. Biederman 	/* Allow the specified ids if we have the appropriate capability
120222d917d8SEric W. Biederman 	 * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
1203a12f4f85SXiaofeng Cao 	 * And the opener of the id file also has the appropriate capability.
120422d917d8SEric W. Biederman 	 */
12056708075fSEric W. Biederman 	if (ns_capable(ns->parent, cap_setid) &&
12066708075fSEric W. Biederman 	    file_ns_capable(file, ns->parent, cap_setid))
120722d917d8SEric W. Biederman 		return true;
120822d917d8SEric W. Biederman 
120922d917d8SEric W. Biederman 	return false;
12105c1469deSEric W. Biederman }
12116164281aSPavel Emelyanov 
proc_setgroups_show(struct seq_file * seq,void * v)12129cc46516SEric W. Biederman int proc_setgroups_show(struct seq_file *seq, void *v)
12139cc46516SEric W. Biederman {
12149cc46516SEric W. Biederman 	struct user_namespace *ns = seq->private;
12156aa7de05SMark Rutland 	unsigned long userns_flags = READ_ONCE(ns->flags);
12169cc46516SEric W. Biederman 
12179cc46516SEric W. Biederman 	seq_printf(seq, "%s\n",
12189cc46516SEric W. Biederman 		   (userns_flags & USERNS_SETGROUPS_ALLOWED) ?
12199cc46516SEric W. Biederman 		   "allow" : "deny");
12209cc46516SEric W. Biederman 	return 0;
12219cc46516SEric W. Biederman }
12229cc46516SEric W. Biederman 
proc_setgroups_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)12239cc46516SEric W. Biederman ssize_t proc_setgroups_write(struct file *file, const char __user *buf,
12249cc46516SEric W. Biederman 			     size_t count, loff_t *ppos)
12259cc46516SEric W. Biederman {
12269cc46516SEric W. Biederman 	struct seq_file *seq = file->private_data;
12279cc46516SEric W. Biederman 	struct user_namespace *ns = seq->private;
12289cc46516SEric W. Biederman 	char kbuf[8], *pos;
12299cc46516SEric W. Biederman 	bool setgroups_allowed;
12309cc46516SEric W. Biederman 	ssize_t ret;
12319cc46516SEric W. Biederman 
12329cc46516SEric W. Biederman 	/* Only allow a very narrow range of strings to be written */
12339cc46516SEric W. Biederman 	ret = -EINVAL;
12349cc46516SEric W. Biederman 	if ((*ppos != 0) || (count >= sizeof(kbuf)))
12359cc46516SEric W. Biederman 		goto out;
12369cc46516SEric W. Biederman 
12379cc46516SEric W. Biederman 	/* What was written? */
12389cc46516SEric W. Biederman 	ret = -EFAULT;
12399cc46516SEric W. Biederman 	if (copy_from_user(kbuf, buf, count))
12409cc46516SEric W. Biederman 		goto out;
12419cc46516SEric W. Biederman 	kbuf[count] = '\0';
12429cc46516SEric W. Biederman 	pos = kbuf;
12439cc46516SEric W. Biederman 
12449cc46516SEric W. Biederman 	/* What is being requested? */
12459cc46516SEric W. Biederman 	ret = -EINVAL;
12469cc46516SEric W. Biederman 	if (strncmp(pos, "allow", 5) == 0) {
12479cc46516SEric W. Biederman 		pos += 5;
12489cc46516SEric W. Biederman 		setgroups_allowed = true;
12499cc46516SEric W. Biederman 	}
12509cc46516SEric W. Biederman 	else if (strncmp(pos, "deny", 4) == 0) {
12519cc46516SEric W. Biederman 		pos += 4;
12529cc46516SEric W. Biederman 		setgroups_allowed = false;
12539cc46516SEric W. Biederman 	}
12549cc46516SEric W. Biederman 	else
12559cc46516SEric W. Biederman 		goto out;
12569cc46516SEric W. Biederman 
12579cc46516SEric W. Biederman 	/* Verify there is not trailing junk on the line */
12589cc46516SEric W. Biederman 	pos = skip_spaces(pos);
12599cc46516SEric W. Biederman 	if (*pos != '\0')
12609cc46516SEric W. Biederman 		goto out;
12619cc46516SEric W. Biederman 
12629cc46516SEric W. Biederman 	ret = -EPERM;
12639cc46516SEric W. Biederman 	mutex_lock(&userns_state_mutex);
12649cc46516SEric W. Biederman 	if (setgroups_allowed) {
12659cc46516SEric W. Biederman 		/* Enabling setgroups after setgroups has been disabled
12669cc46516SEric W. Biederman 		 * is not allowed.
12679cc46516SEric W. Biederman 		 */
12689cc46516SEric W. Biederman 		if (!(ns->flags & USERNS_SETGROUPS_ALLOWED))
12699cc46516SEric W. Biederman 			goto out_unlock;
12709cc46516SEric W. Biederman 	} else {
12719cc46516SEric W. Biederman 		/* Permanently disabling setgroups after setgroups has
12729cc46516SEric W. Biederman 		 * been enabled by writing the gid_map is not allowed.
12739cc46516SEric W. Biederman 		 */
12749cc46516SEric W. Biederman 		if (ns->gid_map.nr_extents != 0)
12759cc46516SEric W. Biederman 			goto out_unlock;
12769cc46516SEric W. Biederman 		ns->flags &= ~USERNS_SETGROUPS_ALLOWED;
12779cc46516SEric W. Biederman 	}
12789cc46516SEric W. Biederman 	mutex_unlock(&userns_state_mutex);
12799cc46516SEric W. Biederman 
12809cc46516SEric W. Biederman 	/* Report a successful write */
12819cc46516SEric W. Biederman 	*ppos = count;
12829cc46516SEric W. Biederman 	ret = count;
12839cc46516SEric W. Biederman out:
12849cc46516SEric W. Biederman 	return ret;
12859cc46516SEric W. Biederman out_unlock:
12869cc46516SEric W. Biederman 	mutex_unlock(&userns_state_mutex);
12879cc46516SEric W. Biederman 	goto out;
12889cc46516SEric W. Biederman }
12899cc46516SEric W. Biederman 
userns_may_setgroups(const struct user_namespace * ns)1290273d2c67SEric W. Biederman bool userns_may_setgroups(const struct user_namespace *ns)
1291273d2c67SEric W. Biederman {
1292273d2c67SEric W. Biederman 	bool allowed;
1293273d2c67SEric W. Biederman 
1294f0d62aecSEric W. Biederman 	mutex_lock(&userns_state_mutex);
1295273d2c67SEric W. Biederman 	/* It is not safe to use setgroups until a gid mapping in
1296273d2c67SEric W. Biederman 	 * the user namespace has been established.
1297273d2c67SEric W. Biederman 	 */
1298273d2c67SEric W. Biederman 	allowed = ns->gid_map.nr_extents != 0;
12999cc46516SEric W. Biederman 	/* Is setgroups allowed? */
13009cc46516SEric W. Biederman 	allowed = allowed && (ns->flags & USERNS_SETGROUPS_ALLOWED);
1301f0d62aecSEric W. Biederman 	mutex_unlock(&userns_state_mutex);
1302273d2c67SEric W. Biederman 
1303273d2c67SEric W. Biederman 	return allowed;
1304273d2c67SEric W. Biederman }
1305273d2c67SEric W. Biederman 
1306d07b846fSSeth Forshee /*
1307a2b42626SEric W. Biederman  * Returns true if @child is the same namespace or a descendant of
1308a2b42626SEric W. Biederman  * @ancestor.
1309d07b846fSSeth Forshee  */
in_userns(const struct user_namespace * ancestor,const struct user_namespace * child)1310a2b42626SEric W. Biederman bool in_userns(const struct user_namespace *ancestor,
1311a2b42626SEric W. Biederman 	       const struct user_namespace *child)
1312a2b42626SEric W. Biederman {
1313a2b42626SEric W. Biederman 	const struct user_namespace *ns;
1314a2b42626SEric W. Biederman 	for (ns = child; ns->level > ancestor->level; ns = ns->parent)
1315a2b42626SEric W. Biederman 		;
1316a2b42626SEric W. Biederman 	return (ns == ancestor);
1317a2b42626SEric W. Biederman }
1318a2b42626SEric W. Biederman 
current_in_userns(const struct user_namespace * target_ns)1319d07b846fSSeth Forshee bool current_in_userns(const struct user_namespace *target_ns)
1320d07b846fSSeth Forshee {
1321a2b42626SEric W. Biederman 	return in_userns(target_ns, current_user_ns());
1322d07b846fSSeth Forshee }
132373f03c2bSSeth Forshee EXPORT_SYMBOL(current_in_userns);
1324d07b846fSSeth Forshee 
to_user_ns(struct ns_common * ns)13253c041184SAl Viro static inline struct user_namespace *to_user_ns(struct ns_common *ns)
13263c041184SAl Viro {
13273c041184SAl Viro 	return container_of(ns, struct user_namespace, ns);
13283c041184SAl Viro }
13293c041184SAl Viro 
userns_get(struct task_struct * task)133064964528SAl Viro static struct ns_common *userns_get(struct task_struct *task)
1331cde1975bSEric W. Biederman {
1332cde1975bSEric W. Biederman 	struct user_namespace *user_ns;
1333cde1975bSEric W. Biederman 
1334cde1975bSEric W. Biederman 	rcu_read_lock();
1335cde1975bSEric W. Biederman 	user_ns = get_user_ns(__task_cred(task)->user_ns);
1336cde1975bSEric W. Biederman 	rcu_read_unlock();
1337cde1975bSEric W. Biederman 
13383c041184SAl Viro 	return user_ns ? &user_ns->ns : NULL;
1339cde1975bSEric W. Biederman }
1340cde1975bSEric W. Biederman 
userns_put(struct ns_common * ns)134164964528SAl Viro static void userns_put(struct ns_common *ns)
1342cde1975bSEric W. Biederman {
13433c041184SAl Viro 	put_user_ns(to_user_ns(ns));
1344cde1975bSEric W. Biederman }
1345cde1975bSEric W. Biederman 
userns_install(struct nsset * nsset,struct ns_common * ns)1346f2a8d52eSChristian Brauner static int userns_install(struct nsset *nsset, struct ns_common *ns)
1347cde1975bSEric W. Biederman {
13483c041184SAl Viro 	struct user_namespace *user_ns = to_user_ns(ns);
1349cde1975bSEric W. Biederman 	struct cred *cred;
1350cde1975bSEric W. Biederman 
1351cde1975bSEric W. Biederman 	/* Don't allow gaining capabilities by reentering
1352cde1975bSEric W. Biederman 	 * the same user namespace.
1353cde1975bSEric W. Biederman 	 */
1354cde1975bSEric W. Biederman 	if (user_ns == current_user_ns())
1355cde1975bSEric W. Biederman 		return -EINVAL;
1356cde1975bSEric W. Biederman 
1357faf00da5SEric W. Biederman 	/* Tasks that share a thread group must share a user namespace */
1358faf00da5SEric W. Biederman 	if (!thread_group_empty(current))
1359cde1975bSEric W. Biederman 		return -EINVAL;
1360cde1975bSEric W. Biederman 
1361e66eded8SEric W. Biederman 	if (current->fs->users != 1)
1362e66eded8SEric W. Biederman 		return -EINVAL;
1363e66eded8SEric W. Biederman 
1364cde1975bSEric W. Biederman 	if (!ns_capable(user_ns, CAP_SYS_ADMIN))
1365cde1975bSEric W. Biederman 		return -EPERM;
1366cde1975bSEric W. Biederman 
1367f2a8d52eSChristian Brauner 	cred = nsset_cred(nsset);
1368cde1975bSEric W. Biederman 	if (!cred)
1369f2a8d52eSChristian Brauner 		return -EINVAL;
1370cde1975bSEric W. Biederman 
1371cde1975bSEric W. Biederman 	put_user_ns(cred->user_ns);
1372cde1975bSEric W. Biederman 	set_cred_user_ns(cred, get_user_ns(user_ns));
1373cde1975bSEric W. Biederman 
1374905ae01cSAlexey Gladkov 	if (set_cred_ucounts(cred) < 0)
1375905ae01cSAlexey Gladkov 		return -EINVAL;
1376905ae01cSAlexey Gladkov 
1377f2a8d52eSChristian Brauner 	return 0;
1378cde1975bSEric W. Biederman }
1379cde1975bSEric W. Biederman 
ns_get_owner(struct ns_common * ns)1380bcac25a5SAndrey Vagin struct ns_common *ns_get_owner(struct ns_common *ns)
1381bcac25a5SAndrey Vagin {
1382bcac25a5SAndrey Vagin 	struct user_namespace *my_user_ns = current_user_ns();
1383bcac25a5SAndrey Vagin 	struct user_namespace *owner, *p;
1384bcac25a5SAndrey Vagin 
1385bcac25a5SAndrey Vagin 	/* See if the owner is in the current user namespace */
1386bcac25a5SAndrey Vagin 	owner = p = ns->ops->owner(ns);
1387bcac25a5SAndrey Vagin 	for (;;) {
1388bcac25a5SAndrey Vagin 		if (!p)
1389bcac25a5SAndrey Vagin 			return ERR_PTR(-EPERM);
1390bcac25a5SAndrey Vagin 		if (p == my_user_ns)
1391bcac25a5SAndrey Vagin 			break;
1392bcac25a5SAndrey Vagin 		p = p->parent;
1393bcac25a5SAndrey Vagin 	}
1394bcac25a5SAndrey Vagin 
1395bcac25a5SAndrey Vagin 	return &get_user_ns(owner)->ns;
1396bcac25a5SAndrey Vagin }
1397bcac25a5SAndrey Vagin 
userns_owner(struct ns_common * ns)1398bcac25a5SAndrey Vagin static struct user_namespace *userns_owner(struct ns_common *ns)
1399bcac25a5SAndrey Vagin {
1400bcac25a5SAndrey Vagin 	return to_user_ns(ns)->parent;
1401bcac25a5SAndrey Vagin }
1402bcac25a5SAndrey Vagin 
1403cde1975bSEric W. Biederman const struct proc_ns_operations userns_operations = {
1404cde1975bSEric W. Biederman 	.name		= "user",
1405cde1975bSEric W. Biederman 	.type		= CLONE_NEWUSER,
1406cde1975bSEric W. Biederman 	.get		= userns_get,
1407cde1975bSEric W. Biederman 	.put		= userns_put,
1408cde1975bSEric W. Biederman 	.install	= userns_install,
1409bcac25a5SAndrey Vagin 	.owner		= userns_owner,
1410a7306ed8SAndrey Vagin 	.get_parent	= ns_get_owner,
1411cde1975bSEric W. Biederman };
1412cde1975bSEric W. Biederman 
user_namespaces_init(void)14136164281aSPavel Emelyanov static __init int user_namespaces_init(void)
14146164281aSPavel Emelyanov {
141530acd0bdSVasily Averin 	user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC | SLAB_ACCOUNT);
14166164281aSPavel Emelyanov 	return 0;
14176164281aSPavel Emelyanov }
1418c96d6660SPaul Gortmaker subsys_initcall(user_namespaces_init);
1419