KEYS: Implement a big key type that can save to tmpfs
[deliverable/linux.git] / security / keys / big_key.c
CommitLineData
ab3c3587
DH
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);
This page took 0.030405 seconds and 5 git commands to generate.