summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/security/keys
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/security/keys')
-rw-r--r--ANDROID_3.4.5/security/keys/Makefile20
-rw-r--r--ANDROID_3.4.5/security/keys/compat.c141
-rw-r--r--ANDROID_3.4.5/security/keys/encrypted-keys/Makefile10
-rw-r--r--ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.c81
-rw-r--r--ANDROID_3.4.5/security/keys/encrypted-keys/ecryptfs_format.h30
-rw-r--r--ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.c1038
-rw-r--r--ANDROID_3.4.5/security/keys/encrypted-keys/encrypted.h66
-rw-r--r--ANDROID_3.4.5/security/keys/encrypted-keys/masterkey_trusted.c47
-rw-r--r--ANDROID_3.4.5/security/keys/gc.c390
-rw-r--r--ANDROID_3.4.5/security/keys/internal.h251
-rw-r--r--ANDROID_3.4.5/security/keys/key.c1031
-rw-r--r--ANDROID_3.4.5/security/keys/keyctl.c1628
-rw-r--r--ANDROID_3.4.5/security/keys/keyring.c1232
-rw-r--r--ANDROID_3.4.5/security/keys/permission.c118
-rw-r--r--ANDROID_3.4.5/security/keys/proc.c352
-rw-r--r--ANDROID_3.4.5/security/keys/process_keys.c878
-rw-r--r--ANDROID_3.4.5/security/keys/request_key.c713
-rw-r--r--ANDROID_3.4.5/security/keys/request_key_auth.c267
-rw-r--r--ANDROID_3.4.5/security/keys/sysctl.c65
-rw-r--r--ANDROID_3.4.5/security/keys/trusted.c1191
-rw-r--r--ANDROID_3.4.5/security/keys/trusted.h134
-rw-r--r--ANDROID_3.4.5/security/keys/user_defined.c228
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;
-}