X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=security%2Fkeys%2Fkey.c;h=14948cf83ef6acc6ea19811465201ff5ae8660f0;hb=eb81071584bed0b04adcaf57e525638d0f92e1e1;hp=01bbc6d9d19b0997a8d984cdd2373d9adc96090b;hpb=b981d8b3f5e008ff10d993be633ad00564fc22cd;p=linux-2.6-omap-h63xx.git diff --git a/security/keys/key.c b/security/keys/key.c index 01bbc6d9d19..14948cf83ef 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1,6 +1,6 @@ -/* key.c: basic authentication token and access key management +/* Basic authentication token and access key management * - * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or @@ -27,6 +27,11 @@ DEFINE_SPINLOCK(key_serial_lock); struct rb_root key_user_tree; /* tree of quota records indexed by UID */ DEFINE_SPINLOCK(key_user_lock); +unsigned int key_quota_root_maxkeys = 200; /* root's key count quota */ +unsigned int key_quota_root_maxbytes = 20000; /* root's key space quota */ +unsigned int key_quota_maxkeys = 200; /* general key count quota */ +unsigned int key_quota_maxbytes = 20000; /* general key space quota */ + static LIST_HEAD(key_types_list); static DECLARE_RWSEM(key_types_sem); @@ -34,7 +39,7 @@ static void key_cleanup(struct work_struct *work); static DECLARE_WORK(key_cleanup_task, key_cleanup); /* we serialise key instantiation and link */ -DECLARE_RWSEM(key_construction_sem); +DEFINE_MUTEX(key_construction_mutex); /* any key who's type gets unegistered will be re-typed to this */ static struct key_type key_type_dead = { @@ -104,7 +109,7 @@ struct key_user *key_user_lookup(uid_t uid) candidate->qnkeys = 0; candidate->qnbytes = 0; spin_lock_init(&candidate->lock); - INIT_LIST_HEAD(&candidate->consq); + mutex_init(&candidate->cons_lock); rb_link_node(&candidate->node, parent, p); rb_insert_color(&candidate->node, &key_user_tree); @@ -137,36 +142,6 @@ void key_user_put(struct key_user *user) } /* end key_user_put() */ -/*****************************************************************************/ -/* - * insert a key with a fixed serial number - */ -static void __init __key_insert_serial(struct key *key) -{ - struct rb_node *parent, **p; - struct key *xkey; - - parent = NULL; - p = &key_serial_tree.rb_node; - - while (*p) { - parent = *p; - xkey = rb_entry(parent, struct key, serial_node); - - if (key->serial < xkey->serial) - p = &(*p)->rb_left; - else if (key->serial > xkey->serial) - p = &(*p)->rb_right; - else - BUG(); - } - - /* we've found a suitable hole - arrange for this key to occupy it */ - rb_link_node(&key->serial_node, parent, p); - rb_insert_color(&key->serial_node, &key_serial_tree); - -} /* end __key_insert_serial() */ - /*****************************************************************************/ /* * assign a key the next unique serial number @@ -266,11 +241,16 @@ struct key *key_alloc(struct key_type *type, const char *desc, /* check that the user's quota permits allocation of another key and * its description */ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { + unsigned maxkeys = (uid == 0) ? + key_quota_root_maxkeys : key_quota_maxkeys; + unsigned maxbytes = (uid == 0) ? + key_quota_root_maxbytes : key_quota_maxbytes; + spin_lock(&user->lock); if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { - if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || - user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES - ) + if (user->qnkeys + 1 >= maxkeys || + user->qnbytes + quotalen >= maxbytes || + user->qnbytes + quotalen < user->qnbytes) goto no_quota; } @@ -375,11 +355,14 @@ int key_payload_reserve(struct key *key, size_t datalen) /* contemplate the quota adjustment */ if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { + unsigned maxbytes = (key->user->uid == 0) ? + key_quota_root_maxbytes : key_quota_maxbytes; + spin_lock(&key->user->lock); if (delta > 0 && - key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES - ) { + (key->user->qnbytes + delta >= maxbytes || + key->user->qnbytes + delta < key->user->qnbytes)) { ret = -EDQUOT; } else { @@ -418,7 +401,7 @@ static int __key_instantiate_and_link(struct key *key, awaken = 0; ret = -EBUSY; - down_write(&key_construction_sem); + mutex_lock(&key_construction_mutex); /* can't instantiate twice */ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { @@ -443,11 +426,11 @@ static int __key_instantiate_and_link(struct key *key, } } - up_write(&key_construction_sem); + mutex_unlock(&key_construction_mutex); /* wake up anyone waiting for a key to be constructed */ if (awaken) - wake_up_all(&request_key_conswq); + wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); return ret; @@ -500,7 +483,7 @@ int key_negate_and_link(struct key *key, if (keyring) down_write(&keyring->sem); - down_write(&key_construction_sem); + mutex_lock(&key_construction_mutex); /* can't instantiate twice */ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { @@ -525,14 +508,14 @@ int key_negate_and_link(struct key *key, key_revoke(instkey); } - up_write(&key_construction_sem); + mutex_unlock(&key_construction_mutex); if (keyring) up_write(&keyring->sem); /* wake up anyone waiting for a key to be constructed */ if (awaken) - wake_up_all(&request_key_conswq); + wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); return ret; @@ -757,11 +740,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, const char *description, const void *payload, size_t plen, + key_perm_t perm, unsigned long flags) { struct key_type *ktype; struct key *keyring, *key = NULL; - key_perm_t perm; key_ref_t key_ref; int ret; @@ -806,21 +789,23 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, goto found_matching_key; } - /* decide on the permissions we want */ - perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; - perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; + /* if the client doesn't provide, decide on the permissions we want */ + if (perm == KEY_PERM_UNDEF) { + perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; + perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; - if (ktype->read) - perm |= KEY_POS_READ | KEY_USR_READ; + if (ktype->read) + perm |= KEY_POS_READ | KEY_USR_READ; - if (ktype == &key_type_keyring || ktype->update) - perm |= KEY_USR_WRITE; + if (ktype == &key_type_keyring || ktype->update) + perm |= KEY_USR_WRITE; + } /* allocate a new key */ key = key_alloc(ktype, description, current->fsuid, current->fsgid, current, perm, flags); if (IS_ERR(key)) { - key_ref = ERR_PTR(PTR_ERR(key)); + key_ref = ERR_CAST(key); goto error_3; } @@ -899,12 +884,14 @@ void key_revoke(struct key *key) { key_check(key); - /* make sure no one's trying to change or use the key when we mark - * it */ - down_write(&key->sem); - set_bit(KEY_FLAG_REVOKED, &key->flags); - - if (key->type->revoke) + /* make sure no one's trying to change or use the key when we mark it + * - we tell lockdep that we might nest because we might be revoking an + * authorisation key whilst holding the sem on a key we've just + * instantiated + */ + down_write_nested(&key->sem, 1); + if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) && + key->type->revoke) key->type->revoke(key); up_write(&key->sem); @@ -1016,17 +1003,4 @@ void __init key_init(void) rb_insert_color(&root_key_user.node, &key_user_tree); - /* record root's user standard keyrings */ - key_check(&root_user_keyring); - key_check(&root_session_keyring); - - __key_insert_serial(&root_user_keyring); - __key_insert_serial(&root_session_keyring); - - keyring_publish_name(&root_user_keyring); - keyring_publish_name(&root_session_keyring); - - /* link the two root keyrings together */ - key_link(&root_session_keyring, &root_user_keyring); - } /* end key_init() */