These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / security / keys / big_key.c
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  * Layout of key payload words.
25  */
26 enum {
27         big_key_data,
28         big_key_path,
29         big_key_path_2nd_part,
30         big_key_len,
31 };
32
33 /*
34  * If the data is under this limit, there's no point creating a shm file to
35  * hold it as the permanently resident metadata for the shmem fs will be at
36  * least as large as the data.
37  */
38 #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
39
40 /*
41  * big_key defined keys take an arbitrary string as the description and an
42  * arbitrary blob of data as the payload
43  */
44 struct key_type key_type_big_key = {
45         .name                   = "big_key",
46         .preparse               = big_key_preparse,
47         .free_preparse          = big_key_free_preparse,
48         .instantiate            = generic_key_instantiate,
49         .revoke                 = big_key_revoke,
50         .destroy                = big_key_destroy,
51         .describe               = big_key_describe,
52         .read                   = big_key_read,
53 };
54
55 /*
56  * Preparse a big key
57  */
58 int big_key_preparse(struct key_preparsed_payload *prep)
59 {
60         struct path *path = (struct path *)&prep->payload.data[big_key_path];
61         struct file *file;
62         ssize_t written;
63         size_t datalen = prep->datalen;
64         int ret;
65
66         ret = -EINVAL;
67         if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
68                 goto error;
69
70         /* Set an arbitrary quota */
71         prep->quotalen = 16;
72
73         prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
74
75         if (datalen > BIG_KEY_FILE_THRESHOLD) {
76                 /* Create a shmem file to store the data in.  This will permit the data
77                  * to be swapped out if needed.
78                  *
79                  * TODO: Encrypt the stored data with a temporary key.
80                  */
81                 file = shmem_kernel_file_setup("", datalen, 0);
82                 if (IS_ERR(file)) {
83                         ret = PTR_ERR(file);
84                         goto error;
85                 }
86
87                 written = kernel_write(file, prep->data, prep->datalen, 0);
88                 if (written != datalen) {
89                         ret = written;
90                         if (written >= 0)
91                                 ret = -ENOMEM;
92                         goto err_fput;
93                 }
94
95                 /* Pin the mount and dentry to the key so that we can open it again
96                  * later
97                  */
98                 *path = file->f_path;
99                 path_get(path);
100                 fput(file);
101         } else {
102                 /* Just store the data in a buffer */
103                 void *data = kmalloc(datalen, GFP_KERNEL);
104                 if (!data)
105                         return -ENOMEM;
106
107                 prep->payload.data[big_key_data] = data;
108                 memcpy(data, prep->data, prep->datalen);
109         }
110         return 0;
111
112 err_fput:
113         fput(file);
114 error:
115         return ret;
116 }
117
118 /*
119  * Clear preparsement.
120  */
121 void big_key_free_preparse(struct key_preparsed_payload *prep)
122 {
123         if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
124                 struct path *path = (struct path *)&prep->payload.data[big_key_path];
125                 path_put(path);
126         } else {
127                 kfree(prep->payload.data[big_key_data]);
128         }
129 }
130
131 /*
132  * dispose of the links from a revoked keyring
133  * - called with the key sem write-locked
134  */
135 void big_key_revoke(struct key *key)
136 {
137         struct path *path = (struct path *)&key->payload.data[big_key_path];
138
139         /* clear the quota */
140         key_payload_reserve(key, 0);
141         if (key_is_instantiated(key) &&
142             (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
143                 vfs_truncate(path, 0);
144 }
145
146 /*
147  * dispose of the data dangling from the corpse of a big_key key
148  */
149 void big_key_destroy(struct key *key)
150 {
151         size_t datalen = (size_t)key->payload.data[big_key_len];
152
153         if (datalen) {
154                 struct path *path = (struct path *)&key->payload.data[big_key_path];
155                 path_put(path);
156                 path->mnt = NULL;
157                 path->dentry = NULL;
158         } else {
159                 kfree(key->payload.data[big_key_data]);
160                 key->payload.data[big_key_data] = NULL;
161         }
162 }
163
164 /*
165  * describe the big_key key
166  */
167 void big_key_describe(const struct key *key, struct seq_file *m)
168 {
169         size_t datalen = (size_t)key->payload.data[big_key_len];
170
171         seq_puts(m, key->description);
172
173         if (key_is_instantiated(key))
174                 seq_printf(m, ": %zu [%s]",
175                            datalen,
176                            datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
177 }
178
179 /*
180  * read the key data
181  * - the key's semaphore is read-locked
182  */
183 long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
184 {
185         size_t datalen = (size_t)key->payload.data[big_key_len];
186         long ret;
187
188         if (!buffer || buflen < datalen)
189                 return datalen;
190
191         if (datalen > BIG_KEY_FILE_THRESHOLD) {
192                 struct path *path = (struct path *)&key->payload.data[big_key_path];
193                 struct file *file;
194                 loff_t pos;
195
196                 file = dentry_open(path, O_RDONLY, current_cred());
197                 if (IS_ERR(file))
198                         return PTR_ERR(file);
199
200                 pos = 0;
201                 ret = vfs_read(file, buffer, datalen, &pos);
202                 fput(file);
203                 if (ret >= 0 && ret != datalen)
204                         ret = -EIO;
205         } else {
206                 ret = datalen;
207                 if (copy_to_user(buffer, key->payload.data[big_key_data],
208                                  datalen) != 0)
209                         ret = -EFAULT;
210         }
211
212         return ret;
213 }
214
215 /*
216  * Module stuff
217  */
218 static int __init big_key_init(void)
219 {
220         return register_key_type(&key_type_big_key);
221 }
222
223 static void __exit big_key_cleanup(void)
224 {
225         unregister_key_type(&key_type_big_key);
226 }
227
228 module_init(big_key_init);
229 module_exit(big_key_cleanup);