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:
commit
d117b9acae
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
Loading…
Reference in New Issue