⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyring.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* keyring.c: keyring handling * * Copyright (C) 2004-5 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 <asm/uaccess.h>#include "internal.h"/* * 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 type definition */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) */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);	}} /* end keyring_publish_name() *//*****************************************************************************//* * initialise a keyring * - we object if we were 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;} /* end keyring_instantiate() *//*****************************************************************************//* * match keyrings on their name */static int keyring_match(const struct key *keyring, const void *description){	return keyring->description &&		strcmp(keyring->description, description) == 0;} /* end keyring_match() *//*****************************************************************************//* * dispose of the data dangling from the corpse of a keyring */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_dereference(keyring->payload.subscriptions);	if (klist) {		for (loop = klist->nkeys - 1; loop >= 0; loop--)			key_put(klist->keys[loop]);		kfree(klist);	}} /* end keyring_destroy() *//*****************************************************************************//* * describe the keyring */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]");	}	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();} /* end keyring_describe() *//*****************************************************************************//* * read a list of key IDs from the keyring's contents * - the keyring's semaphore is read-locked */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(keyring->payload.subscriptions);	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 = klist->keys[loop];				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;} /* end keyring_read() *//*****************************************************************************//* * allocate a keyring and link into the destination keyring */struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,			  struct task_struct *ctx, unsigned long flags,			  struct key *dest){	struct key *keyring;	int ret;	keyring = key_alloc(&key_type_keyring, description,			    uid, gid, ctx,			    (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;} /* end keyring_alloc() *//*****************************************************************************//* * search the supplied keyring tree for a key that matches the criterion * - perform a breadth-then-depth search up to the prescribed limit * - we only find keys on which we have search permission * - we use the supplied match function to see if the description (or other *   feature of interest) matches * - we rely on RCU to prevent the keyring lists from disappearing on us * - we return -EAGAIN if we didn't find any matching key * - we return -ENOKEY if we only found negative matching keys * - we propagate the possession attribute from the keyring ref to the key ref */key_ref_t keyring_search_aux(key_ref_t keyring_ref,			     struct task_struct *context,			     struct key_type *type,			     const void *description,			     key_match_func_t match){	struct {		struct keyring_list *keylist;		int kix;	} stack[KEYRING_SEARCH_MAX_DEPTH];	struct keyring_list *keylist;	struct timespec now;	unsigned long possessed;	struct key *keyring, *key;	key_ref_t key_ref;	long err;	int sp, 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, context, 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;	/* start processing a new keyring */descend:	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))		goto not_this_keyring;	keylist = rcu_dereference(keyring->payload.subscriptions);	if (!keylist)		goto not_this_keyring;	/* iterate through the keys in this keyring first */	for (kix = 0; kix < keylist->nkeys; kix++) {		key = keylist->keys[kix];		/* ignore keys not of this type */		if (key->type != type)			continue;		/* skip revoked keys and expired keys */		if (test_bit(KEY_FLAG_REVOKED, &key->flags))			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),					context, KEY_SEARCH) < 0)			continue;		/* we set a different error code if we find a negative key */		if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {			err = -ENOKEY;			continue;		}		goto found;	}	/* search through the keyrings nested in this one */	kix = 0;ascend:	for (; kix < keylist->nkeys; kix++) {		key = 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),					context, KEY_SEARCH) < 0)			continue;		/* stack the current position */		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--;		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_check(key);	key_ref = make_key_ref(key, possessed);error_2:	rcu_read_unlock();error:	return key_ref;} /* end keyring_search_aux() *//*****************************************************************************//* * search the supplied keyring tree for a key that matches the criterion * - perform a breadth-then-depth search up to the prescribed limit * - we only find keys on which we have search permission * - we readlock the keyrings as we search down the tree * - we return -EAGAIN if we didn't find any matching key * - we return -ENOKEY if we only found negative matching keys */key_ref_t keyring_search(key_ref_t keyring,			 struct key_type *type,			 const char *description){	if (!type->match)		return ERR_PTR(-ENOKEY);	return keyring_search_aux(keyring, current,				  type, description, type->match);} /* end keyring_search() */EXPORT_SYMBOL(keyring_search);/*****************************************************************************//* * search the given keyring only (no recursion) * - keyring must be locked by caller * - caller must guarantee that the keyring is a keyring */key_ref_t __keyring_search_one(key_ref_t keyring_ref,			       const struct key_type *ktype,			       const char *description,			       key_perm_t perm){	struct keyring_list *klist;	unsigned long possessed;	struct key *keyring, *key;	int loop;	keyring = key_ref_to_ptr(keyring_ref);	possessed = is_key_possessed(keyring_ref);	rcu_read_lock();	klist = rcu_dereference(keyring->payload.subscriptions);	if (klist) {		for (loop = 0; loop < klist->nkeys; loop++) {			key = klist->keys[loop];			if (key->type == ktype &&			    (!key->type->match ||			     key->type->match(key, description)) &&			    key_permission(make_key_ref(key, possessed),					   perm) == 0 &&			    !test_bit(KEY_FLAG_REVOKED, &key->flags)			    )				goto found;		}	}	rcu_read_unlock();	return ERR_PTR(-ENOKEY); found:	atomic_inc(&key->usage);	rcu_read_unlock();	return make_key_ref(key, possessed);} /* end __keyring_search_one() *//*****************************************************************************//*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -