A security fix (so a maliciously corrupted file system image won't

panic the kernel) and some fixes for CONFIG_VMAP_STACK.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAlgxCMoACgkQ8vlZVpUN
 gaOX3Af/QOphB5pKrKijhDK9H40nKS6lHtL7klJpvRafUMtVxBDOP3dsRISyGMdF
 w+gQQQv+eFEPefwGcYzdO4PN7FFVirAF9RS/NTFSIB/c8V6FfHzn/DeiftU7CLRW
 ljTP7y8M9eo35TsU8s9D7wfbyfY55MEANiAP8vnpx4JKDb86I/8Eaa6YS91v17vp
 /7TKSUt7PE6UUp7mgTRCX8vK9SxJJ8Xvg2hSzulfrO1DdsfW61RQYXwif+biR85T
 uxFPnV0yvji2EU4cpeIekPqJKUb9Av0aIbSwg19QqcAE0xqxvtSRBKlYnF2IRTuv
 OXoaC30d4UcQrNCkxPDAdH/0BMdcNQ==
 =y+5G
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2016-11-19 18:33:50 -08:00
commit d117b9acae
4 changed files with 51 additions and 36 deletions

View File

@ -39,65 +39,54 @@ static void fname_crypt_complete(struct crypto_async_request *req, int res)
static int fname_encrypt(struct inode *inode, static int fname_encrypt(struct inode *inode,
const struct qstr *iname, struct fscrypt_str *oname) const struct qstr *iname, struct fscrypt_str *oname)
{ {
u32 ciphertext_len;
struct skcipher_request *req = NULL; struct skcipher_request *req = NULL;
DECLARE_FS_COMPLETION_RESULT(ecr); DECLARE_FS_COMPLETION_RESULT(ecr);
struct fscrypt_info *ci = inode->i_crypt_info; struct fscrypt_info *ci = inode->i_crypt_info;
struct crypto_skcipher *tfm = ci->ci_ctfm; struct crypto_skcipher *tfm = ci->ci_ctfm;
int res = 0; int res = 0;
char iv[FS_CRYPTO_BLOCK_SIZE]; char iv[FS_CRYPTO_BLOCK_SIZE];
struct scatterlist src_sg, dst_sg; struct scatterlist sg;
int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
char *workbuf, buf[32], *alloc_buf = NULL; unsigned int lim;
unsigned lim; unsigned int cryptlen;
lim = inode->i_sb->s_cop->max_namelen(inode); lim = inode->i_sb->s_cop->max_namelen(inode);
if (iname->len <= 0 || iname->len > lim) if (iname->len <= 0 || iname->len > lim)
return -EIO; return -EIO;
ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE); /*
ciphertext_len = round_up(ciphertext_len, padding); * Copy the filename to the output buffer for encrypting in-place and
ciphertext_len = min(ciphertext_len, lim); * pad it with the needed number of NUL bytes.
*/
cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
cryptlen = round_up(cryptlen, padding);
cryptlen = min(cryptlen, lim);
memcpy(oname->name, iname->name, iname->len);
memset(oname->name + iname->len, 0, cryptlen - iname->len);
if (ciphertext_len <= sizeof(buf)) { /* Initialize the IV */
workbuf = buf; memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
} else {
alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
if (!alloc_buf)
return -ENOMEM;
workbuf = alloc_buf;
}
/* Allocate request */ /* Set up the encryption request */
req = skcipher_request_alloc(tfm, GFP_NOFS); req = skcipher_request_alloc(tfm, GFP_NOFS);
if (!req) { if (!req) {
printk_ratelimited(KERN_ERR printk_ratelimited(KERN_ERR
"%s: crypto_request_alloc() failed\n", __func__); "%s: skcipher_request_alloc() failed\n", __func__);
kfree(alloc_buf);
return -ENOMEM; return -ENOMEM;
} }
skcipher_request_set_callback(req, skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
fname_crypt_complete, &ecr); fname_crypt_complete, &ecr);
sg_init_one(&sg, oname->name, cryptlen);
skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
/* Copy the input */ /* Do the encryption */
memcpy(workbuf, iname->name, iname->len);
if (iname->len < ciphertext_len)
memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
/* Initialize IV */
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
/* Create encryption request */
sg_init_one(&src_sg, workbuf, ciphertext_len);
sg_init_one(&dst_sg, oname->name, ciphertext_len);
skcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
res = crypto_skcipher_encrypt(req); res = crypto_skcipher_encrypt(req);
if (res == -EINPROGRESS || res == -EBUSY) { if (res == -EINPROGRESS || res == -EBUSY) {
/* Request is being completed asynchronously; wait for it */
wait_for_completion(&ecr.completion); wait_for_completion(&ecr.completion);
res = ecr.res; res = ecr.res;
} }
kfree(alloc_buf);
skcipher_request_free(req); skcipher_request_free(req);
if (res < 0) { if (res < 0) {
printk_ratelimited(KERN_ERR printk_ratelimited(KERN_ERR
@ -105,7 +94,7 @@ static int fname_encrypt(struct inode *inode,
return res; return res;
} }
oname->len = ciphertext_len; oname->len = cryptlen;
return 0; return 0;
} }

View File

@ -185,7 +185,7 @@ int get_crypt_info(struct inode *inode)
struct crypto_skcipher *ctfm; struct crypto_skcipher *ctfm;
const char *cipher_str; const char *cipher_str;
int keysize; int keysize;
u8 raw_key[FS_MAX_KEY_SIZE]; u8 *raw_key = NULL;
int res; int res;
res = fscrypt_initialize(); res = fscrypt_initialize();
@ -238,6 +238,15 @@ int get_crypt_info(struct inode *inode)
if (res) if (res)
goto out; goto out;
/*
* This cannot be a stack buffer because it is passed to the scatterlist
* crypto API as part of key derivation.
*/
res = -ENOMEM;
raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
if (!raw_key)
goto out;
if (fscrypt_dummy_context_enabled(inode)) { if (fscrypt_dummy_context_enabled(inode)) {
memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
goto got_key; goto got_key;
@ -276,7 +285,8 @@ int get_crypt_info(struct inode *inode)
if (res) if (res)
goto out; goto out;
memzero_explicit(raw_key, sizeof(raw_key)); kzfree(raw_key);
raw_key = NULL;
if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
put_crypt_info(crypt_info); put_crypt_info(crypt_info);
goto retry; goto retry;
@ -287,7 +297,7 @@ int get_crypt_info(struct inode *inode)
if (res == -ENOKEY) if (res == -ENOKEY)
res = 0; res = 0;
put_crypt_info(crypt_info); put_crypt_info(crypt_info);
memzero_explicit(raw_key, sizeof(raw_key)); kzfree(raw_key);
return res; return res;
} }

View File

@ -235,6 +235,7 @@ struct ext4_io_submit {
#define EXT4_MAX_BLOCK_SIZE 65536 #define EXT4_MAX_BLOCK_SIZE 65536
#define EXT4_MIN_BLOCK_LOG_SIZE 10 #define EXT4_MIN_BLOCK_LOG_SIZE 10
#define EXT4_MAX_BLOCK_LOG_SIZE 16 #define EXT4_MAX_BLOCK_LOG_SIZE 16
#define EXT4_MAX_CLUSTER_LOG_SIZE 30
#ifdef __KERNEL__ #ifdef __KERNEL__
# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize) # define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize)
#else #else

View File

@ -3565,7 +3565,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (blocksize < EXT4_MIN_BLOCK_SIZE || if (blocksize < EXT4_MIN_BLOCK_SIZE ||
blocksize > EXT4_MAX_BLOCK_SIZE) { blocksize > EXT4_MAX_BLOCK_SIZE) {
ext4_msg(sb, KERN_ERR, ext4_msg(sb, KERN_ERR,
"Unsupported filesystem blocksize %d", blocksize); "Unsupported filesystem blocksize %d (%d log_block_size)",
blocksize, le32_to_cpu(es->s_log_block_size));
goto failed_mount;
}
if (le32_to_cpu(es->s_log_block_size) >
(EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
ext4_msg(sb, KERN_ERR,
"Invalid log block size: %u",
le32_to_cpu(es->s_log_block_size));
goto failed_mount; goto failed_mount;
} }
@ -3697,6 +3705,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
"block size (%d)", clustersize, blocksize); "block size (%d)", clustersize, blocksize);
goto failed_mount; goto failed_mount;
} }
if (le32_to_cpu(es->s_log_cluster_size) >
(EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
ext4_msg(sb, KERN_ERR,
"Invalid log cluster size: %u",
le32_to_cpu(es->s_log_cluster_size));
goto failed_mount;
}
sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) -
le32_to_cpu(es->s_log_block_size); le32_to_cpu(es->s_log_block_size);
sbi->s_clusters_per_group = sbi->s_clusters_per_group =