diff options
Diffstat (limited to 'ANDROID_3.4.5/security/keys')
22 files changed, 0 insertions, 9911 deletions
diff --git a/ANDROID_3.4.5/security/keys/Makefile b/ANDROID_3.4.5/security/keys/Makefile deleted file mode 100644 index a56f1ffd..00000000 --- a/ANDROID_3.4.5/security/keys/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# -# Makefile for key management -# - -obj-y := \ - gc.o \ - key.o \ - keyring.o \ - keyctl.o \ - permission.o \ - process_keys.o \ - request_key.o \ - request_key_auth.o \ - user_defined.o - -obj-$(CONFIG_TRUSTED_KEYS) += trusted.o -obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ -obj-$(CONFIG_KEYS_COMPAT) += compat.o -obj-$(CONFIG_PROC_FS) += proc.o -obj-$(CONFIG_SYSCTL) += sysctl.o diff --git a/ANDROID_3.4.5/security/keys/compat.c b/ANDROID_3.4.5/security/keys/compat.c deleted file mode 100644 index 4c48e134..00000000 --- a/ANDROID_3.4.5/security/keys/compat.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 32-bit compatibility syscall for 64-bit systems - * - * 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/syscalls.h> -#include <linux/keyctl.h> -#include <linux/compat.h> -#include <linux/slab.h> -#include "internal.h" - -/* - * Instantiate a key with the specified compatibility multipart payload and - * link the key into the destination keyring if one is given. - * - * The caller must have the appropriate instantiation permit set for this to - * work (see keyctl_assume_authority). No other permissions are required. - * - * If successful, 0 will be returned. - */ -long compat_keyctl_instantiate_key_iov( - key_serial_t id, - const struct compat_iovec __user *_payload_iov, - unsigned ioc, - key_serial_t ringid) -{ - struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; - long ret; - - if (_payload_iov == 0 || ioc == 0) - goto no_payload; - - ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, - ARRAY_SIZE(iovstack), - iovstack, &iov, 1); - if (ret < 0) - return ret; - if (ret == 0) - goto no_payload_free; - - ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); - - if (iov != iovstack) - kfree(iov); - return ret; - -no_payload_free: - if (iov != iovstack) - kfree(iov); -no_payload: - return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); -} - -/* - * The key control system call, 32-bit compatibility version for 64-bit archs - * - * This should only be called if the 64-bit arch uses weird pointers in 32-bit - * mode or doesn't guarantee that the top 32-bits of the argument registers on - * taking a 32-bit syscall are zero. If you can, you should call sys_keyctl() - * directly. - */ -asmlinkage long compat_sys_keyctl(u32 option, - u32 arg2, u32 arg3, u32 arg4, u32 arg5) -{ - switch (option) { - case KEYCTL_GET_KEYRING_ID: - return keyctl_get_keyring_ID(arg2, arg3); - - case KEYCTL_JOIN_SESSION_KEYRING: - return keyctl_join_session_keyring(compat_ptr(arg2)); - - case KEYCTL_UPDATE: - return keyctl_update_key(arg2, compat_ptr(arg3), arg4); - - case KEYCTL_REVOKE: - return keyctl_revoke_key(arg2); - - case KEYCTL_DESCRIBE: - return keyctl_describe_key(arg2, compat_ptr(arg3), arg4); - - case KEYCTL_CLEAR: - return keyctl_keyring_clear(arg2); - - case KEYCTL_LINK: - return keyctl_keyring_link(arg2, arg3); - - case KEYCTL_UNLINK: - return keyctl_keyring_unlink(arg2, arg3); - - case KEYCTL_SEARCH: - return keyctl_keyring_search(arg2, compat_ptr(arg3), - compat_ptr(arg4), arg5); - - case KEYCTL_READ: - return keyctl_read_key(arg2, compat_ptr(arg3), arg4); - - case KEYCTL_CHOWN: - return keyctl_chown_key(arg2, arg3, arg4); - - case KEYCTL_SETPERM: - return keyctl_setperm_key(arg2, arg3); - - case KEYCTL_INSTANTIATE: - return keyctl_instantiate_key(arg2, compat_ptr(arg3), arg4, - arg5); - - case KEYCTL_NEGATE: - return keyctl_negate_key(arg2, arg3, arg4); - - case KEYCTL_SET_REQKEY_KEYRING: - return keyctl_set_reqkey_keyring(arg2); - - case KEYCTL_SET_TIMEOUT: - return keyctl_set_timeout(arg2, arg3); - - case KEYCTL_ASSUME_AUTHORITY: - return keyctl_assume_authority(arg2); - - case KEYCTL_GET_SECURITY: - return keyctl_get_security(arg2, compat_ptr(arg3), arg4); - - case KEYCTL_SESSION_TO_PARENT: - return keyctl_session_to_parent(); - - case KEYCTL_REJECT: - return keyctl_reject_key(arg2, arg3, arg4, arg5); - - case KEYCTL_INSTANTIATE_IOV: - return compat_keyctl_instantiate_key_iov( - arg2, compat_ptr(arg3), arg4, arg5); - - default: - return -EOPNOTSUPP; - } -} diff --git a/ANDROID_3.4.5/security/keys/encrypted-keys/Makefile b/ANDROID_3.4.5/security/keys/encrypted-keys/Makefile deleted file mode 100644 index d6f84332..00000000 --- a/ANDROID_3.4.5/security/keys/encrypted-keys/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for encrypted keys -# - -obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys.o - -encrypted-keys-y := encrypted.o ecryptfs_format.o -masterkey-$(CONFIG_TRUSTED_KEYS) := masterkey_trusted.o -masterkey-$(CONFIG_TRUSTED_KEYS)-$(CONFIG_ENCRYPTED_KEYS) := masterkey_trusted.o -encrypted-keys-y += $(masterkey-y) $(masterkey-m-m) diff --git a/ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.c b/ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.c deleted file mode 100644 index 6daa3b6f..00000000 --- a/ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ecryptfs_format.c: helper functions for the encrypted key type - * - * Copyright (C) 2006 International Business Machines Corp. - * Copyright (C) 2010 Politecnico di Torino, Italy - * TORSEC group -- http://security.polito.it - * - * Authors: - * Michael A. Halcrow <mahalcro@us.ibm.com> - * Tyler Hicks <tyhicks@ou.edu> - * Roberto Sassu <roberto.sassu@polito.it> - * - * 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, version 2 of the License. - */ - -#include <linux/module.h> -#include "ecryptfs_format.h" - -u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok) -{ - return auth_tok->token.password.session_key_encryption_key; -} -EXPORT_SYMBOL(ecryptfs_get_auth_tok_key); - -/* - * ecryptfs_get_versions() - * - * Source code taken from the software 'ecryptfs-utils' version 83. - * - */ -void ecryptfs_get_versions(int *major, int *minor, int *file_version) -{ - *major = ECRYPTFS_VERSION_MAJOR; - *minor = ECRYPTFS_VERSION_MINOR; - if (file_version) - *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION; -} -EXPORT_SYMBOL(ecryptfs_get_versions); - -/* - * ecryptfs_fill_auth_tok - fill the ecryptfs_auth_tok structure - * - * Fill the ecryptfs_auth_tok structure with required ecryptfs data. - * The source code is inspired to the original function generate_payload() - * shipped with the software 'ecryptfs-utils' version 83. - * - */ -int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok, - const char *key_desc) -{ - int major, minor; - - ecryptfs_get_versions(&major, &minor, NULL); - auth_tok->version = (((uint16_t)(major << 8) & 0xFF00) - | ((uint16_t)minor & 0x00FF)); - auth_tok->token_type = ECRYPTFS_PASSWORD; - strncpy((char *)auth_tok->token.password.signature, key_desc, - ECRYPTFS_PASSWORD_SIG_SIZE); - auth_tok->token.password.session_key_encryption_key_bytes = - ECRYPTFS_MAX_KEY_BYTES; - /* - * Removed auth_tok->token.password.salt and - * auth_tok->token.password.session_key_encryption_key - * initialization from the original code - */ - /* TODO: Make the hash parameterizable via policy */ - auth_tok->token.password.flags |= - ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET; - /* The kernel code will encrypt the session key. */ - auth_tok->session_key.encrypted_key[0] = 0; - auth_tok->session_key.encrypted_key_size = 0; - /* Default; subject to change by kernel eCryptfs */ - auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512; - auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD); - return 0; -} -EXPORT_SYMBOL(ecryptfs_fill_auth_tok); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.h b/ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.h deleted file mode 100644 index 40294de2..00000000 --- a/ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * ecryptfs_format.h: helper functions for the encrypted key type - * - * Copyright (C) 2006 International Business Machines Corp. - * Copyright (C) 2010 Politecnico di Torino, Italy - * TORSEC group -- http://security.polito.it - * - * Authors: - * Michael A. Halcrow <mahalcro@us.ibm.com> - * Tyler Hicks <tyhicks@ou.edu> - * Roberto Sassu <roberto.sassu@polito.it> - * - * 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, version 2 of the License. - */ - -#ifndef __KEYS_ECRYPTFS_H -#define __KEYS_ECRYPTFS_H - -#include <linux/ecryptfs.h> - -#define PGP_DIGEST_ALGO_SHA512 10 - -u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok); -void ecryptfs_get_versions(int *major, int *minor, int *file_version); -int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok, - const char *key_desc); - -#endif /* __KEYS_ECRYPTFS_H */ diff --git a/ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.c b/ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.c deleted file mode 100644 index 2d1bb8af..00000000 --- a/ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * Copyright (C) 2010 IBM Corporation - * Copyright (C) 2010 Politecnico di Torino, Italy - * TORSEC group -- http://security.polito.it - * - * Authors: - * Mimi Zohar <zohar@us.ibm.com> - * Roberto Sassu <roberto.sassu@polito.it> - * - * 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, version 2 of the License. - * - * See Documentation/security/keys-trusted-encrypted.txt - */ - -#include <linux/uaccess.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/parser.h> -#include <linux/string.h> -#include <linux/err.h> -#include <keys/user-type.h> -#include <keys/trusted-type.h> -#include <keys/encrypted-type.h> -#include <linux/key-type.h> -#include <linux/random.h> -#include <linux/rcupdate.h> -#include <linux/scatterlist.h> -#include <linux/crypto.h> -#include <linux/ctype.h> -#include <crypto/hash.h> -#include <crypto/sha.h> -#include <crypto/aes.h> - -#include "encrypted.h" -#include "ecryptfs_format.h" - -static const char KEY_TRUSTED_PREFIX[] = "trusted:"; -static const char KEY_USER_PREFIX[] = "user:"; -static const char hash_alg[] = "sha256"; -static const char hmac_alg[] = "hmac(sha256)"; -static const char blkcipher_alg[] = "cbc(aes)"; -static const char key_format_default[] = "default"; -static const char key_format_ecryptfs[] = "ecryptfs"; -static unsigned int ivsize; -static int blksize; - -#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1) -#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1) -#define KEY_ECRYPTFS_DESC_LEN 16 -#define HASH_SIZE SHA256_DIGEST_SIZE -#define MAX_DATA_SIZE 4096 -#define MIN_DATA_SIZE 20 - -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static struct crypto_shash *hashalg; -static struct crypto_shash *hmacalg; - -enum { - Opt_err = -1, Opt_new, Opt_load, Opt_update -}; - -enum { - Opt_error = -1, Opt_default, Opt_ecryptfs -}; - -static const match_table_t key_format_tokens = { - {Opt_default, "default"}, - {Opt_ecryptfs, "ecryptfs"}, - {Opt_error, NULL} -}; - -static const match_table_t key_tokens = { - {Opt_new, "new"}, - {Opt_load, "load"}, - {Opt_update, "update"}, - {Opt_err, NULL} -}; - -static int aes_get_sizes(void) -{ - struct crypto_blkcipher *tfm; - - tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { - pr_err("encrypted_key: failed to alloc_cipher (%ld)\n", - PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - ivsize = crypto_blkcipher_ivsize(tfm); - blksize = crypto_blkcipher_blocksize(tfm); - crypto_free_blkcipher(tfm); - return 0; -} - -/* - * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key - * - * The description of a encrypted key with format 'ecryptfs' must contain - * exactly 16 hexadecimal characters. - * - */ -static int valid_ecryptfs_desc(const char *ecryptfs_desc) -{ - int i; - - if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) { - pr_err("encrypted_key: key description must be %d hexadecimal " - "characters long\n", KEY_ECRYPTFS_DESC_LEN); - return -EINVAL; - } - - for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) { - if (!isxdigit(ecryptfs_desc[i])) { - pr_err("encrypted_key: key description must contain " - "only hexadecimal characters\n"); - return -EINVAL; - } - } - - return 0; -} - -/* - * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key - * - * key-type:= "trusted:" | "user:" - * desc:= master-key description - * - * Verify that 'key-type' is valid and that 'desc' exists. On key update, - * only the master key description is permitted to change, not the key-type. - * The key-type remains constant. - * - * On success returns 0, otherwise -EINVAL. - */ -static int valid_master_desc(const char *new_desc, const char *orig_desc) -{ - if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { - if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN) - goto out; - if (orig_desc) - if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN)) - goto out; - } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) { - if (strlen(new_desc) == KEY_USER_PREFIX_LEN) - goto out; - if (orig_desc) - if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN)) - goto out; - } else - goto out; - return 0; -out: - return -EINVAL; -} - -/* - * datablob_parse - parse the keyctl data - * - * datablob format: - * new [<format>] <master-key name> <decrypted data length> - * load [<format>] <master-key name> <decrypted data length> - * <encrypted iv + data> - * update <new-master-key name> - * - * Tokenizes a copy of the keyctl data, returning a pointer to each token, - * which is null terminated. - * - * On success returns 0, otherwise -EINVAL. - */ -static int datablob_parse(char *datablob, const char **format, - char **master_desc, char **decrypted_datalen, - char **hex_encoded_iv) -{ - substring_t args[MAX_OPT_ARGS]; - int ret = -EINVAL; - int key_cmd; - int key_format; - char *p, *keyword; - - keyword = strsep(&datablob, " \t"); - if (!keyword) { - pr_info("encrypted_key: insufficient parameters specified\n"); - return ret; - } - key_cmd = match_token(keyword, key_tokens, args); - - /* Get optional format: default | ecryptfs */ - p = strsep(&datablob, " \t"); - if (!p) { - pr_err("encrypted_key: insufficient parameters specified\n"); - return ret; - } - - key_format = match_token(p, key_format_tokens, args); - switch (key_format) { - case Opt_ecryptfs: - case Opt_default: - *format = p; - *master_desc = strsep(&datablob, " \t"); - break; - case Opt_error: - *master_desc = p; - break; - } - - if (!*master_desc) { - pr_info("encrypted_key: master key parameter is missing\n"); - goto out; - } - - if (valid_master_desc(*master_desc, NULL) < 0) { - pr_info("encrypted_key: master key parameter \'%s\' " - "is invalid\n", *master_desc); - goto out; - } - - if (decrypted_datalen) { - *decrypted_datalen = strsep(&datablob, " \t"); - if (!*decrypted_datalen) { - pr_info("encrypted_key: keylen parameter is missing\n"); - goto out; - } - } - - switch (key_cmd) { - case Opt_new: - if (!decrypted_datalen) { - pr_info("encrypted_key: keyword \'%s\' not allowed " - "when called from .update method\n", keyword); - break; - } - ret = 0; - break; - case Opt_load: - if (!decrypted_datalen) { - pr_info("encrypted_key: keyword \'%s\' not allowed " - "when called from .update method\n", keyword); - break; - } - *hex_encoded_iv = strsep(&datablob, " \t"); - if (!*hex_encoded_iv) { - pr_info("encrypted_key: hex blob is missing\n"); - break; - } - ret = 0; - break; - case Opt_update: - if (decrypted_datalen) { - pr_info("encrypted_key: keyword \'%s\' not allowed " - "when called from .instantiate method\n", - keyword); - break; - } - ret = 0; - break; - case Opt_err: - pr_info("encrypted_key: keyword \'%s\' not recognized\n", - keyword); - break; - } -out: - return ret; -} - -/* - * datablob_format - format as an ascii string, before copying to userspace - */ -static char *datablob_format(struct encrypted_key_payload *epayload, - size_t asciiblob_len) -{ - char *ascii_buf, *bufp; - u8 *iv = epayload->iv; - int len; - int i; - - ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL); - if (!ascii_buf) - goto out; - - ascii_buf[asciiblob_len] = '\0'; - - /* copy datablob master_desc and datalen strings */ - len = sprintf(ascii_buf, "%s %s %s ", epayload->format, - epayload->master_desc, epayload->datalen); - - /* convert the hex encoded iv, encrypted-data and HMAC to ascii */ - bufp = &ascii_buf[len]; - for (i = 0; i < (asciiblob_len - len) / 2; i++) - bufp = hex_byte_pack(bufp, iv[i]); -out: - return ascii_buf; -} - -/* - * request_user_key - request the user key - * - * Use a user provided key to encrypt/decrypt an encrypted-key. - */ -static struct key *request_user_key(const char *master_desc, u8 **master_key, - size_t *master_keylen) -{ - struct user_key_payload *upayload; - struct key *ukey; - - ukey = request_key(&key_type_user, master_desc, NULL); - if (IS_ERR(ukey)) - goto error; - - down_read(&ukey->sem); - upayload = ukey->payload.data; - *master_key = upayload->data; - *master_keylen = upayload->datalen; -error: - return ukey; -} - -static struct sdesc *alloc_sdesc(struct crypto_shash *alg) -{ - struct sdesc *sdesc; - int size; - - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - sdesc->shash.flags = 0x0; - return sdesc; -} - -static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen, - const u8 *buf, unsigned int buflen) -{ - struct sdesc *sdesc; - int ret; - - sdesc = alloc_sdesc(hmacalg); - if (IS_ERR(sdesc)) { - pr_info("encrypted_key: can't alloc %s\n", hmac_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_setkey(hmacalg, key, keylen); - if (!ret) - ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest); - kfree(sdesc); - return ret; -} - -static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen) -{ - struct sdesc *sdesc; - int ret; - - sdesc = alloc_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("encrypted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest); - kfree(sdesc); - return ret; -} - -enum derived_key_type { ENC_KEY, AUTH_KEY }; - -/* Derive authentication/encryption key from trusted key */ -static int get_derived_key(u8 *derived_key, enum derived_key_type key_type, - const u8 *master_key, size_t master_keylen) -{ - u8 *derived_buf; - unsigned int derived_buf_len; - int ret; - - derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen; - if (derived_buf_len < HASH_SIZE) - derived_buf_len = HASH_SIZE; - - derived_buf = kzalloc(derived_buf_len, GFP_KERNEL); - if (!derived_buf) { - pr_err("encrypted_key: out of memory\n"); - return -ENOMEM; - } - if (key_type) - strcpy(derived_buf, "AUTH_KEY"); - else - strcpy(derived_buf, "ENC_KEY"); - - memcpy(derived_buf + strlen(derived_buf) + 1, master_key, - master_keylen); - ret = calc_hash(derived_key, derived_buf, derived_buf_len); - kfree(derived_buf); - return ret; -} - -static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, - unsigned int key_len, const u8 *iv, - unsigned int ivsize) -{ - int ret; - - desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(desc->tfm)) { - pr_err("encrypted_key: failed to load %s transform (%ld)\n", - blkcipher_alg, PTR_ERR(desc->tfm)); - return PTR_ERR(desc->tfm); - } - desc->flags = 0; - - ret = crypto_blkcipher_setkey(desc->tfm, key, key_len); - if (ret < 0) { - pr_err("encrypted_key: failed to setkey (%d)\n", ret); - crypto_free_blkcipher(desc->tfm); - return ret; - } - crypto_blkcipher_set_iv(desc->tfm, iv, ivsize); - return 0; -} - -static struct key *request_master_key(struct encrypted_key_payload *epayload, - u8 **master_key, size_t *master_keylen) -{ - struct key *mkey = NULL; - - if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX, - KEY_TRUSTED_PREFIX_LEN)) { - mkey = request_trusted_key(epayload->master_desc + - KEY_TRUSTED_PREFIX_LEN, - master_key, master_keylen); - } else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX, - KEY_USER_PREFIX_LEN)) { - mkey = request_user_key(epayload->master_desc + - KEY_USER_PREFIX_LEN, - master_key, master_keylen); - } else - goto out; - - if (IS_ERR(mkey)) { - int ret = PTR_ERR(mkey); - - if (ret == -ENOTSUPP) - pr_info("encrypted_key: key %s not supported", - epayload->master_desc); - else - pr_info("encrypted_key: key %s not found", - epayload->master_desc); - goto out; - } - - dump_master_key(*master_key, *master_keylen); -out: - return mkey; -} - -/* Before returning data to userspace, encrypt decrypted data. */ -static int derived_key_encrypt(struct encrypted_key_payload *epayload, - const u8 *derived_key, - unsigned int derived_keylen) -{ - struct scatterlist sg_in[2]; - struct scatterlist sg_out[1]; - struct blkcipher_desc desc; - unsigned int encrypted_datalen; - unsigned int padlen; - char pad[16]; - int ret; - - encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); - padlen = encrypted_datalen - epayload->decrypted_datalen; - - ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, - epayload->iv, ivsize); - if (ret < 0) - goto out; - dump_decrypted_data(epayload); - - memset(pad, 0, sizeof pad); - sg_init_table(sg_in, 2); - sg_set_buf(&sg_in[0], epayload->decrypted_data, - epayload->decrypted_datalen); - sg_set_buf(&sg_in[1], pad, padlen); - - sg_init_table(sg_out, 1); - sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen); - - ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen); - crypto_free_blkcipher(desc.tfm); - if (ret < 0) - pr_err("encrypted_key: failed to encrypt (%d)\n", ret); - else - dump_encrypted_data(epayload, encrypted_datalen); -out: - return ret; -} - -static int datablob_hmac_append(struct encrypted_key_payload *epayload, - const u8 *master_key, size_t master_keylen) -{ - u8 derived_key[HASH_SIZE]; - u8 *digest; - int ret; - - ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); - if (ret < 0) - goto out; - - digest = epayload->format + epayload->datablob_len; - ret = calc_hmac(digest, derived_key, sizeof derived_key, - epayload->format, epayload->datablob_len); - if (!ret) - dump_hmac(NULL, digest, HASH_SIZE); -out: - return ret; -} - -/* verify HMAC before decrypting encrypted key */ -static int datablob_hmac_verify(struct encrypted_key_payload *epayload, - const u8 *format, const u8 *master_key, - size_t master_keylen) -{ - u8 derived_key[HASH_SIZE]; - u8 digest[HASH_SIZE]; - int ret; - char *p; - unsigned short len; - - ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); - if (ret < 0) - goto out; - - len = epayload->datablob_len; - if (!format) { - p = epayload->master_desc; - len -= strlen(epayload->format) + 1; - } else - p = epayload->format; - - ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len); - if (ret < 0) - goto out; - ret = memcmp(digest, epayload->format + epayload->datablob_len, - sizeof digest); - if (ret) { - ret = -EINVAL; - dump_hmac("datablob", - epayload->format + epayload->datablob_len, - HASH_SIZE); - dump_hmac("calc", digest, HASH_SIZE); - } -out: - return ret; -} - -static int derived_key_decrypt(struct encrypted_key_payload *epayload, - const u8 *derived_key, - unsigned int derived_keylen) -{ - struct scatterlist sg_in[1]; - struct scatterlist sg_out[2]; - struct blkcipher_desc desc; - unsigned int encrypted_datalen; - char pad[16]; - int ret; - - encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); - ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, - epayload->iv, ivsize); - if (ret < 0) - goto out; - dump_encrypted_data(epayload, encrypted_datalen); - - memset(pad, 0, sizeof pad); - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 2); - sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen); - sg_set_buf(&sg_out[0], epayload->decrypted_data, - epayload->decrypted_datalen); - sg_set_buf(&sg_out[1], pad, sizeof pad); - - ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen); - crypto_free_blkcipher(desc.tfm); - if (ret < 0) - goto out; - dump_decrypted_data(epayload); -out: - return ret; -} - -/* Allocate memory for decrypted key and datablob. */ -static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, - const char *format, - const char *master_desc, - const char *datalen) -{ - struct encrypted_key_payload *epayload = NULL; - unsigned short datablob_len; - unsigned short decrypted_datalen; - unsigned short payload_datalen; - unsigned int encrypted_datalen; - unsigned int format_len; - long dlen; - int ret; - - ret = strict_strtol(datalen, 10, &dlen); - if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) - return ERR_PTR(-EINVAL); - - format_len = (!format) ? strlen(key_format_default) : strlen(format); - decrypted_datalen = dlen; - payload_datalen = decrypted_datalen; - if (format && !strcmp(format, key_format_ecryptfs)) { - if (dlen != ECRYPTFS_MAX_KEY_BYTES) { - pr_err("encrypted_key: keylen for the ecryptfs format " - "must be equal to %d bytes\n", - ECRYPTFS_MAX_KEY_BYTES); - return ERR_PTR(-EINVAL); - } - decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES; - payload_datalen = sizeof(struct ecryptfs_auth_tok); - } - - encrypted_datalen = roundup(decrypted_datalen, blksize); - - datablob_len = format_len + 1 + strlen(master_desc) + 1 - + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen; - - ret = key_payload_reserve(key, payload_datalen + datablob_len - + HASH_SIZE + 1); - if (ret < 0) - return ERR_PTR(ret); - - epayload = kzalloc(sizeof(*epayload) + payload_datalen + - datablob_len + HASH_SIZE + 1, GFP_KERNEL); - if (!epayload) - return ERR_PTR(-ENOMEM); - - epayload->payload_datalen = payload_datalen; - epayload->decrypted_datalen = decrypted_datalen; - epayload->datablob_len = datablob_len; - return epayload; -} - -static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, - const char *format, const char *hex_encoded_iv) -{ - struct key *mkey; - u8 derived_key[HASH_SIZE]; - u8 *master_key; - u8 *hmac; - const char *hex_encoded_data; - unsigned int encrypted_datalen; - size_t master_keylen; - size_t asciilen; - int ret; - - encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); - asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2; - if (strlen(hex_encoded_iv) != asciilen) - return -EINVAL; - - hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2; - ret = hex2bin(epayload->iv, hex_encoded_iv, ivsize); - if (ret < 0) - return -EINVAL; - ret = hex2bin(epayload->encrypted_data, hex_encoded_data, - encrypted_datalen); - if (ret < 0) - return -EINVAL; - - hmac = epayload->format + epayload->datablob_len; - ret = hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), - HASH_SIZE); - if (ret < 0) - return -EINVAL; - - mkey = request_master_key(epayload, &master_key, &master_keylen); - if (IS_ERR(mkey)) - return PTR_ERR(mkey); - - ret = datablob_hmac_verify(epayload, format, master_key, master_keylen); - if (ret < 0) { - pr_err("encrypted_key: bad hmac (%d)\n", ret); - goto out; - } - - ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen); - if (ret < 0) - goto out; - - ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key); - if (ret < 0) - pr_err("encrypted_key: failed to decrypt key (%d)\n", ret); -out: - up_read(&mkey->sem); - key_put(mkey); - return ret; -} - -static void __ekey_init(struct encrypted_key_payload *epayload, - const char *format, const char *master_desc, - const char *datalen) -{ - unsigned int format_len; - - format_len = (!format) ? strlen(key_format_default) : strlen(format); - epayload->format = epayload->payload_data + epayload->payload_datalen; - epayload->master_desc = epayload->format + format_len + 1; - epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; - epayload->iv = epayload->datalen + strlen(datalen) + 1; - epayload->encrypted_data = epayload->iv + ivsize + 1; - epayload->decrypted_data = epayload->payload_data; - - if (!format) - memcpy(epayload->format, key_format_default, format_len); - else { - if (!strcmp(format, key_format_ecryptfs)) - epayload->decrypted_data = - ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data); - - memcpy(epayload->format, format, format_len); - } - - memcpy(epayload->master_desc, master_desc, strlen(master_desc)); - memcpy(epayload->datalen, datalen, strlen(datalen)); -} - -/* - * encrypted_init - initialize an encrypted key - * - * For a new key, use a random number for both the iv and data - * itself. For an old key, decrypt the hex encoded data. - */ -static int encrypted_init(struct encrypted_key_payload *epayload, - const char *key_desc, const char *format, - const char *master_desc, const char *datalen, - const char *hex_encoded_iv) -{ - int ret = 0; - - if (format && !strcmp(format, key_format_ecryptfs)) { - ret = valid_ecryptfs_desc(key_desc); - if (ret < 0) - return ret; - - ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data, - key_desc); - } - - __ekey_init(epayload, format, master_desc, datalen); - if (!hex_encoded_iv) { - get_random_bytes(epayload->iv, ivsize); - - get_random_bytes(epayload->decrypted_data, - epayload->decrypted_datalen); - } else - ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv); - return ret; -} - -/* - * encrypted_instantiate - instantiate an encrypted key - * - * Decrypt an existing encrypted datablob or create a new encrypted key - * based on a kernel random number. - * - * On success, return 0. Otherwise return errno. - */ -static int encrypted_instantiate(struct key *key, const void *data, - size_t datalen) -{ - struct encrypted_key_payload *epayload = NULL; - char *datablob = NULL; - const char *format = NULL; - char *master_desc = NULL; - char *decrypted_datalen = NULL; - char *hex_encoded_iv = NULL; - int ret; - - if (datalen <= 0 || datalen > 32767 || !data) - return -EINVAL; - - datablob = kmalloc(datalen + 1, GFP_KERNEL); - if (!datablob) - return -ENOMEM; - datablob[datalen] = 0; - memcpy(datablob, data, datalen); - ret = datablob_parse(datablob, &format, &master_desc, - &decrypted_datalen, &hex_encoded_iv); - if (ret < 0) - goto out; - - epayload = encrypted_key_alloc(key, format, master_desc, - decrypted_datalen); - if (IS_ERR(epayload)) { - ret = PTR_ERR(epayload); - goto out; - } - ret = encrypted_init(epayload, key->description, format, master_desc, - decrypted_datalen, hex_encoded_iv); - if (ret < 0) { - kfree(epayload); - goto out; - } - - rcu_assign_keypointer(key, epayload); -out: - kfree(datablob); - return ret; -} - -static void encrypted_rcu_free(struct rcu_head *rcu) -{ - struct encrypted_key_payload *epayload; - - epayload = container_of(rcu, struct encrypted_key_payload, rcu); - memset(epayload->decrypted_data, 0, epayload->decrypted_datalen); - kfree(epayload); -} - -/* - * encrypted_update - update the master key description - * - * Change the master key description for an existing encrypted key. - * The next read will return an encrypted datablob using the new - * master key description. - * - * On success, return 0. Otherwise return errno. - */ -static int encrypted_update(struct key *key, const void *data, size_t datalen) -{ - struct encrypted_key_payload *epayload = key->payload.data; - struct encrypted_key_payload *new_epayload; - char *buf; - char *new_master_desc = NULL; - const char *format = NULL; - int ret = 0; - - if (datalen <= 0 || datalen > 32767 || !data) - return -EINVAL; - - buf = kmalloc(datalen + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - buf[datalen] = 0; - memcpy(buf, data, datalen); - ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); - if (ret < 0) - goto out; - - ret = valid_master_desc(new_master_desc, epayload->master_desc); - if (ret < 0) - goto out; - - new_epayload = encrypted_key_alloc(key, epayload->format, - new_master_desc, epayload->datalen); - if (IS_ERR(new_epayload)) { - ret = PTR_ERR(new_epayload); - goto out; - } - - __ekey_init(new_epayload, epayload->format, new_master_desc, - epayload->datalen); - - memcpy(new_epayload->iv, epayload->iv, ivsize); - memcpy(new_epayload->payload_data, epayload->payload_data, - epayload->payload_datalen); - - rcu_assign_keypointer(key, new_epayload); - call_rcu(&epayload->rcu, encrypted_rcu_free); -out: - kfree(buf); - return ret; -} - -/* - * encrypted_read - format and copy the encrypted data to userspace - * - * The resulting datablob format is: - * <master-key name> <decrypted data length> <encrypted iv> <encrypted data> - * - * On success, return to userspace the encrypted key datablob size. - */ -static long encrypted_read(const struct key *key, char __user *buffer, - size_t buflen) -{ - struct encrypted_key_payload *epayload; - struct key *mkey; - u8 *master_key; - size_t master_keylen; - char derived_key[HASH_SIZE]; - char *ascii_buf; - size_t asciiblob_len; - int ret; - - epayload = rcu_dereference_key(key); - - /* returns the hex encoded iv, encrypted-data, and hmac as ascii */ - asciiblob_len = epayload->datablob_len + ivsize + 1 - + roundup(epayload->decrypted_datalen, blksize) - + (HASH_SIZE * 2); - - if (!buffer || buflen < asciiblob_len) - return asciiblob_len; - - mkey = request_master_key(epayload, &master_key, &master_keylen); - if (IS_ERR(mkey)) - return PTR_ERR(mkey); - - ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen); - if (ret < 0) - goto out; - - ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key); - if (ret < 0) - goto out; - - ret = datablob_hmac_append(epayload, master_key, master_keylen); - if (ret < 0) - goto out; - - ascii_buf = datablob_format(epayload, asciiblob_len); - if (!ascii_buf) { - ret = -ENOMEM; - goto out; - } - - up_read(&mkey->sem); - key_put(mkey); - - if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0) - ret = -EFAULT; - kfree(ascii_buf); - - return asciiblob_len; -out: - up_read(&mkey->sem); - key_put(mkey); - return ret; -} - -/* - * encrypted_destroy - before freeing the key, clear the decrypted data - * - * Before freeing the key, clear the memory containing the decrypted - * key data. - */ -static void encrypted_destroy(struct key *key) -{ - struct encrypted_key_payload *epayload = key->payload.data; - - if (!epayload) - return; - - memset(epayload->decrypted_data, 0, epayload->decrypted_datalen); - kfree(key->payload.data); -} - -struct key_type key_type_encrypted = { - .name = "encrypted", - .instantiate = encrypted_instantiate, - .update = encrypted_update, - .match = user_match, - .destroy = encrypted_destroy, - .describe = user_describe, - .read = encrypted_read, -}; -EXPORT_SYMBOL_GPL(key_type_encrypted); - -static void encrypted_shash_release(void) -{ - if (hashalg) - crypto_free_shash(hashalg); - if (hmacalg) - crypto_free_shash(hmacalg); -} - -static int __init encrypted_shash_alloc(void) -{ - int ret; - - hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hmacalg)) { - pr_info("encrypted_key: could not allocate crypto %s\n", - hmac_alg); - return PTR_ERR(hmacalg); - } - - hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hashalg)) { - pr_info("encrypted_key: could not allocate crypto %s\n", - hash_alg); - ret = PTR_ERR(hashalg); - goto hashalg_fail; - } - - return 0; - -hashalg_fail: - crypto_free_shash(hmacalg); - return ret; -} - -static int __init init_encrypted(void) -{ - int ret; - - ret = encrypted_shash_alloc(); - if (ret < 0) - return ret; - ret = register_key_type(&key_type_encrypted); - if (ret < 0) - goto out; - return aes_get_sizes(); -out: - encrypted_shash_release(); - return ret; - -} - -static void __exit cleanup_encrypted(void) -{ - encrypted_shash_release(); - unregister_key_type(&key_type_encrypted); -} - -late_initcall(init_encrypted); -module_exit(cleanup_encrypted); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.h b/ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.h deleted file mode 100644 index 8136a2d4..00000000 --- a/ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __ENCRYPTED_KEY_H -#define __ENCRYPTED_KEY_H - -#define ENCRYPTED_DEBUG 0 -#if defined(CONFIG_TRUSTED_KEYS) || \ - (defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE)) -extern struct key *request_trusted_key(const char *trusted_desc, - u8 **master_key, size_t *master_keylen); -#else -static inline struct key *request_trusted_key(const char *trusted_desc, - u8 **master_key, - size_t *master_keylen) -{ - return ERR_PTR(-EOPNOTSUPP); -} -#endif - -#if ENCRYPTED_DEBUG -static inline void dump_master_key(const u8 *master_key, size_t master_keylen) -{ - print_hex_dump(KERN_ERR, "master key: ", DUMP_PREFIX_NONE, 32, 1, - master_key, master_keylen, 0); -} - -static inline void dump_decrypted_data(struct encrypted_key_payload *epayload) -{ - print_hex_dump(KERN_ERR, "decrypted data: ", DUMP_PREFIX_NONE, 32, 1, - epayload->decrypted_data, - epayload->decrypted_datalen, 0); -} - -static inline void dump_encrypted_data(struct encrypted_key_payload *epayload, - unsigned int encrypted_datalen) -{ - print_hex_dump(KERN_ERR, "encrypted data: ", DUMP_PREFIX_NONE, 32, 1, - epayload->encrypted_data, encrypted_datalen, 0); -} - -static inline void dump_hmac(const char *str, const u8 *digest, - unsigned int hmac_size) -{ - if (str) - pr_info("encrypted_key: %s", str); - print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest, - hmac_size, 0); -} -#else -static inline void dump_master_key(const u8 *master_key, size_t master_keylen) -{ -} - -static inline void dump_decrypted_data(struct encrypted_key_payload *epayload) -{ -} - -static inline void dump_encrypted_data(struct encrypted_key_payload *epayload, - unsigned int encrypted_datalen) -{ -} - -static inline void dump_hmac(const char *str, const u8 *digest, - unsigned int hmac_size) -{ -} -#endif -#endif diff --git a/ANDROID_3.4.5/security/keys/encrypted-keys/masterkey_trusted.c b/ANDROID_3.4.5/security/keys/encrypted-keys/masterkey_trusted.c deleted file mode 100644 index 013f7e5d..00000000 --- a/ANDROID_3.4.5/security/keys/encrypted-keys/masterkey_trusted.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2010 IBM Corporation - * Copyright (C) 2010 Politecnico di Torino, Italy - * TORSEC group -- http://security.polito.it - * - * Authors: - * Mimi Zohar <zohar@us.ibm.com> - * Roberto Sassu <roberto.sassu@polito.it> - * - * 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, version 2 of the License. - * - * See Documentation/security/keys-trusted-encrypted.txt - */ - -#include <linux/uaccess.h> -#include <linux/module.h> -#include <linux/err.h> -#include <keys/trusted-type.h> -#include <keys/encrypted-type.h> -#include "encrypted.h" - -/* - * request_trusted_key - request the trusted key - * - * Trusted keys are sealed to PCRs and other metadata. Although userspace - * manages both trusted/encrypted key-types, like the encrypted key type - * data, trusted key type data is not visible decrypted from userspace. - */ -struct key *request_trusted_key(const char *trusted_desc, - u8 **master_key, size_t *master_keylen) -{ - struct trusted_key_payload *tpayload; - struct key *tkey; - - tkey = request_key(&key_type_trusted, trusted_desc, NULL); - if (IS_ERR(tkey)) - goto error; - - down_read(&tkey->sem); - tpayload = tkey->payload.data; - *master_key = tpayload->key; - *master_keylen = tpayload->key_len; -error: - return tkey; -} diff --git a/ANDROID_3.4.5/security/keys/gc.c b/ANDROID_3.4.5/security/keys/gc.c deleted file mode 100644 index a42b4553..00000000 --- a/ANDROID_3.4.5/security/keys/gc.c +++ /dev/null @@ -1,390 +0,0 @@ -/* Key garbage collector - * - * Copyright (C) 2009-2011 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 Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/security.h> -#include <keys/keyring-type.h> -#include "internal.h" - -/* - * Delay between key revocation/expiry in seconds - */ -unsigned key_gc_delay = 5 * 60; - -/* - * Reaper for unused keys. - */ -static void key_garbage_collector(struct work_struct *work); -DECLARE_WORK(key_gc_work, key_garbage_collector); - -/* - * Reaper for links from keyrings to dead keys. - */ -static void key_gc_timer_func(unsigned long); -static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); - -static time_t key_gc_next_run = LONG_MAX; -static struct key_type *key_gc_dead_keytype; - -static unsigned long key_gc_flags; -#define KEY_GC_KEY_EXPIRED 0 /* A key expired and needs unlinking */ -#define KEY_GC_REAP_KEYTYPE 1 /* A keytype is being unregistered */ -#define KEY_GC_REAPING_KEYTYPE 2 /* Cleared when keytype reaped */ - - -/* - * Any key whose type gets unregistered will be re-typed to this if it can't be - * immediately unlinked. - */ -struct key_type key_type_dead = { - .name = "dead", -}; - -/* - * Schedule a garbage collection run. - * - time precision isn't particularly important - */ -void key_schedule_gc(time_t gc_at) -{ - unsigned long expires; - time_t now = current_kernel_time().tv_sec; - - kenter("%ld", gc_at - now); - - if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) { - kdebug("IMMEDIATE"); - queue_work(system_nrt_wq, &key_gc_work); - } else if (gc_at < key_gc_next_run) { - kdebug("DEFERRED"); - key_gc_next_run = gc_at; - expires = jiffies + (gc_at - now) * HZ; - mod_timer(&key_gc_timer, expires); - } -} - -/* - * Some key's cleanup time was met after it expired, so we need to get the - * reaper to go through a cycle finding expired keys. - */ -static void key_gc_timer_func(unsigned long data) -{ - kenter(""); - key_gc_next_run = LONG_MAX; - set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); - queue_work(system_nrt_wq, &key_gc_work); -} - -/* - * wait_on_bit() sleep function for uninterruptible waiting - */ -static int key_gc_wait_bit(void *flags) -{ - schedule(); - return 0; -} - -/* - * Reap keys of dead type. - * - * We use three flags to make sure we see three complete cycles of the garbage - * collector: the first to mark keys of that type as being dead, the second to - * collect dead links and the third to clean up the dead keys. We have to be - * careful as there may already be a cycle in progress. - * - * The caller must be holding key_types_sem. - */ -void key_gc_keytype(struct key_type *ktype) -{ - kenter("%s", ktype->name); - - key_gc_dead_keytype = ktype; - set_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); - smp_mb(); - set_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags); - - kdebug("schedule"); - queue_work(system_nrt_wq, &key_gc_work); - - kdebug("sleep"); - wait_on_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE, key_gc_wait_bit, - TASK_UNINTERRUPTIBLE); - - key_gc_dead_keytype = NULL; - kleave(""); -} - -/* - * Garbage collect pointers from a keyring. - * - * Not called with any locks held. The keyring's key struct will not be - * deallocated under us as only our caller may deallocate it. - */ -static void key_gc_keyring(struct key *keyring, time_t limit) -{ - struct keyring_list *klist; - struct key *key; - int loop; - - kenter("%x", key_serial(keyring)); - - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) - goto dont_gc; - - /* scan the keyring looking for dead keys */ - rcu_read_lock(); - klist = rcu_dereference(keyring->payload.subscriptions); - if (!klist) - goto unlock_dont_gc; - - loop = klist->nkeys; - smp_rmb(); - for (loop--; loop >= 0; loop--) { - key = klist->keys[loop]; - if (test_bit(KEY_FLAG_DEAD, &key->flags) || - (key->expiry > 0 && key->expiry <= limit)) - goto do_gc; - } - -unlock_dont_gc: - rcu_read_unlock(); -dont_gc: - kleave(" [no gc]"); - return; - -do_gc: - rcu_read_unlock(); - - keyring_gc(keyring, limit); - kleave(" [gc]"); -} - -/* - * Garbage collect an unreferenced, detached key - */ -static noinline void key_gc_unused_key(struct key *key) -{ - 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); -} - -/* - * Garbage collector for unused keys. - * - * This is done 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_garbage_collector(struct work_struct *work) -{ - static u8 gc_state; /* Internal persistent state */ -#define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ -#define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ -#define KEY_GC_SET_TIMER 0x04 /* - We need to restart the timer */ -#define KEY_GC_REAPING_DEAD_1 0x10 /* - We need to mark dead keys */ -#define KEY_GC_REAPING_DEAD_2 0x20 /* - We need to reap dead key links */ -#define KEY_GC_REAPING_DEAD_3 0x40 /* - We need to reap dead keys */ -#define KEY_GC_FOUND_DEAD_KEY 0x80 /* - We found at least one dead key */ - - struct rb_node *cursor; - struct key *key; - time_t new_timer, limit; - - kenter("[%lx,%x]", key_gc_flags, gc_state); - - limit = current_kernel_time().tv_sec; - if (limit > key_gc_delay) - limit -= key_gc_delay; - else - limit = key_gc_delay; - - /* Work out what we're going to be doing in this pass */ - gc_state &= KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2; - gc_state <<= 1; - if (test_and_clear_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags)) - gc_state |= KEY_GC_REAPING_LINKS | KEY_GC_SET_TIMER; - - if (test_and_clear_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) - gc_state |= KEY_GC_REAPING_DEAD_1; - kdebug("new pass %x", gc_state); - - new_timer = LONG_MAX; - - /* As only this function is permitted to remove things from the key - * serial tree, if cursor is non-NULL then it will always point to a - * valid node in the tree - even if lock got dropped. - */ - spin_lock(&key_serial_lock); - cursor = rb_first(&key_serial_tree); - -continue_scanning: - while (cursor) { - key = rb_entry(cursor, struct key, serial_node); - cursor = rb_next(cursor); - - if (atomic_read(&key->usage) == 0) - goto found_unreferenced_key; - - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { - if (key->type == key_gc_dead_keytype) { - gc_state |= KEY_GC_FOUND_DEAD_KEY; - set_bit(KEY_FLAG_DEAD, &key->flags); - key->perm = 0; - goto skip_dead_key; - } - } - - if (gc_state & KEY_GC_SET_TIMER) { - if (key->expiry > limit && key->expiry < new_timer) { - kdebug("will expire %x in %ld", - key_serial(key), key->expiry - limit); - new_timer = key->expiry; - } - } - - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) - if (key->type == key_gc_dead_keytype) - gc_state |= KEY_GC_FOUND_DEAD_KEY; - - if ((gc_state & KEY_GC_REAPING_LINKS) || - unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { - if (key->type == &key_type_keyring) - goto found_keyring; - } - - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) - if (key->type == key_gc_dead_keytype) - goto destroy_dead_key; - - skip_dead_key: - if (spin_is_contended(&key_serial_lock) || need_resched()) - goto contended; - } - -contended: - spin_unlock(&key_serial_lock); - -maybe_resched: - if (cursor) { - cond_resched(); - spin_lock(&key_serial_lock); - goto continue_scanning; - } - - /* We've completed the pass. Set the timer if we need to and queue a - * new cycle if necessary. We keep executing cycles until we find one - * where we didn't reap any keys. - */ - kdebug("pass complete"); - - if (gc_state & KEY_GC_SET_TIMER && new_timer != (time_t)LONG_MAX) { - new_timer += key_gc_delay; - key_schedule_gc(new_timer); - } - - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { - /* Make sure everyone revalidates their keys if we marked a - * bunch as being dead and make sure all keyring ex-payloads - * are destroyed. - */ - kdebug("dead sync"); - synchronize_rcu(); - } - - if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | - KEY_GC_REAPING_DEAD_2))) { - if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { - /* No remaining dead keys: short circuit the remaining - * keytype reap cycles. - */ - kdebug("dead short"); - gc_state &= ~(KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2); - gc_state |= KEY_GC_REAPING_DEAD_3; - } else { - gc_state |= KEY_GC_REAP_AGAIN; - } - } - - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) { - kdebug("dead wake"); - smp_mb(); - clear_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); - wake_up_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE); - } - - if (gc_state & KEY_GC_REAP_AGAIN) - queue_work(system_nrt_wq, &key_gc_work); - kleave(" [end %x]", gc_state); - return; - - /* We found an unreferenced key - once we've removed it from the tree, - * we can safely drop the lock. - */ -found_unreferenced_key: - kdebug("unrefd key %d", key->serial); - rb_erase(&key->serial_node, &key_serial_tree); - spin_unlock(&key_serial_lock); - - key_gc_unused_key(key); - gc_state |= KEY_GC_REAP_AGAIN; - goto maybe_resched; - - /* We found a keyring and we need to check the payload for links to - * dead or expired keys. We don't flag another reap immediately as we - * have to wait for the old payload to be destroyed by RCU before we - * can reap the keys to which it refers. - */ -found_keyring: - spin_unlock(&key_serial_lock); - kdebug("scan keyring %d", key->serial); - key_gc_keyring(key, limit); - goto maybe_resched; - - /* We found a dead key that is still referenced. Reset its type and - * destroy its payload with its semaphore held. - */ -destroy_dead_key: - spin_unlock(&key_serial_lock); - kdebug("destroy key %d", key->serial); - down_write(&key->sem); - key->type = &key_type_dead; - if (key_gc_dead_keytype->destroy) - key_gc_dead_keytype->destroy(key); - memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); - up_write(&key->sem); - goto maybe_resched; -} diff --git a/ANDROID_3.4.5/security/keys/internal.h b/ANDROID_3.4.5/security/keys/internal.h deleted file mode 100644 index 65647f82..00000000 --- a/ANDROID_3.4.5/security/keys/internal.h +++ /dev/null @@ -1,251 +0,0 @@ -/* Authentication token and access key management internal defs - * - * Copyright (C) 2003-5, 2007 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. - */ - -#ifndef _INTERNAL_H -#define _INTERNAL_H - -#include <linux/sched.h> -#include <linux/key-type.h> - -#ifdef __KDEBUG -#define kenter(FMT, ...) \ - printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) -#define kleave(FMT, ...) \ - printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) -#define kdebug(FMT, ...) \ - printk(KERN_DEBUG " "FMT"\n", ##__VA_ARGS__) -#else -#define kenter(FMT, ...) \ - no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) -#define kleave(FMT, ...) \ - no_printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) -#define kdebug(FMT, ...) \ - no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__) -#endif - -extern struct key_type key_type_dead; -extern struct key_type key_type_user; -extern struct key_type key_type_logon; - -/*****************************************************************************/ -/* - * Keep track of keys for a user. - * - * This needs to be separate to user_struct to avoid a refcount-loop - * (user_struct pins some keyrings which pin this struct). - * - * We also keep track of keys under request from userspace for this UID here. - */ -struct key_user { - struct rb_node node; - struct mutex cons_lock; /* construction initiation lock */ - spinlock_t lock; - atomic_t usage; /* for accessing qnkeys & qnbytes */ - atomic_t nkeys; /* number of keys */ - atomic_t nikeys; /* number of instantiated keys */ - uid_t uid; - struct user_namespace *user_ns; - int qnkeys; /* number of keys allocated to this user */ - int qnbytes; /* number of bytes allocated to this user */ -}; - -extern struct rb_root key_user_tree; -extern spinlock_t key_user_lock; -extern struct key_user root_key_user; - -extern struct key_user *key_user_lookup(uid_t uid, - struct user_namespace *user_ns); -extern void key_user_put(struct key_user *user); - -/* - * Key quota limits. - * - root has its own separate limits to everyone else - */ -extern unsigned key_quota_root_maxkeys; -extern unsigned key_quota_root_maxbytes; -extern unsigned key_quota_maxkeys; -extern unsigned key_quota_maxbytes; - -#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ - - -extern struct kmem_cache *key_jar; -extern struct rb_root key_serial_tree; -extern spinlock_t key_serial_lock; -extern struct mutex key_construction_mutex; -extern wait_queue_head_t request_key_conswq; - - -extern struct key_type *key_type_lookup(const char *type); -extern void key_type_put(struct key_type *ktype); - -extern int __key_link_begin(struct key *keyring, - const struct key_type *type, - const char *description, - unsigned long *_prealloc); -extern int __key_link_check_live_key(struct key *keyring, struct key *key); -extern void __key_link(struct key *keyring, struct key *key, - unsigned long *_prealloc); -extern void __key_link_end(struct key *keyring, - struct key_type *type, - unsigned long prealloc); - -extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, - const struct key_type *type, - const char *description, - key_perm_t perm); - -extern struct key *keyring_search_instkey(struct key *keyring, - key_serial_t target_id); - -typedef int (*key_match_func_t)(const struct key *, const void *); - -extern 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); - -extern key_ref_t search_my_process_keyrings(struct key_type *type, - const void *description, - key_match_func_t match, - bool no_state_check, - const struct cred *cred); -extern key_ref_t search_process_keyrings(struct key_type *type, - const void *description, - key_match_func_t match, - const struct cred *cred); - -extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); - -extern int install_user_keyrings(void); -extern int install_thread_keyring_to_cred(struct cred *); -extern int install_process_keyring_to_cred(struct cred *); -extern int install_session_keyring_to_cred(struct cred *, struct key *); - -extern struct key *request_key_and_link(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux, - struct key *dest_keyring, - unsigned long flags); - -extern int lookup_user_key_possessed(const struct key *key, const void *target); -extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, - key_perm_t perm); -#define KEY_LOOKUP_CREATE 0x01 -#define KEY_LOOKUP_PARTIAL 0x02 -#define KEY_LOOKUP_FOR_UNLINK 0x04 - -extern long join_session_keyring(const char *name); - -extern struct work_struct key_gc_work; -extern unsigned key_gc_delay; -extern void keyring_gc(struct key *keyring, time_t limit); -extern void key_schedule_gc(time_t expiry_at); -extern void key_gc_keytype(struct key_type *ktype); - -extern int key_task_permission(const key_ref_t key_ref, - const struct cred *cred, - key_perm_t perm); - -/* - * Check to see whether permission is granted to use a key in the desired way. - */ -static inline int key_permission(const key_ref_t key_ref, key_perm_t perm) -{ - return key_task_permission(key_ref, current_cred(), perm); -} - -/* required permissions */ -#define KEY_VIEW 0x01 /* require permission to view attributes */ -#define KEY_READ 0x02 /* require permission to read content */ -#define KEY_WRITE 0x04 /* require permission to update / modify */ -#define KEY_SEARCH 0x08 /* require permission to search (keyring) or find (key) */ -#define KEY_LINK 0x10 /* require permission to link */ -#define KEY_SETATTR 0x20 /* require permission to change attributes */ -#define KEY_ALL 0x3f /* all the above permissions */ - -/* - * Authorisation record for request_key(). - */ -struct request_key_auth { - struct key *target_key; - struct key *dest_keyring; - const struct cred *cred; - void *callout_info; - size_t callout_len; - pid_t pid; -}; - -extern struct key_type key_type_request_key_auth; -extern struct key *request_key_auth_new(struct key *target, - const void *callout_info, - size_t callout_len, - struct key *dest_keyring); - -extern struct key *key_get_instantiation_authkey(key_serial_t target_id); - -/* - * keyctl() functions - */ -extern long keyctl_get_keyring_ID(key_serial_t, int); -extern long keyctl_join_session_keyring(const char __user *); -extern long keyctl_update_key(key_serial_t, const void __user *, size_t); -extern long keyctl_revoke_key(key_serial_t); -extern long keyctl_keyring_clear(key_serial_t); -extern long keyctl_keyring_link(key_serial_t, key_serial_t); -extern long keyctl_keyring_unlink(key_serial_t, key_serial_t); -extern long keyctl_describe_key(key_serial_t, char __user *, size_t); -extern long keyctl_keyring_search(key_serial_t, const char __user *, - const char __user *, key_serial_t); -extern long keyctl_read_key(key_serial_t, char __user *, size_t); -extern long keyctl_chown_key(key_serial_t, uid_t, gid_t); -extern long keyctl_setperm_key(key_serial_t, key_perm_t); -extern long keyctl_instantiate_key(key_serial_t, const void __user *, - size_t, key_serial_t); -extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); -extern long keyctl_set_reqkey_keyring(int); -extern long keyctl_set_timeout(key_serial_t, unsigned); -extern long keyctl_assume_authority(key_serial_t); -extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, - size_t buflen); -extern long keyctl_session_to_parent(void); -extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); -extern long keyctl_instantiate_key_iov(key_serial_t, - const struct iovec __user *, - unsigned, key_serial_t); - -extern long keyctl_instantiate_key_common(key_serial_t, - const struct iovec __user *, - unsigned, size_t, key_serial_t); - -/* - * Debugging key validation - */ -#ifdef KEY_DEBUGGING -extern void __key_check(const struct key *); - -static inline void key_check(const struct key *key) -{ - if (key && (IS_ERR(key) || key->magic != KEY_DEBUG_MAGIC)) - __key_check(key); -} - -#else - -#define key_check(key) do {} while(0) - -#endif - -#endif /* _INTERNAL_H */ diff --git a/ANDROID_3.4.5/security/keys/key.c b/ANDROID_3.4.5/security/keys/key.c deleted file mode 100644 index 06783cff..00000000 --- a/ANDROID_3.4.5/security/keys/key.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* Basic authentication token and access key management - * - * 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 - * 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/poison.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/security.h> -#include <linux/workqueue.h> -#include <linux/random.h> -#include <linux/err.h> -#include <linux/user_namespace.h> -#include "internal.h" - -struct kmem_cache *key_jar; -struct rb_root key_serial_tree; /* tree of keys indexed by serial */ -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); - -/* We serialise key instantiation and link */ -DEFINE_MUTEX(key_construction_mutex); - -#ifdef KEY_DEBUGGING -void __key_check(const struct key *key) -{ - printk("__key_check: key %p {%08x} should be {%08x}\n", - key, key->magic, KEY_DEBUG_MAGIC); - BUG(); -} -#endif - -/* - * 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) -{ - struct key_user *candidate = NULL, *user; - struct rb_node *parent = NULL; - struct rb_node **p; - -try_again: - p = &key_user_tree.rb_node; - spin_lock(&key_user_lock); - - /* search the tree for a user record with a matching UID */ - while (*p) { - parent = *p; - user = rb_entry(parent, struct key_user, node); - - if (uid < user->uid) - p = &(*p)->rb_left; - else if (uid > user->uid) - p = &(*p)->rb_right; - else if (user_ns < user->user_ns) - p = &(*p)->rb_left; - else if (user_ns > user->user_ns) - p = &(*p)->rb_right; - else - goto found; - } - - /* if we get here, we failed to find a match in the tree */ - if (!candidate) { - /* allocate a candidate user record if we don't already have - * one */ - spin_unlock(&key_user_lock); - - user = NULL; - candidate = kmalloc(sizeof(struct key_user), GFP_KERNEL); - if (unlikely(!candidate)) - goto out; - - /* the allocation may have scheduled, so we need to repeat the - * search lest someone else added the record whilst we were - * asleep */ - goto try_again; - } - - /* if we get here, then the user record still hadn't appeared on the - * second pass - so we use the candidate record */ - atomic_set(&candidate->usage, 1); - atomic_set(&candidate->nkeys, 0); - atomic_set(&candidate->nikeys, 0); - candidate->uid = uid; - candidate->user_ns = get_user_ns(user_ns); - candidate->qnkeys = 0; - candidate->qnbytes = 0; - spin_lock_init(&candidate->lock); - mutex_init(&candidate->cons_lock); - - rb_link_node(&candidate->node, parent, p); - rb_insert_color(&candidate->node, &key_user_tree); - spin_unlock(&key_user_lock); - user = candidate; - goto out; - - /* okay - we found a user record for this UID */ -found: - atomic_inc(&user->usage); - spin_unlock(&key_user_lock); - kfree(candidate); -out: - return user; -} - -/* - * Dispose of a user structure - */ -void key_user_put(struct key_user *user) -{ - if (atomic_dec_and_lock(&user->usage, &key_user_lock)) { - rb_erase(&user->node, &key_user_tree); - spin_unlock(&key_user_lock); - put_user_ns(user->user_ns); - - kfree(user); - } -} - -/* - * 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) -{ - struct rb_node *parent, **p; - struct key *xkey; - - /* propose a random serial number and look for a hole for it in the - * serial number tree */ - do { - get_random_bytes(&key->serial, sizeof(key->serial)); - - key->serial >>= 1; /* negative numbers are not permitted */ - } while (key->serial < 3); - - spin_lock(&key_serial_lock); - -attempt_insertion: - 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 - goto serial_exists; - } - - /* 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); - - spin_unlock(&key_serial_lock); - return; - - /* we found a key with the proposed serial number - walk the tree from - * that point looking for the next unused serial number */ -serial_exists: - for (;;) { - key->serial++; - if (key->serial < 3) { - key->serial = 3; - goto attempt_insertion; - } - - parent = rb_next(parent); - if (!parent) - goto attempt_insertion; - - xkey = rb_entry(parent, struct key, serial_node); - if (key->serial < xkey->serial) - goto attempt_insertion; - } -} - -/** - * 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, - key_perm_t perm, unsigned long flags) -{ - struct key_user *user = NULL; - struct key *key; - size_t desclen, quotalen; - int ret; - - key = ERR_PTR(-EINVAL); - if (!desc || !*desc) - goto error; - - if (type->vet_description) { - ret = type->vet_description(desc); - if (ret < 0) { - key = ERR_PTR(ret); - goto error; - } - } - - desclen = strlen(desc) + 1; - quotalen = desclen + type->def_datalen; - - /* get hold of the key tracking for this user */ - user = key_user_lookup(uid, cred->user->user_ns); - if (!user) - goto no_memory_1; - - /* 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 >= maxkeys || - user->qnbytes + quotalen >= maxbytes || - user->qnbytes + quotalen < user->qnbytes) - goto no_quota; - } - - user->qnkeys++; - user->qnbytes += quotalen; - spin_unlock(&user->lock); - } - - /* allocate and initialise the key and its description */ - key = kmem_cache_alloc(key_jar, GFP_KERNEL); - if (!key) - goto no_memory_2; - - if (desc) { - key->description = kmemdup(desc, desclen, GFP_KERNEL); - if (!key->description) - goto no_memory_3; - } - - atomic_set(&key->usage, 1); - init_rwsem(&key->sem); - lockdep_set_class(&key->sem, &type->lock_class); - key->type = type; - key->user = user; - key->quotalen = quotalen; - key->datalen = type->def_datalen; - key->uid = uid; - key->gid = gid; - key->perm = perm; - key->flags = 0; - key->expiry = 0; - key->payload.data = NULL; - key->security = NULL; - - if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) - key->flags |= 1 << KEY_FLAG_IN_QUOTA; - - memset(&key->type_data, 0, sizeof(key->type_data)); - -#ifdef KEY_DEBUGGING - key->magic = KEY_DEBUG_MAGIC; -#endif - - /* let the security module know about the key */ - ret = security_key_alloc(key, cred, flags); - if (ret < 0) - goto security_error; - - /* publish the key by giving it a serial number */ - atomic_inc(&user->nkeys); - key_alloc_serial(key); - -error: - return key; - -security_error: - kfree(key->description); - kmem_cache_free(key_jar, key); - if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { - spin_lock(&user->lock); - user->qnkeys--; - user->qnbytes -= quotalen; - spin_unlock(&user->lock); - } - key_user_put(user); - key = ERR_PTR(ret); - goto error; - -no_memory_3: - kmem_cache_free(key_jar, key); -no_memory_2: - if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { - spin_lock(&user->lock); - user->qnkeys--; - user->qnbytes -= quotalen; - spin_unlock(&user->lock); - } - key_user_put(user); -no_memory_1: - key = ERR_PTR(-ENOMEM); - goto error; - -no_quota: - spin_unlock(&user->lock); - key_user_put(user); - key = ERR_PTR(-EDQUOT); - goto error; -} -EXPORT_SYMBOL(key_alloc); - -/** - * 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) -{ - int delta = (int)datalen - key->datalen; - int ret = 0; - - key_check(key); - - /* 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 >= maxbytes || - key->user->qnbytes + delta < key->user->qnbytes)) { - ret = -EDQUOT; - } - else { - key->user->qnbytes += delta; - key->quotalen += delta; - } - spin_unlock(&key->user->lock); - } - - /* change the recorded data length if that didn't generate an error */ - if (ret == 0) - key->datalen = datalen; - - return ret; -} -EXPORT_SYMBOL(key_payload_reserve); - -/* - * 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, - size_t datalen, - struct key *keyring, - struct key *authkey, - unsigned long *_prealloc) -{ - int ret, awaken; - - key_check(key); - key_check(keyring); - - awaken = 0; - ret = -EBUSY; - - mutex_lock(&key_construction_mutex); - - /* can't instantiate twice */ - if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { - /* instantiate the key */ - ret = key->type->instantiate(key, data, datalen); - - if (ret == 0) { - /* mark the key as being instantiated */ - atomic_inc(&key->user->nikeys); - set_bit(KEY_FLAG_INSTANTIATED, &key->flags); - - if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) - awaken = 1; - - /* and link it into the destination keyring */ - if (keyring) - __key_link(keyring, key, _prealloc); - - /* disable the authorisation key */ - if (authkey) - key_revoke(authkey); - } - } - - mutex_unlock(&key_construction_mutex); - - /* wake up anyone waiting for a key to be constructed */ - if (awaken) - wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); - - return ret; -} - -/** - * 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, - size_t datalen, - struct key *keyring, - struct key *authkey) -{ - unsigned long prealloc; - int ret; - - if (keyring) { - ret = __key_link_begin(keyring, key->type, key->description, - &prealloc); - if (ret < 0) - return ret; - } - - ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey, - &prealloc); - - if (keyring) - __key_link_end(keyring, key->type, prealloc); - - return ret; -} - -EXPORT_SYMBOL(key_instantiate_and_link); - -/** - * key_reject_and_link - Negatively instantiate a key and link it into the keyring. - * @key: The key to instantiate. - * @timeout: The timeout on the negative key. - * @error: The error to return when the key is hit. - * @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 stored error 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 the stored error code (typically 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_reject_and_link(struct key *key, - unsigned timeout, - unsigned error, - struct key *keyring, - struct key *authkey) -{ - unsigned long prealloc; - struct timespec now; - int ret, awaken, link_ret = 0; - - key_check(key); - key_check(keyring); - - awaken = 0; - ret = -EBUSY; - - if (keyring) - link_ret = __key_link_begin(keyring, key->type, - key->description, &prealloc); - - mutex_lock(&key_construction_mutex); - - /* can't instantiate twice */ - if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { - /* mark the key as being negatively instantiated */ - atomic_inc(&key->user->nikeys); - set_bit(KEY_FLAG_NEGATIVE, &key->flags); - set_bit(KEY_FLAG_INSTANTIATED, &key->flags); - key->type_data.reject_error = -error; - now = current_kernel_time(); - key->expiry = now.tv_sec + timeout; - key_schedule_gc(key->expiry + key_gc_delay); - - if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) - awaken = 1; - - ret = 0; - - /* and link it into the destination keyring */ - if (keyring && link_ret == 0) - __key_link(keyring, key, &prealloc); - - /* disable the authorisation key */ - if (authkey) - key_revoke(authkey); - } - - mutex_unlock(&key_construction_mutex); - - if (keyring) - __key_link_end(keyring, key->type, prealloc); - - /* wake up anyone waiting for a key to be constructed */ - if (awaken) - wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); - - return ret == 0 ? link_ret : ret; -} -EXPORT_SYMBOL(key_reject_and_link); - -/** - * 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) -{ - if (key) { - key_check(key); - - if (atomic_dec_and_test(&key->usage)) - queue_work(system_nrt_wq, &key_gc_work); - } -} -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 is awaiting deletion */ - if (atomic_read(&key->usage) == 0) - 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; -} - -/* - * 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) -{ - 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; -} - -void key_set_timeout(struct key *key, unsigned timeout) -{ - struct timespec now; - time_t expiry = 0; - - /* make the changes with the locks held to prevent races */ - down_write(&key->sem); - - if (timeout > 0) { - now = current_kernel_time(); - expiry = now.tv_sec + timeout; - } - - key->expiry = expiry; - key_schedule_gc(key->expiry + key_gc_delay); - - up_write(&key->sem); -} -EXPORT_SYMBOL_GPL(key_set_timeout); - -/* - * Unlock a key type locked by key_type_lookup(). - */ -void key_type_put(struct key_type *ktype) -{ - up_read(&key_types_sem); -} - -/* - * 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) -{ - 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; -} - -/** - * 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, - const char *description, - const void *payload, - size_t plen, - key_perm_t perm, - unsigned long flags) -{ - unsigned long prealloc; - const struct cred *cred = current_cred(); - struct key_type *ktype; - struct key *keyring, *key = NULL; - 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; - - ret = __key_link_begin(keyring, ktype, description, &prealloc); - if (ret < 0) - goto error_2; - - /* 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; - } - - /* 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 == &key_type_keyring || ktype->update) - perm |= KEY_USR_WRITE; - } - - /* allocate a new key */ - key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred, - perm, flags); - if (IS_ERR(key)) { - key_ref = ERR_CAST(key); - goto error_3; - } - - /* instantiate it and link it into the target keyring */ - ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL, - &prealloc); - 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: - __key_link_end(keyring, ktype, prealloc); - 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 - */ - __key_link_end(keyring, ktype, prealloc); - key_type_put(ktype); - - key_ref = __key_update(key_ref, payload, plen); - goto error; -} -EXPORT_SYMBOL(key_create_or_update); - -/** - * 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) -{ - 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; -} -EXPORT_SYMBOL(key_update); - -/** - * 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) -{ - struct timespec now; - time_t time; - - 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); - - /* set the death time to no more than the expiry time */ - now = current_kernel_time(); - time = now.tv_sec; - if (key->revoked_at == 0 || key->revoked_at > time) { - key->revoked_at = time; - key_schedule_gc(key->revoked_at + key_gc_delay); - } - - up_write(&key->sem); -} -EXPORT_SYMBOL(key_revoke); - -/** - * 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) -{ - struct key_type *p; - int ret; - - memset(&ktype->lock_class, 0, sizeof(ktype->lock_class)); - - 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; -} -EXPORT_SYMBOL(register_key_type); - -/** - * 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) -{ - down_write(&key_types_sem); - list_del_init(&ktype->link); - downgrade_write(&key_types_sem); - key_gc_keytype(ktype); - up_read(&key_types_sem); -} -EXPORT_SYMBOL(unregister_key_type); - -/* - * Initialise the key management state. - */ -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); - list_add_tail(&key_type_logon.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); -} diff --git a/ANDROID_3.4.5/security/keys/keyctl.c b/ANDROID_3.4.5/security/keys/keyctl.c deleted file mode 100644 index fb767c6c..00000000 --- a/ANDROID_3.4.5/security/keys/keyctl.c +++ /dev/null @@ -1,1628 +0,0 @@ -/* Userspace key control operations - * - * 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/syscalls.h> -#include <linux/key.h> -#include <linux/keyctl.h> -#include <linux/fs.h> -#include <linux/capability.h> -#include <linux/string.h> -#include <linux/err.h> -#include <linux/vmalloc.h> -#include <linux/security.h> -#include <asm/uaccess.h> -#include "internal.h" - -static int key_get_type_from_user(char *type, - const char __user *_type, - unsigned len) -{ - int ret; - - ret = strncpy_from_user(type, _type, len); - if (ret < 0) - return ret; - if (ret == 0 || ret >= len) - return -EINVAL; - if (type[0] == '.') - return -EPERM; - type[len - 1] = '\0'; - return 0; -} - -/* - * Extract the description of a new key from userspace and either add it as a - * new key to the specified keyring or update a matching key in that keyring. - * - * The keyring must be writable so that we can attach the key to it. - * - * If successful, the new key's serial number is returned, otherwise an error - * code is returned. - */ -SYSCALL_DEFINE5(add_key, const char __user *, _type, - const char __user *, _description, - const void __user *, _payload, - size_t, plen, - key_serial_t, ringid) -{ - key_ref_t keyring_ref, key_ref; - char type[32], *description; - void *payload; - long ret; - bool vm; - - ret = -EINVAL; - if (plen > 1024 * 1024 - 1) - goto error; - - /* draw all the data into kernel space */ - ret = key_get_type_from_user(type, _type, sizeof(type)); - if (ret < 0) - goto error; - - description = strndup_user(_description, PAGE_SIZE); - if (IS_ERR(description)) { - ret = PTR_ERR(description); - goto error; - } - - /* pull the payload in if one was supplied */ - payload = NULL; - - vm = false; - if (_payload) { - ret = -ENOMEM; - payload = kmalloc(plen, GFP_KERNEL); - if (!payload) { - if (plen <= PAGE_SIZE) - goto error2; - vm = true; - payload = vmalloc(plen); - if (!payload) - goto error2; - } - - ret = -EFAULT; - if (copy_from_user(payload, _payload, plen) != 0) - goto error3; - } - - /* find the target keyring (which must be writable) */ - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); - if (IS_ERR(keyring_ref)) { - ret = PTR_ERR(keyring_ref); - goto error3; - } - - /* create or update the requested key and add it to the target - * keyring */ - key_ref = key_create_or_update(keyring_ref, type, description, - payload, plen, KEY_PERM_UNDEF, - KEY_ALLOC_IN_QUOTA); - if (!IS_ERR(key_ref)) { - ret = key_ref_to_ptr(key_ref)->serial; - key_ref_put(key_ref); - } - else { - ret = PTR_ERR(key_ref); - } - - key_ref_put(keyring_ref); - error3: - if (!vm) - kfree(payload); - else - vfree(payload); - error2: - kfree(description); - error: - return ret; -} - -/* - * Search the process keyrings and keyring trees linked from those for a - * matching key. Keyrings must have appropriate Search permission to be - * searched. - * - * If a key is found, it will be attached to the destination keyring if there's - * one specified and the serial number of the key will be returned. - * - * If no key is found, /sbin/request-key will be invoked if _callout_info is - * non-NULL in an attempt to create a key. The _callout_info string will be - * passed to /sbin/request-key to aid with completing the request. If the - * _callout_info string is "" then it will be changed to "-". - */ -SYSCALL_DEFINE4(request_key, const char __user *, _type, - const char __user *, _description, - const char __user *, _callout_info, - key_serial_t, destringid) -{ - struct key_type *ktype; - struct key *key; - key_ref_t dest_ref; - size_t callout_len; - char type[32], *description, *callout_info; - long ret; - - /* pull the type into kernel space */ - ret = key_get_type_from_user(type, _type, sizeof(type)); - if (ret < 0) - goto error; - - /* pull the description into kernel space */ - description = strndup_user(_description, PAGE_SIZE); - if (IS_ERR(description)) { - ret = PTR_ERR(description); - goto error; - } - - /* pull the callout info into kernel space */ - callout_info = NULL; - callout_len = 0; - if (_callout_info) { - callout_info = strndup_user(_callout_info, PAGE_SIZE); - if (IS_ERR(callout_info)) { - ret = PTR_ERR(callout_info); - goto error2; - } - callout_len = strlen(callout_info); - } - - /* get the destination keyring if specified */ - dest_ref = NULL; - if (destringid) { - dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, - KEY_WRITE); - if (IS_ERR(dest_ref)) { - ret = PTR_ERR(dest_ref); - goto error3; - } - } - - /* find the key type */ - ktype = key_type_lookup(type); - if (IS_ERR(ktype)) { - ret = PTR_ERR(ktype); - goto error4; - } - - /* do the search */ - key = request_key_and_link(ktype, description, callout_info, - callout_len, NULL, key_ref_to_ptr(dest_ref), - KEY_ALLOC_IN_QUOTA); - if (IS_ERR(key)) { - ret = PTR_ERR(key); - goto error5; - } - - /* wait for the key to finish being constructed */ - ret = wait_for_key_construction(key, 1); - if (ret < 0) - goto error6; - - ret = key->serial; - -error6: - key_put(key); -error5: - key_type_put(ktype); -error4: - key_ref_put(dest_ref); -error3: - kfree(callout_info); -error2: - kfree(description); -error: - return ret; -} - -/* - * Get the ID of the specified process keyring. - * - * The requested keyring must have search permission to be found. - * - * If successful, the ID of the requested keyring will be returned. - */ -long keyctl_get_keyring_ID(key_serial_t id, int create) -{ - key_ref_t key_ref; - unsigned long lflags; - long ret; - - lflags = create ? KEY_LOOKUP_CREATE : 0; - key_ref = lookup_user_key(id, lflags, KEY_SEARCH); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error; - } - - ret = key_ref_to_ptr(key_ref)->serial; - key_ref_put(key_ref); -error: - return ret; -} - -/* - * Join a (named) session keyring. - * - * Create and join an anonymous session keyring or join a named session - * keyring, creating it if necessary. A named session keyring must have Search - * permission for it to be joined. Session keyrings without this permit will - * be skipped over. - * - * If successful, the ID of the joined session keyring will be returned. - */ -long keyctl_join_session_keyring(const char __user *_name) -{ - char *name; - long ret; - - /* fetch the name from userspace */ - name = NULL; - if (_name) { - name = strndup_user(_name, PAGE_SIZE); - if (IS_ERR(name)) { - ret = PTR_ERR(name); - goto error; - } - } - - /* join the session */ - ret = join_session_keyring(name); - kfree(name); - -error: - return ret; -} - -/* - * Update a key's data payload from the given data. - * - * The key must grant the caller Write permission and the key type must support - * updating for this to work. A negative key can be positively instantiated - * with this call. - * - * If successful, 0 will be returned. If the key type does not support - * updating, then -EOPNOTSUPP will be returned. - */ -long keyctl_update_key(key_serial_t id, - const void __user *_payload, - size_t plen) -{ - key_ref_t key_ref; - void *payload; - long ret; - - ret = -EINVAL; - if (plen > PAGE_SIZE) - goto error; - - /* pull the payload in if one was supplied */ - payload = NULL; - if (_payload) { - ret = -ENOMEM; - payload = kmalloc(plen, GFP_KERNEL); - if (!payload) - goto error; - - ret = -EFAULT; - if (copy_from_user(payload, _payload, plen) != 0) - goto error2; - } - - /* find the target key (which must be writable) */ - key_ref = lookup_user_key(id, 0, KEY_WRITE); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error2; - } - - /* update the key */ - ret = key_update(key_ref, payload, plen); - - key_ref_put(key_ref); -error2: - kfree(payload); -error: - return ret; -} - -/* - * Revoke a key. - * - * The key must be grant the caller Write or Setattr permission for this to - * work. The key type should give up its quota claim when revoked. The key - * and any links to the key will be automatically garbage collected after a - * certain amount of time (/proc/sys/kernel/keys/gc_delay). - * - * If successful, 0 is returned. - */ -long keyctl_revoke_key(key_serial_t id) -{ - key_ref_t key_ref; - long ret; - - key_ref = lookup_user_key(id, 0, KEY_WRITE); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - if (ret != -EACCES) - goto error; - key_ref = lookup_user_key(id, 0, KEY_SETATTR); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error; - } - } - - key_revoke(key_ref_to_ptr(key_ref)); - ret = 0; - - key_ref_put(key_ref); -error: - return ret; -} - -/* - * Clear the specified keyring, creating an empty process keyring if one of the - * special keyring IDs is used. - * - * The keyring must grant the caller Write permission for this to work. If - * successful, 0 will be returned. - */ -long keyctl_keyring_clear(key_serial_t ringid) -{ - key_ref_t keyring_ref; - long ret; - - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); - if (IS_ERR(keyring_ref)) { - ret = PTR_ERR(keyring_ref); - - /* Root is permitted to invalidate certain special keyrings */ - if (capable(CAP_SYS_ADMIN)) { - keyring_ref = lookup_user_key(ringid, 0, 0); - if (IS_ERR(keyring_ref)) - goto error; - if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR, - &key_ref_to_ptr(keyring_ref)->flags)) - goto clear; - goto error_put; - } - - goto error; - } - -clear: - ret = keyring_clear(key_ref_to_ptr(keyring_ref)); -error_put: - key_ref_put(keyring_ref); -error: - return ret; -} - -/* - * Create a link from a keyring to a key if there's no matching key in the - * keyring, otherwise replace the link to the matching key with a link to the - * new key. - * - * The key must grant the caller Link permission and the the keyring must grant - * the caller Write permission. Furthermore, if an additional link is created, - * the keyring's quota will be extended. - * - * If successful, 0 will be returned. - */ -long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) -{ - key_ref_t keyring_ref, key_ref; - long ret; - - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); - if (IS_ERR(keyring_ref)) { - ret = PTR_ERR(keyring_ref); - goto error; - } - - key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error2; - } - - ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); - - key_ref_put(key_ref); -error2: - key_ref_put(keyring_ref); -error: - return ret; -} - -/* - * Unlink a key from a keyring. - * - * The keyring must grant the caller Write permission for this to work; the key - * itself need not grant the caller anything. If the last link to a key is - * removed then that key will be scheduled for destruction. - * - * If successful, 0 will be returned. - */ -long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) -{ - key_ref_t keyring_ref, key_ref; - long ret; - - keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); - if (IS_ERR(keyring_ref)) { - ret = PTR_ERR(keyring_ref); - goto error; - } - - key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error2; - } - - ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); - - key_ref_put(key_ref); -error2: - key_ref_put(keyring_ref); -error: - return ret; -} - -/* - * Return a description of a key to userspace. - * - * The key must grant the caller View permission for this to work. - * - * If there's a buffer, we place up to buflen bytes of data into it formatted - * in the following way: - * - * type;uid;gid;perm;description<NUL> - * - * If successful, we return the amount of description available, irrespective - * of how much we may have copied into the buffer. - */ -long keyctl_describe_key(key_serial_t keyid, - char __user *buffer, - size_t buflen) -{ - struct key *key, *instkey; - key_ref_t key_ref; - char *tmpbuf; - long ret; - - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); - if (IS_ERR(key_ref)) { - /* viewing a key under construction is permitted if we have the - * authorisation token handy */ - if (PTR_ERR(key_ref) == -EACCES) { - instkey = key_get_instantiation_authkey(keyid); - if (!IS_ERR(instkey)) { - key_put(instkey); - key_ref = lookup_user_key(keyid, - KEY_LOOKUP_PARTIAL, - 0); - if (!IS_ERR(key_ref)) - goto okay; - } - } - - ret = PTR_ERR(key_ref); - goto error; - } - -okay: - /* calculate how much description we're going to return */ - ret = -ENOMEM; - tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!tmpbuf) - goto error2; - - key = key_ref_to_ptr(key_ref); - - ret = snprintf(tmpbuf, PAGE_SIZE - 1, - "%s;%d;%d;%08x;%s", - key->type->name, - key->uid, - key->gid, - key->perm, - key->description ?: ""); - - /* include a NUL char at the end of the data */ - if (ret > PAGE_SIZE - 1) - ret = PAGE_SIZE - 1; - tmpbuf[ret] = 0; - ret++; - - /* consider returning the data */ - if (buffer && buflen > 0) { - if (buflen > ret) - buflen = ret; - - if (copy_to_user(buffer, tmpbuf, buflen) != 0) - ret = -EFAULT; - } - - kfree(tmpbuf); -error2: - key_ref_put(key_ref); -error: - return ret; -} - -/* - * Search the specified keyring and any keyrings it links to for a matching - * key. Only keyrings that grant the caller Search permission will be searched - * (this includes the starting keyring). Only keys with Search permission can - * be found. - * - * If successful, the found key will be linked to the destination keyring if - * supplied and the key has Link permission, and the found key ID will be - * returned. - */ -long keyctl_keyring_search(key_serial_t ringid, - const char __user *_type, - const char __user *_description, - key_serial_t destringid) -{ - struct key_type *ktype; - key_ref_t keyring_ref, key_ref, dest_ref; - char type[32], *description; - long ret; - - /* pull the type and description into kernel space */ - ret = key_get_type_from_user(type, _type, sizeof(type)); - if (ret < 0) - goto error; - - description = strndup_user(_description, PAGE_SIZE); - if (IS_ERR(description)) { - ret = PTR_ERR(description); - goto error; - } - - /* get the keyring at which to begin the search */ - keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); - if (IS_ERR(keyring_ref)) { - ret = PTR_ERR(keyring_ref); - goto error2; - } - - /* get the destination keyring if specified */ - dest_ref = NULL; - if (destringid) { - dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, - KEY_WRITE); - if (IS_ERR(dest_ref)) { - ret = PTR_ERR(dest_ref); - goto error3; - } - } - - /* find the key type */ - ktype = key_type_lookup(type); - if (IS_ERR(ktype)) { - ret = PTR_ERR(ktype); - goto error4; - } - - /* do the search */ - key_ref = keyring_search(keyring_ref, ktype, description); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - - /* treat lack or presence of a negative key the same */ - if (ret == -EAGAIN) - ret = -ENOKEY; - goto error5; - } - - /* link the resulting key to the destination keyring if we can */ - if (dest_ref) { - ret = key_permission(key_ref, KEY_LINK); - if (ret < 0) - goto error6; - - ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); - if (ret < 0) - goto error6; - } - - ret = key_ref_to_ptr(key_ref)->serial; - -error6: - key_ref_put(key_ref); -error5: - key_type_put(ktype); -error4: - key_ref_put(dest_ref); -error3: - key_ref_put(keyring_ref); -error2: - kfree(description); -error: - return ret; -} - -/* - * Read a key's payload. - * - * The key must either grant the caller Read permission, or it must grant the - * caller Search permission when searched for from the process keyrings. - * - * If successful, we place up to buflen bytes of data into the buffer, if one - * is provided, and return the amount of data that is available in the key, - * irrespective of how much we copied into the buffer. - */ -long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) -{ - struct key *key; - key_ref_t key_ref; - long ret; - - /* find the key first */ - key_ref = lookup_user_key(keyid, 0, 0); - if (IS_ERR(key_ref)) { - ret = -ENOKEY; - goto error; - } - - key = key_ref_to_ptr(key_ref); - - /* see if we can read it directly */ - ret = key_permission(key_ref, KEY_READ); - if (ret == 0) - goto can_read_key; - if (ret != -EACCES) - goto error; - - /* we can't; see if it's searchable from this process's keyrings - * - we automatically take account of the fact that it may be - * dangling off an instantiation key - */ - if (!is_key_possessed(key_ref)) { - ret = -EACCES; - goto error2; - } - - /* the key is probably readable - now try to read it */ -can_read_key: - ret = key_validate(key); - if (ret == 0) { - ret = -EOPNOTSUPP; - if (key->type->read) { - /* read the data with the semaphore held (since we - * might sleep) */ - down_read(&key->sem); - ret = key->type->read(key, buffer, buflen); - up_read(&key->sem); - } - } - -error2: - key_put(key); -error: - return ret; -} - -/* - * Change the ownership of a key - * - * The key must grant the caller Setattr permission for this to work, though - * the key need not be fully instantiated yet. For the UID to be changed, or - * for the GID to be changed to a group the caller is not a member of, the - * caller must have sysadmin capability. If either uid or gid is -1 then that - * attribute is not changed. - * - * If the UID is to be changed, the new user must have sufficient quota to - * accept the key. The quota deduction will be removed from the old user to - * the new user should the attribute be changed. - * - * If successful, 0 will be returned. - */ -long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) -{ - struct key_user *newowner, *zapowner = NULL; - struct key *key; - key_ref_t key_ref; - long ret; - - ret = 0; - if (uid == (uid_t) -1 && gid == (gid_t) -1) - goto error; - - key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_SETATTR); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error; - } - - key = key_ref_to_ptr(key_ref); - - /* make the changes with the locks held to prevent chown/chown races */ - ret = -EACCES; - down_write(&key->sem); - - if (!capable(CAP_SYS_ADMIN)) { - /* only the sysadmin can chown a key to some other UID */ - if (uid != (uid_t) -1 && key->uid != uid) - goto error_put; - - /* only the sysadmin can set the key's GID to a group other - * than one of those that the current process subscribes to */ - if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) - goto error_put; - } - - /* change the UID */ - if (uid != (uid_t) -1 && uid != key->uid) { - ret = -ENOMEM; - newowner = key_user_lookup(uid, current_user_ns()); - if (!newowner) - goto error_put; - - /* transfer the quota burden to the new user */ - if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { - unsigned maxkeys = (uid == 0) ? - key_quota_root_maxkeys : key_quota_maxkeys; - unsigned maxbytes = (uid == 0) ? - key_quota_root_maxbytes : key_quota_maxbytes; - - spin_lock(&newowner->lock); - if (newowner->qnkeys + 1 >= maxkeys || - newowner->qnbytes + key->quotalen >= maxbytes || - newowner->qnbytes + key->quotalen < - newowner->qnbytes) - goto quota_overrun; - - newowner->qnkeys++; - newowner->qnbytes += key->quotalen; - spin_unlock(&newowner->lock); - - spin_lock(&key->user->lock); - key->user->qnkeys--; - key->user->qnbytes -= key->quotalen; - spin_unlock(&key->user->lock); - } - - atomic_dec(&key->user->nkeys); - atomic_inc(&newowner->nkeys); - - if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { - atomic_dec(&key->user->nikeys); - atomic_inc(&newowner->nikeys); - } - - zapowner = key->user; - key->user = newowner; - key->uid = uid; - } - - /* change the GID */ - if (gid != (gid_t) -1) - key->gid = gid; - - ret = 0; - -error_put: - up_write(&key->sem); - key_put(key); - if (zapowner) - key_user_put(zapowner); -error: - return ret; - -quota_overrun: - spin_unlock(&newowner->lock); - zapowner = newowner; - ret = -EDQUOT; - goto error_put; -} - -/* - * Change the permission mask on a key. - * - * The key must grant the caller Setattr permission for this to work, though - * the key need not be fully instantiated yet. If the caller does not have - * sysadmin capability, it may only change the permission on keys that it owns. - */ -long keyctl_setperm_key(key_serial_t id, key_perm_t perm) -{ - struct key *key; - key_ref_t key_ref; - long ret; - - ret = -EINVAL; - if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) - goto error; - - key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_SETATTR); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error; - } - - key = key_ref_to_ptr(key_ref); - - /* make the changes with the locks held to prevent chown/chmod races */ - ret = -EACCES; - down_write(&key->sem); - - /* if we're not the sysadmin, we can only change a key that we own */ - if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) { - key->perm = perm; - ret = 0; - } - - up_write(&key->sem); - key_put(key); -error: - return ret; -} - -/* - * Get the destination keyring for instantiation and check that the caller has - * Write permission on it. - */ -static long get_instantiation_keyring(key_serial_t ringid, - struct request_key_auth *rka, - struct key **_dest_keyring) -{ - key_ref_t dkref; - - *_dest_keyring = NULL; - - /* just return a NULL pointer if we weren't asked to make a link */ - if (ringid == 0) - return 0; - - /* if a specific keyring is nominated by ID, then use that */ - if (ringid > 0) { - dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); - if (IS_ERR(dkref)) - return PTR_ERR(dkref); - *_dest_keyring = key_ref_to_ptr(dkref); - return 0; - } - - if (ringid == KEY_SPEC_REQKEY_AUTH_KEY) - return -EINVAL; - - /* otherwise specify the destination keyring recorded in the - * authorisation key (any KEY_SPEC_*_KEYRING) */ - if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) { - *_dest_keyring = key_get(rka->dest_keyring); - return 0; - } - - return -ENOKEY; -} - -/* - * Change the request_key authorisation key on the current process. - */ -static int keyctl_change_reqkey_auth(struct key *key) -{ - struct cred *new; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - key_put(new->request_key_auth); - new->request_key_auth = key_get(key); - - return commit_creds(new); -} - -/* - * Copy the iovec data from userspace - */ -static long copy_from_user_iovec(void *buffer, const struct iovec *iov, - unsigned ioc) -{ - for (; ioc > 0; ioc--) { - if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0) - return -EFAULT; - buffer += iov->iov_len; - iov++; - } - return 0; -} - -/* - * Instantiate a key with the specified payload and link the key into the - * destination keyring if one is given. - * - * The caller must have the appropriate instantiation permit set for this to - * work (see keyctl_assume_authority). No other permissions are required. - * - * If successful, 0 will be returned. - */ -long keyctl_instantiate_key_common(key_serial_t id, - const struct iovec *payload_iov, - unsigned ioc, - size_t plen, - key_serial_t ringid) -{ - const struct cred *cred = current_cred(); - struct request_key_auth *rka; - struct key *instkey, *dest_keyring; - void *payload; - long ret; - bool vm = false; - - kenter("%d,,%zu,%d", id, plen, ringid); - - ret = -EINVAL; - if (plen > 1024 * 1024 - 1) - goto error; - - /* the appropriate instantiation authorisation key must have been - * assumed before calling this */ - ret = -EPERM; - instkey = cred->request_key_auth; - if (!instkey) - goto error; - - rka = instkey->payload.data; - if (rka->target_key->serial != id) - goto error; - - /* pull the payload in if one was supplied */ - payload = NULL; - - if (payload_iov) { - ret = -ENOMEM; - payload = kmalloc(plen, GFP_KERNEL); - if (!payload) { - if (plen <= PAGE_SIZE) - goto error; - vm = true; - payload = vmalloc(plen); - if (!payload) - goto error; - } - - ret = copy_from_user_iovec(payload, payload_iov, ioc); - if (ret < 0) - goto error2; - } - - /* find the destination keyring amongst those belonging to the - * requesting task */ - ret = get_instantiation_keyring(ringid, rka, &dest_keyring); - if (ret < 0) - goto error2; - - /* instantiate the key and link it into a keyring */ - ret = key_instantiate_and_link(rka->target_key, payload, plen, - dest_keyring, instkey); - - key_put(dest_keyring); - - /* discard the assumed authority if it's just been disabled by - * instantiation of the key */ - if (ret == 0) - keyctl_change_reqkey_auth(NULL); - -error2: - if (!vm) - kfree(payload); - else - vfree(payload); -error: - return ret; -} - -/* - * Instantiate a key with the specified payload and link the key into the - * destination keyring if one is given. - * - * The caller must have the appropriate instantiation permit set for this to - * work (see keyctl_assume_authority). No other permissions are required. - * - * If successful, 0 will be returned. - */ -long keyctl_instantiate_key(key_serial_t id, - const void __user *_payload, - size_t plen, - key_serial_t ringid) -{ - if (_payload && plen) { - struct iovec iov[1] = { - [0].iov_base = (void __user *)_payload, - [0].iov_len = plen - }; - - return keyctl_instantiate_key_common(id, iov, 1, plen, ringid); - } - - return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); -} - -/* - * Instantiate a key with the specified multipart payload and link the key into - * the destination keyring if one is given. - * - * The caller must have the appropriate instantiation permit set for this to - * work (see keyctl_assume_authority). No other permissions are required. - * - * If successful, 0 will be returned. - */ -long keyctl_instantiate_key_iov(key_serial_t id, - const struct iovec __user *_payload_iov, - unsigned ioc, - key_serial_t ringid) -{ - struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; - long ret; - - if (_payload_iov == 0 || ioc == 0) - goto no_payload; - - ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, - ARRAY_SIZE(iovstack), iovstack, &iov, 1); - if (ret < 0) - return ret; - if (ret == 0) - goto no_payload_free; - - ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); - - if (iov != iovstack) - kfree(iov); - return ret; - -no_payload_free: - if (iov != iovstack) - kfree(iov); -no_payload: - return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid); -} - -/* - * Negatively instantiate the key with the given timeout (in seconds) and link - * the key into the destination keyring if one is given. - * - * The caller must have the appropriate instantiation permit set for this to - * work (see keyctl_assume_authority). No other permissions are required. - * - * 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 will be returned. - */ -long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) -{ - return keyctl_reject_key(id, timeout, ENOKEY, ringid); -} - -/* - * Negatively instantiate the key with the given timeout (in seconds) and error - * code and link the key into the destination keyring if one is given. - * - * The caller must have the appropriate instantiation permit set for this to - * work (see keyctl_assume_authority). No other permissions are required. - * - * 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 the specified error code until the negative key expires. - * - * If successful, 0 will be returned. - */ -long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error, - key_serial_t ringid) -{ - const struct cred *cred = current_cred(); - struct request_key_auth *rka; - struct key *instkey, *dest_keyring; - long ret; - - kenter("%d,%u,%u,%d", id, timeout, error, ringid); - - /* must be a valid error code and mustn't be a kernel special */ - if (error <= 0 || - error >= MAX_ERRNO || - error == ERESTARTSYS || - error == ERESTARTNOINTR || - error == ERESTARTNOHAND || - error == ERESTART_RESTARTBLOCK) - return -EINVAL; - - /* the appropriate instantiation authorisation key must have been - * assumed before calling this */ - ret = -EPERM; - instkey = cred->request_key_auth; - if (!instkey) - goto error; - - rka = instkey->payload.data; - if (rka->target_key->serial != id) - goto error; - - /* find the destination keyring if present (which must also be - * writable) */ - ret = get_instantiation_keyring(ringid, rka, &dest_keyring); - if (ret < 0) - goto error; - - /* instantiate the key and link it into a keyring */ - ret = key_reject_and_link(rka->target_key, timeout, error, - dest_keyring, instkey); - - key_put(dest_keyring); - - /* discard the assumed authority if it's just been disabled by - * instantiation of the key */ - if (ret == 0) - keyctl_change_reqkey_auth(NULL); - -error: - return ret; -} - -/* - * Read or set the default keyring in which request_key() will cache keys and - * return the old setting. - * - * If a process keyring is specified then this will be created if it doesn't - * yet exist. The old setting will be returned if successful. - */ -long keyctl_set_reqkey_keyring(int reqkey_defl) -{ - struct cred *new; - int ret, old_setting; - - old_setting = current_cred_xxx(jit_keyring); - - if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE) - return old_setting; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - switch (reqkey_defl) { - case KEY_REQKEY_DEFL_THREAD_KEYRING: - ret = install_thread_keyring_to_cred(new); - if (ret < 0) - goto error; - goto set; - - case KEY_REQKEY_DEFL_PROCESS_KEYRING: - ret = install_process_keyring_to_cred(new); - if (ret < 0) { - if (ret != -EEXIST) - goto error; - ret = 0; - } - goto set; - - case KEY_REQKEY_DEFL_DEFAULT: - case KEY_REQKEY_DEFL_SESSION_KEYRING: - case KEY_REQKEY_DEFL_USER_KEYRING: - case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: - case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: - goto set; - - case KEY_REQKEY_DEFL_NO_CHANGE: - case KEY_REQKEY_DEFL_GROUP_KEYRING: - default: - ret = -EINVAL; - goto error; - } - -set: - new->jit_keyring = reqkey_defl; - commit_creds(new); - return old_setting; -error: - abort_creds(new); - return ret; -} - -/* - * Set or clear the timeout on a key. - * - * Either the key must grant the caller Setattr permission or else the caller - * must hold an instantiation authorisation token for the key. - * - * The timeout is either 0 to clear the timeout, or a number of seconds from - * the current time. The key and any links to the key will be automatically - * garbage collected after the timeout expires. - * - * If successful, 0 is returned. - */ -long keyctl_set_timeout(key_serial_t id, unsigned timeout) -{ - struct key *key, *instkey; - key_ref_t key_ref; - long ret; - - key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_SETATTR); - if (IS_ERR(key_ref)) { - /* setting the timeout on a key under construction is permitted - * if we have the authorisation token handy */ - if (PTR_ERR(key_ref) == -EACCES) { - instkey = key_get_instantiation_authkey(id); - if (!IS_ERR(instkey)) { - key_put(instkey); - key_ref = lookup_user_key(id, - KEY_LOOKUP_PARTIAL, - 0); - if (!IS_ERR(key_ref)) - goto okay; - } - } - - ret = PTR_ERR(key_ref); - goto error; - } - -okay: - key = key_ref_to_ptr(key_ref); - key_set_timeout(key, timeout); - key_put(key); - - ret = 0; -error: - return ret; -} - -/* - * Assume (or clear) the authority to instantiate the specified key. - * - * This sets the authoritative token currently in force for key instantiation. - * This must be done for a key to be instantiated. It has the effect of making - * available all the keys from the caller of the request_key() that created a - * key to request_key() calls made by the caller of this function. - * - * The caller must have the instantiation key in their process keyrings with a - * Search permission grant available to the caller. - * - * If the ID given is 0, then the setting will be cleared and 0 returned. - * - * If the ID given has a matching an authorisation key, then that key will be - * set and its ID will be returned. The authorisation key can be read to get - * the callout information passed to request_key(). - */ -long keyctl_assume_authority(key_serial_t id) -{ - struct key *authkey; - long ret; - - /* special key IDs aren't permitted */ - ret = -EINVAL; - if (id < 0) - goto error; - - /* we divest ourselves of authority if given an ID of 0 */ - if (id == 0) { - ret = keyctl_change_reqkey_auth(NULL); - goto error; - } - - /* attempt to assume the authority temporarily granted to us whilst we - * instantiate the specified key - * - the authorisation key must be in the current task's keyrings - * somewhere - */ - authkey = key_get_instantiation_authkey(id); - if (IS_ERR(authkey)) { - ret = PTR_ERR(authkey); - goto error; - } - - ret = keyctl_change_reqkey_auth(authkey); - if (ret < 0) - goto error; - key_put(authkey); - - ret = authkey->serial; -error: - return ret; -} - -/* - * Get a key's the LSM security label. - * - * The key must grant the caller View permission for this to work. - * - * If there's a buffer, then up to buflen bytes of data will be placed into it. - * - * If successful, the amount of information available will be returned, - * irrespective of how much was copied (including the terminal NUL). - */ -long keyctl_get_security(key_serial_t keyid, - char __user *buffer, - size_t buflen) -{ - struct key *key, *instkey; - key_ref_t key_ref; - char *context; - long ret; - - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); - if (IS_ERR(key_ref)) { - if (PTR_ERR(key_ref) != -EACCES) - return PTR_ERR(key_ref); - - /* viewing a key under construction is also permitted if we - * have the authorisation token handy */ - instkey = key_get_instantiation_authkey(keyid); - if (IS_ERR(instkey)) - return PTR_ERR(instkey); - key_put(instkey); - - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); - if (IS_ERR(key_ref)) - return PTR_ERR(key_ref); - } - - key = key_ref_to_ptr(key_ref); - ret = security_key_getsecurity(key, &context); - if (ret == 0) { - /* if no information was returned, give userspace an empty - * string */ - ret = 1; - if (buffer && buflen > 0 && - copy_to_user(buffer, "", 1) != 0) - ret = -EFAULT; - } else if (ret > 0) { - /* return as much data as there's room for */ - if (buffer && buflen > 0) { - if (buflen > ret) - buflen = ret; - - if (copy_to_user(buffer, context, buflen) != 0) - ret = -EFAULT; - } - - kfree(context); - } - - key_ref_put(key_ref); - return ret; -} - -/* - * Attempt to install the calling process's session keyring on the process's - * parent process. - * - * The keyring must exist and must grant the caller LINK permission, and the - * parent process must be single-threaded and must have the same effective - * ownership as this process and mustn't be SUID/SGID. - * - * The keyring will be emplaced on the parent when it next resumes userspace. - * - * If successful, 0 will be returned. - */ -long keyctl_session_to_parent(void) -{ -#ifdef TIF_NOTIFY_RESUME - struct task_struct *me, *parent; - const struct cred *mycred, *pcred; - struct cred *cred, *oldcred; - key_ref_t keyring_r; - int ret; - - keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); - if (IS_ERR(keyring_r)) - return PTR_ERR(keyring_r); - - /* our parent is going to need a new cred struct, a new tgcred struct - * and new security data, so we allocate them here to prevent ENOMEM in - * our parent */ - ret = -ENOMEM; - cred = cred_alloc_blank(); - if (!cred) - goto error_keyring; - - cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); - keyring_r = NULL; - - me = current; - rcu_read_lock(); - write_lock_irq(&tasklist_lock); - - parent = me->real_parent; - ret = -EPERM; - - /* the parent mustn't be init and mustn't be a kernel thread */ - if (parent->pid <= 1 || !parent->mm) - goto not_permitted; - - /* the parent must be single threaded */ - if (!thread_group_empty(parent)) - goto not_permitted; - - /* the parent and the child must have different session keyrings or - * there's no point */ - mycred = current_cred(); - pcred = __task_cred(parent); - if (mycred == pcred || - mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) - goto already_same; - - /* the parent must have the same effective ownership and mustn't be - * SUID/SGID */ - if (pcred->uid != mycred->euid || - pcred->euid != mycred->euid || - pcred->suid != mycred->euid || - pcred->gid != mycred->egid || - pcred->egid != mycred->egid || - pcred->sgid != mycred->egid) - goto not_permitted; - - /* the keyrings must have the same UID */ - if ((pcred->tgcred->session_keyring && - pcred->tgcred->session_keyring->uid != mycred->euid) || - mycred->tgcred->session_keyring->uid != mycred->euid) - goto not_permitted; - - /* if there's an already pending keyring replacement, then we replace - * that */ - oldcred = parent->replacement_session_keyring; - - /* the replacement session keyring is applied just prior to userspace - * restarting */ - parent->replacement_session_keyring = cred; - cred = NULL; - set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); - - write_unlock_irq(&tasklist_lock); - rcu_read_unlock(); - if (oldcred) - put_cred(oldcred); - return 0; - -already_same: - ret = 0; -not_permitted: - write_unlock_irq(&tasklist_lock); - rcu_read_unlock(); - put_cred(cred); - return ret; - -error_keyring: - key_ref_put(keyring_r); - return ret; - -#else /* !TIF_NOTIFY_RESUME */ - /* - * To be removed when TIF_NOTIFY_RESUME has been implemented on - * m68k/xtensa - */ -#warning TIF_NOTIFY_RESUME not implemented - return -EOPNOTSUPP; -#endif /* !TIF_NOTIFY_RESUME */ -} - -/* - * The key control system call - */ -SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, - unsigned long, arg4, unsigned long, arg5) -{ - switch (option) { - case KEYCTL_GET_KEYRING_ID: - return keyctl_get_keyring_ID((key_serial_t) arg2, - (int) arg3); - - case KEYCTL_JOIN_SESSION_KEYRING: - return keyctl_join_session_keyring((const char __user *) arg2); - - case KEYCTL_UPDATE: - return keyctl_update_key((key_serial_t) arg2, - (const void __user *) arg3, - (size_t) arg4); - - case KEYCTL_REVOKE: - return keyctl_revoke_key((key_serial_t) arg2); - - case KEYCTL_DESCRIBE: - return keyctl_describe_key((key_serial_t) arg2, - (char __user *) arg3, - (unsigned) arg4); - - case KEYCTL_CLEAR: - return keyctl_keyring_clear((key_serial_t) arg2); - - case KEYCTL_LINK: - return keyctl_keyring_link((key_serial_t) arg2, - (key_serial_t) arg3); - - case KEYCTL_UNLINK: - return keyctl_keyring_unlink((key_serial_t) arg2, - (key_serial_t) arg3); - - case KEYCTL_SEARCH: - return keyctl_keyring_search((key_serial_t) arg2, - (const char __user *) arg3, - (const char __user *) arg4, - (key_serial_t) arg5); - - case KEYCTL_READ: - return keyctl_read_key((key_serial_t) arg2, - (char __user *) arg3, - (size_t) arg4); - - case KEYCTL_CHOWN: - return keyctl_chown_key((key_serial_t) arg2, - (uid_t) arg3, - (gid_t) arg4); - - case KEYCTL_SETPERM: - return keyctl_setperm_key((key_serial_t) arg2, - (key_perm_t) arg3); - - case KEYCTL_INSTANTIATE: - return keyctl_instantiate_key((key_serial_t) arg2, - (const void __user *) arg3, - (size_t) arg4, - (key_serial_t) arg5); - - case KEYCTL_NEGATE: - return keyctl_negate_key((key_serial_t) arg2, - (unsigned) arg3, - (key_serial_t) arg4); - - case KEYCTL_SET_REQKEY_KEYRING: - return keyctl_set_reqkey_keyring(arg2); - - case KEYCTL_SET_TIMEOUT: - return keyctl_set_timeout((key_serial_t) arg2, - (unsigned) arg3); - - case KEYCTL_ASSUME_AUTHORITY: - return keyctl_assume_authority((key_serial_t) arg2); - - case KEYCTL_GET_SECURITY: - return keyctl_get_security((key_serial_t) arg2, - (char __user *) arg3, - (size_t) arg4); - - case KEYCTL_SESSION_TO_PARENT: - return keyctl_session_to_parent(); - - case KEYCTL_REJECT: - return keyctl_reject_key((key_serial_t) arg2, - (unsigned) arg3, - (unsigned) arg4, - (key_serial_t) arg5); - - case KEYCTL_INSTANTIATE_IOV: - return keyctl_instantiate_key_iov( - (key_serial_t) arg2, - (const struct iovec __user *) arg3, - (unsigned) arg4, - (key_serial_t) arg5); - - default: - return -EOPNOTSUPP; - } -} diff --git a/ANDROID_3.4.5/security/keys/keyring.c b/ANDROID_3.4.5/security/keys/keyring.c deleted file mode 100644 index d605f752..00000000 --- a/ANDROID_3.4.5/security/keys/keyring.c +++ /dev/null @@ -1,1232 +0,0 @@ -/* 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 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. - */ -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_check(keyring->payload.subscriptions, - atomic_read(&keyring->usage) == 0); - if (klist) { - for (loop = klist->nkeys - 1; loop >= 0; loop--) - key_put(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 = 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; -} - -/* - * 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 { - 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_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || - (keyring->expiry && now.tv_sec >= keyring->expiry)) - goto error_2; - - /* 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 */ - nkeys = keylist->nkeys; - smp_rmb(); - for (kix = 0; kix < nkeys; kix++) { - key = keylist->keys[kix]; - kflags = key->flags; - - /* ignore keys not of this type */ - if (key->type != type) - continue; - - /* skip revoked keys and expired keys */ - if (!no_state_check) { - if (kflags & (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 = 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].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; -} - -/** - * keyring_search - Search the supplied keyring tree for a matching key - * @keyring: The root of the keyring tree to be searched. - * @type: The type of keyring we want to find. - * @description: The name of the keyring we want to find. - * - * As keyring_search_aux() above, but using the current task's credentials and - * type's default matching function. - */ -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->cred, - type, description, type->match, false); -} -EXPORT_SYMBOL(keyring_search); - -/* - * Search the given keyring only (no recursion). - * - * The caller must guarantee that the keyring is a keyring and that the - * permission is granted to search the keyring as no check is made here. - * - * RCU is used to make it unnecessary to lock the keyring key list here. - * - * Returns a pointer to the found key with usage count incremented if - * successful and returns -ENOKEY if not found. Revoked keys and keys not - * providing the requested permission are skipped over. - * - * If successful, the possession indicator is propagated from the keyring ref - * to the returned key reference. - */ -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 nkeys, 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) { - nkeys = klist->nkeys; - smp_rmb(); - for (loop = 0; loop < 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); -} - -/* - * Find a keyring with the specified name. - * - * All named keyrings in the current user namespace are searched, provided they - * grant Search permission directly to the caller (unless this check is - * skipped). Keyrings whose usage points have reached zero or who have been - * revoked are skipped. - * - * Returns a pointer to the keyring with the keyring's refcount having being - * incremented on success. -ENOKEY is returned if a key could not be found. - */ -struct key *find_keyring_by_name(const char *name, bool skip_perm_check) -{ - struct key *keyring; - int bucket; - - if (!name) - return ERR_PTR(-EINVAL); - - bucket = keyring_hash(name); - - read_lock(&keyring_name_lock); - - if (keyring_name_hash[bucket].next) { - /* search this hash bucket for a keyring with a matching name - * that's readable and that hasn't been revoked */ - list_for_each_entry(keyring, - &keyring_name_hash[bucket], - type_data.link - ) { - if (keyring->user->user_ns != current_user_ns()) - continue; - - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) - continue; - - if (strcmp(keyring->description, name) != 0) - continue; - - if (!skip_perm_check && - key_permission(make_key_ref(keyring, 0), - KEY_SEARCH) < 0) - continue; - - /* we've got a match but we might end up racing with - * key_cleanup() if the keyring is currently 'dead' - * (ie. it has a zero usage count) */ - if (!atomic_inc_not_zero(&keyring->usage)) - continue; - goto out; - } - } - - keyring = ERR_PTR(-ENOKEY); -out: - read_unlock(&keyring_name_lock); - return keyring; -} - -/* - * See if a cycle will will be created by inserting acyclic tree B in acyclic - * tree A at the topmost level (ie: as a direct child of A). - * - * Since we are adding B to A at the top level, checking for cycles should just - * be a matter of seeing if node A is somewhere in tree B. - */ -static int keyring_detect_cycle(struct key *A, struct key *B) -{ - struct { - struct keyring_list *keylist; - int kix; - } stack[KEYRING_SEARCH_MAX_DEPTH]; - - struct keyring_list *keylist; - struct key *subtree, *key; - int sp, nkeys, kix, ret; - - rcu_read_lock(); - - ret = -EDEADLK; - if (A == B) - goto cycle_detected; - - subtree = B; - sp = 0; - - /* start processing a new keyring */ -descend: - if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) - goto not_this_keyring; - - keylist = rcu_dereference(subtree->payload.subscriptions); - if (!keylist) - goto not_this_keyring; - kix = 0; - -ascend: - /* iterate through the remaining keys in this keyring */ - nkeys = keylist->nkeys; - smp_rmb(); - for (; kix < nkeys; kix++) { - key = keylist->keys[kix]; - - if (key == A) - goto cycle_detected; - - /* recursively check nested keyrings */ - if (key->type == &key_type_keyring) { - if (sp >= KEYRING_SEARCH_MAX_DEPTH) - goto too_deep; - - /* stack the current position */ - stack[sp].keylist = keylist; - stack[sp].kix = kix; - sp++; - - /* begin again with the new keyring */ - subtree = 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 checking of a keyring higher up in the tree */ - sp--; - keylist = stack[sp].keylist; - kix = stack[sp].kix + 1; - goto ascend; - } - - ret = 0; /* no cycles detected */ - -error: - rcu_read_unlock(); - return ret; - -too_deep: - ret = -ELOOP; - goto error; - -cycle_detected: - ret = -EDEADLK; - goto error; -} - -/* - * Dispose of a keyring list after the RCU grace period, freeing the unlinked - * key - */ -static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) -{ - struct keyring_list *klist = - container_of(rcu, struct keyring_list, rcu); - - if (klist->delkey != USHRT_MAX) - key_put(klist->keys[klist->delkey]); - kfree(klist); -} - -/* - * Preallocate memory so that a key can be linked into to a keyring. - */ -int __key_link_begin(struct key *keyring, const struct key_type *type, - const char *description, unsigned long *_prealloc) - __acquires(&keyring->sem) -{ - struct keyring_list *klist, *nklist; - unsigned long prealloc; - unsigned max; - size_t size; - int loop, ret; - - kenter("%d,%s,%s,", key_serial(keyring), type->name, description); - - if (keyring->type != &key_type_keyring) - return -ENOTDIR; - - down_write(&keyring->sem); - - ret = -EKEYREVOKED; - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) - goto error_krsem; - - /* serialise link/link calls to prevent parallel calls causing a cycle - * when linking two keyring in opposite orders */ - if (type == &key_type_keyring) - down_write(&keyring_serialise_link_sem); - - klist = rcu_dereference_locked_keyring(keyring); - - /* see if there's a matching key we can displace */ - if (klist && klist->nkeys > 0) { - for (loop = klist->nkeys - 1; loop >= 0; loop--) { - if (klist->keys[loop]->type == type && - strcmp(klist->keys[loop]->description, - description) == 0 - ) { - /* found a match - we'll replace this one with - * the new key */ - size = sizeof(struct key *) * klist->maxkeys; - size += sizeof(*klist); - BUG_ON(size > PAGE_SIZE); - - ret = -ENOMEM; - nklist = kmemdup(klist, size, GFP_KERNEL); - if (!nklist) - goto error_sem; - - /* note replacement slot */ - klist->delkey = nklist->delkey = loop; - prealloc = (unsigned long)nklist; - goto done; - } - } - } - - /* check that we aren't going to overrun the user's quota */ - ret = key_payload_reserve(keyring, - keyring->datalen + KEYQUOTA_LINK_BYTES); - if (ret < 0) - goto error_sem; - - if (klist && klist->nkeys < klist->maxkeys) { - /* there's sufficient slack space to append directly */ - nklist = NULL; - prealloc = KEY_LINK_FIXQUOTA; - } else { - /* grow the key list */ - max = 4; - if (klist) - max += klist->maxkeys; - - ret = -ENFILE; - if (max > USHRT_MAX - 1) - goto error_quota; - size = sizeof(*klist) + sizeof(struct key *) * max; - if (size > PAGE_SIZE) - goto error_quota; - - ret = -ENOMEM; - nklist = kmalloc(size, GFP_KERNEL); - if (!nklist) - goto error_quota; - - nklist->maxkeys = max; - if (klist) { - memcpy(nklist->keys, klist->keys, - sizeof(struct key *) * klist->nkeys); - nklist->delkey = klist->nkeys; - nklist->nkeys = klist->nkeys + 1; - klist->delkey = USHRT_MAX; - } else { - nklist->nkeys = 1; - nklist->delkey = 0; - } - - /* add the key into the new space */ - nklist->keys[nklist->delkey] = NULL; - } - - prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; -done: - *_prealloc = prealloc; - kleave(" = 0"); - return 0; - -error_quota: - /* undo the quota changes */ - key_payload_reserve(keyring, - keyring->datalen - KEYQUOTA_LINK_BYTES); -error_sem: - if (type == &key_type_keyring) - up_write(&keyring_serialise_link_sem); -error_krsem: - up_write(&keyring->sem); - kleave(" = %d", ret); - return ret; -} - -/* - * Check already instantiated keys aren't going to be a problem. - * - * The caller must have called __key_link_begin(). Don't need to call this for - * keys that were created since __key_link_begin() was called. - */ -int __key_link_check_live_key(struct key *keyring, struct key *key) -{ - if (key->type == &key_type_keyring) - /* check that we aren't going to create a cycle by linking one - * keyring to another */ - return keyring_detect_cycle(keyring, key); - return 0; -} - -/* - * Link a key into to a keyring. - * - * Must be called with __key_link_begin() having being called. Discards any - * already extant link to matching key if there is one, so that each keyring - * holds at most one link to any given key of a particular type+description - * combination. - */ -void __key_link(struct key *keyring, struct key *key, - unsigned long *_prealloc) -{ - struct keyring_list *klist, *nklist; - - nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); - *_prealloc = 0; - - kenter("%d,%d,%p", keyring->serial, key->serial, nklist); - - klist = rcu_dereference_locked_keyring(keyring); - - atomic_inc(&key->usage); - - /* there's a matching key we can displace or an empty slot in a newly - * allocated list we can fill */ - if (nklist) { - kdebug("replace %hu/%hu/%hu", - nklist->delkey, nklist->nkeys, nklist->maxkeys); - - nklist->keys[nklist->delkey] = key; - - rcu_assign_pointer(keyring->payload.subscriptions, nklist); - - /* dispose of the old keyring list and, if there was one, the - * displaced key */ - if (klist) { - kdebug("dispose %hu/%hu/%hu", - klist->delkey, klist->nkeys, klist->maxkeys); - call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); - } - } else { - /* there's sufficient slack space to append directly */ - klist->keys[klist->nkeys] = key; - smp_wmb(); - klist->nkeys++; - } -} - -/* - * Finish linking a key into to a keyring. - * - * Must be called with __key_link_begin() having being called. - */ -void __key_link_end(struct key *keyring, struct key_type *type, - unsigned long prealloc) - __releases(&keyring->sem) -{ - BUG_ON(type == NULL); - BUG_ON(type->name == NULL); - kenter("%d,%s,%lx", keyring->serial, type->name, prealloc); - - if (type == &key_type_keyring) - up_write(&keyring_serialise_link_sem); - - if (prealloc) { - if (prealloc & KEY_LINK_FIXQUOTA) - key_payload_reserve(keyring, - keyring->datalen - - KEYQUOTA_LINK_BYTES); - kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA)); - } - up_write(&keyring->sem); -} - -/** - * key_link - Link a key to a keyring - * @keyring: The keyring to make the link in. - * @key: The key to link to. - * - * Make a link in a keyring to a key, such that the keyring holds a reference - * on that key and the key can potentially be found by searching that keyring. - * - * This function will write-lock the keyring's semaphore and will consume some - * of the user's key data quota to hold the link. - * - * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, - * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is - * full, -EDQUOT if there is insufficient key data quota remaining to add - * another link or -ENOMEM if there's insufficient memory. - * - * It is assumed that the caller has checked that it is permitted for a link to - * be made (the keyring should have Write permission and the key Link - * permission). - */ -int key_link(struct key *keyring, struct key *key) -{ - unsigned long prealloc; - int ret; - - key_check(keyring); - key_check(key); - - ret = __key_link_begin(keyring, key->type, key->description, &prealloc); - if (ret == 0) { - ret = __key_link_check_live_key(keyring, key); - if (ret == 0) - __key_link(keyring, key, &prealloc); - __key_link_end(keyring, key->type, prealloc); - } - - return ret; -} -EXPORT_SYMBOL(key_link); - -/** - * key_unlink - Unlink the first link to a key from a keyring. - * @keyring: The keyring to remove the link from. - * @key: The key the link is to. - * - * Remove a link from a keyring to a key. - * - * This function will write-lock the keyring's semaphore. - * - * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if - * the key isn't linked to by the keyring or -ENOMEM if there's insufficient - * memory. - * - * It is assumed that the caller has checked that it is permitted for a link to - * be removed (the keyring should have Write permission; no permissions are - * required on the key). - */ -int key_unlink(struct key *keyring, struct key *key) -{ - struct keyring_list *klist, *nklist; - int loop, ret; - - key_check(keyring); - key_check(key); - - ret = -ENOTDIR; - if (keyring->type != &key_type_keyring) - goto error; - - down_write(&keyring->sem); - - klist = rcu_dereference_locked_keyring(keyring); - if (klist) { - /* search the keyring for the key */ - for (loop = 0; loop < klist->nkeys; loop++) - if (klist->keys[loop] == key) - goto key_is_present; - } - - up_write(&keyring->sem); - ret = -ENOENT; - goto error; - -key_is_present: - /* we need to copy the key list for RCU purposes */ - nklist = kmalloc(sizeof(*klist) + - sizeof(struct key *) * klist->maxkeys, - GFP_KERNEL); - if (!nklist) - goto nomem; - nklist->maxkeys = klist->maxkeys; - nklist->nkeys = klist->nkeys - 1; - - if (loop > 0) - memcpy(&nklist->keys[0], - &klist->keys[0], - loop * sizeof(struct key *)); - - if (loop < nklist->nkeys) - memcpy(&nklist->keys[loop], - &klist->keys[loop + 1], - (nklist->nkeys - loop) * sizeof(struct key *)); - - /* adjust the user's quota */ - key_payload_reserve(keyring, - keyring->datalen - KEYQUOTA_LINK_BYTES); - - rcu_assign_pointer(keyring->payload.subscriptions, nklist); - - up_write(&keyring->sem); - - /* schedule for later cleanup */ - klist->delkey = loop; - call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); - - ret = 0; - -error: - return ret; -nomem: - ret = -ENOMEM; - up_write(&keyring->sem); - goto error; -} -EXPORT_SYMBOL(key_unlink); - -/* - * Dispose of a keyring list after the RCU grace period, releasing the keys it - * links to. - */ -static void keyring_clear_rcu_disposal(struct rcu_head *rcu) -{ - struct keyring_list *klist; - int loop; - - klist = container_of(rcu, struct keyring_list, rcu); - - for (loop = klist->nkeys - 1; loop >= 0; loop--) - key_put(klist->keys[loop]); - - kfree(klist); -} - -/** - * keyring_clear - Clear a keyring - * @keyring: The keyring to clear. - * - * Clear the contents of the specified keyring. - * - * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring. - */ -int keyring_clear(struct key *keyring) -{ - struct keyring_list *klist; - int ret; - - ret = -ENOTDIR; - if (keyring->type == &key_type_keyring) { - /* detach the pointer block with the locks held */ - down_write(&keyring->sem); - - klist = rcu_dereference_locked_keyring(keyring); - if (klist) { - /* adjust the quota */ - key_payload_reserve(keyring, - sizeof(struct keyring_list)); - - rcu_assign_pointer(keyring->payload.subscriptions, - NULL); - } - - up_write(&keyring->sem); - - /* free the keys after the locks have been dropped */ - if (klist) - call_rcu(&klist->rcu, keyring_clear_rcu_disposal); - - ret = 0; - } - - return ret; -} -EXPORT_SYMBOL(keyring_clear); - -/* - * Dispose of the links from a revoked keyring. - * - * This is called with the key sem write-locked. - */ -static void keyring_revoke(struct key *keyring) -{ - struct keyring_list *klist; - - klist = rcu_dereference_locked_keyring(keyring); - - /* adjust the quota */ - key_payload_reserve(keyring, 0); - - if (klist) { - rcu_assign_pointer(keyring->payload.subscriptions, NULL); - call_rcu(&klist->rcu, keyring_clear_rcu_disposal); - } -} - -/* - * Determine whether a key is dead. - */ -static bool key_is_dead(struct key *key, time_t limit) -{ - return test_bit(KEY_FLAG_DEAD, &key->flags) || - (key->expiry > 0 && key->expiry <= limit); -} - -/* - * Collect garbage from the contents of a keyring, replacing the old list with - * a new one with the pointers all shuffled down. - * - * Dead keys are classed as oned that are flagged as being dead or are revoked, - * expired or negative keys that were revoked or expired before the specified - * limit. - */ -void keyring_gc(struct key *keyring, time_t limit) -{ - struct keyring_list *klist, *new; - struct key *key; - int loop, keep, max; - - kenter("{%x,%s}", key_serial(keyring), keyring->description); - - down_write(&keyring->sem); - - klist = rcu_dereference_locked_keyring(keyring); - if (!klist) - goto no_klist; - - /* work out how many subscriptions we're keeping */ - keep = 0; - for (loop = klist->nkeys - 1; loop >= 0; loop--) - if (!key_is_dead(klist->keys[loop], limit)) - keep++; - - if (keep == klist->nkeys) - goto just_return; - - /* allocate a new keyring payload */ - max = roundup(keep, 4); - new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), - GFP_KERNEL); - if (!new) - goto nomem; - new->maxkeys = max; - new->nkeys = 0; - new->delkey = 0; - - /* install the live keys - * - must take care as expired keys may be updated back to life - */ - keep = 0; - for (loop = klist->nkeys - 1; loop >= 0; loop--) { - key = klist->keys[loop]; - if (!key_is_dead(key, limit)) { - if (keep >= max) - goto discard_new; - new->keys[keep++] = key_get(key); - } - } - new->nkeys = keep; - - /* adjust the quota */ - key_payload_reserve(keyring, - sizeof(struct keyring_list) + - KEYQUOTA_LINK_BYTES * keep); - - if (keep == 0) { - rcu_assign_pointer(keyring->payload.subscriptions, NULL); - kfree(new); - } else { - rcu_assign_pointer(keyring->payload.subscriptions, new); - } - - up_write(&keyring->sem); - - call_rcu(&klist->rcu, keyring_clear_rcu_disposal); - kleave(" [yes]"); - return; - -discard_new: - new->nkeys = keep; - keyring_clear_rcu_disposal(&new->rcu); - up_write(&keyring->sem); - kleave(" [discard]"); - return; - -just_return: - up_write(&keyring->sem); - kleave(" [no dead]"); - return; - -no_klist: - up_write(&keyring->sem); - kleave(" [no_klist]"); - return; - -nomem: - up_write(&keyring->sem); - kleave(" [oom]"); -} diff --git a/ANDROID_3.4.5/security/keys/permission.c b/ANDROID_3.4.5/security/keys/permission.c deleted file mode 100644 index c35b5229..00000000 --- a/ANDROID_3.4.5/security/keys/permission.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Key permission checking - * - * Copyright (C) 2005 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/security.h> -#include "internal.h" - -/** - * key_task_permission - Check a key can be used - * @key_ref: The key to check. - * @cred: The credentials to use. - * @perm: The permissions to check for. - * - * Check to see whether permission is granted to use a key in the desired way, - * but permit the security modules to override. - * - * The caller must hold either a ref on cred or must hold the RCU readlock. - * - * Returns 0 if successful, -EACCES if access is denied based on the - * permissions bits or the LSM check. - */ -int key_task_permission(const key_ref_t key_ref, const struct cred *cred, - key_perm_t perm) -{ - struct key *key; - key_perm_t kperm; - int ret; - - key = key_ref_to_ptr(key_ref); - - if (key->user->user_ns != cred->user->user_ns) - goto use_other_perms; - - /* use the second 8-bits of permissions for keys the caller owns */ - if (key->uid == cred->fsuid) { - kperm = key->perm >> 16; - goto use_these_perms; - } - - /* use the third 8-bits of permissions for keys the caller has a group - * membership in common with */ - if (key->gid != -1 && key->perm & KEY_GRP_ALL) { - if (key->gid == cred->fsgid) { - kperm = key->perm >> 8; - goto use_these_perms; - } - - ret = groups_search(cred->group_info, key->gid); - if (ret) { - kperm = key->perm >> 8; - goto use_these_perms; - } - } - -use_other_perms: - - /* otherwise use the least-significant 8-bits */ - kperm = key->perm; - -use_these_perms: - - /* use the top 8-bits of permissions for keys the caller possesses - * - possessor permissions are additive with other permissions - */ - if (is_key_possessed(key_ref)) - kperm |= key->perm >> 24; - - kperm = kperm & perm & KEY_ALL; - - if (kperm != perm) - return -EACCES; - - /* let LSM be the final arbiter */ - return security_key_permission(key_ref, cred, perm); -} -EXPORT_SYMBOL(key_task_permission); - -/** - * key_validate - Validate a key. - * @key: The key to be validated. - * - * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if - * the key's type has been removed or if the key has been revoked or - * -EKEYEXPIRED if the key has expired. - */ -int key_validate(struct key *key) -{ - struct timespec now; - int ret = 0; - - if (key) { - /* check it's still accessible */ - ret = -EKEYREVOKED; - if (test_bit(KEY_FLAG_REVOKED, &key->flags) || - test_bit(KEY_FLAG_DEAD, &key->flags)) - goto error; - - /* check it hasn't expired */ - ret = 0; - if (key->expiry) { - now = current_kernel_time(); - if (now.tv_sec >= key->expiry) - ret = -EKEYEXPIRED; - } - } - -error: - return ret; -} -EXPORT_SYMBOL(key_validate); diff --git a/ANDROID_3.4.5/security/keys/proc.c b/ANDROID_3.4.5/security/keys/proc.c deleted file mode 100644 index 49bbc979..00000000 --- a/ANDROID_3.4.5/security/keys/proc.c +++ /dev/null @@ -1,352 +0,0 @@ -/* procfs files for key database enumeration - * - * Copyright (C) 2004 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/fs.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <asm/errno.h> -#include "internal.h" - -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS -static int proc_keys_open(struct inode *inode, struct file *file); -static void *proc_keys_start(struct seq_file *p, loff_t *_pos); -static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); -static void proc_keys_stop(struct seq_file *p, void *v); -static int proc_keys_show(struct seq_file *m, void *v); - -static const struct seq_operations proc_keys_ops = { - .start = proc_keys_start, - .next = proc_keys_next, - .stop = proc_keys_stop, - .show = proc_keys_show, -}; - -static const struct file_operations proc_keys_fops = { - .open = proc_keys_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif - -static int proc_key_users_open(struct inode *inode, struct file *file); -static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); -static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos); -static void proc_key_users_stop(struct seq_file *p, void *v); -static int proc_key_users_show(struct seq_file *m, void *v); - -static const struct seq_operations proc_key_users_ops = { - .start = proc_key_users_start, - .next = proc_key_users_next, - .stop = proc_key_users_stop, - .show = proc_key_users_show, -}; - -static const struct file_operations proc_key_users_fops = { - .open = proc_key_users_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * Declare the /proc files. - */ -static int __init key_proc_init(void) -{ - struct proc_dir_entry *p; - -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS - p = proc_create("keys", 0, NULL, &proc_keys_fops); - if (!p) - panic("Cannot create /proc/keys\n"); -#endif - - p = proc_create("key-users", 0, NULL, &proc_key_users_fops); - if (!p) - panic("Cannot create /proc/key-users\n"); - - return 0; -} - -__initcall(key_proc_init); - -/* - * Implement "/proc/keys" to provide a list of the keys on the system that - * grant View permission to the caller. - */ -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS - -static struct rb_node *key_serial_next(struct rb_node *n) -{ - struct user_namespace *user_ns = current_user_ns(); - - n = rb_next(n); - while (n) { - struct key *key = rb_entry(n, struct key, serial_node); - if (key->user->user_ns == user_ns) - break; - n = rb_next(n); - } - return n; -} - -static int proc_keys_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_keys_ops); -} - -static struct key *find_ge_key(key_serial_t id) -{ - struct user_namespace *user_ns = current_user_ns(); - struct rb_node *n = key_serial_tree.rb_node; - struct key *minkey = NULL; - - while (n) { - struct key *key = rb_entry(n, struct key, serial_node); - if (id < key->serial) { - if (!minkey || minkey->serial > key->serial) - minkey = key; - n = n->rb_left; - } else if (id > key->serial) { - n = n->rb_right; - } else { - minkey = key; - break; - } - key = NULL; - } - - if (!minkey) - return NULL; - - for (;;) { - if (minkey->user->user_ns == user_ns) - return minkey; - n = rb_next(&minkey->serial_node); - if (!n) - return NULL; - minkey = rb_entry(n, struct key, serial_node); - } -} - -static void *proc_keys_start(struct seq_file *p, loff_t *_pos) - __acquires(key_serial_lock) -{ - key_serial_t pos = *_pos; - struct key *key; - - spin_lock(&key_serial_lock); - - if (*_pos > INT_MAX) - return NULL; - key = find_ge_key(pos); - if (!key) - return NULL; - *_pos = key->serial; - return &key->serial_node; -} - -static inline key_serial_t key_node_serial(struct rb_node *n) -{ - struct key *key = rb_entry(n, struct key, serial_node); - return key->serial; -} - -static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) -{ - struct rb_node *n; - - n = key_serial_next(v); - if (n) - *_pos = key_node_serial(n); - return n; -} - -static void proc_keys_stop(struct seq_file *p, void *v) - __releases(key_serial_lock) -{ - spin_unlock(&key_serial_lock); -} - -static int proc_keys_show(struct seq_file *m, void *v) -{ - const struct cred *cred = current_cred(); - struct rb_node *_p = v; - struct key *key = rb_entry(_p, struct key, serial_node); - struct timespec now; - unsigned long timo; - key_ref_t key_ref, skey_ref; - char xbuf[12]; - int rc; - - key_ref = make_key_ref(key, 0); - - /* determine if the key is possessed by this process (a test we can - * skip if the key does not indicate the possessor can view it - */ - if (key->perm & KEY_POS_VIEW) { - skey_ref = search_my_process_keyrings(key->type, key, - lookup_user_key_possessed, - true, cred); - if (!IS_ERR(skey_ref)) { - key_ref_put(skey_ref); - key_ref = make_key_ref(key, 1); - } - } - - /* check whether the current task is allowed to view the key (assuming - * non-possession) - * - the caller holds a spinlock, and thus the RCU read lock, making our - * access to __current_cred() safe - */ - rc = key_task_permission(key_ref, cred, KEY_VIEW); - if (rc < 0) - return 0; - - now = current_kernel_time(); - - rcu_read_lock(); - - /* come up with a suitable timeout value */ - if (key->expiry == 0) { - memcpy(xbuf, "perm", 5); - } else if (now.tv_sec >= key->expiry) { - memcpy(xbuf, "expd", 5); - } else { - timo = key->expiry - now.tv_sec; - - if (timo < 60) - sprintf(xbuf, "%lus", timo); - else if (timo < 60*60) - sprintf(xbuf, "%lum", timo / 60); - else if (timo < 60*60*24) - sprintf(xbuf, "%luh", timo / (60*60)); - else if (timo < 60*60*24*7) - sprintf(xbuf, "%lud", timo / (60*60*24)); - else - sprintf(xbuf, "%luw", timo / (60*60*24*7)); - } - -#define showflag(KEY, LETTER, FLAG) \ - (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') - - seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", - key->serial, - showflag(key, 'I', KEY_FLAG_INSTANTIATED), - showflag(key, 'R', KEY_FLAG_REVOKED), - showflag(key, 'D', KEY_FLAG_DEAD), - showflag(key, 'Q', KEY_FLAG_IN_QUOTA), - showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), - showflag(key, 'N', KEY_FLAG_NEGATIVE), - atomic_read(&key->usage), - xbuf, - key->perm, - key->uid, - key->gid, - key->type->name); - -#undef showflag - - if (key->type->describe) - key->type->describe(key, m); - seq_putc(m, '\n'); - - rcu_read_unlock(); - return 0; -} - -#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ - -static struct rb_node *__key_user_next(struct rb_node *n) -{ - while (n) { - struct key_user *user = rb_entry(n, struct key_user, node); - if (user->user_ns == current_user_ns()) - break; - n = rb_next(n); - } - return n; -} - -static struct rb_node *key_user_next(struct rb_node *n) -{ - return __key_user_next(rb_next(n)); -} - -static struct rb_node *key_user_first(struct rb_root *r) -{ - struct rb_node *n = rb_first(r); - return __key_user_next(n); -} - -/* - * Implement "/proc/key-users" to provides a list of the key users and their - * quotas. - */ -static int proc_key_users_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_key_users_ops); -} - -static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) - __acquires(key_user_lock) -{ - struct rb_node *_p; - loff_t pos = *_pos; - - spin_lock(&key_user_lock); - - _p = key_user_first(&key_user_tree); - while (pos > 0 && _p) { - pos--; - _p = key_user_next(_p); - } - - return _p; -} - -static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) -{ - (*_pos)++; - return key_user_next((struct rb_node *)v); -} - -static void proc_key_users_stop(struct seq_file *p, void *v) - __releases(key_user_lock) -{ - spin_unlock(&key_user_lock); -} - -static int proc_key_users_show(struct seq_file *m, void *v) -{ - struct rb_node *_p = v; - struct key_user *user = rb_entry(_p, struct key_user, node); - unsigned maxkeys = (user->uid == 0) ? - key_quota_root_maxkeys : key_quota_maxkeys; - unsigned maxbytes = (user->uid == 0) ? - key_quota_root_maxbytes : key_quota_maxbytes; - - seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", - user->uid, - atomic_read(&user->usage), - atomic_read(&user->nkeys), - atomic_read(&user->nikeys), - user->qnkeys, - maxkeys, - user->qnbytes, - maxbytes); - - return 0; -} diff --git a/ANDROID_3.4.5/security/keys/process_keys.c b/ANDROID_3.4.5/security/keys/process_keys.c deleted file mode 100644 index be7ecb20..00000000 --- a/ANDROID_3.4.5/security/keys/process_keys.c +++ /dev/null @@ -1,878 +0,0 @@ -/* Manage a process's keyrings - * - * 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/keyctl.h> -#include <linux/fs.h> -#include <linux/err.h> -#include <linux/mutex.h> -#include <linux/security.h> -#include <linux/user_namespace.h> -#include <asm/uaccess.h> -#include "internal.h" - -/* Session keyring create vs join semaphore */ -static DEFINE_MUTEX(key_session_mutex); - -/* User keyring creation semaphore */ -static DEFINE_MUTEX(key_user_keyring_mutex); - -/* The root user's tracking struct */ -struct key_user root_key_user = { - .usage = ATOMIC_INIT(3), - .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), - .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), - .nkeys = ATOMIC_INIT(2), - .nikeys = ATOMIC_INIT(2), - .uid = 0, - .user_ns = &init_user_ns, -}; - -/* - * Install the user and user session keyrings for the current process's UID. - */ -int install_user_keyrings(void) -{ - struct user_struct *user; - const struct cred *cred; - struct key *uid_keyring, *session_keyring; - char buf[20]; - int ret; - - cred = current_cred(); - user = cred->user; - - kenter("%p{%u}", user, user->uid); - - if (user->uid_keyring) { - kleave(" = 0 [exist]"); - return 0; - } - - mutex_lock(&key_user_keyring_mutex); - ret = 0; - - if (!user->uid_keyring) { - /* get the UID-specific keyring - * - there may be one in existence already as it may have been - * pinned by a session, but the user_struct pointing to it - * may have been destroyed by setuid */ - sprintf(buf, "_uid.%u", user->uid); - - uid_keyring = find_keyring_by_name(buf, true); - if (IS_ERR(uid_keyring)) { - uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, - cred, KEY_ALLOC_IN_QUOTA, - NULL); - if (IS_ERR(uid_keyring)) { - ret = PTR_ERR(uid_keyring); - goto error; - } - } - - /* get a default session keyring (which might also exist - * already) */ - sprintf(buf, "_uid_ses.%u", user->uid); - - session_keyring = find_keyring_by_name(buf, true); - if (IS_ERR(session_keyring)) { - session_keyring = - keyring_alloc(buf, user->uid, (gid_t) -1, - cred, KEY_ALLOC_IN_QUOTA, NULL); - if (IS_ERR(session_keyring)) { - ret = PTR_ERR(session_keyring); - goto error_release; - } - - /* we install a link from the user session keyring to - * the user keyring */ - ret = key_link(session_keyring, uid_keyring); - if (ret < 0) - goto error_release_both; - } - - /* install the keyrings */ - user->uid_keyring = uid_keyring; - user->session_keyring = session_keyring; - } - - mutex_unlock(&key_user_keyring_mutex); - kleave(" = 0"); - return 0; - -error_release_both: - key_put(session_keyring); -error_release: - key_put(uid_keyring); -error: - mutex_unlock(&key_user_keyring_mutex); - kleave(" = %d", ret); - return ret; -} - -/* - * Install a fresh thread keyring directly to new credentials. This keyring is - * allowed to overrun the quota. - */ -int install_thread_keyring_to_cred(struct cred *new) -{ - struct key *keyring; - - keyring = keyring_alloc("_tid", new->uid, new->gid, new, - KEY_ALLOC_QUOTA_OVERRUN, NULL); - if (IS_ERR(keyring)) - return PTR_ERR(keyring); - - new->thread_keyring = keyring; - return 0; -} - -/* - * Install a fresh thread keyring, discarding the old one. - */ -static int install_thread_keyring(void) -{ - struct cred *new; - int ret; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - BUG_ON(new->thread_keyring); - - ret = install_thread_keyring_to_cred(new); - if (ret < 0) { - abort_creds(new); - return ret; - } - - return commit_creds(new); -} - -/* - * Install a process keyring directly to a credentials struct. - * - * Returns -EEXIST if there was already a process keyring, 0 if one installed, - * and other value on any other error - */ -int install_process_keyring_to_cred(struct cred *new) -{ - struct key *keyring; - int ret; - - if (new->tgcred->process_keyring) - return -EEXIST; - - keyring = keyring_alloc("_pid", new->uid, new->gid, - new, KEY_ALLOC_QUOTA_OVERRUN, NULL); - if (IS_ERR(keyring)) - return PTR_ERR(keyring); - - spin_lock_irq(&new->tgcred->lock); - if (!new->tgcred->process_keyring) { - new->tgcred->process_keyring = keyring; - keyring = NULL; - ret = 0; - } else { - ret = -EEXIST; - } - spin_unlock_irq(&new->tgcred->lock); - key_put(keyring); - return ret; -} - -/* - * Make sure a process keyring is installed for the current process. The - * existing process keyring is not replaced. - * - * Returns 0 if there is a process keyring by the end of this function, some - * error otherwise. - */ -static int install_process_keyring(void) -{ - struct cred *new; - int ret; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - ret = install_process_keyring_to_cred(new); - if (ret < 0) { - abort_creds(new); - return ret != -EEXIST ? ret : 0; - } - - return commit_creds(new); -} - -/* - * Install a session keyring directly to a credentials struct. - */ -int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) -{ - unsigned long flags; - struct key *old; - - might_sleep(); - - /* create an empty session keyring */ - if (!keyring) { - flags = KEY_ALLOC_QUOTA_OVERRUN; - if (cred->tgcred->session_keyring) - flags = KEY_ALLOC_IN_QUOTA; - - keyring = keyring_alloc("_ses", cred->uid, cred->gid, - cred, flags, NULL); - if (IS_ERR(keyring)) - return PTR_ERR(keyring); - } else { - atomic_inc(&keyring->usage); - } - - /* install the keyring */ - spin_lock_irq(&cred->tgcred->lock); - old = cred->tgcred->session_keyring; - rcu_assign_pointer(cred->tgcred->session_keyring, keyring); - spin_unlock_irq(&cred->tgcred->lock); - - /* we're using RCU on the pointer, but there's no point synchronising - * on it if it didn't previously point to anything */ - if (old) { - synchronize_rcu(); - key_put(old); - } - - return 0; -} - -/* - * Install a session keyring, discarding the old one. If a keyring is not - * supplied, an empty one is invented. - */ -static int install_session_keyring(struct key *keyring) -{ - struct cred *new; - int ret; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - ret = install_session_keyring_to_cred(new, keyring); - if (ret < 0) { - abort_creds(new); - return ret; - } - - return commit_creds(new); -} - -/* - * Handle the fsuid changing. - */ -void key_fsuid_changed(struct task_struct *tsk) -{ - /* update the ownership of the thread keyring */ - BUG_ON(!tsk->cred); - if (tsk->cred->thread_keyring) { - down_write(&tsk->cred->thread_keyring->sem); - tsk->cred->thread_keyring->uid = tsk->cred->fsuid; - up_write(&tsk->cred->thread_keyring->sem); - } -} - -/* - * Handle the fsgid changing. - */ -void key_fsgid_changed(struct task_struct *tsk) -{ - /* update the ownership of the thread keyring */ - BUG_ON(!tsk->cred); - if (tsk->cred->thread_keyring) { - down_write(&tsk->cred->thread_keyring->sem); - tsk->cred->thread_keyring->gid = tsk->cred->fsgid; - up_write(&tsk->cred->thread_keyring->sem); - } -} - -/* - * Search the process keyrings attached to the supplied cred for the first - * matching key. - * - * The search criteria are the type and the match function. The description is - * given to the match function as a parameter, but doesn't otherwise influence - * the search. Typically the match function will compare the description - * parameter to the key's description. - * - * This can only search keyrings that grant Search permission to the supplied - * credentials. Keyrings linked to searched keyrings will also be searched if - * they grant Search permission too. Keys can only be found if they grant - * Search permission to the credentials. - * - * Returns a pointer to the key with the key usage count incremented if - * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only - * matched negative keys. - * - * In the case of a successful return, the possession attribute is set on the - * returned key reference. - */ -key_ref_t search_my_process_keyrings(struct key_type *type, - const void *description, - key_match_func_t match, - bool no_state_check, - const struct cred *cred) -{ - key_ref_t key_ref, ret, err; - - /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were - * searchable, but we failed to find a key or we found a negative key; - * otherwise we want to return a sample error (probably -EACCES) if - * none of the keyrings were searchable - * - * in terms of priority: success > -ENOKEY > -EAGAIN > other error - */ - key_ref = NULL; - ret = NULL; - err = ERR_PTR(-EAGAIN); - - /* search the thread keyring first */ - if (cred->thread_keyring) { - key_ref = keyring_search_aux( - make_key_ref(cred->thread_keyring, 1), - cred, type, description, match, no_state_check); - if (!IS_ERR(key_ref)) - goto found; - - switch (PTR_ERR(key_ref)) { - case -EAGAIN: /* no key */ - if (ret) - break; - case -ENOKEY: /* negative key */ - ret = key_ref; - break; - default: - err = key_ref; - break; - } - } - - /* search the process keyring second */ - if (cred->tgcred->process_keyring) { - key_ref = keyring_search_aux( - make_key_ref(cred->tgcred->process_keyring, 1), - cred, type, description, match, no_state_check); - if (!IS_ERR(key_ref)) - goto found; - - switch (PTR_ERR(key_ref)) { - case -EAGAIN: /* no key */ - if (ret) - break; - case -ENOKEY: /* negative key */ - ret = key_ref; - break; - default: - err = key_ref; - break; - } - } - - /* search the session keyring */ - if (cred->tgcred->session_keyring) { - rcu_read_lock(); - key_ref = keyring_search_aux( - make_key_ref(rcu_dereference( - cred->tgcred->session_keyring), - 1), - cred, type, description, match, no_state_check); - rcu_read_unlock(); - - if (!IS_ERR(key_ref)) - goto found; - - switch (PTR_ERR(key_ref)) { - case -EAGAIN: /* no key */ - if (ret) - break; - case -ENOKEY: /* negative key */ - ret = key_ref; - break; - default: - err = key_ref; - break; - } - } - /* or search the user-session keyring */ - else if (cred->user->session_keyring) { - key_ref = keyring_search_aux( - make_key_ref(cred->user->session_keyring, 1), - cred, type, description, match, no_state_check); - if (!IS_ERR(key_ref)) - goto found; - - switch (PTR_ERR(key_ref)) { - case -EAGAIN: /* no key */ - if (ret) - break; - case -ENOKEY: /* negative key */ - ret = key_ref; - break; - default: - err = key_ref; - break; - } - } - - /* no key - decide on the error we're going to go for */ - key_ref = ret ? ret : err; - -found: - return key_ref; -} - -/* - * Search the process keyrings attached to the supplied cred for the first - * matching key in the manner of search_my_process_keyrings(), but also search - * the keys attached to the assumed authorisation key using its credentials if - * one is available. - * - * Return same as search_my_process_keyrings(). - */ -key_ref_t search_process_keyrings(struct key_type *type, - const void *description, - key_match_func_t match, - const struct cred *cred) -{ - struct request_key_auth *rka; - key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; - - might_sleep(); - - key_ref = search_my_process_keyrings(type, description, match, - false, cred); - if (!IS_ERR(key_ref)) - goto found; - err = key_ref; - - /* if this process has an instantiation authorisation key, then we also - * search the keyrings of the process mentioned there - * - we don't permit access to request_key auth keys via this method - */ - if (cred->request_key_auth && - cred == current_cred() && - type != &key_type_request_key_auth - ) { - /* defend against the auth key being revoked */ - down_read(&cred->request_key_auth->sem); - - if (key_validate(cred->request_key_auth) == 0) { - rka = cred->request_key_auth->payload.data; - - key_ref = search_process_keyrings(type, description, - match, rka->cred); - - up_read(&cred->request_key_auth->sem); - - if (!IS_ERR(key_ref)) - goto found; - - ret = key_ref; - } else { - up_read(&cred->request_key_auth->sem); - } - } - - /* no key - decide on the error we're going to go for */ - if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) - key_ref = ERR_PTR(-ENOKEY); - else if (err == ERR_PTR(-EACCES)) - key_ref = ret; - else - key_ref = err; - -found: - return key_ref; -} - -/* - * See if the key we're looking at is the target key. - */ -int lookup_user_key_possessed(const struct key *key, const void *target) -{ - return key == target; -} - -/* - * Look up a key ID given us by userspace with a given permissions mask to get - * the key it refers to. - * - * Flags can be passed to request that special keyrings be created if referred - * to directly, to permit partially constructed keys to be found and to skip - * validity and permission checks on the found key. - * - * Returns a pointer to the key with an incremented usage count if successful; - * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond - * to a key or the best found key was a negative key; -EKEYREVOKED or - * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the - * found key doesn't grant the requested permit or the LSM denied access to it; - * or -ENOMEM if a special keyring couldn't be created. - * - * In the case of a successful return, the possession attribute is set on the - * returned key reference. - */ -key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, - key_perm_t perm) -{ - struct request_key_auth *rka; - const struct cred *cred; - struct key *key; - key_ref_t key_ref, skey_ref; - int ret; - -try_again: - cred = get_current_cred(); - key_ref = ERR_PTR(-ENOKEY); - - switch (id) { - case KEY_SPEC_THREAD_KEYRING: - if (!cred->thread_keyring) { - if (!(lflags & KEY_LOOKUP_CREATE)) - goto error; - - ret = install_thread_keyring(); - if (ret < 0) { - key_ref = ERR_PTR(ret); - goto error; - } - goto reget_creds; - } - - key = cred->thread_keyring; - atomic_inc(&key->usage); - key_ref = make_key_ref(key, 1); - break; - - case KEY_SPEC_PROCESS_KEYRING: - if (!cred->tgcred->process_keyring) { - if (!(lflags & KEY_LOOKUP_CREATE)) - goto error; - - ret = install_process_keyring(); - if (ret < 0) { - key_ref = ERR_PTR(ret); - goto error; - } - goto reget_creds; - } - - key = cred->tgcred->process_keyring; - atomic_inc(&key->usage); - key_ref = make_key_ref(key, 1); - break; - - case KEY_SPEC_SESSION_KEYRING: - if (!cred->tgcred->session_keyring) { - /* always install a session keyring upon access if one - * doesn't exist yet */ - ret = install_user_keyrings(); - if (ret < 0) - goto error; - if (lflags & KEY_LOOKUP_CREATE) - ret = join_session_keyring(NULL); - else - ret = install_session_keyring( - cred->user->session_keyring); - - if (ret < 0) - goto error; - goto reget_creds; - } else if (cred->tgcred->session_keyring == - cred->user->session_keyring && - lflags & KEY_LOOKUP_CREATE) { - ret = join_session_keyring(NULL); - if (ret < 0) - goto error; - goto reget_creds; - } - - rcu_read_lock(); - key = rcu_dereference(cred->tgcred->session_keyring); - atomic_inc(&key->usage); - rcu_read_unlock(); - key_ref = make_key_ref(key, 1); - break; - - case KEY_SPEC_USER_KEYRING: - if (!cred->user->uid_keyring) { - ret = install_user_keyrings(); - if (ret < 0) - goto error; - } - - key = cred->user->uid_keyring; - atomic_inc(&key->usage); - key_ref = make_key_ref(key, 1); - break; - - case KEY_SPEC_USER_SESSION_KEYRING: - if (!cred->user->session_keyring) { - ret = install_user_keyrings(); - if (ret < 0) - goto error; - } - - key = cred->user->session_keyring; - atomic_inc(&key->usage); - key_ref = make_key_ref(key, 1); - break; - - case KEY_SPEC_GROUP_KEYRING: - /* group keyrings are not yet supported */ - key_ref = ERR_PTR(-EINVAL); - goto error; - - case KEY_SPEC_REQKEY_AUTH_KEY: - key = cred->request_key_auth; - if (!key) - goto error; - - atomic_inc(&key->usage); - key_ref = make_key_ref(key, 1); - break; - - case KEY_SPEC_REQUESTOR_KEYRING: - if (!cred->request_key_auth) - goto error; - - down_read(&cred->request_key_auth->sem); - if (test_bit(KEY_FLAG_REVOKED, - &cred->request_key_auth->flags)) { - key_ref = ERR_PTR(-EKEYREVOKED); - key = NULL; - } else { - rka = cred->request_key_auth->payload.data; - key = rka->dest_keyring; - atomic_inc(&key->usage); - } - up_read(&cred->request_key_auth->sem); - if (!key) - goto error; - key_ref = make_key_ref(key, 1); - break; - - default: - key_ref = ERR_PTR(-EINVAL); - if (id < 1) - goto error; - - key = key_lookup(id); - if (IS_ERR(key)) { - key_ref = ERR_CAST(key); - goto error; - } - - key_ref = make_key_ref(key, 0); - - /* check to see if we possess the key */ - skey_ref = search_process_keyrings(key->type, key, - lookup_user_key_possessed, - cred); - - if (!IS_ERR(skey_ref)) { - key_put(key); - key_ref = skey_ref; - } - - break; - } - - /* unlink does not use the nominated key in any way, so can skip all - * the permission checks as it is only concerned with the keyring */ - if (lflags & KEY_LOOKUP_FOR_UNLINK) { - ret = 0; - goto error; - } - - if (!(lflags & KEY_LOOKUP_PARTIAL)) { - ret = wait_for_key_construction(key, true); - switch (ret) { - case -ERESTARTSYS: - goto invalid_key; - default: - if (perm) - goto invalid_key; - case 0: - break; - } - } else if (perm) { - ret = key_validate(key); - if (ret < 0) - goto invalid_key; - } - - ret = -EIO; - if (!(lflags & KEY_LOOKUP_PARTIAL) && - !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) - goto invalid_key; - - /* check the permissions */ - ret = key_task_permission(key_ref, cred, perm); - if (ret < 0) - goto invalid_key; - -error: - put_cred(cred); - return key_ref; - -invalid_key: - key_ref_put(key_ref); - key_ref = ERR_PTR(ret); - goto error; - - /* if we attempted to install a keyring, then it may have caused new - * creds to be installed */ -reget_creds: - put_cred(cred); - goto try_again; -} - -/* - * Join the named keyring as the session keyring if possible else attempt to - * create a new one of that name and join that. - * - * If the name is NULL, an empty anonymous keyring will be installed as the - * session keyring. - * - * Named session keyrings are joined with a semaphore held to prevent the - * keyrings from going away whilst the attempt is made to going them and also - * to prevent a race in creating compatible session keyrings. - */ -long join_session_keyring(const char *name) -{ - const struct cred *old; - struct cred *new; - struct key *keyring; - long ret, serial; - - /* only permit this if there's a single thread in the thread group - - * this avoids us having to adjust the creds on all threads and risking - * ENOMEM */ - if (!current_is_single_threaded()) - return -EMLINK; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - old = current_cred(); - - /* if no name is provided, install an anonymous keyring */ - if (!name) { - ret = install_session_keyring_to_cred(new, NULL); - if (ret < 0) - goto error; - - serial = new->tgcred->session_keyring->serial; - ret = commit_creds(new); - if (ret == 0) - ret = serial; - goto okay; - } - - /* allow the user to join or create a named keyring */ - mutex_lock(&key_session_mutex); - - /* look for an existing keyring of this name */ - keyring = find_keyring_by_name(name, false); - if (PTR_ERR(keyring) == -ENOKEY) { - /* not found - try and create a new one */ - keyring = keyring_alloc(name, old->uid, old->gid, old, - KEY_ALLOC_IN_QUOTA, NULL); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto error2; - } - } else if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto error2; - } - - /* we've got a keyring - now to install it */ - ret = install_session_keyring_to_cred(new, keyring); - if (ret < 0) - goto error2; - - commit_creds(new); - mutex_unlock(&key_session_mutex); - - ret = keyring->serial; - key_put(keyring); -okay: - return ret; - -error2: - mutex_unlock(&key_session_mutex); -error: - abort_creds(new); - return ret; -} - -/* - * Replace a process's session keyring on behalf of one of its children when - * the target process is about to resume userspace execution. - */ -void key_replace_session_keyring(void) -{ - const struct cred *old; - struct cred *new; - - if (!current->replacement_session_keyring) - return; - - write_lock_irq(&tasklist_lock); - new = current->replacement_session_keyring; - current->replacement_session_keyring = NULL; - write_unlock_irq(&tasklist_lock); - - if (!new) - return; - - old = current_cred(); - new-> uid = old-> uid; - new-> euid = old-> euid; - new-> suid = old-> suid; - new->fsuid = old->fsuid; - new-> gid = old-> gid; - new-> egid = old-> egid; - new-> sgid = old-> sgid; - new->fsgid = old->fsgid; - new->user = get_uid(old->user); - new->user_ns = new->user->user_ns; - new->group_info = get_group_info(old->group_info); - - new->securebits = old->securebits; - new->cap_inheritable = old->cap_inheritable; - new->cap_permitted = old->cap_permitted; - new->cap_effective = old->cap_effective; - new->cap_bset = old->cap_bset; - - new->jit_keyring = old->jit_keyring; - new->thread_keyring = key_get(old->thread_keyring); - new->tgcred->tgid = old->tgcred->tgid; - new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); - - security_transfer_creds(new, old); - - commit_creds(new); -} diff --git a/ANDROID_3.4.5/security/keys/request_key.c b/ANDROID_3.4.5/security/keys/request_key.c deleted file mode 100644 index cc379031..00000000 --- a/ANDROID_3.4.5/security/keys/request_key.c +++ /dev/null @@ -1,713 +0,0 @@ -/* Request a key from userspace - * - * Copyright (C) 2004-2007 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. - * - * See Documentation/security/keys-request-key.txt - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kmod.h> -#include <linux/err.h> -#include <linux/keyctl.h> -#include <linux/slab.h> -#include "internal.h" - -#define key_negative_timeout 60 /* default timeout on a negative key's existence */ - -/* - * wait_on_bit() sleep function for uninterruptible waiting - */ -static int key_wait_bit(void *flags) -{ - schedule(); - return 0; -} - -/* - * wait_on_bit() sleep function for interruptible waiting - */ -static int key_wait_bit_intr(void *flags) -{ - schedule(); - return signal_pending(current) ? -ERESTARTSYS : 0; -} - -/** - * complete_request_key - Complete the construction of a key. - * @cons: The key construction record. - * @error: The success or failute of the construction. - * - * Complete the attempt to construct a key. The key will be negated - * if an error is indicated. The authorisation key will be revoked - * unconditionally. - */ -void complete_request_key(struct key_construction *cons, int error) -{ - kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error); - - if (error < 0) - key_negate_and_link(cons->key, key_negative_timeout, NULL, - cons->authkey); - else - key_revoke(cons->authkey); - - key_put(cons->key); - key_put(cons->authkey); - kfree(cons); -} -EXPORT_SYMBOL(complete_request_key); - -/* - * Initialise a usermode helper that is going to have a specific session - * keyring. - * - * This is called in context of freshly forked kthread before kernel_execve(), - * so we can simply install the desired session_keyring at this point. - */ -static int umh_keys_init(struct subprocess_info *info, struct cred *cred) -{ - struct key *keyring = info->data; - - return install_session_keyring_to_cred(cred, keyring); -} - -/* - * Clean up a usermode helper with session keyring. - */ -static void umh_keys_cleanup(struct subprocess_info *info) -{ - struct key *keyring = info->data; - key_put(keyring); -} - -/* - * Call a usermode helper with a specific session keyring. - */ -static int call_usermodehelper_keys(char *path, char **argv, char **envp, - struct key *session_keyring, int wait) -{ - gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; - struct subprocess_info *info = - call_usermodehelper_setup(path, argv, envp, gfp_mask); - - if (!info) - return -ENOMEM; - - call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup, - key_get(session_keyring)); - return call_usermodehelper_exec(info, wait); -} - -/* - * Request userspace finish the construction of a key - * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" - */ -static int call_sbin_request_key(struct key_construction *cons, - const char *op, - void *aux) -{ - const struct cred *cred = current_cred(); - key_serial_t prkey, sskey; - struct key *key = cons->key, *authkey = cons->authkey, *keyring, - *session; - char *argv[9], *envp[3], uid_str[12], gid_str[12]; - char key_str[12], keyring_str[3][12]; - char desc[20]; - int ret, i; - - kenter("{%d},{%d},%s", key->serial, authkey->serial, op); - - ret = install_user_keyrings(); - if (ret < 0) - goto error_alloc; - - /* allocate a new session keyring */ - sprintf(desc, "_req.%u", key->serial); - - cred = get_current_cred(); - keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, - KEY_ALLOC_QUOTA_OVERRUN, NULL); - put_cred(cred); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto error_alloc; - } - - /* attach the auth key to the session keyring */ - ret = key_link(keyring, authkey); - if (ret < 0) - goto error_link; - - /* record the UID and GID */ - sprintf(uid_str, "%d", cred->fsuid); - sprintf(gid_str, "%d", cred->fsgid); - - /* we say which key is under construction */ - sprintf(key_str, "%d", key->serial); - - /* we specify the process's default keyrings */ - sprintf(keyring_str[0], "%d", - cred->thread_keyring ? cred->thread_keyring->serial : 0); - - prkey = 0; - if (cred->tgcred->process_keyring) - prkey = cred->tgcred->process_keyring->serial; - sprintf(keyring_str[1], "%d", prkey); - - rcu_read_lock(); - session = rcu_dereference(cred->tgcred->session_keyring); - if (!session) - session = cred->user->session_keyring; - sskey = session->serial; - rcu_read_unlock(); - - sprintf(keyring_str[2], "%d", sskey); - - /* set up a minimal environment */ - i = 0; - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - envp[i] = NULL; - - /* set up the argument list */ - i = 0; - argv[i++] = "/sbin/request-key"; - argv[i++] = (char *) op; - argv[i++] = key_str; - argv[i++] = uid_str; - argv[i++] = gid_str; - argv[i++] = keyring_str[0]; - argv[i++] = keyring_str[1]; - argv[i++] = keyring_str[2]; - argv[i] = NULL; - - /* do it */ - ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, - UMH_WAIT_PROC); - kdebug("usermode -> 0x%x", ret); - if (ret >= 0) { - /* ret is the exit/wait code */ - if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) || - key_validate(key) < 0) - ret = -ENOKEY; - else - /* ignore any errors from userspace if the key was - * instantiated */ - ret = 0; - } - -error_link: - key_put(keyring); - -error_alloc: - complete_request_key(cons, ret); - kleave(" = %d", ret); - return ret; -} - -/* - * Call out to userspace for key construction. - * - * Program failure is ignored in favour of key status. - */ -static int construct_key(struct key *key, const void *callout_info, - size_t callout_len, void *aux, - struct key *dest_keyring) -{ - struct key_construction *cons; - request_key_actor_t actor; - struct key *authkey; - int ret; - - kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux); - - cons = kmalloc(sizeof(*cons), GFP_KERNEL); - if (!cons) - return -ENOMEM; - - /* allocate an authorisation key */ - authkey = request_key_auth_new(key, callout_info, callout_len, - dest_keyring); - if (IS_ERR(authkey)) { - kfree(cons); - ret = PTR_ERR(authkey); - authkey = NULL; - } else { - cons->authkey = key_get(authkey); - cons->key = key_get(key); - - /* make the call */ - actor = call_sbin_request_key; - if (key->type->request_key) - actor = key->type->request_key; - - ret = actor(cons, "create", aux); - - /* check that the actor called complete_request_key() prior to - * returning an error */ - WARN_ON(ret < 0 && - !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); - key_put(authkey); - } - - kleave(" = %d", ret); - return ret; -} - -/* - * Get the appropriate destination keyring for the request. - * - * The keyring selected is returned with an extra reference upon it which the - * caller must release. - */ -static void construct_get_dest_keyring(struct key **_dest_keyring) -{ - struct request_key_auth *rka; - const struct cred *cred = current_cred(); - struct key *dest_keyring = *_dest_keyring, *authkey; - - kenter("%p", dest_keyring); - - /* find the appropriate keyring */ - if (dest_keyring) { - /* the caller supplied one */ - key_get(dest_keyring); - } else { - /* use a default keyring; falling through the cases until we - * find one that we actually have */ - switch (cred->jit_keyring) { - case KEY_REQKEY_DEFL_DEFAULT: - case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: - if (cred->request_key_auth) { - authkey = cred->request_key_auth; - down_read(&authkey->sem); - rka = authkey->payload.data; - if (!test_bit(KEY_FLAG_REVOKED, - &authkey->flags)) - dest_keyring = - key_get(rka->dest_keyring); - up_read(&authkey->sem); - if (dest_keyring) - break; - } - - case KEY_REQKEY_DEFL_THREAD_KEYRING: - dest_keyring = key_get(cred->thread_keyring); - if (dest_keyring) - break; - - case KEY_REQKEY_DEFL_PROCESS_KEYRING: - dest_keyring = key_get(cred->tgcred->process_keyring); - if (dest_keyring) - break; - - case KEY_REQKEY_DEFL_SESSION_KEYRING: - rcu_read_lock(); - dest_keyring = key_get( - rcu_dereference(cred->tgcred->session_keyring)); - rcu_read_unlock(); - - if (dest_keyring) - break; - - case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: - dest_keyring = - key_get(cred->user->session_keyring); - break; - - case KEY_REQKEY_DEFL_USER_KEYRING: - dest_keyring = key_get(cred->user->uid_keyring); - break; - - case KEY_REQKEY_DEFL_GROUP_KEYRING: - default: - BUG(); - } - } - - *_dest_keyring = dest_keyring; - kleave(" [dk %d]", key_serial(dest_keyring)); - return; -} - -/* - * Allocate a new key in under-construction state and attempt to link it in to - * the requested keyring. - * - * May return a key that's already under construction instead if there was a - * race between two thread calling request_key(). - */ -static int construct_alloc_key(struct key_type *type, - const char *description, - struct key *dest_keyring, - unsigned long flags, - struct key_user *user, - struct key **_key) -{ - const struct cred *cred = current_cred(); - unsigned long prealloc; - struct key *key; - key_ref_t key_ref; - int ret; - - kenter("%s,%s,,,", type->name, description); - - *_key = NULL; - mutex_lock(&user->cons_lock); - - key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, - KEY_POS_ALL, flags); - if (IS_ERR(key)) - goto alloc_failed; - - set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); - - if (dest_keyring) { - ret = __key_link_begin(dest_keyring, type, description, - &prealloc); - if (ret < 0) - goto link_prealloc_failed; - } - - /* attach the key to the destination keyring under lock, but we do need - * to do another check just in case someone beat us to it whilst we - * waited for locks */ - mutex_lock(&key_construction_mutex); - - key_ref = search_process_keyrings(type, description, type->match, cred); - if (!IS_ERR(key_ref)) - goto key_already_present; - - if (dest_keyring) - __key_link(dest_keyring, key, &prealloc); - - mutex_unlock(&key_construction_mutex); - if (dest_keyring) - __key_link_end(dest_keyring, type, prealloc); - mutex_unlock(&user->cons_lock); - *_key = key; - kleave(" = 0 [%d]", key_serial(key)); - return 0; - - /* the key is now present - we tell the caller that we found it by - * returning -EINPROGRESS */ -key_already_present: - key_put(key); - mutex_unlock(&key_construction_mutex); - key = key_ref_to_ptr(key_ref); - if (dest_keyring) { - ret = __key_link_check_live_key(dest_keyring, key); - if (ret == 0) - __key_link(dest_keyring, key, &prealloc); - __key_link_end(dest_keyring, type, prealloc); - if (ret < 0) - goto link_check_failed; - } - mutex_unlock(&user->cons_lock); - *_key = key; - kleave(" = -EINPROGRESS [%d]", key_serial(key)); - return -EINPROGRESS; - -link_check_failed: - mutex_unlock(&user->cons_lock); - key_put(key); - kleave(" = %d [linkcheck]", ret); - return ret; - -link_prealloc_failed: - mutex_unlock(&user->cons_lock); - kleave(" = %d [prelink]", ret); - return ret; - -alloc_failed: - mutex_unlock(&user->cons_lock); - kleave(" = %ld", PTR_ERR(key)); - return PTR_ERR(key); -} - -/* - * Commence key construction. - */ -static struct key *construct_key_and_link(struct key_type *type, - const char *description, - const char *callout_info, - size_t callout_len, - void *aux, - struct key *dest_keyring, - unsigned long flags) -{ - struct key_user *user; - struct key *key; - int ret; - - kenter(""); - - user = key_user_lookup(current_fsuid(), current_user_ns()); - if (!user) - return ERR_PTR(-ENOMEM); - - construct_get_dest_keyring(&dest_keyring); - - ret = construct_alloc_key(type, description, dest_keyring, flags, user, - &key); - key_user_put(user); - - if (ret == 0) { - ret = construct_key(key, callout_info, callout_len, aux, - dest_keyring); - if (ret < 0) { - kdebug("cons failed"); - goto construction_failed; - } - } else if (ret == -EINPROGRESS) { - ret = 0; - } else { - goto couldnt_alloc_key; - } - - key_put(dest_keyring); - kleave(" = key %d", key_serial(key)); - return key; - -construction_failed: - key_negate_and_link(key, key_negative_timeout, NULL, NULL); - key_put(key); -couldnt_alloc_key: - key_put(dest_keyring); - kleave(" = %d", ret); - return ERR_PTR(ret); -} - -/** - * request_key_and_link - Request a key and cache it in a keyring. - * @type: The type of key we want. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @callout_len: The length of callout_info. - * @aux: Auxiliary data for the upcall. - * @dest_keyring: Where to cache the key. - * @flags: Flags to key_alloc(). - * - * A key matching the specified criteria is searched for in the process's - * keyrings and returned with its usage count incremented if found. Otherwise, - * if callout_info is not NULL, a key will be allocated and some service - * (probably in userspace) will be asked to instantiate it. - * - * If successfully found or created, the key will be linked to the destination - * keyring if one is provided. - * - * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED - * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was - * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT - * if insufficient key quota was available to create a new key; or -ENOMEM if - * insufficient memory was available. - * - * If the returned key was created, then it may still be under construction, - * and wait_for_key_construction() should be used to wait for that to complete. - */ -struct key *request_key_and_link(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux, - struct key *dest_keyring, - unsigned long flags) -{ - const struct cred *cred = current_cred(); - struct key *key; - key_ref_t key_ref; - int ret; - - kenter("%s,%s,%p,%zu,%p,%p,%lx", - type->name, description, callout_info, callout_len, aux, - dest_keyring, flags); - - /* search all the process keyrings for a key */ - key_ref = search_process_keyrings(type, description, type->match, cred); - - if (!IS_ERR(key_ref)) { - key = key_ref_to_ptr(key_ref); - if (dest_keyring) { - construct_get_dest_keyring(&dest_keyring); - ret = key_link(dest_keyring, key); - key_put(dest_keyring); - if (ret < 0) { - key_put(key); - key = ERR_PTR(ret); - goto error; - } - } - } else if (PTR_ERR(key_ref) != -EAGAIN) { - key = ERR_CAST(key_ref); - } else { - /* the search failed, but the keyrings were searchable, so we - * should consult userspace if we can */ - key = ERR_PTR(-ENOKEY); - if (!callout_info) - goto error; - - key = construct_key_and_link(type, description, callout_info, - callout_len, aux, dest_keyring, - flags); - } - -error: - kleave(" = %p", key); - return key; -} - -/** - * wait_for_key_construction - Wait for construction of a key to complete - * @key: The key being waited for. - * @intr: Whether to wait interruptibly. - * - * Wait for a key to finish being constructed. - * - * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY - * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was - * revoked or expired. - */ -int wait_for_key_construction(struct key *key, bool intr) -{ - int ret; - - ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT, - intr ? key_wait_bit_intr : key_wait_bit, - intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (ret < 0) - return ret; - if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) - return key->type_data.reject_error; - return key_validate(key); -} -EXPORT_SYMBOL(wait_for_key_construction); - -/** - * request_key - Request a key and wait for construction - * @type: Type of key. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * - * As for request_key_and_link() except that it does not add the returned key - * to a keyring if found, new keys are always allocated in the user's quota, - * the callout_info must be a NUL-terminated string and no auxiliary data can - * be passed. - * - * Furthermore, it then works as wait_for_key_construction() to wait for the - * completion of keys undergoing construction with a non-interruptible wait. - */ -struct key *request_key(struct key_type *type, - const char *description, - const char *callout_info) -{ - struct key *key; - size_t callout_len = 0; - int ret; - - if (callout_info) - callout_len = strlen(callout_info); - key = request_key_and_link(type, description, callout_info, callout_len, - NULL, NULL, KEY_ALLOC_IN_QUOTA); - if (!IS_ERR(key)) { - ret = wait_for_key_construction(key, false); - if (ret < 0) { - key_put(key); - return ERR_PTR(ret); - } - } - return key; -} -EXPORT_SYMBOL(request_key); - -/** - * request_key_with_auxdata - Request a key with auxiliary data for the upcaller - * @type: The type of key we want. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @callout_len: The length of callout_info. - * @aux: Auxiliary data for the upcall. - * - * As for request_key_and_link() except that it does not add the returned key - * to a keyring if found and new keys are always allocated in the user's quota. - * - * Furthermore, it then works as wait_for_key_construction() to wait for the - * completion of keys undergoing construction with a non-interruptible wait. - */ -struct key *request_key_with_auxdata(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux) -{ - struct key *key; - int ret; - - key = request_key_and_link(type, description, callout_info, callout_len, - aux, NULL, KEY_ALLOC_IN_QUOTA); - if (!IS_ERR(key)) { - ret = wait_for_key_construction(key, false); - if (ret < 0) { - key_put(key); - return ERR_PTR(ret); - } - } - return key; -} -EXPORT_SYMBOL(request_key_with_auxdata); - -/* - * request_key_async - Request a key (allow async construction) - * @type: Type of key. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @callout_len: The length of callout_info. - * - * As for request_key_and_link() except that it does not add the returned key - * to a keyring if found, new keys are always allocated in the user's quota and - * no auxiliary data can be passed. - * - * The caller should call wait_for_key_construction() to wait for the - * completion of the returned key if it is still undergoing construction. - */ -struct key *request_key_async(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len) -{ - return request_key_and_link(type, description, callout_info, - callout_len, NULL, NULL, - KEY_ALLOC_IN_QUOTA); -} -EXPORT_SYMBOL(request_key_async); - -/* - * request a key with auxiliary data for the upcaller (allow async construction) - * @type: Type of key. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @callout_len: The length of callout_info. - * @aux: Auxiliary data for the upcall. - * - * As for request_key_and_link() except that it does not add the returned key - * to a keyring if found and new keys are always allocated in the user's quota. - * - * The caller should call wait_for_key_construction() to wait for the - * completion of the returned key if it is still undergoing construction. - */ -struct key *request_key_async_with_auxdata(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux) -{ - return request_key_and_link(type, description, callout_info, - callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); -} -EXPORT_SYMBOL(request_key_async_with_auxdata); diff --git a/ANDROID_3.4.5/security/keys/request_key_auth.c b/ANDROID_3.4.5/security/keys/request_key_auth.c deleted file mode 100644 index 60d4e3f5..00000000 --- a/ANDROID_3.4.5/security/keys/request_key_auth.c +++ /dev/null @@ -1,267 +0,0 @@ -/* Request key authorisation token key definition. - * - * Copyright (C) 2005 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. - * - * See Documentation/security/keys-request-key.txt - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/err.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <asm/uaccess.h> -#include "internal.h" - -static int request_key_auth_instantiate(struct key *, const void *, size_t); -static void request_key_auth_describe(const struct key *, struct seq_file *); -static void request_key_auth_revoke(struct key *); -static void request_key_auth_destroy(struct key *); -static long request_key_auth_read(const struct key *, char __user *, size_t); - -/* - * The request-key authorisation key type definition. - */ -struct key_type key_type_request_key_auth = { - .name = ".request_key_auth", - .def_datalen = sizeof(struct request_key_auth), - .instantiate = request_key_auth_instantiate, - .describe = request_key_auth_describe, - .revoke = request_key_auth_revoke, - .destroy = request_key_auth_destroy, - .read = request_key_auth_read, -}; - -/* - * Instantiate a request-key authorisation key. - */ -static int request_key_auth_instantiate(struct key *key, - const void *data, - size_t datalen) -{ - key->payload.data = (struct request_key_auth *) data; - return 0; -} - -/* - * Describe an authorisation token. - */ -static void request_key_auth_describe(const struct key *key, - struct seq_file *m) -{ - struct request_key_auth *rka = key->payload.data; - - seq_puts(m, "key:"); - seq_puts(m, key->description); - if (key_is_instantiated(key)) - seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); -} - -/* - * Read the callout_info data (retrieves the callout information). - * - the key's semaphore is read-locked - */ -static long request_key_auth_read(const struct key *key, - char __user *buffer, size_t buflen) -{ - struct request_key_auth *rka = key->payload.data; - size_t datalen; - long ret; - - datalen = rka->callout_len; - ret = datalen; - - /* we can return the data as is */ - if (buffer && buflen > 0) { - if (buflen > datalen) - buflen = datalen; - - if (copy_to_user(buffer, rka->callout_info, buflen) != 0) - ret = -EFAULT; - } - - return ret; -} - -/* - * Handle revocation of an authorisation token key. - * - * Called with the key sem write-locked. - */ -static void request_key_auth_revoke(struct key *key) -{ - struct request_key_auth *rka = key->payload.data; - - kenter("{%d}", key->serial); - - if (rka->cred) { - put_cred(rka->cred); - rka->cred = NULL; - } -} - -/* - * Destroy an instantiation authorisation token key. - */ -static void request_key_auth_destroy(struct key *key) -{ - struct request_key_auth *rka = key->payload.data; - - kenter("{%d}", key->serial); - - if (rka->cred) { - put_cred(rka->cred); - rka->cred = NULL; - } - - key_put(rka->target_key); - key_put(rka->dest_keyring); - kfree(rka->callout_info); - kfree(rka); -} - -/* - * Create an authorisation token for /sbin/request-key or whoever to gain - * access to the caller's security data. - */ -struct key *request_key_auth_new(struct key *target, const void *callout_info, - size_t callout_len, struct key *dest_keyring) -{ - struct request_key_auth *rka, *irka; - const struct cred *cred = current->cred; - struct key *authkey = NULL; - char desc[20]; - int ret; - - kenter("%d,", target->serial); - - /* allocate a auth record */ - rka = kmalloc(sizeof(*rka), GFP_KERNEL); - if (!rka) { - kleave(" = -ENOMEM"); - return ERR_PTR(-ENOMEM); - } - rka->callout_info = kmalloc(callout_len, GFP_KERNEL); - if (!rka->callout_info) { - kleave(" = -ENOMEM"); - kfree(rka); - return ERR_PTR(-ENOMEM); - } - - /* see if the calling process is already servicing the key request of - * another process */ - if (cred->request_key_auth) { - /* it is - use that instantiation context here too */ - down_read(&cred->request_key_auth->sem); - - /* if the auth key has been revoked, then the key we're - * servicing is already instantiated */ - if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags)) - goto auth_key_revoked; - - irka = cred->request_key_auth->payload.data; - rka->cred = get_cred(irka->cred); - rka->pid = irka->pid; - - up_read(&cred->request_key_auth->sem); - } - else { - /* it isn't - use this process as the context */ - rka->cred = get_cred(cred); - rka->pid = current->pid; - } - - rka->target_key = key_get(target); - rka->dest_keyring = key_get(dest_keyring); - memcpy(rka->callout_info, callout_info, callout_len); - rka->callout_len = callout_len; - - /* allocate the auth key */ - sprintf(desc, "%x", target->serial); - - authkey = key_alloc(&key_type_request_key_auth, desc, - cred->fsuid, cred->fsgid, cred, - KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | - KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); - if (IS_ERR(authkey)) { - ret = PTR_ERR(authkey); - goto error_alloc; - } - - /* construct the auth key */ - ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); - if (ret < 0) - goto error_inst; - - kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); - return authkey; - -auth_key_revoked: - up_read(&cred->request_key_auth->sem); - kfree(rka->callout_info); - kfree(rka); - kleave("= -EKEYREVOKED"); - return ERR_PTR(-EKEYREVOKED); - -error_inst: - key_revoke(authkey); - key_put(authkey); -error_alloc: - key_put(rka->target_key); - key_put(rka->dest_keyring); - kfree(rka->callout_info); - kfree(rka); - kleave("= %d", ret); - return ERR_PTR(ret); -} - -/* - * See if an authorisation key is associated with a particular key. - */ -static int key_get_instantiation_authkey_match(const struct key *key, - const void *_id) -{ - struct request_key_auth *rka = key->payload.data; - key_serial_t id = (key_serial_t)(unsigned long) _id; - - return rka->target_key->serial == id; -} - -/* - * Search the current process's keyrings for the authorisation key for - * instantiation of a key. - */ -struct key *key_get_instantiation_authkey(key_serial_t target_id) -{ - const struct cred *cred = current_cred(); - struct key *authkey; - key_ref_t authkey_ref; - - authkey_ref = search_process_keyrings( - &key_type_request_key_auth, - (void *) (unsigned long) target_id, - key_get_instantiation_authkey_match, - cred); - - if (IS_ERR(authkey_ref)) { - authkey = ERR_CAST(authkey_ref); - if (authkey == ERR_PTR(-EAGAIN)) - authkey = ERR_PTR(-ENOKEY); - goto error; - } - - authkey = key_ref_to_ptr(authkey_ref); - if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { - key_put(authkey); - authkey = ERR_PTR(-EKEYREVOKED); - } - -error: - return authkey; -} diff --git a/ANDROID_3.4.5/security/keys/sysctl.c b/ANDROID_3.4.5/security/keys/sysctl.c deleted file mode 100644 index ee32d181..00000000 --- a/ANDROID_3.4.5/security/keys/sysctl.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Key management controls - * - * Copyright (C) 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 Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#include <linux/key.h> -#include <linux/sysctl.h> -#include "internal.h" - -static const int zero, one = 1, max = INT_MAX; - -ctl_table key_sysctls[] = { - { - .procname = "maxkeys", - .data = &key_quota_maxkeys, - .maxlen = sizeof(unsigned), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *) &one, - .extra2 = (void *) &max, - }, - { - .procname = "maxbytes", - .data = &key_quota_maxbytes, - .maxlen = sizeof(unsigned), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *) &one, - .extra2 = (void *) &max, - }, - { - .procname = "root_maxkeys", - .data = &key_quota_root_maxkeys, - .maxlen = sizeof(unsigned), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *) &one, - .extra2 = (void *) &max, - }, - { - .procname = "root_maxbytes", - .data = &key_quota_root_maxbytes, - .maxlen = sizeof(unsigned), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *) &one, - .extra2 = (void *) &max, - }, - { - .procname = "gc_delay", - .data = &key_gc_delay, - .maxlen = sizeof(unsigned), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *) &zero, - .extra2 = (void *) &max, - }, - { } -}; diff --git a/ANDROID_3.4.5/security/keys/trusted.c b/ANDROID_3.4.5/security/keys/trusted.c deleted file mode 100644 index 2d5d041f..00000000 --- a/ANDROID_3.4.5/security/keys/trusted.c +++ /dev/null @@ -1,1191 +0,0 @@ -/* - * Copyright (C) 2010 IBM Corporation - * - * Author: - * David Safford <safford@us.ibm.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, version 2 of the License. - * - * See Documentation/security/keys-trusted-encrypted.txt - */ - -#include <linux/uaccess.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/parser.h> -#include <linux/string.h> -#include <linux/err.h> -#include <keys/user-type.h> -#include <keys/trusted-type.h> -#include <linux/key-type.h> -#include <linux/rcupdate.h> -#include <linux/crypto.h> -#include <crypto/hash.h> -#include <crypto/sha.h> -#include <linux/capability.h> -#include <linux/tpm.h> -#include <linux/tpm_command.h> - -#include "trusted.h" - -static const char hmac_alg[] = "hmac(sha1)"; -static const char hash_alg[] = "sha1"; - -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static struct crypto_shash *hashalg; -static struct crypto_shash *hmacalg; - -static struct sdesc *init_sdesc(struct crypto_shash *alg) -{ - struct sdesc *sdesc; - int size; - - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - sdesc->shash.flags = 0x0; - return sdesc; -} - -static int TSS_sha1(const unsigned char *data, unsigned int datalen, - unsigned char *digest) -{ - struct sdesc *sdesc; - int ret; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); - kfree(sdesc); - return ret; -} - -static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, ...) -{ - struct sdesc *sdesc; - va_list argp; - unsigned int dlen; - unsigned char *data; - int ret; - - sdesc = init_sdesc(hmacalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hmac_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_setkey(hmacalg, key, keylen); - if (ret < 0) - goto out; - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - - va_start(argp, keylen); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - data = va_arg(argp, unsigned char *); - if (data == NULL) { - ret = -EINVAL; - break; - } - ret = crypto_shash_update(&sdesc->shash, data, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, digest); -out: - kfree(sdesc); - return ret; -} - -/* - * calculate authorization info fields to send to TPM - */ -static int TSS_authhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, unsigned char *h1, - unsigned char *h2, unsigned char h3, ...) -{ - unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; - unsigned int dlen; - unsigned char *data; - unsigned char c; - int ret; - va_list argp; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - - c = h3; - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - va_start(argp, h3); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - data = va_arg(argp, unsigned char *); - if (!data) { - ret = -EINVAL; - break; - } - ret = crypto_shash_update(&sdesc->shash, data, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); - if (!ret) - ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE, - paramdigest, TPM_NONCE_SIZE, h1, - TPM_NONCE_SIZE, h2, 1, &c, 0, 0); -out: - kfree(sdesc); - return ret; -} - -/* - * verify the AUTH1_COMMAND (Seal) result from TPM - */ -static int TSS_checkhmac1(unsigned char *buffer, - const uint32_t command, - const unsigned char *ononce, - const unsigned char *key, - unsigned int keylen, ...) -{ - uint32_t bufsize; - uint16_t tag; - uint32_t ordinal; - uint32_t result; - unsigned char *enonce; - unsigned char *continueflag; - unsigned char *authdata; - unsigned char testhmac[SHA1_DIGEST_SIZE]; - unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; - unsigned int dlen; - unsigned int dpos; - va_list argp; - int ret; - - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); - tag = LOAD16(buffer, 0); - ordinal = command; - result = LOAD32N(buffer, TPM_RETURN_OFFSET); - if (tag == TPM_TAG_RSP_COMMAND) - return 0; - if (tag != TPM_TAG_RSP_AUTH1_COMMAND) - return -EINVAL; - authdata = buffer + bufsize - SHA1_DIGEST_SIZE; - continueflag = authdata - 1; - enonce = continueflag - TPM_NONCE_SIZE; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); - if (ret < 0) - goto out; - va_start(argp, keylen); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - dpos = va_arg(argp, unsigned int); - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); - if (ret < 0) - goto out; - - ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce, - 1, continueflag, 0, 0); - if (ret < 0) - goto out; - - if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE)) - ret = -EINVAL; -out: - kfree(sdesc); - return ret; -} - -/* - * verify the AUTH2_COMMAND (unseal) result from TPM - */ -static int TSS_checkhmac2(unsigned char *buffer, - const uint32_t command, - const unsigned char *ononce, - const unsigned char *key1, - unsigned int keylen1, - const unsigned char *key2, - unsigned int keylen2, ...) -{ - uint32_t bufsize; - uint16_t tag; - uint32_t ordinal; - uint32_t result; - unsigned char *enonce1; - unsigned char *continueflag1; - unsigned char *authdata1; - unsigned char *enonce2; - unsigned char *continueflag2; - unsigned char *authdata2; - unsigned char testhmac1[SHA1_DIGEST_SIZE]; - unsigned char testhmac2[SHA1_DIGEST_SIZE]; - unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; - unsigned int dlen; - unsigned int dpos; - va_list argp; - int ret; - - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); - tag = LOAD16(buffer, 0); - ordinal = command; - result = LOAD32N(buffer, TPM_RETURN_OFFSET); - - if (tag == TPM_TAG_RSP_COMMAND) - return 0; - if (tag != TPM_TAG_RSP_AUTH2_COMMAND) - return -EINVAL; - authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1 - + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE); - authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); - continueflag1 = authdata1 - 1; - continueflag2 = authdata2 - 1; - enonce1 = continueflag1 - TPM_NONCE_SIZE; - enonce2 = continueflag2 - TPM_NONCE_SIZE; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); - if (ret < 0) - goto out; - - va_start(argp, keylen2); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - dpos = va_arg(argp, unsigned int); - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); - if (ret < 0) - goto out; - - ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE, - paramdigest, TPM_NONCE_SIZE, enonce1, - TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0); - if (ret < 0) - goto out; - if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { - ret = -EINVAL; - goto out; - } - ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE, - paramdigest, TPM_NONCE_SIZE, enonce2, - TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0); - if (ret < 0) - goto out; - if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE)) - ret = -EINVAL; -out: - kfree(sdesc); - return ret; -} - -/* - * For key specific tpm requests, we will generate and send our - * own TPM command packets using the drivers send function. - */ -static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, - size_t buflen) -{ - int rc; - - dump_tpm_buf(cmd); - rc = tpm_send(chip_num, cmd, buflen); - dump_tpm_buf(cmd); - if (rc > 0) - /* Can't return positive return codes values to keyctl */ - rc = -EPERM; - return rc; -} - -/* - * get a random value from TPM - */ -static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len) -{ - int ret; - - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_COMMAND); - store32(tb, TPM_GETRANDOM_SIZE); - store32(tb, TPM_ORD_GETRANDOM); - store32(tb, len); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data); - if (!ret) - memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len); - return ret; -} - -static int my_get_random(unsigned char *buf, int len) -{ - struct tpm_buf *tb; - int ret; - - tb = kmalloc(sizeof *tb, GFP_KERNEL); - if (!tb) - return -ENOMEM; - ret = tpm_get_random(tb, buf, len); - - kfree(tb); - return ret; -} - -/* - * Lock a trusted key, by extending a selected PCR. - * - * Prevents a trusted key that is sealed to PCRs from being accessed. - * This uses the tpm driver's extend function. - */ -static int pcrlock(const int pcrnum) -{ - unsigned char hash[SHA1_DIGEST_SIZE]; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - ret = my_get_random(hash, SHA1_DIGEST_SIZE); - if (ret < 0) - return ret; - return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; -} - -/* - * Create an object specific authorisation protocol (OSAP) session - */ -static int osap(struct tpm_buf *tb, struct osapsess *s, - const unsigned char *key, uint16_t type, uint32_t handle) -{ - unsigned char enonce[TPM_NONCE_SIZE]; - unsigned char ononce[TPM_NONCE_SIZE]; - int ret; - - ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE); - if (ret < 0) - return ret; - - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_COMMAND); - store32(tb, TPM_OSAP_SIZE); - store32(tb, TPM_ORD_OSAP); - store16(tb, type); - store32(tb, handle); - storebytes(tb, ononce, TPM_NONCE_SIZE); - - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); - if (ret < 0) - return ret; - - s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), - TPM_NONCE_SIZE); - memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + - TPM_NONCE_SIZE]), TPM_NONCE_SIZE); - return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, - enonce, TPM_NONCE_SIZE, ononce, 0, 0); -} - -/* - * Create an object independent authorisation protocol (oiap) session - */ -static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) -{ - int ret; - - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_COMMAND); - store32(tb, TPM_OIAP_SIZE); - store32(tb, TPM_ORD_OIAP); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); - if (ret < 0) - return ret; - - *handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], - TPM_NONCE_SIZE); - return 0; -} - -struct tpm_digests { - unsigned char encauth[SHA1_DIGEST_SIZE]; - unsigned char pubauth[SHA1_DIGEST_SIZE]; - unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; - unsigned char xorhash[SHA1_DIGEST_SIZE]; - unsigned char nonceodd[TPM_NONCE_SIZE]; -}; - -/* - * Have the TPM seal(encrypt) the trusted key, possibly based on - * Platform Configuration Registers (PCRs). AUTH1 for sealing key. - */ -static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, - uint32_t keyhandle, const unsigned char *keyauth, - const unsigned char *data, uint32_t datalen, - unsigned char *blob, uint32_t *bloblen, - const unsigned char *blobauth, - const unsigned char *pcrinfo, uint32_t pcrinfosize) -{ - struct osapsess sess; - struct tpm_digests *td; - unsigned char cont; - uint32_t ordinal; - uint32_t pcrsize; - uint32_t datsize; - int sealinfosize; - int encdatasize; - int storedsize; - int ret; - int i; - - /* alloc some work space for all the hashes */ - td = kmalloc(sizeof *td, GFP_KERNEL); - if (!td) - return -ENOMEM; - - /* get session for sealing key */ - ret = osap(tb, &sess, keyauth, keytype, keyhandle); - if (ret < 0) - goto out; - dump_sess(&sess); - - /* calculate encrypted authorization value */ - memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); - memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); - ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); - if (ret < 0) - goto out; - - ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE); - if (ret < 0) - goto out; - ordinal = htonl(TPM_ORD_SEAL); - datsize = htonl(datalen); - pcrsize = htonl(pcrinfosize); - cont = 0; - - /* encrypt data authorization key */ - for (i = 0; i < SHA1_DIGEST_SIZE; ++i) - td->encauth[i] = td->xorhash[i] ^ blobauth[i]; - - /* calculate authorization HMAC value */ - if (pcrinfosize == 0) { - /* no pcr info specified */ - ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, - sess.enonce, td->nonceodd, cont, - sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, - td->encauth, sizeof(uint32_t), &pcrsize, - sizeof(uint32_t), &datsize, datalen, data, 0, - 0); - } else { - /* pcr info specified */ - ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, - sess.enonce, td->nonceodd, cont, - sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, - td->encauth, sizeof(uint32_t), &pcrsize, - pcrinfosize, pcrinfo, sizeof(uint32_t), - &datsize, datalen, data, 0, 0); - } - if (ret < 0) - goto out; - - /* build and send the TPM request packet */ - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); - store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen); - store32(tb, TPM_ORD_SEAL); - store32(tb, keyhandle); - storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); - store32(tb, pcrinfosize); - storebytes(tb, pcrinfo, pcrinfosize); - store32(tb, datalen); - storebytes(tb, data, datalen); - store32(tb, sess.handle); - storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); - - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); - if (ret < 0) - goto out; - - /* calculate the size of the returned Blob */ - sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t)); - encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) + - sizeof(uint32_t) + sealinfosize); - storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize + - sizeof(uint32_t) + encdatasize; - - /* check the HMAC in the response */ - ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret, - SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, - 0); - - /* copy the returned blob to caller */ - if (!ret) { - memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize); - *bloblen = storedsize; - } -out: - kfree(td); - return ret; -} - -/* - * use the AUTH2_COMMAND form of unseal, to authorize both key and blob - */ -static int tpm_unseal(struct tpm_buf *tb, - uint32_t keyhandle, const unsigned char *keyauth, - const unsigned char *blob, int bloblen, - const unsigned char *blobauth, - unsigned char *data, unsigned int *datalen) -{ - unsigned char nonceodd[TPM_NONCE_SIZE]; - unsigned char enonce1[TPM_NONCE_SIZE]; - unsigned char enonce2[TPM_NONCE_SIZE]; - unsigned char authdata1[SHA1_DIGEST_SIZE]; - unsigned char authdata2[SHA1_DIGEST_SIZE]; - uint32_t authhandle1 = 0; - uint32_t authhandle2 = 0; - unsigned char cont = 0; - uint32_t ordinal; - uint32_t keyhndl; - int ret; - - /* sessions for unsealing key and data */ - ret = oiap(tb, &authhandle1, enonce1); - if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); - return ret; - } - ret = oiap(tb, &authhandle2, enonce2); - if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); - return ret; - } - - ordinal = htonl(TPM_ORD_UNSEAL); - keyhndl = htonl(SRKHANDLE); - ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE); - if (ret < 0) { - pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); - return ret; - } - ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, - enonce1, nonceodd, cont, sizeof(uint32_t), - &ordinal, bloblen, blob, 0, 0); - if (ret < 0) - return ret; - ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE, - enonce2, nonceodd, cont, sizeof(uint32_t), - &ordinal, bloblen, blob, 0, 0); - if (ret < 0) - return ret; - - /* build and send TPM request packet */ - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); - store32(tb, TPM_UNSEAL_SIZE + bloblen); - store32(tb, TPM_ORD_UNSEAL); - store32(tb, keyhandle); - storebytes(tb, blob, bloblen); - store32(tb, authhandle1); - storebytes(tb, nonceodd, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, authdata1, SHA1_DIGEST_SIZE); - store32(tb, authhandle2); - storebytes(tb, nonceodd, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, authdata2, SHA1_DIGEST_SIZE); - - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); - if (ret < 0) { - pr_info("trusted_key: authhmac failed (%d)\n", ret); - return ret; - } - - *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); - ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, - keyauth, SHA1_DIGEST_SIZE, - blobauth, SHA1_DIGEST_SIZE, - sizeof(uint32_t), TPM_DATA_OFFSET, - *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, - 0); - if (ret < 0) { - pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret); - return ret; - } - memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); - return 0; -} - -/* - * Have the TPM seal(encrypt) the symmetric key - */ -static int key_seal(struct trusted_key_payload *p, - struct trusted_key_options *o) -{ - struct tpm_buf *tb; - int ret; - - tb = kzalloc(sizeof *tb, GFP_KERNEL); - if (!tb) - return -ENOMEM; - - /* include migratable flag at end of sealed key */ - p->key[p->key_len] = p->migratable; - - ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth, - p->key, p->key_len + 1, p->blob, &p->blob_len, - o->blobauth, o->pcrinfo, o->pcrinfo_len); - if (ret < 0) - pr_info("trusted_key: srkseal failed (%d)\n", ret); - - kfree(tb); - return ret; -} - -/* - * Have the TPM unseal(decrypt) the symmetric key - */ -static int key_unseal(struct trusted_key_payload *p, - struct trusted_key_options *o) -{ - struct tpm_buf *tb; - int ret; - - tb = kzalloc(sizeof *tb, GFP_KERNEL); - if (!tb) - return -ENOMEM; - - ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len, - o->blobauth, p->key, &p->key_len); - if (ret < 0) - pr_info("trusted_key: srkunseal failed (%d)\n", ret); - else - /* pull migratable flag out of sealed key */ - p->migratable = p->key[--p->key_len]; - - kfree(tb); - return ret; -} - -enum { - Opt_err = -1, - Opt_new, Opt_load, Opt_update, - Opt_keyhandle, Opt_keyauth, Opt_blobauth, - Opt_pcrinfo, Opt_pcrlock, Opt_migratable -}; - -static const match_table_t key_tokens = { - {Opt_new, "new"}, - {Opt_load, "load"}, - {Opt_update, "update"}, - {Opt_keyhandle, "keyhandle=%s"}, - {Opt_keyauth, "keyauth=%s"}, - {Opt_blobauth, "blobauth=%s"}, - {Opt_pcrinfo, "pcrinfo=%s"}, - {Opt_pcrlock, "pcrlock=%s"}, - {Opt_migratable, "migratable=%s"}, - {Opt_err, NULL} -}; - -/* can have zero or more token= options */ -static int getoptions(char *c, struct trusted_key_payload *pay, - struct trusted_key_options *opt) -{ - substring_t args[MAX_OPT_ARGS]; - char *p = c; - int token; - int res; - unsigned long handle; - unsigned long lock; - - while ((p = strsep(&c, " \t"))) { - if (*p == '\0' || *p == ' ' || *p == '\t') - continue; - token = match_token(p, key_tokens, args); - - switch (token) { - case Opt_pcrinfo: - opt->pcrinfo_len = strlen(args[0].from) / 2; - if (opt->pcrinfo_len > MAX_PCRINFO_SIZE) - return -EINVAL; - res = hex2bin(opt->pcrinfo, args[0].from, - opt->pcrinfo_len); - if (res < 0) - return -EINVAL; - break; - case Opt_keyhandle: - res = strict_strtoul(args[0].from, 16, &handle); - if (res < 0) - return -EINVAL; - opt->keytype = SEAL_keytype; - opt->keyhandle = handle; - break; - case Opt_keyauth: - if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) - return -EINVAL; - res = hex2bin(opt->keyauth, args[0].from, - SHA1_DIGEST_SIZE); - if (res < 0) - return -EINVAL; - break; - case Opt_blobauth: - if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) - return -EINVAL; - res = hex2bin(opt->blobauth, args[0].from, - SHA1_DIGEST_SIZE); - if (res < 0) - return -EINVAL; - break; - case Opt_migratable: - if (*args[0].from == '0') - pay->migratable = 0; - else - return -EINVAL; - break; - case Opt_pcrlock: - res = strict_strtoul(args[0].from, 10, &lock); - if (res < 0) - return -EINVAL; - opt->pcrlock = lock; - break; - default: - return -EINVAL; - } - } - return 0; -} - -/* - * datablob_parse - parse the keyctl data and fill in the - * payload and options structures - * - * On success returns 0, otherwise -EINVAL. - */ -static int datablob_parse(char *datablob, struct trusted_key_payload *p, - struct trusted_key_options *o) -{ - substring_t args[MAX_OPT_ARGS]; - long keylen; - int ret = -EINVAL; - int key_cmd; - char *c; - - /* main command */ - c = strsep(&datablob, " \t"); - if (!c) - return -EINVAL; - key_cmd = match_token(c, key_tokens, args); - switch (key_cmd) { - case Opt_new: - /* first argument is key size */ - c = strsep(&datablob, " \t"); - if (!c) - return -EINVAL; - ret = strict_strtol(c, 10, &keylen); - if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) - return -EINVAL; - p->key_len = keylen; - ret = getoptions(datablob, p, o); - if (ret < 0) - return ret; - ret = Opt_new; - break; - case Opt_load: - /* first argument is sealed blob */ - c = strsep(&datablob, " \t"); - if (!c) - return -EINVAL; - p->blob_len = strlen(c) / 2; - if (p->blob_len > MAX_BLOB_SIZE) - return -EINVAL; - ret = hex2bin(p->blob, c, p->blob_len); - if (ret < 0) - return -EINVAL; - ret = getoptions(datablob, p, o); - if (ret < 0) - return ret; - ret = Opt_load; - break; - case Opt_update: - /* all arguments are options */ - ret = getoptions(datablob, p, o); - if (ret < 0) - return ret; - ret = Opt_update; - break; - case Opt_err: - return -EINVAL; - break; - } - return ret; -} - -static struct trusted_key_options *trusted_options_alloc(void) -{ - struct trusted_key_options *options; - - options = kzalloc(sizeof *options, GFP_KERNEL); - if (options) { - /* set any non-zero defaults */ - options->keytype = SRK_keytype; - options->keyhandle = SRKHANDLE; - } - return options; -} - -static struct trusted_key_payload *trusted_payload_alloc(struct key *key) -{ - struct trusted_key_payload *p = NULL; - int ret; - - ret = key_payload_reserve(key, sizeof *p); - if (ret < 0) - return p; - p = kzalloc(sizeof *p, GFP_KERNEL); - if (p) - p->migratable = 1; /* migratable by default */ - return p; -} - -/* - * trusted_instantiate - create a new trusted key - * - * Unseal an existing trusted blob or, for a new key, get a - * random key, then seal and create a trusted key-type key, - * adding it to the specified keyring. - * - * On success, return 0. Otherwise return errno. - */ -static int trusted_instantiate(struct key *key, const void *data, - size_t datalen) -{ - struct trusted_key_payload *payload = NULL; - struct trusted_key_options *options = NULL; - char *datablob; - int ret = 0; - int key_cmd; - - if (datalen <= 0 || datalen > 32767 || !data) - return -EINVAL; - - datablob = kmalloc(datalen + 1, GFP_KERNEL); - if (!datablob) - return -ENOMEM; - memcpy(datablob, data, datalen); - datablob[datalen] = '\0'; - - options = trusted_options_alloc(); - if (!options) { - ret = -ENOMEM; - goto out; - } - payload = trusted_payload_alloc(key); - if (!payload) { - ret = -ENOMEM; - goto out; - } - - key_cmd = datablob_parse(datablob, payload, options); - if (key_cmd < 0) { - ret = key_cmd; - goto out; - } - - dump_payload(payload); - dump_options(options); - - switch (key_cmd) { - case Opt_load: - ret = key_unseal(payload, options); - dump_payload(payload); - dump_options(options); - if (ret < 0) - pr_info("trusted_key: key_unseal failed (%d)\n", ret); - break; - case Opt_new: - ret = my_get_random(payload->key, payload->key_len); - if (ret < 0) { - pr_info("trusted_key: key_create failed (%d)\n", ret); - goto out; - } - ret = key_seal(payload, options); - if (ret < 0) - pr_info("trusted_key: key_seal failed (%d)\n", ret); - break; - default: - ret = -EINVAL; - goto out; - } - if (!ret && options->pcrlock) - ret = pcrlock(options->pcrlock); -out: - kfree(datablob); - kfree(options); - if (!ret) - rcu_assign_keypointer(key, payload); - else - kfree(payload); - return ret; -} - -static void trusted_rcu_free(struct rcu_head *rcu) -{ - struct trusted_key_payload *p; - - p = container_of(rcu, struct trusted_key_payload, rcu); - memset(p->key, 0, p->key_len); - kfree(p); -} - -/* - * trusted_update - reseal an existing key with new PCR values - */ -static int trusted_update(struct key *key, const void *data, size_t datalen) -{ - struct trusted_key_payload *p = key->payload.data; - struct trusted_key_payload *new_p; - struct trusted_key_options *new_o; - char *datablob; - int ret = 0; - - if (!p->migratable) - return -EPERM; - if (datalen <= 0 || datalen > 32767 || !data) - return -EINVAL; - - datablob = kmalloc(datalen + 1, GFP_KERNEL); - if (!datablob) - return -ENOMEM; - new_o = trusted_options_alloc(); - if (!new_o) { - ret = -ENOMEM; - goto out; - } - new_p = trusted_payload_alloc(key); - if (!new_p) { - ret = -ENOMEM; - goto out; - } - - memcpy(datablob, data, datalen); - datablob[datalen] = '\0'; - ret = datablob_parse(datablob, new_p, new_o); - if (ret != Opt_update) { - ret = -EINVAL; - kfree(new_p); - goto out; - } - /* copy old key values, and reseal with new pcrs */ - new_p->migratable = p->migratable; - new_p->key_len = p->key_len; - memcpy(new_p->key, p->key, p->key_len); - dump_payload(p); - dump_payload(new_p); - - ret = key_seal(new_p, new_o); - if (ret < 0) { - pr_info("trusted_key: key_seal failed (%d)\n", ret); - kfree(new_p); - goto out; - } - if (new_o->pcrlock) { - ret = pcrlock(new_o->pcrlock); - if (ret < 0) { - pr_info("trusted_key: pcrlock failed (%d)\n", ret); - kfree(new_p); - goto out; - } - } - rcu_assign_keypointer(key, new_p); - call_rcu(&p->rcu, trusted_rcu_free); -out: - kfree(datablob); - kfree(new_o); - return ret; -} - -/* - * trusted_read - copy the sealed blob data to userspace in hex. - * On success, return to userspace the trusted key datablob size. - */ -static long trusted_read(const struct key *key, char __user *buffer, - size_t buflen) -{ - struct trusted_key_payload *p; - char *ascii_buf; - char *bufp; - int i; - - p = rcu_dereference_key(key); - if (!p) - return -EINVAL; - if (!buffer || buflen <= 0) - return 2 * p->blob_len; - ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL); - if (!ascii_buf) - return -ENOMEM; - - bufp = ascii_buf; - for (i = 0; i < p->blob_len; i++) - bufp = hex_byte_pack(bufp, p->blob[i]); - if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) { - kfree(ascii_buf); - return -EFAULT; - } - kfree(ascii_buf); - return 2 * p->blob_len; -} - -/* - * trusted_destroy - before freeing the key, clear the decrypted data - */ -static void trusted_destroy(struct key *key) -{ - struct trusted_key_payload *p = key->payload.data; - - if (!p) - return; - memset(p->key, 0, p->key_len); - kfree(key->payload.data); -} - -struct key_type key_type_trusted = { - .name = "trusted", - .instantiate = trusted_instantiate, - .update = trusted_update, - .match = user_match, - .destroy = trusted_destroy, - .describe = user_describe, - .read = trusted_read, -}; - -EXPORT_SYMBOL_GPL(key_type_trusted); - -static void trusted_shash_release(void) -{ - if (hashalg) - crypto_free_shash(hashalg); - if (hmacalg) - crypto_free_shash(hmacalg); -} - -static int __init trusted_shash_alloc(void) -{ - int ret; - - hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hmacalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", - hmac_alg); - return PTR_ERR(hmacalg); - } - - hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hashalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", - hash_alg); - ret = PTR_ERR(hashalg); - goto hashalg_fail; - } - - return 0; - -hashalg_fail: - crypto_free_shash(hmacalg); - return ret; -} - -static int __init init_trusted(void) -{ - int ret; - - ret = trusted_shash_alloc(); - if (ret < 0) - return ret; - ret = register_key_type(&key_type_trusted); - if (ret < 0) - trusted_shash_release(); - return ret; -} - -static void __exit cleanup_trusted(void) -{ - trusted_shash_release(); - unregister_key_type(&key_type_trusted); -} - -late_initcall(init_trusted); -module_exit(cleanup_trusted); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/security/keys/trusted.h b/ANDROID_3.4.5/security/keys/trusted.h deleted file mode 100644 index 3249fbd2..00000000 --- a/ANDROID_3.4.5/security/keys/trusted.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef __TRUSTED_KEY_H -#define __TRUSTED_KEY_H - -/* implementation specific TPM constants */ -#define MAX_PCRINFO_SIZE 64 -#define MAX_BUF_SIZE 512 -#define TPM_GETRANDOM_SIZE 14 -#define TPM_OSAP_SIZE 36 -#define TPM_OIAP_SIZE 10 -#define TPM_SEAL_SIZE 87 -#define TPM_UNSEAL_SIZE 104 -#define TPM_SIZE_OFFSET 2 -#define TPM_RETURN_OFFSET 6 -#define TPM_DATA_OFFSET 10 - -#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) -#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) -#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) - -struct tpm_buf { - int len; - unsigned char data[MAX_BUF_SIZE]; -}; - -#define INIT_BUF(tb) (tb->len = 0) - -struct osapsess { - uint32_t handle; - unsigned char secret[SHA1_DIGEST_SIZE]; - unsigned char enonce[TPM_NONCE_SIZE]; -}; - -/* discrete values, but have to store in uint16_t for TPM use */ -enum { - SEAL_keytype = 1, - SRK_keytype = 4 -}; - -struct trusted_key_options { - uint16_t keytype; - uint32_t keyhandle; - unsigned char keyauth[SHA1_DIGEST_SIZE]; - unsigned char blobauth[SHA1_DIGEST_SIZE]; - uint32_t pcrinfo_len; - unsigned char pcrinfo[MAX_PCRINFO_SIZE]; - int pcrlock; -}; - -#define TPM_DEBUG 0 - -#if TPM_DEBUG -static inline void dump_options(struct trusted_key_options *o) -{ - pr_info("trusted_key: sealing key type %d\n", o->keytype); - pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle); - pr_info("trusted_key: pcrlock %d\n", o->pcrlock); - pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len); - print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, - 16, 1, o->pcrinfo, o->pcrinfo_len, 0); -} - -static inline void dump_payload(struct trusted_key_payload *p) -{ - pr_info("trusted_key: key_len %d\n", p->key_len); - print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE, - 16, 1, p->key, p->key_len, 0); - pr_info("trusted_key: bloblen %d\n", p->blob_len); - print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE, - 16, 1, p->blob, p->blob_len, 0); - pr_info("trusted_key: migratable %d\n", p->migratable); -} - -static inline void dump_sess(struct osapsess *s) -{ - print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, - 16, 1, &s->handle, 4, 0); - pr_info("trusted-key: secret:\n"); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, - 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); - pr_info("trusted-key: enonce:\n"); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, - 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); -} - -static inline void dump_tpm_buf(unsigned char *buf) -{ - int len; - - pr_info("\ntrusted-key: tpm buffer\n"); - len = LOAD32(buf, TPM_SIZE_OFFSET); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); -} -#else -static inline void dump_options(struct trusted_key_options *o) -{ -} - -static inline void dump_payload(struct trusted_key_payload *p) -{ -} - -static inline void dump_sess(struct osapsess *s) -{ -} - -static inline void dump_tpm_buf(unsigned char *buf) -{ -} -#endif - -static inline void store8(struct tpm_buf *buf, const unsigned char value) -{ - buf->data[buf->len++] = value; -} - -static inline void store16(struct tpm_buf *buf, const uint16_t value) -{ - *(uint16_t *) & buf->data[buf->len] = htons(value); - buf->len += sizeof value; -} - -static inline void store32(struct tpm_buf *buf, const uint32_t value) -{ - *(uint32_t *) & buf->data[buf->len] = htonl(value); - buf->len += sizeof value; -} - -static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, - const int len) -{ - memcpy(buf->data + buf->len, in, len); - buf->len += len; -} -#endif diff --git a/ANDROID_3.4.5/security/keys/user_defined.c b/ANDROID_3.4.5/security/keys/user_defined.c deleted file mode 100644 index c7660a25..00000000 --- a/ANDROID_3.4.5/security/keys/user_defined.c +++ /dev/null @@ -1,228 +0,0 @@ -/* user_defined.c: user defined key type - * - * Copyright (C) 2004 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/slab.h> -#include <linux/seq_file.h> -#include <linux/err.h> -#include <keys/user-type.h> -#include <asm/uaccess.h> -#include "internal.h" - -static int logon_vet_description(const char *desc); - -/* - * user defined keys take an arbitrary string as the description and an - * arbitrary blob of data as the payload - */ -struct key_type key_type_user = { - .name = "user", - .instantiate = user_instantiate, - .update = user_update, - .match = user_match, - .revoke = user_revoke, - .destroy = user_destroy, - .describe = user_describe, - .read = user_read, -}; - -EXPORT_SYMBOL_GPL(key_type_user); - -/* - * This key type is essentially the same as key_type_user, but it does - * not define a .read op. This is suitable for storing username and - * password pairs in the keyring that you do not want to be readable - * from userspace. - */ -struct key_type key_type_logon = { - .name = "logon", - .instantiate = user_instantiate, - .update = user_update, - .match = user_match, - .revoke = user_revoke, - .destroy = user_destroy, - .describe = user_describe, - .vet_description = logon_vet_description, -}; -EXPORT_SYMBOL_GPL(key_type_logon); - -/* - * instantiate a user defined key - */ -int user_instantiate(struct key *key, const void *data, size_t datalen) -{ - struct user_key_payload *upayload; - int ret; - - ret = -EINVAL; - if (datalen <= 0 || datalen > 32767 || !data) - goto error; - - ret = key_payload_reserve(key, datalen); - if (ret < 0) - goto error; - - ret = -ENOMEM; - upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); - if (!upayload) - goto error; - - /* attach the data */ - upayload->datalen = datalen; - memcpy(upayload->data, data, datalen); - rcu_assign_keypointer(key, upayload); - ret = 0; - -error: - return ret; -} - -EXPORT_SYMBOL_GPL(user_instantiate); - -/* - * update a user defined key - * - the key's semaphore is write-locked - */ -int user_update(struct key *key, const void *data, size_t datalen) -{ - struct user_key_payload *upayload, *zap; - int ret; - - ret = -EINVAL; - if (datalen <= 0 || datalen > 32767 || !data) - goto error; - - /* construct a replacement payload */ - ret = -ENOMEM; - upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); - if (!upayload) - goto error; - - upayload->datalen = datalen; - memcpy(upayload->data, data, datalen); - - /* check the quota and attach the new data */ - zap = upayload; - - ret = key_payload_reserve(key, datalen); - - if (ret == 0) { - /* attach the new data, displacing the old */ - zap = key->payload.data; - rcu_assign_keypointer(key, upayload); - key->expiry = 0; - } - - if (zap) - kfree_rcu(zap, rcu); - -error: - return ret; -} - -EXPORT_SYMBOL_GPL(user_update); - -/* - * match users on their name - */ -int user_match(const struct key *key, const void *description) -{ - return strcmp(key->description, description) == 0; -} - -EXPORT_SYMBOL_GPL(user_match); - -/* - * dispose of the links from a revoked keyring - * - called with the key sem write-locked - */ -void user_revoke(struct key *key) -{ - struct user_key_payload *upayload = key->payload.data; - - /* clear the quota */ - key_payload_reserve(key, 0); - - if (upayload) { - rcu_assign_keypointer(key, NULL); - kfree_rcu(upayload, rcu); - } -} - -EXPORT_SYMBOL(user_revoke); - -/* - * dispose of the data dangling from the corpse of a user key - */ -void user_destroy(struct key *key) -{ - struct user_key_payload *upayload = key->payload.data; - - kfree(upayload); -} - -EXPORT_SYMBOL_GPL(user_destroy); - -/* - * describe the user key - */ -void user_describe(const struct key *key, struct seq_file *m) -{ - seq_puts(m, key->description); - if (key_is_instantiated(key)) - seq_printf(m, ": %u", key->datalen); -} - -EXPORT_SYMBOL_GPL(user_describe); - -/* - * read the key data - * - the key's semaphore is read-locked - */ -long user_read(const struct key *key, char __user *buffer, size_t buflen) -{ - struct user_key_payload *upayload; - long ret; - - upayload = rcu_dereference_key(key); - ret = upayload->datalen; - - /* we can return the data as is */ - if (buffer && buflen > 0) { - if (buflen > upayload->datalen) - buflen = upayload->datalen; - - if (copy_to_user(buffer, upayload->data, buflen) != 0) - ret = -EFAULT; - } - - return ret; -} - -EXPORT_SYMBOL_GPL(user_read); - -/* Vet the description for a "logon" key */ -static int logon_vet_description(const char *desc) -{ - char *p; - - /* require a "qualified" description string */ - p = strchr(desc, ':'); - if (!p) - return -EINVAL; - - /* also reject description with ':' as first char */ - if (p == desc) - return -EINVAL; - - return 0; -} |