diff options
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 240 |
1 files changed, 173 insertions, 67 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index 3a92d736587..84d4eb568b0 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -39,10 +39,10 @@ static DECLARE_RWSEM(key_types_sem); static void key_cleanup(struct work_struct *work); static DECLARE_WORK(key_cleanup_task, key_cleanup); -/* we serialise key instantiation and link */ +/* We serialise key instantiation and link */ DEFINE_MUTEX(key_construction_mutex); -/* any key who's type gets unegistered will be re-typed to this */ +/* Any key who's type gets unegistered will be re-typed to this */ static struct key_type key_type_dead = { .name = "dead", }; @@ -57,8 +57,8 @@ void __key_check(const struct key *key) #endif /* - * get the key quota record for a user, allocating a new record if one doesn't - * already exist + * Get the key quota record for a user, allocating a new record if one doesn't + * already exist. */ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns) { @@ -66,7 +66,7 @@ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns) struct rb_node *parent = NULL; struct rb_node **p; - try_again: +try_again: p = &key_user_tree.rb_node; spin_lock(&key_user_lock); @@ -123,16 +123,16 @@ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns) goto out; /* okay - we found a user record for this UID */ - found: +found: atomic_inc(&user->usage); spin_unlock(&key_user_lock); kfree(candidate); - out: +out: return user; } /* - * dispose of a user structure + * Dispose of a user structure */ void key_user_put(struct key_user *user) { @@ -146,9 +146,8 @@ void key_user_put(struct key_user *user) } /* - * assign a key the next unique serial number - * - these are assigned randomly to avoid security issues through covert - * channel problems + * Allocate a serial number for a key. These are assigned randomly to avoid + * security issues through covert channel problems. */ static inline void key_alloc_serial(struct key *key) { @@ -208,14 +207,34 @@ serial_exists: } } -/* - * allocate a key of the specified type - * - update the user's quota to reflect the existence of the key - * - called from a key-type operation with key_types_sem read-locked by - * key_create_or_update() - * - this prevents unregistration of the key type - * - upon return the key is as yet uninstantiated; the caller needs to either - * instantiate the key or discard it before returning +/** + * key_alloc - Allocate a key of the specified type. + * @type: The type of key to allocate. + * @desc: The key description to allow the key to be searched out. + * @uid: The owner of the new key. + * @gid: The group ID for the new key's group permissions. + * @cred: The credentials specifying UID namespace. + * @perm: The permissions mask of the new key. + * @flags: Flags specifying quota properties. + * + * Allocate a key of the specified type with the attributes given. The key is + * returned in an uninstantiated state and the caller needs to instantiate the + * key before returning. + * + * The user's key count quota is updated to reflect the creation of the key and + * the user's key data quota has the default for the key type reserved. The + * instantiation function should amend this as necessary. If insufficient + * quota is available, -EDQUOT will be returned. + * + * The LSM security modules can prevent a key being created, in which case + * -EACCES will be returned. + * + * Returns a pointer to the new key if successful and an error code otherwise. + * + * Note that the caller needs to ensure the key type isn't uninstantiated. + * Internally this can be done by locking key_types_sem. Externally, this can + * be done by either never unregistering the key type, or making sure + * key_alloc() calls don't race with module unloading. */ struct key *key_alloc(struct key_type *type, const char *desc, uid_t uid, gid_t gid, const struct cred *cred, @@ -338,11 +357,18 @@ no_quota: key = ERR_PTR(-EDQUOT); goto error; } - EXPORT_SYMBOL(key_alloc); -/* - * reserve an amount of quota for the key's payload +/** + * key_payload_reserve - Adjust data quota reservation for the key's payload + * @key: The key to make the reservation for. + * @datalen: The amount of data payload the caller now wants. + * + * Adjust the amount of the owning user's key data quota that a key reserves. + * If the amount is increased, then -EDQUOT may be returned if there isn't + * enough free quota available. + * + * If successful, 0 is returned. */ int key_payload_reserve(struct key *key, size_t datalen) { @@ -376,12 +402,13 @@ int key_payload_reserve(struct key *key, size_t datalen) return ret; } - EXPORT_SYMBOL(key_payload_reserve); /* - * instantiate a key and link it into the target keyring atomically - * - called with the target keyring's semaphore writelocked + * Instantiate a key and link it into the target keyring atomically. Must be + * called with the target keyring's semaphore writelocked. The target key's + * semaphore need not be locked as instantiation is serialised by + * key_construction_mutex. */ static int __key_instantiate_and_link(struct key *key, const void *data, @@ -432,8 +459,21 @@ static int __key_instantiate_and_link(struct key *key, return ret; } -/* - * instantiate a key and link it into the target keyring atomically +/** + * key_instantiate_and_link - Instantiate a key and link it into the keyring. + * @key: The key to instantiate. + * @data: The data to use to instantiate the keyring. + * @datalen: The length of @data. + * @keyring: Keyring to create a link in on success (or NULL). + * @authkey: The authorisation token permitting instantiation. + * + * Instantiate a key that's in the uninstantiated state using the provided data + * and, if successful, link it in to the destination keyring if one is + * supplied. + * + * If successful, 0 is returned, the authorisation token is revoked and anyone + * waiting for the key is woken up. If the key was already instantiated, + * -EBUSY will be returned. */ int key_instantiate_and_link(struct key *key, const void *data, @@ -462,8 +502,24 @@ int key_instantiate_and_link(struct key *key, EXPORT_SYMBOL(key_instantiate_and_link); -/* - * negatively instantiate a key and link it into the target keyring atomically +/** + * key_negate_and_link - Negatively instantiate a key and link it into the keyring. + * @key: The key to instantiate. + * @timeout: The timeout on the negative key. + * @keyring: Keyring to create a link in on success (or NULL). + * @authkey: The authorisation token permitting instantiation. + * + * Negatively instantiate a key that's in the uninstantiated state and, if + * successful, set its timeout and link it in to the destination keyring if one + * is supplied. The key and any links to the key will be automatically garbage + * collected after the timeout expires. + * + * Negative keys are used to rate limit repeated request_key() calls by causing + * them to return -ENOKEY until the negative key expires. + * + * If successful, 0 is returned, the authorisation token is revoked and anyone + * waiting for the key is woken up. If the key was already instantiated, + * -EBUSY will be returned. */ int key_negate_and_link(struct key *key, unsigned timeout, @@ -525,15 +581,18 @@ int key_negate_and_link(struct key *key, EXPORT_SYMBOL(key_negate_and_link); /* - * do cleaning up in process context so that we don't have to disable - * interrupts all over the place + * Garbage collect keys in process context so that we don't have to disable + * interrupts all over the place. + * + * key_put() schedules this rather than trying to do the cleanup itself, which + * means key_put() doesn't have to sleep. */ static void key_cleanup(struct work_struct *work) { struct rb_node *_n; struct key *key; - go_again: +go_again: /* look for a dead key in the tree */ spin_lock(&key_serial_lock); @@ -547,7 +606,7 @@ static void key_cleanup(struct work_struct *work) spin_unlock(&key_serial_lock); return; - found_dead_key: +found_dead_key: /* we found a dead key - once we've removed it from the tree, we can * drop the lock */ rb_erase(&key->serial_node, &key_serial_tree); @@ -586,10 +645,13 @@ static void key_cleanup(struct work_struct *work) goto go_again; } -/* - * dispose of a reference to a key - * - when all the references are gone, we schedule the cleanup task to come and - * pull it out of the tree in definite process context +/** + * key_put - Discard a reference to a key. + * @key: The key to discard a reference from. + * + * Discard a reference to a key, and when all the references are gone, we + * schedule the cleanup task to come and pull it out of the tree in process + * context at some later time. */ void key_put(struct key *key) { @@ -600,11 +662,10 @@ void key_put(struct key *key) schedule_work(&key_cleanup_task); } } - EXPORT_SYMBOL(key_put); /* - * find a key by its serial number + * Find a key by its serial number. */ struct key *key_lookup(key_serial_t id) { @@ -626,11 +687,11 @@ struct key *key_lookup(key_serial_t id) goto found; } - not_found: +not_found: key = ERR_PTR(-ENOKEY); goto error; - found: +found: /* pretend it doesn't exist if it is awaiting deletion */ if (atomic_read(&key->usage) == 0) goto not_found; @@ -640,14 +701,16 @@ struct key *key_lookup(key_serial_t id) */ atomic_inc(&key->usage); - error: +error: spin_unlock(&key_serial_lock); return key; } /* - * find and lock the specified key type against removal - * - we return with the sem readlocked + * Find and lock the specified key type against removal. + * + * We return with the sem read-locked if successful. If the type wasn't + * available -ENOKEY is returned instead. */ struct key_type *key_type_lookup(const char *type) { @@ -665,12 +728,12 @@ struct key_type *key_type_lookup(const char *type) up_read(&key_types_sem); ktype = ERR_PTR(-ENOKEY); - found_kernel_type: +found_kernel_type: return ktype; } /* - * unlock a key type + * Unlock a key type locked by key_type_lookup(). */ void key_type_put(struct key_type *ktype) { @@ -678,9 +741,10 @@ void key_type_put(struct key_type *ktype) } /* - * attempt to update an existing key - * - the key has an incremented refcount - * - we need to put the key if we get an error + * Attempt to update an existing key. + * + * The key is given to us with an incremented refcount that we need to discard + * if we get an error. */ static inline key_ref_t __key_update(key_ref_t key_ref, const void *payload, size_t plen) @@ -717,9 +781,30 @@ error: goto out; } -/* - * search the specified keyring for a key of the same description; if one is - * found, update it, otherwise add a new one +/** + * key_create_or_update - Update or create and instantiate a key. + * @keyring_ref: A pointer to the destination keyring with possession flag. + * @type: The type of key. + * @description: The searchable description for the key. + * @payload: The data to use to instantiate or update the key. + * @plen: The length of @payload. + * @perm: The permissions mask for a new key. + * @flags: The quota flags for a new key. + * + * Search the destination keyring for a key of the same description and if one + * is found, update it, otherwise create and instantiate a new one and create a + * link to it from that keyring. + * + * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be + * concocted. + * + * Returns a pointer to the new key if successful, -ENODEV if the key type + * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the + * caller isn't permitted to modify the keyring or the LSM did not permit + * creation of the key. + * + * On success, the possession flag from the keyring ref will be tacked on to + * the key ref before it is returned. */ key_ref_t key_create_or_update(key_ref_t keyring_ref, const char *type, @@ -827,11 +912,20 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, key_ref = __key_update(key_ref, payload, plen); goto error; } - EXPORT_SYMBOL(key_create_or_update); -/* - * update a key +/** + * key_update - Update a key's contents. + * @key_ref: The pointer (plus possession flag) to the key. + * @payload: The data to be used to update the key. + * @plen: The length of @payload. + * + * Attempt to update the contents of a key with the given payload data. The + * caller must be granted Write permission on the key. Negative keys can be + * instantiated by this method. + * + * Returns 0 on success, -EACCES if not permitted and -EOPNOTSUPP if the key + * type does not support updating. The key type may return other errors. */ int key_update(key_ref_t key_ref, const void *payload, size_t plen) { @@ -861,11 +955,16 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) error: return ret; } - EXPORT_SYMBOL(key_update); -/* - * revoke a key +/** + * key_revoke - Revoke a key. + * @key: The key to be revoked. + * + * Mark a key as being revoked and ask the type to free up its resources. The + * revocation timeout is set and the key and all its links will be + * automatically garbage collected after key_gc_delay amount of time if they + * are not manually dealt with first. */ void key_revoke(struct key *key) { @@ -894,11 +993,15 @@ void key_revoke(struct key *key) up_write(&key->sem); } - EXPORT_SYMBOL(key_revoke); -/* - * register a type of key +/** + * register_key_type - Register a type of key. + * @ktype: The new key type. + * + * Register a new key type. + * + * Returns 0 on success or -EEXIST if a type of this name already exists. */ int register_key_type(struct key_type *ktype) { @@ -918,15 +1021,19 @@ int register_key_type(struct key_type *ktype) list_add(&ktype->link, &key_types_list); ret = 0; - out: +out: up_write(&key_types_sem); return ret; } - EXPORT_SYMBOL(register_key_type); -/* - * unregister a type of key +/** + * unregister_key_type - Unregister a type of key. + * @ktype: The key type. + * + * Unregister a key type and mark all the extant keys of this type as dead. + * Those keys of this type are then destroyed to get rid of their payloads and + * they and their links will be garbage collected as soon as possible. */ void unregister_key_type(struct key_type *ktype) { @@ -974,11 +1081,10 @@ void unregister_key_type(struct key_type *ktype) key_schedule_gc(0); } - EXPORT_SYMBOL(unregister_key_type); /* - * initialise the key management stuff + * Initialise the key management state. */ void __init key_init(void) { |