cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ucount.c (9305B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3#include <linux/stat.h>
      4#include <linux/sysctl.h>
      5#include <linux/slab.h>
      6#include <linux/cred.h>
      7#include <linux/hash.h>
      8#include <linux/kmemleak.h>
      9#include <linux/user_namespace.h>
     10
     11struct ucounts init_ucounts = {
     12	.ns    = &init_user_ns,
     13	.uid   = GLOBAL_ROOT_UID,
     14	.count = ATOMIC_INIT(1),
     15};
     16
     17#define UCOUNTS_HASHTABLE_BITS 10
     18static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
     19static DEFINE_SPINLOCK(ucounts_lock);
     20
     21#define ucounts_hashfn(ns, uid)						\
     22	hash_long((unsigned long)__kuid_val(uid) + (unsigned long)(ns), \
     23		  UCOUNTS_HASHTABLE_BITS)
     24#define ucounts_hashentry(ns, uid)	\
     25	(ucounts_hashtable + ucounts_hashfn(ns, uid))
     26
     27
     28#ifdef CONFIG_SYSCTL
     29static struct ctl_table_set *
     30set_lookup(struct ctl_table_root *root)
     31{
     32	return &current_user_ns()->set;
     33}
     34
     35static int set_is_seen(struct ctl_table_set *set)
     36{
     37	return &current_user_ns()->set == set;
     38}
     39
     40static int set_permissions(struct ctl_table_header *head,
     41				  struct ctl_table *table)
     42{
     43	struct user_namespace *user_ns =
     44		container_of(head->set, struct user_namespace, set);
     45	int mode;
     46
     47	/* Allow users with CAP_SYS_RESOURCE unrestrained access */
     48	if (ns_capable(user_ns, CAP_SYS_RESOURCE))
     49		mode = (table->mode & S_IRWXU) >> 6;
     50	else
     51	/* Allow all others at most read-only access */
     52		mode = table->mode & S_IROTH;
     53	return (mode << 6) | (mode << 3) | mode;
     54}
     55
     56static struct ctl_table_root set_root = {
     57	.lookup = set_lookup,
     58	.permissions = set_permissions,
     59};
     60
     61static long ue_zero = 0;
     62static long ue_int_max = INT_MAX;
     63
     64#define UCOUNT_ENTRY(name)					\
     65	{							\
     66		.procname	= name,				\
     67		.maxlen		= sizeof(long),			\
     68		.mode		= 0644,				\
     69		.proc_handler	= proc_doulongvec_minmax,	\
     70		.extra1		= &ue_zero,			\
     71		.extra2		= &ue_int_max,			\
     72	}
     73static struct ctl_table user_table[] = {
     74	UCOUNT_ENTRY("max_user_namespaces"),
     75	UCOUNT_ENTRY("max_pid_namespaces"),
     76	UCOUNT_ENTRY("max_uts_namespaces"),
     77	UCOUNT_ENTRY("max_ipc_namespaces"),
     78	UCOUNT_ENTRY("max_net_namespaces"),
     79	UCOUNT_ENTRY("max_mnt_namespaces"),
     80	UCOUNT_ENTRY("max_cgroup_namespaces"),
     81	UCOUNT_ENTRY("max_time_namespaces"),
     82#ifdef CONFIG_INOTIFY_USER
     83	UCOUNT_ENTRY("max_inotify_instances"),
     84	UCOUNT_ENTRY("max_inotify_watches"),
     85#endif
     86#ifdef CONFIG_FANOTIFY
     87	UCOUNT_ENTRY("max_fanotify_groups"),
     88	UCOUNT_ENTRY("max_fanotify_marks"),
     89#endif
     90	{ },
     91	{ },
     92	{ },
     93	{ },
     94	{ }
     95};
     96#endif /* CONFIG_SYSCTL */
     97
     98bool setup_userns_sysctls(struct user_namespace *ns)
     99{
    100#ifdef CONFIG_SYSCTL
    101	struct ctl_table *tbl;
    102
    103	BUILD_BUG_ON(ARRAY_SIZE(user_table) != UCOUNT_COUNTS + 1);
    104	setup_sysctl_set(&ns->set, &set_root, set_is_seen);
    105	tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL);
    106	if (tbl) {
    107		int i;
    108		for (i = 0; i < UCOUNT_COUNTS; i++) {
    109			tbl[i].data = &ns->ucount_max[i];
    110		}
    111		ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
    112	}
    113	if (!ns->sysctls) {
    114		kfree(tbl);
    115		retire_sysctl_set(&ns->set);
    116		return false;
    117	}
    118#endif
    119	return true;
    120}
    121
    122void retire_userns_sysctls(struct user_namespace *ns)
    123{
    124#ifdef CONFIG_SYSCTL
    125	struct ctl_table *tbl;
    126
    127	tbl = ns->sysctls->ctl_table_arg;
    128	unregister_sysctl_table(ns->sysctls);
    129	retire_sysctl_set(&ns->set);
    130	kfree(tbl);
    131#endif
    132}
    133
    134static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struct hlist_head *hashent)
    135{
    136	struct ucounts *ucounts;
    137
    138	hlist_for_each_entry(ucounts, hashent, node) {
    139		if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns))
    140			return ucounts;
    141	}
    142	return NULL;
    143}
    144
    145static void hlist_add_ucounts(struct ucounts *ucounts)
    146{
    147	struct hlist_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid);
    148	spin_lock_irq(&ucounts_lock);
    149	hlist_add_head(&ucounts->node, hashent);
    150	spin_unlock_irq(&ucounts_lock);
    151}
    152
    153static inline bool get_ucounts_or_wrap(struct ucounts *ucounts)
    154{
    155	/* Returns true on a successful get, false if the count wraps. */
    156	return !atomic_add_negative(1, &ucounts->count);
    157}
    158
    159struct ucounts *get_ucounts(struct ucounts *ucounts)
    160{
    161	if (!get_ucounts_or_wrap(ucounts)) {
    162		put_ucounts(ucounts);
    163		ucounts = NULL;
    164	}
    165	return ucounts;
    166}
    167
    168struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
    169{
    170	struct hlist_head *hashent = ucounts_hashentry(ns, uid);
    171	struct ucounts *ucounts, *new;
    172	bool wrapped;
    173
    174	spin_lock_irq(&ucounts_lock);
    175	ucounts = find_ucounts(ns, uid, hashent);
    176	if (!ucounts) {
    177		spin_unlock_irq(&ucounts_lock);
    178
    179		new = kzalloc(sizeof(*new), GFP_KERNEL);
    180		if (!new)
    181			return NULL;
    182
    183		new->ns = ns;
    184		new->uid = uid;
    185		atomic_set(&new->count, 1);
    186
    187		spin_lock_irq(&ucounts_lock);
    188		ucounts = find_ucounts(ns, uid, hashent);
    189		if (ucounts) {
    190			kfree(new);
    191		} else {
    192			hlist_add_head(&new->node, hashent);
    193			get_user_ns(new->ns);
    194			spin_unlock_irq(&ucounts_lock);
    195			return new;
    196		}
    197	}
    198	wrapped = !get_ucounts_or_wrap(ucounts);
    199	spin_unlock_irq(&ucounts_lock);
    200	if (wrapped) {
    201		put_ucounts(ucounts);
    202		return NULL;
    203	}
    204	return ucounts;
    205}
    206
    207void put_ucounts(struct ucounts *ucounts)
    208{
    209	unsigned long flags;
    210
    211	if (atomic_dec_and_lock_irqsave(&ucounts->count, &ucounts_lock, flags)) {
    212		hlist_del_init(&ucounts->node);
    213		spin_unlock_irqrestore(&ucounts_lock, flags);
    214		put_user_ns(ucounts->ns);
    215		kfree(ucounts);
    216	}
    217}
    218
    219static inline bool atomic_long_inc_below(atomic_long_t *v, int u)
    220{
    221	long c, old;
    222	c = atomic_long_read(v);
    223	for (;;) {
    224		if (unlikely(c >= u))
    225			return false;
    226		old = atomic_long_cmpxchg(v, c, c+1);
    227		if (likely(old == c))
    228			return true;
    229		c = old;
    230	}
    231}
    232
    233struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
    234			   enum ucount_type type)
    235{
    236	struct ucounts *ucounts, *iter, *bad;
    237	struct user_namespace *tns;
    238	ucounts = alloc_ucounts(ns, uid);
    239	for (iter = ucounts; iter; iter = tns->ucounts) {
    240		long max;
    241		tns = iter->ns;
    242		max = READ_ONCE(tns->ucount_max[type]);
    243		if (!atomic_long_inc_below(&iter->ucount[type], max))
    244			goto fail;
    245	}
    246	return ucounts;
    247fail:
    248	bad = iter;
    249	for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
    250		atomic_long_dec(&iter->ucount[type]);
    251
    252	put_ucounts(ucounts);
    253	return NULL;
    254}
    255
    256void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
    257{
    258	struct ucounts *iter;
    259	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
    260		long dec = atomic_long_dec_if_positive(&iter->ucount[type]);
    261		WARN_ON_ONCE(dec < 0);
    262	}
    263	put_ucounts(ucounts);
    264}
    265
    266long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
    267{
    268	struct ucounts *iter;
    269	long max = LONG_MAX;
    270	long ret = 0;
    271
    272	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
    273		long new = atomic_long_add_return(v, &iter->ucount[type]);
    274		if (new < 0 || new > max)
    275			ret = LONG_MAX;
    276		else if (iter == ucounts)
    277			ret = new;
    278		max = READ_ONCE(iter->ns->ucount_max[type]);
    279	}
    280	return ret;
    281}
    282
    283bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
    284{
    285	struct ucounts *iter;
    286	long new = -1; /* Silence compiler warning */
    287	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
    288		long dec = atomic_long_sub_return(v, &iter->ucount[type]);
    289		WARN_ON_ONCE(dec < 0);
    290		if (iter == ucounts)
    291			new = dec;
    292	}
    293	return (new == 0);
    294}
    295
    296static void do_dec_rlimit_put_ucounts(struct ucounts *ucounts,
    297				struct ucounts *last, enum ucount_type type)
    298{
    299	struct ucounts *iter, *next;
    300	for (iter = ucounts; iter != last; iter = next) {
    301		long dec = atomic_long_sub_return(1, &iter->ucount[type]);
    302		WARN_ON_ONCE(dec < 0);
    303		next = iter->ns->ucounts;
    304		if (dec == 0)
    305			put_ucounts(iter);
    306	}
    307}
    308
    309void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum ucount_type type)
    310{
    311	do_dec_rlimit_put_ucounts(ucounts, NULL, type);
    312}
    313
    314long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
    315{
    316	/* Caller must hold a reference to ucounts */
    317	struct ucounts *iter;
    318	long max = LONG_MAX;
    319	long dec, ret = 0;
    320
    321	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
    322		long new = atomic_long_add_return(1, &iter->ucount[type]);
    323		if (new < 0 || new > max)
    324			goto unwind;
    325		if (iter == ucounts)
    326			ret = new;
    327		max = READ_ONCE(iter->ns->ucount_max[type]);
    328		/*
    329		 * Grab an extra ucount reference for the caller when
    330		 * the rlimit count was previously 0.
    331		 */
    332		if (new != 1)
    333			continue;
    334		if (!get_ucounts(iter))
    335			goto dec_unwind;
    336	}
    337	return ret;
    338dec_unwind:
    339	dec = atomic_long_sub_return(1, &iter->ucount[type]);
    340	WARN_ON_ONCE(dec < 0);
    341unwind:
    342	do_dec_rlimit_put_ucounts(ucounts, iter, type);
    343	return 0;
    344}
    345
    346bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long rlimit)
    347{
    348	struct ucounts *iter;
    349	long max = rlimit;
    350	if (rlimit > LONG_MAX)
    351		max = LONG_MAX;
    352	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
    353		long val = get_ucounts_value(iter, type);
    354		if (val < 0 || val > max)
    355			return true;
    356		max = READ_ONCE(iter->ns->ucount_max[type]);
    357	}
    358	return false;
    359}
    360
    361static __init int user_namespace_sysctl_init(void)
    362{
    363#ifdef CONFIG_SYSCTL
    364	static struct ctl_table_header *user_header;
    365	static struct ctl_table empty[1];
    366	/*
    367	 * It is necessary to register the user directory in the
    368	 * default set so that registrations in the child sets work
    369	 * properly.
    370	 */
    371	user_header = register_sysctl("user", empty);
    372	kmemleak_ignore(user_header);
    373	BUG_ON(!user_header);
    374	BUG_ON(!setup_userns_sysctls(&init_user_ns));
    375#endif
    376	hlist_add_ucounts(&init_ucounts);
    377	inc_rlimit_ucounts(&init_ucounts, UCOUNT_RLIMIT_NPROC, 1);
    378	return 0;
    379}
    380subsys_initcall(user_namespace_sysctl_init);