xref: /openbmc/linux/kernel/user.c (revision ce5a23c8)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * The "user cache".
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * (C) Copyright 1991-2000 Linus Torvalds
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * We have a per-user structure to keep track of how many
81da177e4SLinus Torvalds  * processes, files etc the user has claimed, in order to be
91da177e4SLinus Torvalds  * able to have per-user limits for system resources.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/init.h>
131da177e4SLinus Torvalds #include <linux/sched.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
151da177e4SLinus Torvalds #include <linux/bitops.h>
161da177e4SLinus Torvalds #include <linux/key.h>
178703e8a4SIngo Molnar #include <linux/sched/user.h>
184021cb27SIngo Molnar #include <linux/interrupt.h>
199984de1aSPaul Gortmaker #include <linux/export.h>
20acce292cSCedric Le Goater #include <linux/user_namespace.h>
210bb80f24SDavid Howells #include <linux/proc_ns.h>
221da177e4SLinus Torvalds 
2359607db3SSerge E. Hallyn /*
2459607db3SSerge E. Hallyn  * userns count is 1 for root user, 1 for init_uts_ns,
2559607db3SSerge E. Hallyn  * and 1 for... ?
2659607db3SSerge E. Hallyn  */
27aee16ce7SPavel Emelyanov struct user_namespace init_user_ns = {
2822d917d8SEric W. Biederman 	.uid_map = {
2922d917d8SEric W. Biederman 		.nr_extents = 1,
30aa4bf44dSChristian Brauner 		{
3122d917d8SEric W. Biederman 			.extent[0] = {
3222d917d8SEric W. Biederman 				.first = 0,
3322d917d8SEric W. Biederman 				.lower_first = 0,
344b06a81fSEric W. Biederman 				.count = 4294967295U,
3522d917d8SEric W. Biederman 			},
3622d917d8SEric W. Biederman 		},
37aa4bf44dSChristian Brauner 	},
3822d917d8SEric W. Biederman 	.gid_map = {
3922d917d8SEric W. Biederman 		.nr_extents = 1,
40aa4bf44dSChristian Brauner 		{
4122d917d8SEric W. Biederman 			.extent[0] = {
4222d917d8SEric W. Biederman 				.first = 0,
4322d917d8SEric W. Biederman 				.lower_first = 0,
444b06a81fSEric W. Biederman 				.count = 4294967295U,
4522d917d8SEric W. Biederman 			},
4622d917d8SEric W. Biederman 		},
47aa4bf44dSChristian Brauner 	},
48f76d207aSEric W. Biederman 	.projid_map = {
49f76d207aSEric W. Biederman 		.nr_extents = 1,
50aa4bf44dSChristian Brauner 		{
51f76d207aSEric W. Biederman 			.extent[0] = {
52f76d207aSEric W. Biederman 				.first = 0,
53f76d207aSEric W. Biederman 				.lower_first = 0,
54f76d207aSEric W. Biederman 				.count = 4294967295U,
55f76d207aSEric W. Biederman 			},
56f76d207aSEric W. Biederman 		},
57aa4bf44dSChristian Brauner 	},
58265cbd62SKirill Tkhai 	.ns.count = REFCOUNT_INIT(3),
59783291e6SEric W. Biederman 	.owner = GLOBAL_ROOT_UID,
60783291e6SEric W. Biederman 	.group = GLOBAL_ROOT_GID,
61435d5f4bSAl Viro 	.ns.inum = PROC_USER_INIT_INO,
6233c42940SAl Viro #ifdef CONFIG_USER_NS
6333c42940SAl Viro 	.ns.ops = &userns_operations,
6433c42940SAl Viro #endif
659cc46516SEric W. Biederman 	.flags = USERNS_INIT_FLAGS,
66b206f281SDavid Howells #ifdef CONFIG_KEYS
67b206f281SDavid Howells 	.keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
680f44e4d9SDavid Howells 	.keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem),
69f36f8c75SDavid Howells #endif
70aee16ce7SPavel Emelyanov };
71aee16ce7SPavel Emelyanov EXPORT_SYMBOL_GPL(init_user_ns);
72aee16ce7SPavel Emelyanov 
731da177e4SLinus Torvalds /*
741da177e4SLinus Torvalds  * UID task count cache, to get fast user lookup in "alloc_uid"
751da177e4SLinus Torvalds  * when changing user ID's (ie setuid() and friends).
761da177e4SLinus Torvalds  */
771da177e4SLinus Torvalds 
787b44ab97SEric W. Biederman #define UIDHASH_BITS	(CONFIG_BASE_SMALL ? 3 : 7)
797b44ab97SEric W. Biederman #define UIDHASH_SZ	(1 << UIDHASH_BITS)
801da177e4SLinus Torvalds #define UIDHASH_MASK		(UIDHASH_SZ - 1)
811da177e4SLinus Torvalds #define __uidhashfn(uid)	(((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
827b44ab97SEric W. Biederman #define uidhashentry(uid)	(uidhash_table + __uidhashfn((__kuid_val(uid))))
831da177e4SLinus Torvalds 
84e18b890bSChristoph Lameter static struct kmem_cache *uid_cachep;
85de83dbd9SJason Yan static struct hlist_head uidhash_table[UIDHASH_SZ];
864021cb27SIngo Molnar 
874021cb27SIngo Molnar /*
884021cb27SIngo Molnar  * The uidhash_lock is mostly taken from process context, but it is
894021cb27SIngo Molnar  * occasionally also taken from softirq/tasklet context, when
904021cb27SIngo Molnar  * task-structs get RCU-freed. Hence all locking must be softirq-safe.
913fa97c9dSAndrew Morton  * But free_uid() is also called with local interrupts disabled, and running
923fa97c9dSAndrew Morton  * local_bh_enable() with local interrupts disabled is an error - we'll run
933fa97c9dSAndrew Morton  * softirq callbacks, and they can unconditionally enable interrupts, and
943fa97c9dSAndrew Morton  * the caller of free_uid() didn't expect that..
954021cb27SIngo Molnar  */
961da177e4SLinus Torvalds static DEFINE_SPINLOCK(uidhash_lock);
971da177e4SLinus Torvalds 
98783291e6SEric W. Biederman /* root_user.__count is 1, for init task cred */
991da177e4SLinus Torvalds struct user_struct root_user = {
100fc371912SSebastian Andrzej Siewior 	.__count	= REFCOUNT_INIT(1),
1017b44ab97SEric W. Biederman 	.uid		= GLOBAL_ROOT_UID,
102bef3efbeSLuck, Tony 	.ratelimit	= RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),
1031da177e4SLinus Torvalds };
1041da177e4SLinus Torvalds 
1055cb350baSDhaval Giani /*
1065cb350baSDhaval Giani  * These routines must be called with the uidhash spinlock held!
1075cb350baSDhaval Giani  */
uid_hash_insert(struct user_struct * up,struct hlist_head * hashent)10840aeb400SAlexey Dobriyan static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
1095cb350baSDhaval Giani {
1105cb350baSDhaval Giani 	hlist_add_head(&up->uidhash_node, hashent);
1115cb350baSDhaval Giani }
1125cb350baSDhaval Giani 
uid_hash_remove(struct user_struct * up)11340aeb400SAlexey Dobriyan static void uid_hash_remove(struct user_struct *up)
1145cb350baSDhaval Giani {
1155cb350baSDhaval Giani 	hlist_del_init(&up->uidhash_node);
1165cb350baSDhaval Giani }
1175cb350baSDhaval Giani 
uid_hash_find(kuid_t uid,struct hlist_head * hashent)1187b44ab97SEric W. Biederman static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
1193959214fSKay Sievers {
1203959214fSKay Sievers 	struct user_struct *user;
1213959214fSKay Sievers 
122b67bfe0dSSasha Levin 	hlist_for_each_entry(user, hashent, uidhash_node) {
1237b44ab97SEric W. Biederman 		if (uid_eq(user->uid, uid)) {
124fc371912SSebastian Andrzej Siewior 			refcount_inc(&user->__count);
1253959214fSKay Sievers 			return user;
1263959214fSKay Sievers 		}
1273959214fSKay Sievers 	}
1283959214fSKay Sievers 
1293959214fSKay Sievers 	return NULL;
1303959214fSKay Sievers }
1313959214fSKay Sievers 
user_epoll_alloc(struct user_struct * up)1321e1c1583SNicholas Piggin static int user_epoll_alloc(struct user_struct *up)
1331e1c1583SNicholas Piggin {
1341e1c1583SNicholas Piggin #ifdef CONFIG_EPOLL
1351e1c1583SNicholas Piggin 	return percpu_counter_init(&up->epoll_watches, 0, GFP_KERNEL);
1361e1c1583SNicholas Piggin #else
1371e1c1583SNicholas Piggin 	return 0;
1381e1c1583SNicholas Piggin #endif
1391e1c1583SNicholas Piggin }
1401e1c1583SNicholas Piggin 
user_epoll_free(struct user_struct * up)1411e1c1583SNicholas Piggin static void user_epoll_free(struct user_struct *up)
1421e1c1583SNicholas Piggin {
1431e1c1583SNicholas Piggin #ifdef CONFIG_EPOLL
1441e1c1583SNicholas Piggin 	percpu_counter_destroy(&up->epoll_watches);
1451e1c1583SNicholas Piggin #endif
1461e1c1583SNicholas Piggin }
1471e1c1583SNicholas Piggin 
1485cb350baSDhaval Giani /* IRQs are disabled and uidhash_lock is held upon function entry.
1495cb350baSDhaval Giani  * IRQ state (as stored in flags) is restored and uidhash_lock released
1505cb350baSDhaval Giani  * upon function exit.
1515cb350baSDhaval Giani  */
free_user(struct user_struct * up,unsigned long flags)15218b6e041SSerge Hallyn static void free_user(struct user_struct *up, unsigned long flags)
153571428beSNamhyung Kim 	__releases(&uidhash_lock)
1545cb350baSDhaval Giani {
1555cb350baSDhaval Giani 	uid_hash_remove(up);
1565cb350baSDhaval Giani 	spin_unlock_irqrestore(&uidhash_lock, flags);
1571e1c1583SNicholas Piggin 	user_epoll_free(up);
1585cb350baSDhaval Giani 	kmem_cache_free(uid_cachep, up);
1595cb350baSDhaval Giani }
16024e377a8SSrivatsa Vaddagiri 
1611da177e4SLinus Torvalds /*
1621da177e4SLinus Torvalds  * Locate the user_struct for the passed UID.  If found, take a ref on it.  The
1631da177e4SLinus Torvalds  * caller must undo that ref with free_uid().
1641da177e4SLinus Torvalds  *
1651da177e4SLinus Torvalds  * If the user_struct could not be found, return NULL.
1661da177e4SLinus Torvalds  */
find_user(kuid_t uid)1677b44ab97SEric W. Biederman struct user_struct *find_user(kuid_t uid)
1681da177e4SLinus Torvalds {
1691da177e4SLinus Torvalds 	struct user_struct *ret;
1703fa97c9dSAndrew Morton 	unsigned long flags;
1711da177e4SLinus Torvalds 
1723fa97c9dSAndrew Morton 	spin_lock_irqsave(&uidhash_lock, flags);
1737b44ab97SEric W. Biederman 	ret = uid_hash_find(uid, uidhashentry(uid));
1743fa97c9dSAndrew Morton 	spin_unlock_irqrestore(&uidhash_lock, flags);
1751da177e4SLinus Torvalds 	return ret;
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds 
free_uid(struct user_struct * up)1781da177e4SLinus Torvalds void free_uid(struct user_struct *up)
1791da177e4SLinus Torvalds {
1803fa97c9dSAndrew Morton 	unsigned long flags;
1813fa97c9dSAndrew Morton 
18236f57413SAndrew Morton 	if (!up)
18336f57413SAndrew Morton 		return;
18436f57413SAndrew Morton 
185ce0a568dSAnna-Maria Gleixner 	if (refcount_dec_and_lock_irqsave(&up->__count, &uidhash_lock, &flags))
1865cb350baSDhaval Giani 		free_user(up, flags);
1871da177e4SLinus Torvalds }
188*ce5a23c8SJason Gunthorpe EXPORT_SYMBOL_GPL(free_uid);
1891da177e4SLinus Torvalds 
alloc_uid(kuid_t uid)1907b44ab97SEric W. Biederman struct user_struct *alloc_uid(kuid_t uid)
1911da177e4SLinus Torvalds {
1927b44ab97SEric W. Biederman 	struct hlist_head *hashent = uidhashentry(uid);
1938eb703e4SPavel Emelyanov 	struct user_struct *up, *new;
1941da177e4SLinus Torvalds 
1953fa97c9dSAndrew Morton 	spin_lock_irq(&uidhash_lock);
1961da177e4SLinus Torvalds 	up = uid_hash_find(uid, hashent);
1973fa97c9dSAndrew Morton 	spin_unlock_irq(&uidhash_lock);
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	if (!up) {
200354a1f4dSAndrew Morton 		new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL);
2018eb703e4SPavel Emelyanov 		if (!new)
2026c4e121fSRasmus Villemoes 			return NULL;
2035e8869bbSPavel Emelyanov 
2041da177e4SLinus Torvalds 		new->uid = uid;
205fc371912SSebastian Andrzej Siewior 		refcount_set(&new->__count, 1);
2061e1c1583SNicholas Piggin 		if (user_epoll_alloc(new)) {
2071e1c1583SNicholas Piggin 			kmem_cache_free(uid_cachep, new);
2081e1c1583SNicholas Piggin 			return NULL;
2091e1c1583SNicholas Piggin 		}
210bef3efbeSLuck, Tony 		ratelimit_state_init(&new->ratelimit, HZ, 100);
211bef3efbeSLuck, Tony 		ratelimit_set_flags(&new->ratelimit, RATELIMIT_MSG_ON_RELEASE);
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 		/*
2141da177e4SLinus Torvalds 		 * Before adding this, check whether we raced
2151da177e4SLinus Torvalds 		 * on adding the same user already..
2161da177e4SLinus Torvalds 		 */
2173fa97c9dSAndrew Morton 		spin_lock_irq(&uidhash_lock);
2181da177e4SLinus Torvalds 		up = uid_hash_find(uid, hashent);
2191da177e4SLinus Torvalds 		if (up) {
2201e1c1583SNicholas Piggin 			user_epoll_free(new);
2211da177e4SLinus Torvalds 			kmem_cache_free(uid_cachep, new);
2221da177e4SLinus Torvalds 		} else {
2231da177e4SLinus Torvalds 			uid_hash_insert(new, hashent);
2241da177e4SLinus Torvalds 			up = new;
2251da177e4SLinus Torvalds 		}
2263fa97c9dSAndrew Morton 		spin_unlock_irq(&uidhash_lock);
2271da177e4SLinus Torvalds 	}
2285cb350baSDhaval Giani 
2291da177e4SLinus Torvalds 	return up;
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds 
uid_cache_init(void)2321da177e4SLinus Torvalds static int __init uid_cache_init(void)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	int n;
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
23720c2df83SPaul Mundt 			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	for(n = 0; n < UIDHASH_SZ; ++n)
2407b44ab97SEric W. Biederman 		INIT_HLIST_HEAD(uidhash_table + n);
2411da177e4SLinus Torvalds 
2421e1c1583SNicholas Piggin 	if (user_epoll_alloc(&root_user))
2431e1c1583SNicholas Piggin 		panic("root_user epoll percpu counter alloc failed");
2441e1c1583SNicholas Piggin 
2451da177e4SLinus Torvalds 	/* Insert the root user immediately (init already runs as root) */
2463fa97c9dSAndrew Morton 	spin_lock_irq(&uidhash_lock);
2477b44ab97SEric W. Biederman 	uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
2483fa97c9dSAndrew Morton 	spin_unlock_irq(&uidhash_lock);
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	return 0;
2511da177e4SLinus Torvalds }
252c96d6660SPaul Gortmaker subsys_initcall(uid_cache_init);
253