aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-09-24 05:35:18 -0400
committerDavid Howells <dhowells@redhat.com>2013-09-24 05:35:18 -0400
commitab3c3587f8cda9083209a61dbe3a4407d3cada10 (patch)
treec479efb4b7a834ee5d3b74d81560a2214c463431
parentb2a4df200d570b2c33a57e1ebfa5896e4bc81b69 (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.h25
-rw-r--r--include/linux/key.h1
-rw-r--r--security/keys/Kconfig11
-rw-r--r--security/keys/Makefile1
-rw-r--r--security/keys/big_key.c204
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
17extern struct key_type key_type_big_key;
18
19extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
20extern void big_key_revoke(struct key *key);
21extern void big_key_destroy(struct key *key);
22extern void big_key_describe(const struct key *big_key, struct seq_file *m);
23extern 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
23config 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
23config TRUSTED_KEYS 34config 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#
25obj-$(CONFIG_BIG_KEYS) += big_key.o
25obj-$(CONFIG_TRUSTED_KEYS) += trusted.o 26obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
26obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ 27obj-$(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
21MODULE_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 */
34struct 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 */
48int 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
102err_fput:
103 fput(file);
104err_quota:
105 key_payload_reserve(key, 0);
106error:
107 return ret;
108}
109
110/*
111 * dispose of the links from a revoked keyring
112 * - called with the key sem write-locked
113 */
114void 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);
122}
123
124/*
125 * dispose of the data dangling from the corpse of a big_key key
126 */
127void big_key_destroy(struct key *key)
128{
129 if (key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) {
130 struct path *path = (struct path *)&key->payload.data2;
131 path_put(path);
132 path->mnt = NULL;
133 path->dentry = NULL;
134 } else {
135 kfree(key->payload.data);
136 key->payload.data = NULL;
137 }
138}
139
140/*
141 * describe the big_key key
142 */
143void big_key_describe(const struct key *key, struct seq_file *m)
144{
145 unsigned long datalen = key->type_data.x[1];
146
147 seq_puts(m, key->description);
148
149 if (key_is_instantiated(key))
150 seq_printf(m, ": %lu [%s]",
151 datalen,
152 datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
153}
154
155/*
156 * read the key data
157 * - the key's semaphore is read-locked
158 */
159long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
160{
161 unsigned long datalen = key->type_data.x[1];
162 long ret;
163
164 if (!buffer || buflen < datalen)
165 return datalen;
166
167 if (datalen > BIG_KEY_FILE_THRESHOLD) {
168 struct path *path = (struct path *)&key->payload.data2;
169 struct file *file;
170 loff_t pos;
171
172 file = dentry_open(path, O_RDONLY, current_cred());
173 if (IS_ERR(file))
174 return PTR_ERR(file);
175
176 pos = 0;
177 ret = vfs_read(file, buffer, datalen, &pos);
178 fput(file);
179 if (ret >= 0 && ret != datalen)
180 ret = -EIO;
181 } else {
182 ret = datalen;
183 if (copy_to_user(buffer, key->payload.data, datalen) != 0)
184 ret = -EFAULT;
185 }
186
187 return ret;
188}
189
190/*
191 * Module stuff
192 */
193static int __init big_key_init(void)
194{
195 return register_key_type(&key_type_big_key);
196}
197
198static void __exit big_key_cleanup(void)
199{
200 unregister_key_type(&key_type_big_key);
201}
202
203module_init(big_key_init);
204module_exit(big_key_cleanup);