diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-19 21:33:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-19 21:33:50 -0500 |
commit | d117b9acaeada0b243f31e0fe83e111fcc9a6644 (patch) | |
tree | 3ba4fefa66b461127523bef71f2472b28e6d4342 /fs | |
parent | 50d438fb9e4229cb37ec89a22c066b626e30885c (diff) | |
parent | 8cdf3372fe8368f56315e66bea9f35053c418093 (diff) |
Merge tag 'ext4_for_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 fixes from Ted Ts'o:
"A security fix (so a maliciously corrupted file system image won't
panic the kernel) and some fixes for CONFIG_VMAP_STACK"
* tag 'ext4_for_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: sanity check the block and cluster size at mount time
fscrypto: don't use on-stack buffer for key derivation
fscrypto: don't use on-stack buffer for filename encryption
Diffstat (limited to 'fs')
-rw-r--r-- | fs/crypto/fname.c | 53 | ||||
-rw-r--r-- | fs/crypto/keyinfo.c | 16 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 1 | ||||
-rw-r--r-- | fs/ext4/super.c | 17 |
4 files changed, 51 insertions, 36 deletions
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 9a28133ac3b8..9b774f4b50c8 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c | |||
@@ -39,65 +39,54 @@ static void fname_crypt_complete(struct crypto_async_request *req, int res) | |||
39 | static int fname_encrypt(struct inode *inode, | 39 | static int fname_encrypt(struct inode *inode, |
40 | const struct qstr *iname, struct fscrypt_str *oname) | 40 | const struct qstr *iname, struct fscrypt_str *oname) |
41 | { | 41 | { |
42 | u32 ciphertext_len; | ||
43 | struct skcipher_request *req = NULL; | 42 | struct skcipher_request *req = NULL; |
44 | DECLARE_FS_COMPLETION_RESULT(ecr); | 43 | DECLARE_FS_COMPLETION_RESULT(ecr); |
45 | struct fscrypt_info *ci = inode->i_crypt_info; | 44 | struct fscrypt_info *ci = inode->i_crypt_info; |
46 | struct crypto_skcipher *tfm = ci->ci_ctfm; | 45 | struct crypto_skcipher *tfm = ci->ci_ctfm; |
47 | int res = 0; | 46 | int res = 0; |
48 | char iv[FS_CRYPTO_BLOCK_SIZE]; | 47 | char iv[FS_CRYPTO_BLOCK_SIZE]; |
49 | struct scatterlist src_sg, dst_sg; | 48 | struct scatterlist sg; |
50 | int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); | 49 | int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); |
51 | char *workbuf, buf[32], *alloc_buf = NULL; | 50 | unsigned int lim; |
52 | unsigned lim; | 51 | unsigned int cryptlen; |
53 | 52 | ||
54 | lim = inode->i_sb->s_cop->max_namelen(inode); | 53 | lim = inode->i_sb->s_cop->max_namelen(inode); |
55 | if (iname->len <= 0 || iname->len > lim) | 54 | if (iname->len <= 0 || iname->len > lim) |
56 | return -EIO; | 55 | return -EIO; |
57 | 56 | ||
58 | ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE); | 57 | /* |
59 | ciphertext_len = round_up(ciphertext_len, padding); | 58 | * Copy the filename to the output buffer for encrypting in-place and |
60 | ciphertext_len = min(ciphertext_len, lim); | 59 | * pad it with the needed number of NUL bytes. |
60 | */ | ||
61 | cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE); | ||
62 | cryptlen = round_up(cryptlen, padding); | ||
63 | cryptlen = min(cryptlen, lim); | ||
64 | memcpy(oname->name, iname->name, iname->len); | ||
65 | memset(oname->name + iname->len, 0, cryptlen - iname->len); | ||
61 | 66 | ||
62 | if (ciphertext_len <= sizeof(buf)) { | 67 | /* Initialize the IV */ |
63 | workbuf = buf; | 68 | memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); |
64 | } else { | ||
65 | alloc_buf = kmalloc(ciphertext_len, GFP_NOFS); | ||
66 | if (!alloc_buf) | ||
67 | return -ENOMEM; | ||
68 | workbuf = alloc_buf; | ||
69 | } | ||
70 | 69 | ||
71 | /* Allocate request */ | 70 | /* Set up the encryption request */ |
72 | req = skcipher_request_alloc(tfm, GFP_NOFS); | 71 | req = skcipher_request_alloc(tfm, GFP_NOFS); |
73 | if (!req) { | 72 | if (!req) { |
74 | printk_ratelimited(KERN_ERR | 73 | printk_ratelimited(KERN_ERR |
75 | "%s: crypto_request_alloc() failed\n", __func__); | 74 | "%s: skcipher_request_alloc() failed\n", __func__); |
76 | kfree(alloc_buf); | ||
77 | return -ENOMEM; | 75 | return -ENOMEM; |
78 | } | 76 | } |
79 | skcipher_request_set_callback(req, | 77 | skcipher_request_set_callback(req, |
80 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | 78 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, |
81 | fname_crypt_complete, &ecr); | 79 | fname_crypt_complete, &ecr); |
80 | sg_init_one(&sg, oname->name, cryptlen); | ||
81 | skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); | ||
82 | 82 | ||
83 | /* Copy the input */ | 83 | /* Do the encryption */ |
84 | memcpy(workbuf, iname->name, iname->len); | ||
85 | if (iname->len < ciphertext_len) | ||
86 | memset(workbuf + iname->len, 0, ciphertext_len - iname->len); | ||
87 | |||
88 | /* Initialize IV */ | ||
89 | memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); | ||
90 | |||
91 | /* Create encryption request */ | ||
92 | sg_init_one(&src_sg, workbuf, ciphertext_len); | ||
93 | sg_init_one(&dst_sg, oname->name, ciphertext_len); | ||
94 | skcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv); | ||
95 | res = crypto_skcipher_encrypt(req); | 84 | res = crypto_skcipher_encrypt(req); |
96 | if (res == -EINPROGRESS || res == -EBUSY) { | 85 | if (res == -EINPROGRESS || res == -EBUSY) { |
86 | /* Request is being completed asynchronously; wait for it */ | ||
97 | wait_for_completion(&ecr.completion); | 87 | wait_for_completion(&ecr.completion); |
98 | res = ecr.res; | 88 | res = ecr.res; |
99 | } | 89 | } |
100 | kfree(alloc_buf); | ||
101 | skcipher_request_free(req); | 90 | skcipher_request_free(req); |
102 | if (res < 0) { | 91 | if (res < 0) { |
103 | printk_ratelimited(KERN_ERR | 92 | printk_ratelimited(KERN_ERR |
@@ -105,7 +94,7 @@ static int fname_encrypt(struct inode *inode, | |||
105 | return res; | 94 | return res; |
106 | } | 95 | } |
107 | 96 | ||
108 | oname->len = ciphertext_len; | 97 | oname->len = cryptlen; |
109 | return 0; | 98 | return 0; |
110 | } | 99 | } |
111 | 100 | ||
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 | ||
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 282a51b07c57..a8a750f59621 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -235,6 +235,7 @@ struct ext4_io_submit { | |||
235 | #define EXT4_MAX_BLOCK_SIZE 65536 | 235 | #define EXT4_MAX_BLOCK_SIZE 65536 |
236 | #define EXT4_MIN_BLOCK_LOG_SIZE 10 | 236 | #define EXT4_MIN_BLOCK_LOG_SIZE 10 |
237 | #define EXT4_MAX_BLOCK_LOG_SIZE 16 | 237 | #define EXT4_MAX_BLOCK_LOG_SIZE 16 |
238 | #define EXT4_MAX_CLUSTER_LOG_SIZE 30 | ||
238 | #ifdef __KERNEL__ | 239 | #ifdef __KERNEL__ |
239 | # define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize) | 240 | # define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize) |
240 | #else | 241 | #else |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 20da99da0a34..52b0530c5d65 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -3565,7 +3565,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3565 | if (blocksize < EXT4_MIN_BLOCK_SIZE || | 3565 | if (blocksize < EXT4_MIN_BLOCK_SIZE || |
3566 | blocksize > EXT4_MAX_BLOCK_SIZE) { | 3566 | blocksize > EXT4_MAX_BLOCK_SIZE) { |
3567 | ext4_msg(sb, KERN_ERR, | 3567 | ext4_msg(sb, KERN_ERR, |
3568 | "Unsupported filesystem blocksize %d", blocksize); | 3568 | "Unsupported filesystem blocksize %d (%d log_block_size)", |
3569 | blocksize, le32_to_cpu(es->s_log_block_size)); | ||
3570 | goto failed_mount; | ||
3571 | } | ||
3572 | if (le32_to_cpu(es->s_log_block_size) > | ||
3573 | (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { | ||
3574 | ext4_msg(sb, KERN_ERR, | ||
3575 | "Invalid log block size: %u", | ||
3576 | le32_to_cpu(es->s_log_block_size)); | ||
3569 | goto failed_mount; | 3577 | goto failed_mount; |
3570 | } | 3578 | } |
3571 | 3579 | ||
@@ -3697,6 +3705,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3697 | "block size (%d)", clustersize, blocksize); | 3705 | "block size (%d)", clustersize, blocksize); |
3698 | goto failed_mount; | 3706 | goto failed_mount; |
3699 | } | 3707 | } |
3708 | if (le32_to_cpu(es->s_log_cluster_size) > | ||
3709 | (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { | ||
3710 | ext4_msg(sb, KERN_ERR, | ||
3711 | "Invalid log cluster size: %u", | ||
3712 | le32_to_cpu(es->s_log_cluster_size)); | ||
3713 | goto failed_mount; | ||
3714 | } | ||
3700 | sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - | 3715 | sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - |
3701 | le32_to_cpu(es->s_log_block_size); | 3716 | le32_to_cpu(es->s_log_block_size); |
3702 | sbi->s_clusters_per_group = | 3717 | sbi->s_clusters_per_group = |