diff options
| author | David Howells <dhowells@redhat.com> | 2013-09-24 05:35:18 -0400 |
|---|---|---|
| committer | David Howells <dhowells@redhat.com> | 2013-09-24 05:35:18 -0400 |
| commit | ab3c3587f8cda9083209a61dbe3a4407d3cada10 (patch) | |
| tree | c479efb4b7a834ee5d3b74d81560a2214c463431 | |
| parent | b2a4df200d570b2c33a57e1ebfa5896e4bc81b69 (diff) | |
KEYS: Implement a big key type that can save to tmpfs
Implement a big key type that can save its contents to tmpfs and thus
swapspace when memory is tight. This is useful for Kerberos ticket caches.
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Simo Sorce <simo@redhat.com>
| -rw-r--r-- | include/keys/big_key-type.h | 25 | ||||
| -rw-r--r-- | include/linux/key.h | 1 | ||||
| -rw-r--r-- | security/keys/Kconfig | 11 | ||||
| -rw-r--r-- | security/keys/Makefile | 1 | ||||
| -rw-r--r-- | security/keys/big_key.c | 204 |
5 files changed, 242 insertions, 0 deletions
diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h new file mode 100644 index 000000000000..d69bc8af3292 --- /dev/null +++ b/include/keys/big_key-type.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* Big capacity key type. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _KEYS_BIG_KEY_TYPE_H | ||
| 13 | #define _KEYS_BIG_KEY_TYPE_H | ||
| 14 | |||
| 15 | #include <linux/key-type.h> | ||
| 16 | |||
| 17 | extern struct key_type key_type_big_key; | ||
| 18 | |||
| 19 | extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | ||
| 20 | extern void big_key_revoke(struct key *key); | ||
| 21 | extern void big_key_destroy(struct key *key); | ||
| 22 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); | ||
| 23 | extern long big_key_read(const struct key *key, char __user *buffer, size_t buflen); | ||
| 24 | |||
| 25 | #endif /* _KEYS_BIG_KEY_TYPE_H */ | ||
diff --git a/include/linux/key.h b/include/linux/key.h index 2417f789d29b..010dbb618aca 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -201,6 +201,7 @@ struct key { | |||
| 201 | unsigned long value; | 201 | unsigned long value; |
| 202 | void __rcu *rcudata; | 202 | void __rcu *rcudata; |
| 203 | void *data; | 203 | void *data; |
| 204 | void *data2[2]; | ||
| 204 | } payload; | 205 | } payload; |
| 205 | struct assoc_array keys; | 206 | struct assoc_array keys; |
| 206 | }; | 207 | }; |
diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 15e0dfe8c80f..b56362275ec8 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig | |||
| @@ -20,6 +20,17 @@ config KEYS | |||
| 20 | 20 | ||
| 21 | If you are unsure as to whether this is required, answer N. | 21 | If you are unsure as to whether this is required, answer N. |
| 22 | 22 | ||
| 23 | config BIG_KEYS | ||
| 24 | tristate "Large payload keys" | ||
| 25 | depends on KEYS | ||
| 26 | depends on TMPFS | ||
| 27 | help | ||
| 28 | This option provides support for holding large keys within the kernel | ||
| 29 | (for example Kerberos ticket caches). The data may be stored out to | ||
| 30 | swapspace by tmpfs. | ||
| 31 | |||
| 32 | If you are unsure as to whether this is required, answer N. | ||
| 33 | |||
| 23 | config TRUSTED_KEYS | 34 | config TRUSTED_KEYS |
| 24 | tristate "TRUSTED KEYS" | 35 | tristate "TRUSTED KEYS" |
| 25 | depends on KEYS && TCG_TPM | 36 | depends on KEYS && TCG_TPM |
diff --git a/security/keys/Makefile b/security/keys/Makefile index 504aaa008388..c487c77a00be 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
| @@ -22,5 +22,6 @@ obj-$(CONFIG_SYSCTL) += sysctl.o | |||
| 22 | # | 22 | # |
| 23 | # Key types | 23 | # Key types |
| 24 | # | 24 | # |
| 25 | obj-$(CONFIG_BIG_KEYS) += big_key.o | ||
| 25 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | 26 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o |
| 26 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | 27 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c new file mode 100644 index 000000000000..5f9defc4a807 --- /dev/null +++ b/security/keys/big_key.c | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | /* Large capacity key type | ||
| 2 | * | ||
| 3 | * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/seq_file.h> | ||
| 15 | #include <linux/file.h> | ||
| 16 | #include <linux/shmem_fs.h> | ||
| 17 | #include <linux/err.h> | ||
| 18 | #include <keys/user-type.h> | ||
| 19 | #include <keys/big_key-type.h> | ||
| 20 | |||
| 21 | MODULE_LICENSE("GPL"); | ||
| 22 | |||
| 23 | /* | ||
| 24 | * If the data is under this limit, there's no point creating a shm file to | ||
| 25 | * hold it as the permanently resident metadata for the shmem fs will be at | ||
| 26 | * least as large as the data. | ||
| 27 | */ | ||
| 28 | #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry)) | ||
| 29 | |||
| 30 | /* | ||
| 31 | * big_key defined keys take an arbitrary string as the description and an | ||
| 32 | * arbitrary blob of data as the payload | ||
| 33 | */ | ||
| 34 | struct key_type key_type_big_key = { | ||
| 35 | .name = "big_key", | ||
| 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | ||
| 37 | .instantiate = big_key_instantiate, | ||
| 38 | .match = user_match, | ||
| 39 | .revoke = big_key_revoke, | ||
| 40 | .destroy = big_key_destroy, | ||
| 41 | .describe = big_key_describe, | ||
| 42 | .read = big_key_read, | ||
| 43 | }; | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Instantiate a big key | ||
| 47 | */ | ||
| 48 | int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
| 49 | { | ||
| 50 | struct path *path = (struct path *)&key->payload.data2; | ||
| 51 | struct file *file; | ||
| 52 | ssize_t written; | ||
| 53 | size_t datalen = prep->datalen; | ||
| 54 | int ret; | ||
| 55 | |||
| 56 | ret = -EINVAL; | ||
| 57 | if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) | ||
| 58 | goto error; | ||
| 59 | |||
| 60 | /* Set an arbitrary quota */ | ||
| 61 | ret = key_payload_reserve(key, 16); | ||
| 62 | if (ret < 0) | ||
| 63 | goto error; | ||
| 64 | |||
| 65 | key->type_data.x[1] = datalen; | ||
| 66 | |||
| 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | ||
| 68 | /* Create a shmem file to store the data in. This will permit the data | ||
| 69 | * to be swapped out if needed. | ||
| 70 | * | ||
| 71 | * TODO: Encrypt the stored data with a temporary key. | ||
| 72 | */ | ||
| 73 | file = shmem_file_setup("", datalen, 0); | ||
| 74 | if (IS_ERR(file)) | ||
| 75 | goto err_quota; | ||
| 76 | |||
| 77 | written = kernel_write(file, prep->data, prep->datalen, 0); | ||
| 78 | if (written != datalen) { | ||
| 79 | if (written >= 0) | ||
| 80 | ret = -ENOMEM; | ||
| 81 | goto err_fput; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* Pin the mount and dentry to the key so that we can open it again | ||
| 85 | * later | ||
| 86 | */ | ||
| 87 | *path = file->f_path; | ||
| 88 | path_get(path); | ||
| 89 | fput(file); | ||
| 90 | } else { | ||
| 91 | /* Just store the data in a buffer */ | ||
| 92 | void *data = kmalloc(datalen, GFP_KERNEL); | ||
| 93 | if (!data) { | ||
| 94 | ret = -ENOMEM; | ||
| 95 | goto err_quota; | ||
| 96 | } | ||
| 97 | |||
| 98 | key->payload.data = memcpy(data, prep->data, prep->datalen); | ||
| 99 | } | ||
| 100 | return 0; | ||
| 101 | |||
| 102 | err_fput: | ||
| 103 | fput(file); | ||
| 104 | err_quota: | ||
| 105 | key_payload_reserve(key, 0); | ||
| 106 | error: | ||
| 107 | return ret; | ||
| 108 | } | ||
| 109 | |||
| 110 | /* | ||
| 111 | * dispose of the links from a revoked keyring | ||
| 112 | * - called with the key sem write-locked | ||
| 113 | */ | ||
| 114 | void big_key_revoke(struct key *key) | ||
| 115 | { | ||
| 116 | struct path *path = (struct path *)&key->payload.data2; | ||
| 117 | |||
| 118 | /* clear the quota */ | ||
| 119 | key_payload_reserve(key, 0); | ||
| 120 | if (key_is_instantiated(key) && key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) | ||
| 121 | vfs_truncate(path, 0); | ||
