📄 key.c
字号:
/* and link it into the destination keyring */ if (keyring) ret = __key_link(keyring, key); /* disable the authorisation key */ if (instkey) key_revoke(instkey); } 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_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); return ret;} /* end key_negate_and_link() */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 */static void key_cleanup(struct work_struct *work){ struct rb_node *_n; struct key *key; go_again: /* look for a dead key in the tree */ spin_lock(&key_serial_lock); for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { key = rb_entry(_n, struct key, serial_node); if (atomic_read(&key->usage) == 0) goto found_dead_key; } spin_unlock(&key_serial_lock); return; 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); spin_unlock(&key_serial_lock); key_check(key); security_key_free(key); /* deal with the user's key tracking and quota */ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { spin_lock(&key->user->lock); key->user->qnkeys--; key->user->qnbytes -= key->quotalen; spin_unlock(&key->user->lock); } atomic_dec(&key->user->nkeys); if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) atomic_dec(&key->user->nikeys); key_user_put(key->user); /* now throw away the key memory */ if (key->type->destroy) key->type->destroy(key); kfree(key->description);#ifdef KEY_DEBUGGING key->magic = KEY_DEBUG_MAGIC_X;#endif kmem_cache_free(key_jar, key); /* there may, of course, be more than one key to destroy */ goto go_again;} /* end key_cleanup() *//*****************************************************************************//* * 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 */void key_put(struct key *key){ if (key) { key_check(key); if (atomic_dec_and_test(&key->usage)) schedule_work(&key_cleanup_task); }} /* end key_put() */EXPORT_SYMBOL(key_put);/*****************************************************************************//* * find a key by its serial number */struct key *key_lookup(key_serial_t id){ struct rb_node *n; struct key *key; spin_lock(&key_serial_lock); /* search the tree for the specified key */ n = key_serial_tree.rb_node; while (n) { key = rb_entry(n, struct key, serial_node); if (id < key->serial) n = n->rb_left; else if (id > key->serial) n = n->rb_right; else goto found; } not_found: key = ERR_PTR(-ENOKEY); goto error; found: /* pretend it doesn't exist if it's dead */ if (atomic_read(&key->usage) == 0 || test_bit(KEY_FLAG_DEAD, &key->flags) || key->type == &key_type_dead) goto not_found; /* this races with key_put(), but that doesn't matter since key_put() * doesn't actually change the key */ atomic_inc(&key->usage); error: spin_unlock(&key_serial_lock); return key;} /* end key_lookup() *//*****************************************************************************//* * find and lock the specified key type against removal * - we return with the sem readlocked */struct key_type *key_type_lookup(const char *type){ struct key_type *ktype; down_read(&key_types_sem); /* look up the key type to see if it's one of the registered kernel * types */ list_for_each_entry(ktype, &key_types_list, link) { if (strcmp(ktype->name, type) == 0) goto found_kernel_type; } up_read(&key_types_sem); ktype = ERR_PTR(-ENOKEY); found_kernel_type: return ktype;} /* end key_type_lookup() *//*****************************************************************************//* * unlock a key type */void key_type_put(struct key_type *ktype){ up_read(&key_types_sem);} /* end key_type_put() *//*****************************************************************************//* * attempt to update an existing key * - the key has an incremented refcount * - we need to put the key if we get an error */static inline key_ref_t __key_update(key_ref_t key_ref, const void *payload, size_t plen){ struct key *key = key_ref_to_ptr(key_ref); int ret; /* need write permission on the key to update it */ ret = key_permission(key_ref, KEY_WRITE); if (ret < 0) goto error; ret = -EEXIST; if (!key->type->update) goto error; down_write(&key->sem); ret = key->type->update(key, payload, plen); if (ret == 0) /* updating a negative key instantiates it */ clear_bit(KEY_FLAG_NEGATIVE, &key->flags); up_write(&key->sem); if (ret < 0) goto error;out: return key_ref;error: key_put(key); key_ref = ERR_PTR(ret); goto out;} /* end __key_update() *//*****************************************************************************//* * search the specified keyring for a key of the same description; if one is * found, update it, otherwise add a new one */key_ref_t key_create_or_update(key_ref_t keyring_ref, const char *type, const char *description, const void *payload, size_t plen, unsigned long flags){ struct key_type *ktype; struct key *keyring, *key = NULL; key_perm_t perm; key_ref_t key_ref; int ret; /* look up the key type to see if it's one of the registered kernel * types */ ktype = key_type_lookup(type); if (IS_ERR(ktype)) { key_ref = ERR_PTR(-ENODEV); goto error; } key_ref = ERR_PTR(-EINVAL); if (!ktype->match || !ktype->instantiate) goto error_2; keyring = key_ref_to_ptr(keyring_ref); key_check(keyring); key_ref = ERR_PTR(-ENOTDIR); if (keyring->type != &key_type_keyring) goto error_2; down_write(&keyring->sem); /* if we're going to allocate a new key, we're going to have * to modify the keyring */ ret = key_permission(keyring_ref, KEY_WRITE); if (ret < 0) { key_ref = ERR_PTR(ret); goto error_3; } /* if it's possible to update this type of key, search for an existing * key of the same type and description in the destination keyring and * update that instead if possible */ if (ktype->update) { key_ref = __keyring_search_one(keyring_ref, ktype, description, 0); if (!IS_ERR(key_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 (ktype->read) perm |= KEY_POS_READ | KEY_USR_READ; 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)); goto error_3; } /* instantiate it and link it into the target keyring */ ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL); if (ret < 0) { key_put(key); key_ref = ERR_PTR(ret); goto error_3; } key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); error_3: up_write(&keyring->sem); error_2: key_type_put(ktype); error: return key_ref; found_matching_key: /* we found a matching key, so we're going to try to update it * - we can drop the locks first as we have the key pinned */ up_write(&keyring->sem); key_type_put(ktype); key_ref = __key_update(key_ref, payload, plen); goto error;} /* end key_create_or_update() */EXPORT_SYMBOL(key_create_or_update);/*****************************************************************************//* * update a key */int key_update(key_ref_t key_ref, const void *payload, size_t plen){ struct key *key = key_ref_to_ptr(key_ref); int ret; key_check(key); /* the key must be writable */ ret = key_permission(key_ref, KEY_WRITE); if (ret < 0) goto error; /* attempt to update it if supported */ ret = -EOPNOTSUPP; if (key->type->update) { down_write(&key->sem); ret = key->type->update(key, payload, plen); if (ret == 0) /* updating a negative key instantiates it */ clear_bit(KEY_FLAG_NEGATIVE, &key->flags); up_write(&key->sem); } error: return ret;} /* end key_update() */EXPORT_SYMBOL(key_update);/*****************************************************************************//* * revoke a key */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 * - 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);} /* end key_revoke() */EXPORT_SYMBOL(key_revoke);/*****************************************************************************//* * register a type of key */int register_key_type(struct key_type *ktype){ struct key_type *p; int ret; ret = -EEXIST; down_write(&key_types_sem); /* disallow key types with the same name */ list_for_each_entry(p, &key_types_list, link) { if (strcmp(p->name, ktype->name) == 0) goto out; } /* store the type */ list_add(&ktype->link, &key_types_list); ret = 0; out: up_write(&key_types_sem); return ret;} /* end register_key_type() */EXPORT_SYMBOL(register_key_type);/*****************************************************************************//* * unregister a type of key */void unregister_key_type(struct key_type *ktype){ struct rb_node *_n; struct key *key; down_write(&key_types_sem); /* withdraw the key type */ list_del_init(&ktype->link); /* mark all the keys of this type dead */ spin_lock(&key_serial_lock); for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { key = rb_entry(_n, struct key, serial_node); if (key->type == ktype) key->type = &key_type_dead; } spin_unlock(&key_serial_lock); /* make sure everyone revalidates their keys */ synchronize_rcu(); /* we should now be able to destroy the payloads of all the keys of * this type with impunity */ spin_lock(&key_serial_lock); for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { key = rb_entry(_n, struct key, serial_node); if (key->type == ktype) { if (ktype->destroy) ktype->destroy(key); memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); } } spin_unlock(&key_serial_lock); up_write(&key_types_sem);} /* end unregister_key_type() */EXPORT_SYMBOL(unregister_key_type);/*****************************************************************************//* * initialise the key management stuff */void __init key_init(void){ /* allocate a slab in which we can store keys */ key_jar = kmem_cache_create("key_jar", sizeof(struct key), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); /* add the special key types */ list_add_tail(&key_type_keyring.link, &key_types_list); list_add_tail(&key_type_dead.link, &key_types_list); list_add_tail(&key_type_user.link, &key_types_list); /* record the root user tracking */ rb_link_node(&root_key_user.node, NULL, &key_user_tree.rb_node); 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() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -