LCOV - code coverage report
Current view: top level - kernel - user.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 33 40 82.5 %
Date: 2015-04-12 14:34:49 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /*
       2             :  * The "user cache".
       3             :  *
       4             :  * (C) Copyright 1991-2000 Linus Torvalds
       5             :  *
       6             :  * We have a per-user structure to keep track of how many
       7             :  * processes, files etc the user has claimed, in order to be
       8             :  * able to have per-user limits for system resources. 
       9             :  */
      10             : 
      11             : #include <linux/init.h>
      12             : #include <linux/sched.h>
      13             : #include <linux/slab.h>
      14             : #include <linux/bitops.h>
      15             : #include <linux/key.h>
      16             : #include <linux/interrupt.h>
      17             : #include <linux/export.h>
      18             : #include <linux/user_namespace.h>
      19             : #include <linux/proc_ns.h>
      20             : 
      21             : /*
      22             :  * userns count is 1 for root user, 1 for init_uts_ns,
      23             :  * and 1 for... ?
      24             :  */
      25             : struct user_namespace init_user_ns = {
      26             :         .uid_map = {
      27             :                 .nr_extents = 1,
      28             :                 .extent[0] = {
      29             :                         .first = 0,
      30             :                         .lower_first = 0,
      31             :                         .count = 4294967295U,
      32             :                 },
      33             :         },
      34             :         .gid_map = {
      35             :                 .nr_extents = 1,
      36             :                 .extent[0] = {
      37             :                         .first = 0,
      38             :                         .lower_first = 0,
      39             :                         .count = 4294967295U,
      40             :                 },
      41             :         },
      42             :         .projid_map = {
      43             :                 .nr_extents = 1,
      44             :                 .extent[0] = {
      45             :                         .first = 0,
      46             :                         .lower_first = 0,
      47             :                         .count = 4294967295U,
      48             :                 },
      49             :         },
      50             :         .count = ATOMIC_INIT(3),
      51             :         .owner = GLOBAL_ROOT_UID,
      52             :         .group = GLOBAL_ROOT_GID,
      53             :         .ns.inum = PROC_USER_INIT_INO,
      54             : #ifdef CONFIG_USER_NS
      55             :         .ns.ops = &userns_operations,
      56             : #endif
      57             :         .flags = USERNS_INIT_FLAGS,
      58             : #ifdef CONFIG_PERSISTENT_KEYRINGS
      59             :         .persistent_keyring_register_sem =
      60             :         __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
      61             : #endif
      62             : };
      63             : EXPORT_SYMBOL_GPL(init_user_ns);
      64             : 
      65             : /*
      66             :  * UID task count cache, to get fast user lookup in "alloc_uid"
      67             :  * when changing user ID's (ie setuid() and friends).
      68             :  */
      69             : 
      70             : #define UIDHASH_BITS    (CONFIG_BASE_SMALL ? 3 : 7)
      71             : #define UIDHASH_SZ      (1 << UIDHASH_BITS)
      72             : #define UIDHASH_MASK            (UIDHASH_SZ - 1)
      73             : #define __uidhashfn(uid)        (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
      74             : #define uidhashentry(uid)       (uidhash_table + __uidhashfn((__kuid_val(uid))))
      75             : 
      76             : static struct kmem_cache *uid_cachep;
      77             : struct hlist_head uidhash_table[UIDHASH_SZ];
      78             : 
      79             : /*
      80             :  * The uidhash_lock is mostly taken from process context, but it is
      81             :  * occasionally also taken from softirq/tasklet context, when
      82             :  * task-structs get RCU-freed. Hence all locking must be softirq-safe.
      83             :  * But free_uid() is also called with local interrupts disabled, and running
      84             :  * local_bh_enable() with local interrupts disabled is an error - we'll run
      85             :  * softirq callbacks, and they can unconditionally enable interrupts, and
      86             :  * the caller of free_uid() didn't expect that..
      87             :  */
      88             : static DEFINE_SPINLOCK(uidhash_lock);
      89             : 
      90             : /* root_user.__count is 1, for init task cred */
      91             : struct user_struct root_user = {
      92             :         .__count        = ATOMIC_INIT(1),
      93             :         .processes      = ATOMIC_INIT(1),
      94             :         .sigpending     = ATOMIC_INIT(0),
      95             :         .locked_shm     = 0,
      96             :         .uid            = GLOBAL_ROOT_UID,
      97             : };
      98             : 
      99             : /*
     100             :  * These routines must be called with the uidhash spinlock held!
     101             :  */
     102             : static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
     103             : {
     104          14 :         hlist_add_head(&up->uidhash_node, hashent);
     105             : }
     106             : 
     107             : static void uid_hash_remove(struct user_struct *up)
     108             : {
     109             :         hlist_del_init(&up->uidhash_node);
     110             : }
     111             : 
     112         131 : static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
     113             : {
     114             :         struct user_struct *user;
     115             : 
     116         131 :         hlist_for_each_entry(user, hashent, uidhash_node) {
     117         103 :                 if (uid_eq(user->uid, uid)) {
     118         103 :                         atomic_inc(&user->__count);
     119         103 :                         return user;
     120             :                 }
     121             :         }
     122             : 
     123             :         return NULL;
     124             : }
     125             : 
     126             : /* IRQs are disabled and uidhash_lock is held upon function entry.
     127             :  * IRQ state (as stored in flags) is restored and uidhash_lock released
     128             :  * upon function exit.
     129             :  */
     130          10 : static void free_user(struct user_struct *up, unsigned long flags)
     131             :         __releases(&uidhash_lock)
     132             : {
     133             :         uid_hash_remove(up);
     134             :         spin_unlock_irqrestore(&uidhash_lock, flags);
     135          10 :         key_put(up->uid_keyring);
     136          10 :         key_put(up->session_keyring);
     137          10 :         kmem_cache_free(uid_cachep, up);
     138          10 : }
     139             : 
     140             : /*
     141             :  * Locate the user_struct for the passed UID.  If found, take a ref on it.  The
     142             :  * caller must undo that ref with free_uid().
     143             :  *
     144             :  * If the user_struct could not be found, return NULL.
     145             :  */
     146           0 : struct user_struct *find_user(kuid_t uid)
     147             : {
     148             :         struct user_struct *ret;
     149             :         unsigned long flags;
     150             : 
     151           0 :         spin_lock_irqsave(&uidhash_lock, flags);
     152           0 :         ret = uid_hash_find(uid, uidhashentry(uid));
     153             :         spin_unlock_irqrestore(&uidhash_lock, flags);
     154           0 :         return ret;
     155             : }
     156             : 
     157       23106 : void free_uid(struct user_struct *up)
     158             : {
     159             :         unsigned long flags;
     160             : 
     161       23106 :         if (!up)
     162       23106 :                 return;
     163             : 
     164             :         local_irq_save(flags);
     165       23106 :         if (atomic_dec_and_lock(&up->__count, &uidhash_lock))
     166          10 :                 free_user(up, flags);
     167             :         else
     168       23096 :                 local_irq_restore(flags);
     169             : }
     170             : 
     171         117 : struct user_struct *alloc_uid(kuid_t uid)
     172             : {
     173         117 :         struct hlist_head *hashent = uidhashentry(uid);
     174             :         struct user_struct *up, *new;
     175             : 
     176             :         spin_lock_irq(&uidhash_lock);
     177         117 :         up = uid_hash_find(uid, hashent);
     178             :         spin_unlock_irq(&uidhash_lock);
     179             : 
     180         117 :         if (!up) {
     181          14 :                 new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL);
     182          14 :                 if (!new)
     183             :                         goto out_unlock;
     184             : 
     185          14 :                 new->uid = uid;
     186          14 :                 atomic_set(&new->__count, 1);
     187             : 
     188             :                 /*
     189             :                  * Before adding this, check whether we raced
     190             :                  * on adding the same user already..
     191             :                  */
     192             :                 spin_lock_irq(&uidhash_lock);
     193          14 :                 up = uid_hash_find(uid, hashent);
     194          14 :                 if (up) {
     195           0 :                         key_put(new->uid_keyring);
     196           0 :                         key_put(new->session_keyring);
     197           0 :                         kmem_cache_free(uid_cachep, new);
     198             :                 } else {
     199             :                         uid_hash_insert(new, hashent);
     200             :                         up = new;
     201             :                 }
     202             :                 spin_unlock_irq(&uidhash_lock);
     203             :         }
     204             : 
     205         117 :         return up;
     206             : 
     207             : out_unlock:
     208             :         return NULL;
     209             : }
     210             : 
     211           1 : static int __init uid_cache_init(void)
     212             : {
     213             :         int n;
     214             : 
     215           1 :         uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
     216             :                         0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
     217             : 
     218         129 :         for(n = 0; n < UIDHASH_SZ; ++n)
     219         128 :                 INIT_HLIST_HEAD(uidhash_table + n);
     220             : 
     221             :         /* Insert the root user immediately (init already runs as root) */
     222             :         spin_lock_irq(&uidhash_lock);
     223             :         uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
     224             :         spin_unlock_irq(&uidhash_lock);
     225             : 
     226           1 :         return 0;
     227             : }
     228             : subsys_initcall(uid_cache_init);

Generated by: LCOV version 1.11