/* Keyring handling * * Copyright (C) 2004-2005, 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 * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/security.h>#include <linux/seq_file.h>#include <linux/err.h>#include <keys/keyring-type.h>#include <linux/uaccess.h>#include "internal.h" #define rcu_dereference_locked_keyring(keyring) \ (rcu_dereference_protected( \ (keyring)->payload.subscriptions, \ rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) #define rcu_deref_link_locked(klist, index, keyring) \ (rcu_dereference_protected( \ (klist)->keys[index], \ rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) #define MAX_KEYRING_LINKS \ min_t(size_t, USHRT_MAX - 1, \ ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) #define KEY_LINK_FIXQUOTA 1UL /* * When plumbing the depths of the key tree, this sets a hard limit * set on how deep we're willing to go. */#define KEYRING_SEARCH_MAX_DEPTH 6 /* * We keep all named keyrings in a hash to speed looking them up. */#define KEYRING_NAME_HASH_SIZE (1 << 5) static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE];static DEFINE_RWLOCK(keyring_name_lock); static inline unsigned keyring_hash(const char *desc){ unsigned bucket = 0; for (; *desc; desc++) bucket += (unsigned char)*desc; return bucket & (KEYRING_NAME_HASH_SIZE - 1);} /* * The keyring key type definition. Keyrings are simply keys of this type and * can be treated as ordinary keys in addition to having their own special * operations. */static int keyring_instantiate(struct key *keyring, const void *data, size_t datalen);static int keyring_match(const struct key *keyring, const void *criterion);static void keyring_revoke(struct key *keyring);static void keyring_destroy(struct key *keyring);static void keyring_describe(const struct key *keyring, struct seq_file *m);static long keyring_read(const struct key *keyring, char __user *buffer, size_t buflen); struct key_type key_type_keyring = { .name = "keyring", .def_datalen = sizeof(struct keyring_list), .instantiate = keyring_instantiate, .match = keyring_match, .revoke = keyring_revoke, .destroy = keyring_destroy, .describe = keyring_describe, .read = keyring_read,};EXPORT_SYMBOL(key_type_keyring); /* * Semaphore to serialise link/link calls to prevent two link calls in parallel * introducing a cycle. */static DECLARE_RWSEM(keyring_serialise_link_sem); /* * Publish the name of a keyring so that it can be found by name (if it has * one). */static void keyring_publish_name(struct key *keyring){ int bucket; if (keyring->description) { bucket = keyring_hash(keyring->description); write_lock(&keyring_name_lock); if (!keyring_name_hash[bucket].next) INIT_LIST_HEAD(&keyring_name_hash[bucket]); list_add_tail(&keyring->type_data.link, &keyring_name_hash[bucket]); write_unlock(&keyring_name_lock); }} /* * Initialise a keyring. * * Returns 0 on success, -EINVAL if given any data. */static int keyring_instantiate(struct key *keyring, const void *data, size_t datalen){ int ret; ret = -EINVAL; if (datalen == 0) { /* make the keyring available by name if it has one */ keyring_publish_name(keyring); ret = 0; } return ret;} /* * Match keyrings on their name */static int keyring_match(const struct key *keyring, const void *description){ return keyring->description && strcmp(keyring->description, description) == 0;} /* * Clean up a keyring when it is destroyed. Unpublish its name if it had one * and dispose of its data. * * The garbage collector detects the final key_put(), removes the keyring from * the serial number tree and then does RCU synchronisation before coming here, * so we shouldn't need to worry about code poking around here with the RCU * readlock held by this time. */static void keyring_destroy(struct key *keyring){ struct keyring_list *klist; int loop; if (keyring->description) { write_lock(&keyring_name_lock); if (keyring->type_data.link.next != NULL && !list_empty(&keyring->type_data.link)) list_del(&keyring->type_data.link); write_unlock(&keyring_name_lock); } klist = rcu_access_pointer(keyring->payload.subscriptions); if (klist) { for (loop = klist->nkeys - 1; loop >= 0; loop--) key_put(rcu_access_pointer(klist->keys[loop])); kfree(klist); }} /* * Describe a keyring for /proc. */static void keyring_describe(const struct key *keyring, struct seq_file *m){ struct keyring_list *klist; if (keyring->description) seq_puts(m, keyring->description); else seq_puts(m, "[anon]"); if (key_is_instantiated(keyring)) { rcu_read_lock(); klist = rcu_dereference(keyring->payload.subscriptions); if (klist) seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); else seq_puts(m, ": empty"); rcu_read_unlock(); }} /* * Read a list of key IDs from the keyring's contents in binary form * * The keyring's semaphore is read-locked by the caller. */static long keyring_read(const struct key *keyring, char __user *buffer, size_t buflen){ struct keyring_list *klist; struct key *key; size_t qty, tmp; int loop, ret; ret = 0; klist = rcu_dereference_locked_keyring(keyring); if (klist) { /* calculate how much data we could return */ qty = klist->nkeys * sizeof(key_serial_t); if (buffer && buflen > 0) { if (buflen > qty) buflen = qty; /* copy the IDs of the subscribed keys into the * buffer */ ret = -EFAULT; for (loop = 0; loop < klist->nkeys; loop++) { key = rcu_deref_link_locked(klist, loop, keyring); tmp = sizeof(key_serial_t); if (tmp > buflen) tmp = buflen; if (copy_to_user(buffer, &key->serial, tmp) != 0) goto error; buflen -= tmp; if (buflen == 0) break; buffer += tmp; } } ret = qty; } error: return ret;} /* * Allocate a keyring and link into the destination keyring. */struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, const struct cred *cred, unsigned long flags, struct key *dest){ struct key *keyring; int ret; keyring = key_alloc(&key_type_keyring, description, uid, gid, cred, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, flags); if (!IS_ERR(keyring)) { ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); if (ret < 0) { key_put(keyring); keyring = ERR_PTR(ret); } } return keyring;} /** * keyring_search_aux - Search a keyring tree for a key matching some criteria * @keyring_ref: A pointer to the keyring with possession indicator. * @cred: The credentials to use for permissions checks. * @type: The type of key to search for. * @description: Parameter for @match. * @match: Function to rule on whether or not a key is the one required. * @no_state_check: Don't check if a matching key is bad * * Search the supplied keyring tree for a key that matches the criteria given. * The root keyring and any linked keyrings must grant Search permission to the * caller to be searchable and keys can only be found if they too grant Search * to the caller. The possession flag on the root keyring pointer controls use * of the possessor bits in permissions checking of the entire tree. In * addition, the LSM gets to forbid keyring searches and key matches. * * The search is performed as a breadth-then-depth search up to the prescribed * limit (KEYRING_SEARCH_MAX_DEPTH). * * Keys are matched to the type provided and are then filtered by the match * function, which is given the description to use in any way it sees fit. The * match function may use any attributes of a key that it wishes to to * determine the match. Normally the match function from the key type would be * used. * * RCU is used to prevent the keyring key lists from disappearing without the * need to take lots of locks. * * Returns a pointer to the found key and increments the key usage count if * successful; -EAGAIN if no matching keys were found, or if expired or revoked * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the * specified keyring wasn't a keyring. * * In the case of a successful return, the possession attribute from * @keyring_ref is propagated to the returned key reference. */key_ref_t keyring_search_aux(key_ref_t keyring_ref, const struct cred *cred, struct key_type *type, const void *description, key_match_func_t match, bool no_state_check){ struct { /* Need a separate keylist pointer for RCU purposes */ struct key *keyring; struct keyring_list *keylist; int kix; } stack[KEYRING_SEARCH_MAX_DEPTH]; struct keyring_list *keylist; struct timespec now; unsigned long possessed, kflags; struct key *keyring, *key; key_ref_t key_ref; long err; int sp, nkeys, kix; keyring = key_ref_to_ptr(keyring_ref); possessed = is_key_possessed(keyring_ref); key_check(keyring); /* top keyring must have search permission to begin the search */ err = key_task_permission(keyring_ref, cred, KEY_SEARCH); if (err < 0) { key_ref = ERR_PTR(err); goto error; } key_ref = ERR_PTR(-ENOTDIR); if (keyring->type != &key_type_keyring) goto error; rcu_read_lock(); now = current_kernel_time(); err = -EAGAIN; sp = 0; /* firstly we should check to see if this top-level keyring is what we * are looking for */ key_ref = ERR_PTR(-EAGAIN); kflags = keyring->flags; if (keyring->type == type && match(keyring, description)) { key = keyring; if (no_state_check) goto found; /* check it isn't negative and hasn't expired or been * revoked */ if (kflags & (1 << KEY_FLAG_REVOKED)) goto error_2; if (key->expiry && now.tv_sec >= key->expiry) goto error_2; key_ref = ERR_PTR(key->type_data.reject_error); if (kflags & (1 << KEY_FLAG_NEGATIVE)) goto error_2; goto found; } /* otherwise, the top keyring must not be revoked, expired, or * negatively instantiated if we are to search it */ key_ref = ERR_PTR(-EAGAIN); if (kflags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || (keyring->expiry && now.tv_sec >= keyring->expiry)) goto error_2; /* start processing a new keyring */descend: kflags = keyring->flags; if (kflags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED))) goto not_this_keyring; keylist = rcu_dereference(keyring->payload.subscriptions); if (!keylist) goto not_this_keyring; /* iterate through the keys in this keyring first */ nkeys = keylist->nkeys; smp_rmb(); for (kix = 0; kix < nkeys; kix++) { key = rcu_dereference(keylist->keys[kix]); kflags = key->flags; /* ignore keys not of this type */ if (key->type != type) continue; /* skip invalidated, revoked and expired keys */ if (!no_state_check) { if (kflags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED))) continue; if (key->expiry && now.tv_sec >= key->expiry) continue; } /* keys that don't match */ if (!match(key, description)) continue; /* key must have search permissions */ if (key_task_permission(make_key_ref(key, possessed), cred, KEY_SEARCH) < 0) continue; if (no_state_check) goto found; /* we set a different error code if we pass a negative key */ if (kflags & (1 << KEY_FLAG_NEGATIVE)) { err = key->type_data.reject_error; continue; } goto found; } /* search through the keyrings nested in this one */ kix = 0;ascend: nkeys = keylist->nkeys; smp_rmb(); for (; kix < nkeys; kix++) { key = rcu_dereference(keylist->keys[kix]); if (key->type != &key_type_keyring) continue; /* recursively search nested keyrings * - only search keyrings for which we have search permission */ if (sp >= KEYRING_SEARCH_MAX_DEPTH) continue; if (key_task_permission(make_key_ref(key, possessed), cred, KEY_SEARCH) < 0) continue; /* stack the current position */ stack[sp].keyring = keyring; stack[sp].keylist = keylist; stack[sp].kix = kix; sp++; /* begin again with the new keyring */ keyring = key; goto descend; } /* the keyring we're looking at was disqualified or didn't contain a * matching key */not_this_keyring: if (sp > 0) { /* resume the processing of a keyring higher up in the tree */ sp--; keyring = stack[sp].keyring; keylist = stack[sp].keylist; kix = stack[sp].kix + 1; goto ascend; } key_ref = ERR_PTR(err); goto error_2; /* we found a viable match */found: atomic_inc(&key->usage); key->last_used_at = now.tv_sec; keyring->last_used_at = now.tv_sec; while (sp > 0) stack[--sp].keyring->last_used_at = now.tv_sec; key_check(key); key_ref = make_key_ref(key, possessed);error_2: rcu_read_unlock();Lines 1–500 of 1279. Load more
/* Keyring handling * * Copyright (C) 2004-2005, 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 * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/security.h> #include <linux/seq_file.h> #include <linux/err.h> #include <keys/keyring-type.h> #include <linux/uaccess.h> #include "internal.h" #define rcu_dereference_locked_keyring(keyring) \ (rcu_dereference_protected( \ (keyring)->payload.subscriptions, \ rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) #define rcu_deref_link_locked(klist, index, keyring) \ (rcu_dereference_protected( \ (klist)->keys[index], \ rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) #define MAX_KEYRING_LINKS \ min_t(size_t, USHRT_MAX - 1, \ ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) #define KEY_LINK_FIXQUOTA 1UL /* * When plumbing the depths of the key tree, this sets a hard limit * set on how deep we're willing to go. */ #define KEYRING_SEARCH_MAX_DEPTH 6 /* * We keep all named keyrings in a hash to speed looking them up. */ #define KEYRING_NAME_HASH_SIZE (1 << 5) static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; static DEFINE_RWLOCK(keyring_name_lock); static inline unsigned keyring_hash(const char *desc) { unsigned bucket = 0; for (; *desc; desc++) bucket += (unsigned char)*desc; return bucket & (KEYRING_NAME_HASH_SIZE - 1); } /* * The keyring key type definition. Keyrings are simply keys of this type and * can be treated as ordinary keys in addition to having their own special * operations. */ static int keyring_instantiate(struct key *keyring, const void *data, size_t datalen); static int keyring_match(const struct key *keyring, const void *criterion); static void keyring_revoke(struct key *keyring); static void keyring_destroy(struct key *keyring); static void keyring_describe(const struct key *keyring, struct seq_file *m); static long keyring_read(const struct key *keyring, char __user *buffer, size_t buflen); struct key_type key_type_keyring = { .name = "keyring", .def_datalen = sizeof(struct keyring_list), .instantiate = keyring_instantiate, .match = keyring_match, .revoke = keyring_revoke, .destroy = keyring_destroy, .describe = keyring_describe, .read = keyring_read, }; EXPORT_SYMBOL(key_type_keyring); /* * Semaphore to serialise link/link calls to prevent two link calls in parallel * introducing a cycle. */ static DECLARE_RWSEM(keyring_serialise_link_sem); /* * Publish the name of a keyring so that it can be found by name (if it has * one). */ static void keyring_publish_name(struct key *keyring) { int bucket; if (keyring->description) { bucket = keyring_hash(keyring->description); write_lock(&keyring_name_lock); if (!keyring_name_hash[bucket].next) INIT_LIST_HEAD(&keyring_name_hash[bucket]); list_add_tail(&keyring->type_data.link, &keyring_name_hash[bucket]); write_unlock(&keyring_name_lock); } } /* * Initialise a keyring. * * Returns 0 on success, -EINVAL if given any data. */ static int keyring_instantiate(struct key *keyring, const void *data, size_t datalen) { int ret; ret = -EINVAL; if (datalen == 0) { /* make the keyring available by name if it has one */ keyring_publish_name(keyring); ret = 0; } return ret; } /* * Match keyrings on their name */ static int keyring_match(const struct key *keyring, const void *description) { return keyring->description && strcmp(keyring->description, description) == 0; } /* * Clean up a keyring when it is destroyed. Unpublish its name if it had one * and dispose of its data. * * The garbage collector detects the final key_put(), removes the keyring from * the serial number tree and then does RCU synchronisation before coming here, * so we shouldn't need to worry about code poking around here with the RCU * readlock held by this time. */ static void keyring_destroy(struct key *keyring) { struct keyring_list *klist; int loop; if (keyring->description) { write_lock(&keyring_name_lock); if (keyring->type_data.link.next != NULL && !list_empty(&keyring->type_data.link)) list_del(&keyring->type_data.link); write_unlock(&keyring_name_lock); } klist = rcu_access_pointer(keyring->payload.subscriptions); if (klist) { for (loop = klist->nkeys - 1; loop >= 0; loop--) key_put(rcu_access_pointer(klist->keys[loop])); kfree(klist); } } /* * Describe a keyring for /proc. */ static void keyring_describe(const struct key *keyring, struct seq_file *m) { struct keyring_list *klist; if (keyring->description) seq_puts(m, keyring->description); else seq_puts(m, "[anon]"); if (key_is_instantiated(keyring)) { rcu_read_lock(); klist = rcu_dereference(keyring->payload.subscriptions); if (klist) seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); else seq_puts(m, ": empty"); rcu_read_unlock(); } } /* * Read a list of key IDs from the keyring's contents in binary form * * The keyring's semaphore is read-locked by the caller. */ static long keyring_read(const struct key *keyring, char __user *buffer, size_t buflen) { struct keyring_list *klist; struct key *key; size_t qty, tmp; int loop, ret; ret = 0; klist = rcu_dereference_locked_keyring(keyring); if (klist) { /* calculate how much data we could return */ qty = klist->nkeys * sizeof(key_serial_t); if (buffer && buflen > 0) { if (buflen > qty) buflen = qty; /* copy the IDs of the subscribed keys into the * buffer */ ret = -EFAULT; for (loop = 0; loop < klist->nkeys; loop++) { key = rcu_deref_link_locked(klist, loop, keyring); tmp = sizeof(key_serial_t); if (tmp > buflen) tmp = buflen; if (copy_to_user(buffer, &key->serial, tmp) != 0) goto error; buflen -= tmp; if (buflen == 0) break; buffer += tmp; } } ret = qty; } error: return ret; } /* * Allocate a keyring and link into the destination keyring. */ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, const struct cred *cred, unsigned long flags, struct key *dest) { struct key *keyring; int ret; keyring = key_alloc(&key_type_keyring, description, uid, gid, cred, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, flags); if (!IS_ERR(keyring)) { ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); if (ret < 0) { key_put(keyring); keyring = ERR_PTR(ret); } } return keyring; } /** * keyring_search_aux - Search a keyring tree for a key matching some criteria * @keyring_ref: A pointer to the keyring with possession indicator. * @cred: The credentials to use for permissions checks. * @type: The type of key to search for. * @description: Parameter for @match. * @match: Function to rule on whether or not a key is the one required. * @no_state_check: Don't check if a matching key is bad * * Search the supplied keyring tree for a key that matches the criteria given. * The root keyring and any linked keyrings must grant Search permission to the * caller to be searchable and keys can only be found if they too grant Search * to the caller. The possession flag on the root keyring pointer controls use * of the possessor bits in permissions checking of the entire tree. In * addition, the LSM gets to forbid keyring searches and key matches. * * The search is performed as a breadth-then-depth search up to the prescribed * limit (KEYRING_SEARCH_MAX_DEPTH). * * Keys are matched to the type provided and are then filtered by the match * function, which is given the description to use in any way it sees fit. The * match function may use any attributes of a key that it wishes to to * determine the match. Normally the match function from the key type would be * used. * * RCU is used to prevent the keyring key lists from disappearing without the * need to take lots of locks. * * Returns a pointer to the found key and increments the key usage count if * successful; -EAGAIN if no matching keys were found, or if expired or revoked * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the * specified keyring wasn't a keyring. * * In the case of a successful return, the possession attribute from * @keyring_ref is propagated to the returned key reference. */ key_ref_t keyring_search_aux(key_ref_t keyring_ref, const struct cred *cred, struct key_type *type, const void *description, key_match_func_t match, bool no_state_check) { struct { /* Need a separate keylist pointer for RCU purposes */ struct key *keyring; struct keyring_list *keylist; int kix; } stack[KEYRING_SEARCH_MAX_DEPTH]; struct keyring_list *keylist; struct timespec now; unsigned long possessed, kflags; struct key *keyring, *key; key_ref_t key_ref; long err; int sp, nkeys, kix; keyring = key_ref_to_ptr(keyring_ref); possessed = is_key_possessed(keyring_ref); key_check(keyring); /* top keyring must have search permission to begin the search */ err = key_task_permission(keyring_ref, cred, KEY_SEARCH); if (err < 0) { key_ref = ERR_PTR(err); goto error; } key_ref = ERR_PTR(-ENOTDIR); if (keyring->type != &key_type_keyring) goto error; rcu_read_lock(); now = current_kernel_time(); err = -EAGAIN; sp = 0; /* firstly we should check to see if this top-level keyring is what we * are looking for */ key_ref = ERR_PTR(-EAGAIN); kflags = keyring->flags; if (keyring->type == type && match(keyring, description)) { key = keyring; if (no_state_check) goto found; /* check it isn't negative and hasn't expired or been * revoked */ if (kflags & (1 << KEY_FLAG_REVOKED)) goto error_2; if (key->expiry && now.tv_sec >= key->expiry) goto error_2; key_ref = ERR_PTR(key->type_data.reject_error); if (kflags & (1 << KEY_FLAG_NEGATIVE)) goto error_2; goto found; } /* otherwise, the top keyring must not be revoked, expired, or * negatively instantiated if we are to search it */ key_ref = ERR_PTR(-EAGAIN); if (kflags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || (keyring->expiry && now.tv_sec >= keyring->expiry)) goto error_2; /* start processing a new keyring */ descend: kflags = keyring->flags; if (kflags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED))) goto not_this_keyring; keylist = rcu_dereference(keyring->payload.subscriptions); if (!keylist) goto not_this_keyring; /* iterate through the keys in this keyring first */ nkeys = keylist->nkeys; smp_rmb(); for (kix = 0; kix < nkeys; kix++) { key = rcu_dereference(keylist->keys[kix]); kflags = key->flags; /* ignore keys not of this type */ if (key->type != type) continue; /* skip invalidated, revoked and expired keys */ if (!no_state_check) { if (kflags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED))) continue; if (key->expiry && now.tv_sec >= key->expiry) continue; } /* keys that don't match */ if (!match(key, description)) continue; /* key must have search permissions */ if (key_task_permission(make_key_ref(key, possessed), cred, KEY_SEARCH) < 0) continue; if (no_state_check) goto found; /* we set a different error code if we pass a negative key */ if (kflags & (1 << KEY_FLAG_NEGATIVE)) { err = key->type_data.reject_error; continue; } goto found; } /* search through the keyrings nested in this one */ kix = 0; ascend: nkeys = keylist->nkeys; smp_rmb(); for (; kix < nkeys; kix++) { key = rcu_dereference(keylist->keys[kix]); if (key->type != &key_type_keyring) continue; /* recursively search nested keyrings * - only search keyrings for which we have search permission */ if (sp >= KEYRING_SEARCH_MAX_DEPTH) continue; if (key_task_permission(make_key_ref(key, possessed), cred, KEY_SEARCH) < 0) continue; /* stack the current position */ stack[sp].keyring = keyring; stack[sp].keylist = keylist; stack[sp].kix = kix; sp++; /* begin again with the new keyring */ keyring = key; goto descend; } /* the keyring we're looking at was disqualified or didn't contain a * matching key */ not_this_keyring: if (sp > 0) { /* resume the processing of a keyring higher up in the tree */ sp--; keyring = stack[sp].keyring; keylist = stack[sp].keylist; kix = stack[sp].kix + 1; goto ascend; } key_ref = ERR_PTR(err); goto error_2; /* we found a viable match */ found: atomic_inc(&key->usage); key->last_used_at = now.tv_sec; keyring->last_used_at = now.tv_sec; while (sp > 0) stack[--sp].keyring->last_used_at = now.tv_sec; key_check(key); key_ref = make_key_ref(key, possessed); error_2: rcu_read_unlock();