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