| From e9ff56ac352446f55141aaef1553cee662b2e310 Mon Sep 17 00:00:00 2001 |
| From: Eric Biggers <ebiggers@google.com> |
| Date: Thu, 8 Jun 2017 14:48:10 +0100 |
| Subject: KEYS: encrypted: avoid encrypting/decrypting stack buffers |
| |
| From: Eric Biggers <ebiggers@google.com> |
| |
| commit e9ff56ac352446f55141aaef1553cee662b2e310 upstream. |
| |
| Since v4.9, the crypto API cannot (normally) be used to encrypt/decrypt |
| stack buffers because the stack may be virtually mapped. Fix this for |
| the padding buffers in encrypted-keys by using ZERO_PAGE for the |
| encryption padding and by allocating a temporary heap buffer for the |
| decryption padding. |
| |
| Tested with CONFIG_DEBUG_SG=y: |
| keyctl new_session |
| keyctl add user master "abcdefghijklmnop" @s |
| keyid=$(keyctl add encrypted desc "new user:master 25" @s) |
| datablob="$(keyctl pipe $keyid)" |
| keyctl unlink $keyid |
| keyid=$(keyctl add encrypted desc "load $datablob" @s) |
| datablob2="$(keyctl pipe $keyid)" |
| [ "$datablob" = "$datablob2" ] && echo "Success!" |
| |
| Cc: Andy Lutomirski <luto@kernel.org> |
| Cc: Herbert Xu <herbert@gondor.apana.org.au> |
| Cc: Mimi Zohar <zohar@linux.vnet.ibm.com> |
| Signed-off-by: Eric Biggers <ebiggers@google.com> |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: James Morris <james.l.morris@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| security/keys/encrypted-keys/encrypted.c | 17 +++++++++-------- |
| 1 file changed, 9 insertions(+), 8 deletions(-) |
| |
| --- a/security/keys/encrypted-keys/encrypted.c |
| +++ b/security/keys/encrypted-keys/encrypted.c |
| @@ -480,12 +480,9 @@ static int derived_key_encrypt(struct en |
| struct skcipher_request *req; |
| unsigned int encrypted_datalen; |
| u8 iv[AES_BLOCK_SIZE]; |
| - unsigned int padlen; |
| - char pad[16]; |
| int ret; |
| |
| encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); |
| - padlen = encrypted_datalen - epayload->decrypted_datalen; |
| |
| req = init_skcipher_req(derived_key, derived_keylen); |
| ret = PTR_ERR(req); |
| @@ -493,11 +490,10 @@ static int derived_key_encrypt(struct en |
| goto out; |
| dump_decrypted_data(epayload); |
| |
| - memset(pad, 0, sizeof pad); |
| sg_init_table(sg_in, 2); |
| sg_set_buf(&sg_in[0], epayload->decrypted_data, |
| epayload->decrypted_datalen); |
| - sg_set_buf(&sg_in[1], pad, padlen); |
| + sg_set_page(&sg_in[1], ZERO_PAGE(0), AES_BLOCK_SIZE, 0); |
| |
| sg_init_table(sg_out, 1); |
| sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen); |
| @@ -584,9 +580,14 @@ static int derived_key_decrypt(struct en |
| struct skcipher_request *req; |
| unsigned int encrypted_datalen; |
| u8 iv[AES_BLOCK_SIZE]; |
| - char pad[16]; |
| + u8 *pad; |
| int ret; |
| |
| + /* Throwaway buffer to hold the unused zero padding at the end */ |
| + pad = kmalloc(AES_BLOCK_SIZE, GFP_KERNEL); |
| + if (!pad) |
| + return -ENOMEM; |
| + |
| encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); |
| req = init_skcipher_req(derived_key, derived_keylen); |
| ret = PTR_ERR(req); |
| @@ -594,13 +595,12 @@ static int derived_key_decrypt(struct en |
| goto out; |
| dump_encrypted_data(epayload, encrypted_datalen); |
| |
| - memset(pad, 0, sizeof pad); |
| sg_init_table(sg_in, 1); |
| sg_init_table(sg_out, 2); |
| sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen); |
| sg_set_buf(&sg_out[0], epayload->decrypted_data, |
| epayload->decrypted_datalen); |
| - sg_set_buf(&sg_out[1], pad, sizeof pad); |
| + sg_set_buf(&sg_out[1], pad, AES_BLOCK_SIZE); |
| |
| memcpy(iv, epayload->iv, sizeof(iv)); |
| skcipher_request_set_crypt(req, sg_in, sg_out, encrypted_datalen, iv); |
| @@ -612,6 +612,7 @@ static int derived_key_decrypt(struct en |
| goto out; |
| dump_decrypted_data(epayload); |
| out: |
| + kfree(pad); |
| return ret; |
| } |
| |