|
Jan Kara |
fff6de |
From 4ea99936a1630f51fc3a2d61a58ec4a1c4b7d55a Mon Sep 17 00:00:00 2001
|
|
Jan Kara |
fff6de |
From: Theodore Ts'o <tytso@mit.edu>
|
|
Jan Kara |
fff6de |
Date: Thu, 7 Nov 2019 21:43:41 -0500
|
|
Jan Kara |
fff6de |
Subject: [PATCH] ext4: add more paranoia checking in ext4_expand_extra_isize
|
|
Jan Kara |
fff6de |
handling
|
|
Jan Kara |
fff6de |
Git-commit: 4ea99936a1630f51fc3a2d61a58ec4a1c4b7d55a
|
|
Jan Kara |
fff6de |
Patch-mainline: v5.5-rc1
|
|
Jan Kara |
fff6de |
References: bsc#1159297 CVE-2019-19767
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
It's possible to specify a non-zero s_want_extra_isize via debugging
|
|
Jan Kara |
fff6de |
option, and this can cause bad things(tm) to happen when using a file
|
|
Jan Kara |
fff6de |
system with an inode size of 128 bytes.
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
Add better checking when the file system is mounted, as well as when
|
|
Jan Kara |
fff6de |
we are actually doing the trying to do the inode expansion.
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
Link: https://lore.kernel.org/r/20191110121510.GH23325@mit.edu
|
|
Jan Kara |
fff6de |
Reported-by: syzbot+f8d6f8386ceacdbfff57@syzkaller.appspotmail.com
|
|
Jan Kara |
fff6de |
Reported-by: syzbot+33d7ea72e47de3bdf4e1@syzkaller.appspotmail.com
|
|
Jan Kara |
fff6de |
Reported-by: syzbot+44b6763edfc17144296f@syzkaller.appspotmail.com
|
|
Jan Kara |
fff6de |
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Jan Kara |
fff6de |
Cc: stable@kernel.org
|
|
Jan Kara |
fff6de |
Acked-by: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
---
|
|
Jan Kara |
fff6de |
fs/ext4/inode.c | 15 +++++++++++++++
|
|
Jan Kara |
fff6de |
fs/ext4/super.c | 21 ++++++++++++---------
|
|
Jan Kara |
fff6de |
2 files changed, 27 insertions(+), 9 deletions(-)
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
--- a/fs/ext4/inode.c
|
|
Jan Kara |
fff6de |
+++ b/fs/ext4/inode.c
|
|
Jan Kara |
fff6de |
@@ -5736,6 +5736,21 @@ static int ext4_expand_extra_isize(struc
|
|
Jan Kara |
fff6de |
{
|
|
Jan Kara |
fff6de |
struct ext4_inode *raw_inode;
|
|
Jan Kara |
fff6de |
struct ext4_xattr_ibody_header *header;
|
|
Jan Kara |
fff6de |
+ unsigned int inode_size = EXT4_INODE_SIZE(inode->i_sb);
|
|
Jan Kara |
fff6de |
+ struct ext4_inode_info *ei = EXT4_I(inode);
|
|
Jan Kara |
fff6de |
+
|
|
Jan Kara |
fff6de |
+ /* this was checked at iget time, but double check for good measure */
|
|
Jan Kara |
fff6de |
+ if ((EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > inode_size) ||
|
|
Jan Kara |
fff6de |
+ (ei->i_extra_isize & 3)) {
|
|
Jan Kara |
fff6de |
+ EXT4_ERROR_INODE(inode, "bad extra_isize %u (inode size %u)",
|
|
Jan Kara |
fff6de |
+ ei->i_extra_isize,
|
|
Jan Kara |
fff6de |
+ EXT4_INODE_SIZE(inode->i_sb));
|
|
Jan Kara |
fff6de |
+ return -EFSCORRUPTED;
|
|
Jan Kara |
fff6de |
+ }
|
|
Jan Kara |
fff6de |
+ if ((new_extra_isize < ei->i_extra_isize) ||
|
|
Jan Kara |
fff6de |
+ (new_extra_isize < 4) ||
|
|
Jan Kara |
fff6de |
+ (new_extra_isize > inode_size - EXT4_GOOD_OLD_INODE_SIZE))
|
|
Jan Kara |
fff6de |
+ return -EINVAL; /* Should never happen */
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
|
|
Jan Kara |
fff6de |
return 0;
|
|
Jan Kara |
fff6de |
--- a/fs/ext4/super.c
|
|
Jan Kara |
fff6de |
+++ b/fs/ext4/super.c
|
|
Jan Kara |
fff6de |
@@ -3429,12 +3429,15 @@ static void ext4_clamp_want_extra_isize(
|
|
Jan Kara |
fff6de |
{
|
|
Jan Kara |
fff6de |
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
|
Jan Kara |
fff6de |
struct ext4_super_block *es = sbi->s_es;
|
|
Jan Kara |
fff6de |
+ unsigned def_extra_isize = sizeof(struct ext4_inode) -
|
|
Jan Kara |
fff6de |
+ EXT4_GOOD_OLD_INODE_SIZE;
|
|
Jan Kara |
fff6de |
|
|
Jan Kara |
fff6de |
- /* determine the minimum size of new large inodes, if present */
|
|
Jan Kara |
fff6de |
- if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
|
|
Jan Kara |
fff6de |
- sbi->s_want_extra_isize == 0) {
|
|
Jan Kara |
fff6de |
- sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
|
Jan Kara |
fff6de |
- EXT4_GOOD_OLD_INODE_SIZE;
|
|
Jan Kara |
fff6de |
+ if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) {
|
|
Jan Kara |
fff6de |
+ sbi->s_want_extra_isize = 0;
|
|
Jan Kara |
fff6de |
+ return;
|
|
Jan Kara |
fff6de |
+ }
|
|
Jan Kara |
fff6de |
+ if (sbi->s_want_extra_isize < 4) {
|
|
Jan Kara |
fff6de |
+ sbi->s_want_extra_isize = def_extra_isize;
|
|
Jan Kara |
fff6de |
if (ext4_has_feature_extra_isize(sb)) {
|
|
Jan Kara |
fff6de |
if (sbi->s_want_extra_isize <
|
|
Jan Kara |
fff6de |
le16_to_cpu(es->s_want_extra_isize))
|
|
Jan Kara |
fff6de |
@@ -3447,10 +3450,10 @@ static void ext4_clamp_want_extra_isize(
|
|
Jan Kara |
fff6de |
}
|
|
Jan Kara |
fff6de |
}
|
|
Jan Kara |
fff6de |
/* Check if enough inode space is available */
|
|
Jan Kara |
fff6de |
- if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
|
|
Jan Kara |
fff6de |
- sbi->s_inode_size) {
|
|
Jan Kara |
fff6de |
- sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
|
Jan Kara |
fff6de |
- EXT4_GOOD_OLD_INODE_SIZE;
|
|
Jan Kara |
fff6de |
+ if ((sbi->s_want_extra_isize > sbi->s_inode_size) ||
|
|
Jan Kara |
fff6de |
+ (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
|
|
Jan Kara |
fff6de |
+ sbi->s_inode_size)) {
|
|
Jan Kara |
fff6de |
+ sbi->s_want_extra_isize = def_extra_isize;
|
|
Jan Kara |
fff6de |
ext4_msg(sb, KERN_INFO,
|
|
Jan Kara |
fff6de |
"required extra inode space not available");
|
|
Jan Kara |
fff6de |
}
|