diff options
author | Eric Biggers <ebiggers@google.com> | 2016-11-13 20:41:09 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-11-19 20:56:13 -0500 |
commit | 0f0909e242f73c1154272cf04f07fc9afe13e5b8 (patch) | |
tree | ff64e7ce77a05f3cfebe72b2f2706bf5f2101e88 /fs | |
parent | 3c7018ebf8dbf14e7cd4f5dc648c51fc979f45bb (diff) |
fscrypto: don't use on-stack buffer for key derivation
With the new (in 4.9) option to use a virtually-mapped stack
(CONFIG_VMAP_STACK), stack buffers cannot be used as input/output for
the scatterlist crypto API because they may not be directly mappable to
struct page. get_crypt_info() was using a stack buffer to hold the
output from the encryption operation used to derive the per-file key.
Fix it by using a heap buffer.
This bug could most easily be observed in a CONFIG_DEBUG_SG kernel
because this allowed the BUG in sg_set_buf() to be triggered.
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/crypto/keyinfo.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 82f0285f5d08..67fb6d8876d0 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c | |||
@@ -185,7 +185,7 @@ int get_crypt_info(struct inode *inode) | |||
185 | struct crypto_skcipher *ctfm; | 185 | struct crypto_skcipher *ctfm; |
186 | const char *cipher_str; | 186 | const char *cipher_str; |
187 | int keysize; | 187 | int keysize; |
188 | u8 raw_key[FS_MAX_KEY_SIZE]; | 188 | u8 *raw_key = NULL; |
189 | int res; | 189 | int res; |
190 | 190 | ||
191 | res = fscrypt_initialize(); | 191 | res = fscrypt_initialize(); |
@@ -238,6 +238,15 @@ retry: | |||
238 | if (res) | 238 | if (res) |
239 | goto out; | 239 | goto out; |
240 | 240 | ||
241 | /* | ||
242 | * This cannot be a stack buffer because it is passed to the scatterlist | ||
243 | * crypto API as part of key derivation. | ||
244 | */ | ||
245 | res = -ENOMEM; | ||
246 | raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); | ||
247 | if (!raw_key) | ||
248 | goto out; | ||
249 | |||
241 | if (fscrypt_dummy_context_enabled(inode)) { | 250 | if (fscrypt_dummy_context_enabled(inode)) { |
242 | memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); | 251 | memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); |
243 | goto got_key; | 252 | goto got_key; |
@@ -276,7 +285,8 @@ got_key: | |||
276 | if (res) | 285 | if (res) |
277 | goto out; | 286 | goto out; |
278 | 287 | ||
279 | memzero_explicit(raw_key, sizeof(raw_key)); | 288 | kzfree(raw_key); |
289 | raw_key = NULL; | ||
280 | if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { | 290 | if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { |
281 | put_crypt_info(crypt_info); | 291 | put_crypt_info(crypt_info); |
282 | goto retry; | 292 | goto retry; |
@@ -287,7 +297,7 @@ out: | |||
287 | if (res == -ENOKEY) | 297 | if (res == -ENOKEY) |
288 | res = 0; | 298 | res = 0; |
289 | put_crypt_info(crypt_info); | 299 | put_crypt_info(crypt_info); |
290 | memzero_explicit(raw_key, sizeof(raw_key)); | 300 | kzfree(raw_key); |
291 | return res; | 301 | return res; |
292 | } | 302 | } |
293 | 303 | ||