Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

security/keys: rewrite big_key crypto to use library interface

A while back, I noticed that the crypto and crypto API usage in big_keys
were entirely broken in multiple ways, so I rewrote it. Now, I'm
rewriting it again, but this time using the simpler ChaCha20Poly1305
library function. This makes the file considerably more simple; the
diffstat alone should justify this commit. It also should be faster,
since it no longer requires a mutex around the "aead api object" (nor
allocations), allowing us to encrypt multiple items in parallel. We also
benefit from being able to pass any type of pointer, so we can get rid
of the ridiculously complex custom page allocator that big_key really
doesn't need.

[DH: Change the select CRYPTO_LIB_CHACHA20POLY1305 to a depends on as
select doesn't propagate and the build can end up with an =y dependending
on some =m pieces.

The depends on CRYPTO also had to be removed otherwise the configurator
complains about a recursive dependency.]

Cc: Andy Lutomirski <luto@kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: kernel-hardening@lists.openwall.com
Reviewed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: David Howells <dhowells@redhat.com>

authored by

Jason A. Donenfeld and committed by
David Howells
521fd61c 2ce113fa

+35 -209
+1 -3
security/keys/Kconfig
··· 60 60 bool "Large payload keys" 61 61 depends on KEYS 62 62 depends on TMPFS 63 - select CRYPTO 64 - select CRYPTO_AES 65 - select CRYPTO_GCM 63 + depends on CRYPTO_LIB_CHACHA20POLY1305 = y 66 64 help 67 65 This option provides support for holding large keys within the kernel 68 66 (for example Kerberos ticket caches). The data may be stored out to
+34 -206
security/keys/big_key.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* Large capacity key type 3 3 * 4 - * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 4 + * Copyright (C) 2017-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 5 5 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. 6 6 * Written by David Howells (dhowells@redhat.com) 7 7 */ ··· 12 12 #include <linux/file.h> 13 13 #include <linux/shmem_fs.h> 14 14 #include <linux/err.h> 15 - #include <linux/scatterlist.h> 16 15 #include <linux/random.h> 17 - #include <linux/vmalloc.h> 18 16 #include <keys/user-type.h> 19 17 #include <keys/big_key-type.h> 20 - #include <crypto/aead.h> 21 - #include <crypto/gcm.h> 22 - 23 - struct big_key_buf { 24 - unsigned int nr_pages; 25 - void *virt; 26 - struct scatterlist *sg; 27 - struct page *pages[]; 28 - }; 18 + #include <crypto/chacha20poly1305.h> 29 19 30 20 /* 31 21 * Layout of key payload words. ··· 28 38 }; 29 39 30 40 /* 31 - * Crypto operation with big_key data 32 - */ 33 - enum big_key_op { 34 - BIG_KEY_ENC, 35 - BIG_KEY_DEC, 36 - }; 37 - 38 - /* 39 41 * If the data is under this limit, there's no point creating a shm file to 40 42 * hold it as the permanently resident metadata for the shmem fs will be at 41 43 * least as large as the data. 42 44 */ 43 45 #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry)) 44 - 45 - /* 46 - * Key size for big_key data encryption 47 - */ 48 - #define ENC_KEY_SIZE 32 49 - 50 - /* 51 - * Authentication tag length 52 - */ 53 - #define ENC_AUTHTAG_SIZE 16 54 46 55 47 /* 56 48 * big_key defined keys take an arbitrary string as the description and an ··· 47 75 .destroy = big_key_destroy, 48 76 .describe = big_key_describe, 49 77 .read = big_key_read, 50 - /* no ->update(); don't add it without changing big_key_crypt() nonce */ 78 + /* no ->update(); don't add it without changing chacha20poly1305's nonce */ 51 79 }; 52 - 53 - /* 54 - * Crypto names for big_key data authenticated encryption 55 - */ 56 - static const char big_key_alg_name[] = "gcm(aes)"; 57 - #define BIG_KEY_IV_SIZE GCM_AES_IV_SIZE 58 - 59 - /* 60 - * Crypto algorithms for big_key data authenticated encryption 61 - */ 62 - static struct crypto_aead *big_key_aead; 63 - 64 - /* 65 - * Since changing the key affects the entire object, we need a mutex. 66 - */ 67 - static DEFINE_MUTEX(big_key_aead_lock); 68 - 69 - /* 70 - * Encrypt/decrypt big_key data 71 - */ 72 - static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key) 73 - { 74 - int ret; 75 - struct aead_request *aead_req; 76 - /* We always use a zero nonce. The reason we can get away with this is 77 - * because we're using a different randomly generated key for every 78 - * different encryption. Notably, too, key_type_big_key doesn't define 79 - * an .update function, so there's no chance we'll wind up reusing the 80 - * key to encrypt updated data. Simply put: one key, one encryption. 81 - */ 82 - u8 zero_nonce[BIG_KEY_IV_SIZE]; 83 - 84 - aead_req = aead_request_alloc(big_key_aead, GFP_KERNEL); 85 - if (!aead_req) 86 - return -ENOMEM; 87 - 88 - memset(zero_nonce, 0, sizeof(zero_nonce)); 89 - aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce); 90 - aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); 91 - aead_request_set_ad(aead_req, 0); 92 - 93 - mutex_lock(&big_key_aead_lock); 94 - if (crypto_aead_setkey(big_key_aead, key, ENC_KEY_SIZE)) { 95 - ret = -EAGAIN; 96 - goto error; 97 - } 98 - if (op == BIG_KEY_ENC) 99 - ret = crypto_aead_encrypt(aead_req); 100 - else 101 - ret = crypto_aead_decrypt(aead_req); 102 - error: 103 - mutex_unlock(&big_key_aead_lock); 104 - aead_request_free(aead_req); 105 - return ret; 106 - } 107 - 108 - /* 109 - * Free up the buffer. 110 - */ 111 - static void big_key_free_buffer(struct big_key_buf *buf) 112 - { 113 - unsigned int i; 114 - 115 - if (buf->virt) { 116 - memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); 117 - vunmap(buf->virt); 118 - } 119 - 120 - for (i = 0; i < buf->nr_pages; i++) 121 - if (buf->pages[i]) 122 - __free_page(buf->pages[i]); 123 - 124 - kfree(buf); 125 - } 126 - 127 - /* 128 - * Allocate a buffer consisting of a set of pages with a virtual mapping 129 - * applied over them. 130 - */ 131 - static void *big_key_alloc_buffer(size_t len) 132 - { 133 - struct big_key_buf *buf; 134 - unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 135 - unsigned int i, l; 136 - 137 - buf = kzalloc(sizeof(struct big_key_buf) + 138 - sizeof(struct page) * npg + 139 - sizeof(struct scatterlist) * npg, 140 - GFP_KERNEL); 141 - if (!buf) 142 - return NULL; 143 - 144 - buf->nr_pages = npg; 145 - buf->sg = (void *)(buf->pages + npg); 146 - sg_init_table(buf->sg, npg); 147 - 148 - for (i = 0; i < buf->nr_pages; i++) { 149 - buf->pages[i] = alloc_page(GFP_KERNEL); 150 - if (!buf->pages[i]) 151 - goto nomem; 152 - 153 - l = min_t(size_t, len, PAGE_SIZE); 154 - sg_set_page(&buf->sg[i], buf->pages[i], l, 0); 155 - len -= l; 156 - } 157 - 158 - buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); 159 - if (!buf->virt) 160 - goto nomem; 161 - 162 - return buf; 163 - 164 - nomem: 165 - big_key_free_buffer(buf); 166 - return NULL; 167 - } 168 80 169 81 /* 170 82 * Preparse a big key 171 83 */ 172 84 int big_key_preparse(struct key_preparsed_payload *prep) 173 85 { 174 - struct big_key_buf *buf; 175 86 struct path *path = (struct path *)&prep->payload.data[big_key_path]; 176 87 struct file *file; 177 - u8 *enckey; 88 + u8 *buf, *enckey; 178 89 ssize_t written; 179 - size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE; 90 + size_t datalen = prep->datalen; 91 + size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE; 180 92 int ret; 181 93 182 94 if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) ··· 76 220 * to be swapped out if needed. 77 221 * 78 222 * File content is stored encrypted with randomly generated key. 223 + * Since the key is random for each file, we can set the nonce 224 + * to zero, provided we never define a ->update() call. 79 225 */ 80 226 loff_t pos = 0; 81 227 82 - buf = big_key_alloc_buffer(enclen); 228 + buf = kvmalloc(enclen, GFP_KERNEL); 83 229 if (!buf) 84 230 return -ENOMEM; 85 - memcpy(buf->virt, prep->data, datalen); 86 231 87 232 /* generate random key */ 88 - enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); 233 + enckey = kmalloc(CHACHA20POLY1305_KEY_SIZE, GFP_KERNEL); 89 234 if (!enckey) { 90 235 ret = -ENOMEM; 91 236 goto error; 92 237 } 93 - ret = get_random_bytes_wait(enckey, ENC_KEY_SIZE); 238 + ret = get_random_bytes_wait(enckey, CHACHA20POLY1305_KEY_SIZE); 94 239 if (unlikely(ret)) 95 240 goto err_enckey; 96 241 97 - /* encrypt aligned data */ 98 - ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey); 99 - if (ret) 100 - goto err_enckey; 242 + /* encrypt data */ 243 + chacha20poly1305_encrypt(buf, prep->data, datalen, NULL, 0, 244 + 0, enckey); 101 245 102 246 /* save aligned data to file */ 103 247 file = shmem_kernel_file_setup("", enclen, 0); ··· 106 250 goto err_enckey; 107 251 } 108 252 109 - written = kernel_write(file, buf->virt, enclen, &pos); 253 + written = kernel_write(file, buf, enclen, &pos); 110 254 if (written != enclen) { 111 255 ret = written; 112 256 if (written >= 0) 113 - ret = -ENOMEM; 257 + ret = -EIO; 114 258 goto err_fput; 115 259 } 116 260 ··· 121 265 *path = file->f_path; 122 266 path_get(path); 123 267 fput(file); 124 - big_key_free_buffer(buf); 268 + memzero_explicit(buf, enclen); 269 + kvfree(buf); 125 270 } else { 126 271 /* Just store the data in a buffer */ 127 272 void *data = kmalloc(datalen, GFP_KERNEL); ··· 140 283 err_enckey: 141 284 kzfree(enckey); 142 285 error: 143 - big_key_free_buffer(buf); 286 + memzero_explicit(buf, enclen); 287 + kvfree(buf); 144 288 return ret; 145 289 } 146 290 ··· 219 361 return datalen; 220 362 221 363 if (datalen > BIG_KEY_FILE_THRESHOLD) { 222 - struct big_key_buf *buf; 223 364 struct path *path = (struct path *)&key->payload.data[big_key_path]; 224 365 struct file *file; 225 - u8 *enckey = (u8 *)key->payload.data[big_key_data]; 226 - size_t enclen = datalen + ENC_AUTHTAG_SIZE; 366 + u8 *buf, *enckey = (u8 *)key->payload.data[big_key_data]; 367 + size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE; 227 368 loff_t pos = 0; 228 369 229 - buf = big_key_alloc_buffer(enclen); 370 + buf = kvmalloc(enclen, GFP_KERNEL); 230 371 if (!buf) 231 372 return -ENOMEM; 232 373 ··· 236 379 } 237 380 238 381 /* read file to kernel and decrypt */ 239 - ret = kernel_read(file, buf->virt, enclen, &pos); 240 - if (ret >= 0 && ret != enclen) { 241 - ret = -EIO; 382 + ret = kernel_read(file, buf, enclen, &pos); 383 + if (ret != enclen) { 384 + if (ret >= 0) 385 + ret = -EIO; 242 386 goto err_fput; 243 387 } 244 388 245 - ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey); 246 - if (ret) 389 + ret = chacha20poly1305_decrypt(buf, buf, enclen, NULL, 0, 0, 390 + enckey) ? 0 : -EBADMSG; 391 + if (unlikely(ret)) 247 392 goto err_fput; 248 393 249 394 ret = datalen; 250 395 251 396 /* copy out decrypted data */ 252 - memcpy(buffer, buf->virt, datalen); 397 + memcpy(buffer, buf, datalen); 253 398 254 399 err_fput: 255 400 fput(file); 256 401 error: 257 - big_key_free_buffer(buf); 402 + memzero_explicit(buf, enclen); 403 + kvfree(buf); 258 404 } else { 259 405 ret = datalen; 260 406 memcpy(buffer, key->payload.data[big_key_data], datalen); ··· 271 411 */ 272 412 static int __init big_key_init(void) 273 413 { 274 - int ret; 275 - 276 - /* init block cipher */ 277 - big_key_aead = crypto_alloc_aead(big_key_alg_name, 0, CRYPTO_ALG_ASYNC); 278 - if (IS_ERR(big_key_aead)) { 279 - ret = PTR_ERR(big_key_aead); 280 - pr_err("Can't alloc crypto: %d\n", ret); 281 - return ret; 282 - } 283 - 284 - if (unlikely(crypto_aead_ivsize(big_key_aead) != BIG_KEY_IV_SIZE)) { 285 - WARN(1, "big key algorithm changed?"); 286 - ret = -EINVAL; 287 - goto free_aead; 288 - } 289 - 290 - ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE); 291 - if (ret < 0) { 292 - pr_err("Can't set crypto auth tag len: %d\n", ret); 293 - goto free_aead; 294 - } 295 - 296 - ret = register_key_type(&key_type_big_key); 297 - if (ret < 0) { 298 - pr_err("Can't register type: %d\n", ret); 299 - goto free_aead; 300 - } 301 - 302 - return 0; 303 - 304 - free_aead: 305 - crypto_free_aead(big_key_aead); 306 - return ret; 414 + return register_key_type(&key_type_big_key); 307 415 } 308 416 309 417 late_initcall(big_key_init);