linux/kernel/user.c
<<
>>
Prefs
   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 */
  25struct 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        .proc_inum = PROC_USER_INIT_INO,
  54};
  55EXPORT_SYMBOL_GPL(init_user_ns);
  56
  57/*
  58 * UID task count cache, to get fast user lookup in "alloc_uid"
  59 * when changing user ID's (ie setuid() and friends).
  60 */
  61
  62#define UIDHASH_BITS    (CONFIG_BASE_SMALL ? 3 : 7)
  63#define UIDHASH_SZ      (1 << UIDHASH_BITS)
  64#define UIDHASH_MASK            (UIDHASH_SZ - 1)
  65#define __uidhashfn(uid)        (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
  66#define uidhashentry(uid)       (uidhash_table + __uidhashfn((__kuid_val(uid))))
  67
  68static struct kmem_cache *uid_cachep;
  69struct hlist_head uidhash_table[UIDHASH_SZ];
  70
  71/*
  72 * The uidhash_lock is mostly taken from process context, but it is
  73 * occasionally also taken from softirq/tasklet context, when
  74 * task-structs get RCU-freed. Hence all locking must be softirq-safe.
  75 * But free_uid() is also called with local interrupts disabled, and running
  76 * local_bh_enable() with local interrupts disabled is an error - we'll run
  77 * softirq callbacks, and they can unconditionally enable interrupts, and
  78 * the caller of free_uid() didn't expect that..
  79 */
  80static DEFINE_SPINLOCK(uidhash_lock);
  81
  82/* root_user.__count is 1, for init task cred */
  83struct user_struct root_user = {
  84        .__count        = ATOMIC_INIT(1),
  85        .processes      = ATOMIC_INIT(1),
  86        .files          = ATOMIC_INIT(0),
  87        .sigpending     = ATOMIC_INIT(0),
  88        .locked_shm     = 0,
  89        .uid            = GLOBAL_ROOT_UID,
  90};
  91
  92/*
  93 * These routines must be called with the uidhash spinlock held!
  94 */
  95static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
  96{
  97        hlist_add_head(&up->uidhash_node, hashent);
  98}
  99
 100static void uid_hash_remove(struct user_struct *up)
 101{
 102        hlist_del_init(&up->uidhash_node);
 103}
 104
 105static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
 106{
 107        struct user_struct *user;
 108
 109        hlist_for_each_entry(user, hashent, uidhash_node) {
 110                if (uid_eq(user->uid, uid)) {
 111                        atomic_inc(&user->__count);
 112                        return user;
 113                }
 114        }
 115
 116        return NULL;
 117}
 118
 119/* IRQs are disabled and uidhash_lock is held upon function entry.
 120 * IRQ state (as stored in flags) is restored and uidhash_lock released
 121 * upon function exit.
 122 */
 123static void free_user(struct user_struct *up, unsigned long flags)
 124        __releases(&uidhash_lock)
 125{
 126        uid_hash_remove(up);
 127        spin_unlock_irqrestore(&uidhash_lock, flags);
 128        key_put(up->uid_keyring);
 129        key_put(up->session_keyring);
 130        kmem_cache_free(uid_cachep, up);
 131}
 132
 133/*
 134 * Locate the user_struct for the passed UID.  If found, take a ref on it.  The
 135 * caller must undo that ref with free_uid().
 136 *
 137 * If the user_struct could not be found, return NULL.
 138 */
 139struct user_struct *find_user(kuid_t uid)
 140{
 141        struct user_struct *ret;
 142        unsigned long flags;
 143
 144        spin_lock_irqsave(&uidhash_lock, flags);
 145        ret = uid_hash_find(uid, uidhashentry(uid));
 146        spin_unlock_irqrestore(&uidhash_lock, flags);
 147        return ret;
 148}
 149
 150void free_uid(struct user_struct *up)
 151{
 152        unsigned long flags;
 153
 154        if (!up)
 155                return;
 156
 157        local_irq_save(flags);
 158        if (atomic_dec_and_lock(&up->__count, &uidhash_lock))
 159                free_user(up, flags);
 160        else
 161                local_irq_restore(flags);
 162}
 163
 164struct user_struct *alloc_uid(kuid_t uid)
 165{
 166        struct hlist_head *hashent = uidhashentry(uid);
 167        struct user_struct *up, *new;
 168
 169        spin_lock_irq(&uidhash_lock);
 170        up = uid_hash_find(uid, hashent);
 171        spin_unlock_irq(&uidhash_lock);
 172
 173        if (!up) {
 174                new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL);
 175                if (!new)
 176                        goto out_unlock;
 177
 178                new->uid = uid;
 179                atomic_set(&new->__count, 1);
 180
 181                /*
 182                 * Before adding this, check whether we raced
 183                 * on adding the same user already..
 184                 */
 185                spin_lock_irq(&uidhash_lock);
 186                up = uid_hash_find(uid, hashent);
 187                if (up) {
 188                        key_put(new->uid_keyring);
 189                        key_put(new->session_keyring);
 190                        kmem_cache_free(uid_cachep, new);
 191                } else {
 192                        uid_hash_insert(new, hashent);
 193                        up = new;
 194                }
 195                spin_unlock_irq(&uidhash_lock);
 196        }
 197
 198        return up;
 199
 200out_unlock:
 201        return NULL;
 202}
 203
 204static int __init uid_cache_init(void)
 205{
 206        int n;
 207
 208        uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
 209                        0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 210
 211        for(n = 0; n < UIDHASH_SZ; ++n)
 212                INIT_HLIST_HEAD(uidhash_table + n);
 213
 214        /* Insert the root user immediately (init already runs as root) */
 215        spin_lock_irq(&uidhash_lock);
 216        uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
 217        spin_unlock_irq(&uidhash_lock);
 218
 219        return 0;
 220}
 221
 222module_init(uid_cache_init);
 223
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.