LCOV - code coverage report
Current view: top level - kernel - ucount.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 75 106 70.8 %
Date: 2021-04-22 12:43:58 Functions: 8 12 66.7 %

          Line data    Source code
       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             : 
      11             : #define UCOUNTS_HASHTABLE_BITS 10
      12             : static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
      13             : static DEFINE_SPINLOCK(ucounts_lock);
      14             : 
      15             : #define ucounts_hashfn(ns, uid)                                         \
      16             :         hash_long((unsigned long)__kuid_val(uid) + (unsigned long)(ns), \
      17             :                   UCOUNTS_HASHTABLE_BITS)
      18             : #define ucounts_hashentry(ns, uid)      \
      19             :         (ucounts_hashtable + ucounts_hashfn(ns, uid))
      20             : 
      21             : 
      22             : #ifdef CONFIG_SYSCTL
      23             : static struct ctl_table_set *
      24           0 : set_lookup(struct ctl_table_root *root)
      25             : {
      26           0 :         return &current_user_ns()->set;
      27             : }
      28             : 
      29           0 : static int set_is_seen(struct ctl_table_set *set)
      30             : {
      31           0 :         return &current_user_ns()->set == set;
      32             : }
      33             : 
      34           0 : static int set_permissions(struct ctl_table_header *head,
      35             :                                   struct ctl_table *table)
      36             : {
      37           0 :         struct user_namespace *user_ns =
      38           0 :                 container_of(head->set, struct user_namespace, set);
      39           0 :         int mode;
      40             : 
      41             :         /* Allow users with CAP_SYS_RESOURCE unrestrained access */
      42           0 :         if (ns_capable(user_ns, CAP_SYS_RESOURCE))
      43           0 :                 mode = (table->mode & S_IRWXU) >> 6;
      44             :         else
      45             :         /* Allow all others at most read-only access */
      46           0 :                 mode = table->mode & S_IROTH;
      47           0 :         return (mode << 6) | (mode << 3) | mode;
      48             : }
      49             : 
      50             : static struct ctl_table_root set_root = {
      51             :         .lookup = set_lookup,
      52             :         .permissions = set_permissions,
      53             : };
      54             : 
      55             : #define UCOUNT_ENTRY(name)                              \
      56             :         {                                               \
      57             :                 .procname       = name,                 \
      58             :                 .maxlen         = sizeof(int),          \
      59             :                 .mode           = 0644,                 \
      60             :                 .proc_handler   = proc_dointvec_minmax, \
      61             :                 .extra1         = SYSCTL_ZERO,          \
      62             :                 .extra2         = SYSCTL_INT_MAX,       \
      63             :         }
      64             : static struct ctl_table user_table[] = {
      65             :         UCOUNT_ENTRY("max_user_namespaces"),
      66             :         UCOUNT_ENTRY("max_pid_namespaces"),
      67             :         UCOUNT_ENTRY("max_uts_namespaces"),
      68             :         UCOUNT_ENTRY("max_ipc_namespaces"),
      69             :         UCOUNT_ENTRY("max_net_namespaces"),
      70             :         UCOUNT_ENTRY("max_mnt_namespaces"),
      71             :         UCOUNT_ENTRY("max_cgroup_namespaces"),
      72             :         UCOUNT_ENTRY("max_time_namespaces"),
      73             : #ifdef CONFIG_INOTIFY_USER
      74             :         UCOUNT_ENTRY("max_inotify_instances"),
      75             :         UCOUNT_ENTRY("max_inotify_watches"),
      76             : #endif
      77             :         { }
      78             : };
      79             : #endif /* CONFIG_SYSCTL */
      80             : 
      81           1 : bool setup_userns_sysctls(struct user_namespace *ns)
      82             : {
      83             : #ifdef CONFIG_SYSCTL
      84           1 :         struct ctl_table *tbl;
      85             : 
      86           1 :         BUILD_BUG_ON(ARRAY_SIZE(user_table) != UCOUNT_COUNTS + 1);
      87           1 :         setup_sysctl_set(&ns->set, &set_root, set_is_seen);
      88           1 :         tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL);
      89           1 :         if (tbl) {
      90             :                 int i;
      91          11 :                 for (i = 0; i < UCOUNT_COUNTS; i++) {
      92          10 :                         tbl[i].data = &ns->ucount_max[i];
      93             :                 }
      94           1 :                 ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
      95             :         }
      96           1 :         if (!ns->sysctls) {
      97           0 :                 kfree(tbl);
      98           0 :                 retire_sysctl_set(&ns->set);
      99           0 :                 return false;
     100             :         }
     101             : #endif
     102             :         return true;
     103             : }
     104             : 
     105           0 : void retire_userns_sysctls(struct user_namespace *ns)
     106             : {
     107             : #ifdef CONFIG_SYSCTL
     108           0 :         struct ctl_table *tbl;
     109             : 
     110           0 :         tbl = ns->sysctls->ctl_table_arg;
     111           0 :         unregister_sysctl_table(ns->sysctls);
     112           0 :         retire_sysctl_set(&ns->set);
     113           0 :         kfree(tbl);
     114             : #endif
     115           0 : }
     116             : 
     117         159 : static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struct hlist_head *hashent)
     118             : {
     119         159 :         struct ucounts *ucounts;
     120             : 
     121         318 :         hlist_for_each_entry(ucounts, hashent, node) {
     122         153 :                 if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns))
     123         153 :                         return ucounts;
     124             :         }
     125             :         return NULL;
     126             : }
     127             : 
     128         156 : static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
     129             : {
     130         156 :         struct hlist_head *hashent = ucounts_hashentry(ns, uid);
     131         156 :         struct ucounts *ucounts, *new;
     132             : 
     133         156 :         spin_lock_irq(&ucounts_lock);
     134         156 :         ucounts = find_ucounts(ns, uid, hashent);
     135         156 :         if (!ucounts) {
     136           3 :                 spin_unlock_irq(&ucounts_lock);
     137             : 
     138           3 :                 new = kzalloc(sizeof(*new), GFP_KERNEL);
     139           3 :                 if (!new)
     140             :                         return NULL;
     141             : 
     142           3 :                 new->ns = ns;
     143           3 :                 new->uid = uid;
     144           3 :                 new->count = 0;
     145             : 
     146           3 :                 spin_lock_irq(&ucounts_lock);
     147           3 :                 ucounts = find_ucounts(ns, uid, hashent);
     148           3 :                 if (ucounts) {
     149           0 :                         kfree(new);
     150             :                 } else {
     151           3 :                         hlist_add_head(&new->node, hashent);
     152           3 :                         ucounts = new;
     153             :                 }
     154             :         }
     155         156 :         if (ucounts->count == INT_MAX)
     156             :                 ucounts = NULL;
     157             :         else
     158         156 :                 ucounts->count += 1;
     159         156 :         spin_unlock_irq(&ucounts_lock);
     160         156 :         return ucounts;
     161             : }
     162             : 
     163          86 : static void put_ucounts(struct ucounts *ucounts)
     164             : {
     165          86 :         unsigned long flags;
     166             : 
     167          86 :         spin_lock_irqsave(&ucounts_lock, flags);
     168          86 :         ucounts->count -= 1;
     169          86 :         if (!ucounts->count)
     170           0 :                 hlist_del_init(&ucounts->node);
     171             :         else
     172             :                 ucounts = NULL;
     173          86 :         spin_unlock_irqrestore(&ucounts_lock, flags);
     174             : 
     175          86 :         kfree(ucounts);
     176          86 : }
     177             : 
     178         156 : static inline bool atomic_inc_below(atomic_t *v, int u)
     179             : {
     180         156 :         int c, old;
     181         156 :         c = atomic_read(v);
     182         156 :         for (;;) {
     183         156 :                 if (unlikely(c >= u))
     184             :                         return false;
     185         156 :                 old = atomic_cmpxchg(v, c, c+1);
     186         156 :                 if (likely(old == c))
     187             :                         return true;
     188             :                 c = old;
     189             :         }
     190             : }
     191             : 
     192         156 : struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
     193             :                            enum ucount_type type)
     194             : {
     195         156 :         struct ucounts *ucounts, *iter, *bad;
     196         156 :         struct user_namespace *tns;
     197         156 :         ucounts = get_ucounts(ns, uid);
     198         468 :         for (iter = ucounts; iter; iter = tns->ucounts) {
     199         156 :                 int max;
     200         156 :                 tns = iter->ns;
     201         156 :                 max = READ_ONCE(tns->ucount_max[type]);
     202         156 :                 if (!atomic_inc_below(&iter->ucount[type], max))
     203           0 :                         goto fail;
     204             :         }
     205             :         return ucounts;
     206           0 : fail:
     207           0 :         bad = iter;
     208           0 :         for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
     209           0 :                 atomic_dec(&iter->ucount[type]);
     210             : 
     211           0 :         put_ucounts(ucounts);
     212           0 :         return NULL;
     213             : }
     214             : 
     215          86 : void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
     216             : {
     217          86 :         struct ucounts *iter;
     218         172 :         for (iter = ucounts; iter; iter = iter->ns->ucounts) {
     219          86 :                 int dec = atomic_dec_if_positive(&iter->ucount[type]);
     220          86 :                 WARN_ON_ONCE(dec < 0);
     221             :         }
     222          86 :         put_ucounts(ucounts);
     223          86 : }
     224             : 
     225           1 : static __init int user_namespace_sysctl_init(void)
     226             : {
     227             : #ifdef CONFIG_SYSCTL
     228           1 :         static struct ctl_table_header *user_header;
     229           1 :         static struct ctl_table empty[1];
     230             :         /*
     231             :          * It is necessary to register the user directory in the
     232             :          * default set so that registrations in the child sets work
     233             :          * properly.
     234             :          */
     235           1 :         user_header = register_sysctl("user", empty);
     236           1 :         kmemleak_ignore(user_header);
     237           1 :         BUG_ON(!user_header);
     238           1 :         BUG_ON(!setup_userns_sysctls(&init_user_ns));
     239             : #endif
     240           1 :         return 0;
     241             : }
     242             : subsys_initcall(user_namespace_sysctl_init);

Generated by: LCOV version 1.14