1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Large capacity key type
4 * Copyright (C) 2017-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
6 * Written by David Howells (dhowells@redhat.com)
9 #define pr_fmt(fmt) "big_key: "fmt
10 #include <linux/init.h>
11 #include <linux/seq_file.h>
12 #include <linux/file.h>
13 #include <linux/shmem_fs.h>
14 #include <linux/err.h>
15 #include <linux/random.h>
16 #include <keys/user-type.h>
17 #include <keys/big_key-type.h>
18 #include <crypto/chacha20poly1305.h>
21 * Layout of key payload words.
23 struct big_key_payload
{
28 #define to_big_key_payload(payload) \
29 (struct big_key_payload *)((payload).data)
32 * If the data is under this limit, there's no point creating a shm file to
33 * hold it as the permanently resident metadata for the shmem fs will be at
34 * least as large as the data.
36 #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
39 * big_key defined keys take an arbitrary string as the description and an
40 * arbitrary blob of data as the payload
42 struct key_type key_type_big_key
= {
44 .preparse
= big_key_preparse
,
45 .free_preparse
= big_key_free_preparse
,
46 .instantiate
= generic_key_instantiate
,
47 .revoke
= big_key_revoke
,
48 .destroy
= big_key_destroy
,
49 .describe
= big_key_describe
,
51 .update
= big_key_update
,
57 int big_key_preparse(struct key_preparsed_payload
*prep
)
59 struct big_key_payload
*payload
= to_big_key_payload(prep
->payload
);
63 size_t datalen
= prep
->datalen
;
64 size_t enclen
= datalen
+ CHACHA20POLY1305_AUTHTAG_SIZE
;
67 BUILD_BUG_ON(sizeof(*payload
) != sizeof(prep
->payload
.data
));
69 if (datalen
<= 0 || datalen
> 1024 * 1024 || !prep
->data
)
72 /* Set an arbitrary quota */
75 payload
->length
= datalen
;
77 if (datalen
> BIG_KEY_FILE_THRESHOLD
) {
78 /* Create a shmem file to store the data in. This will permit the data
79 * to be swapped out if needed.
81 * File content is stored encrypted with randomly generated key.
82 * Since the key is random for each file, we can set the nonce
83 * to zero, provided we never define a ->update() call.
87 buf
= kvmalloc(enclen
, GFP_KERNEL
);
91 /* generate random key */
92 enckey
= kmalloc(CHACHA20POLY1305_KEY_SIZE
, GFP_KERNEL
);
97 ret
= get_random_bytes_wait(enckey
, CHACHA20POLY1305_KEY_SIZE
);
102 chacha20poly1305_encrypt(buf
, prep
->data
, datalen
, NULL
, 0,
105 /* save aligned data to file */
106 file
= shmem_kernel_file_setup("", enclen
, 0);
112 written
= kernel_write(file
, buf
, enclen
, &pos
);
113 if (written
!= enclen
) {
120 /* Pin the mount and dentry to the key so that we can open it again
123 payload
->data
= enckey
;
124 payload
->path
= file
->f_path
;
125 path_get(&payload
->path
);
127 kvfree_sensitive(buf
, enclen
);
129 /* Just store the data in a buffer */
130 void *data
= kmalloc(datalen
, GFP_KERNEL
);
135 payload
->data
= data
;
136 memcpy(data
, prep
->data
, prep
->datalen
);
143 kfree_sensitive(enckey
);
145 kvfree_sensitive(buf
, enclen
);
150 * Clear preparsement.
152 void big_key_free_preparse(struct key_preparsed_payload
*prep
)
154 struct big_key_payload
*payload
= to_big_key_payload(prep
->payload
);
156 if (prep
->datalen
> BIG_KEY_FILE_THRESHOLD
)
157 path_put(&payload
->path
);
158 kfree_sensitive(payload
->data
);
162 * dispose of the links from a revoked keyring
163 * - called with the key sem write-locked
165 void big_key_revoke(struct key
*key
)
167 struct big_key_payload
*payload
= to_big_key_payload(key
->payload
);
169 /* clear the quota */
170 key_payload_reserve(key
, 0);
171 if (key_is_positive(key
) && payload
->length
> BIG_KEY_FILE_THRESHOLD
)
172 vfs_truncate(&payload
->path
, 0);
176 * dispose of the data dangling from the corpse of a big_key key
178 void big_key_destroy(struct key
*key
)
180 struct big_key_payload
*payload
= to_big_key_payload(key
->payload
);
182 if (payload
->length
> BIG_KEY_FILE_THRESHOLD
) {
183 path_put(&payload
->path
);
184 payload
->path
.mnt
= NULL
;
185 payload
->path
.dentry
= NULL
;
187 kfree_sensitive(payload
->data
);
188 payload
->data
= NULL
;
194 int big_key_update(struct key
*key
, struct key_preparsed_payload
*prep
)
198 ret
= key_payload_reserve(key
, prep
->datalen
);
202 if (key_is_positive(key
))
203 big_key_destroy(key
);
205 return generic_key_instantiate(key
, prep
);
209 * describe the big_key key
211 void big_key_describe(const struct key
*key
, struct seq_file
*m
)
213 struct big_key_payload
*payload
= to_big_key_payload(key
->payload
);
215 seq_puts(m
, key
->description
);
217 if (key_is_positive(key
))
218 seq_printf(m
, ": %zu [%s]",
220 payload
->length
> BIG_KEY_FILE_THRESHOLD
? "file" : "buff");
225 * - the key's semaphore is read-locked
227 long big_key_read(const struct key
*key
, char *buffer
, size_t buflen
)
229 struct big_key_payload
*payload
= to_big_key_payload(key
->payload
);
230 size_t datalen
= payload
->length
;
233 if (!buffer
|| buflen
< datalen
)
236 if (datalen
> BIG_KEY_FILE_THRESHOLD
) {
238 u8
*buf
, *enckey
= payload
->data
;
239 size_t enclen
= datalen
+ CHACHA20POLY1305_AUTHTAG_SIZE
;
242 buf
= kvmalloc(enclen
, GFP_KERNEL
);
246 file
= dentry_open(&payload
->path
, O_RDONLY
, current_cred());
252 /* read file to kernel and decrypt */
253 ret
= kernel_read(file
, buf
, enclen
, &pos
);
260 ret
= chacha20poly1305_decrypt(buf
, buf
, enclen
, NULL
, 0, 0,
261 enckey
) ? 0 : -EBADMSG
;
267 /* copy out decrypted data */
268 memcpy(buffer
, buf
, datalen
);
273 kvfree_sensitive(buf
, enclen
);
276 memcpy(buffer
, payload
->data
, datalen
);
285 static int __init
big_key_init(void)
287 return register_key_type(&key_type_big_key
);
290 late_initcall(big_key_init
);