From 047d5d774fe56908a2986dc194d9df7b6a8724c6 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 4 Sep 2016 17:31:07 -0400 Subject: [PATCH] e2fsck: enforce that the extra isize fields in the superblock are sane Invalid extra isize fields can cause crashes in e2fsprogs and possibly in the kernel for some architectures due to unaligned accesses. Signed-off-by: Theodore Ts'o --- e2fsck/problem.c | 10 ++++++++++ e2fsck/problem.h | 6 ++++++ e2fsck/super.c | 30 +++++++++++++++++++++++++++++- tests/f_sb_extra_isize/expect.1 | 13 +++++++++++++ tests/f_sb_extra_isize/expect.2 | 7 +++++++ tests/f_sb_extra_isize/image.gz | Bin 0 -> 719 bytes tests/f_sb_extra_isize/name | 1 + 7 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/f_sb_extra_isize/expect.1 create mode 100644 tests/f_sb_extra_isize/expect.2 create mode 100644 tests/f_sb_extra_isize/image.gz create mode 100644 tests/f_sb_extra_isize/name diff --git a/e2fsck/problem.c b/e2fsck/problem.c index ff91abd9..34a671e5 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -477,6 +477,16 @@ static struct e2fsck_problem problem_table[] = { N_("Error initializing quota context in support library: %m\n"), PROMPT_NULL, PR_FATAL }, + /* Bad s_min_extra_isize in superblock */ + { PR_0_BAD_MIN_EXTRA_ISIZE, + N_("Bad required extra isize in @S (%N). "), + PROMPT_FIX, 0 }, + + /* Bad s_min_extra_isize in superblock */ + { PR_0_BAD_WANT_EXTRA_ISIZE, + N_("Bad desired extra isize in @S (%N). "), + PROMPT_FIX, 0 }, + /* Pass 1 errors */ /* Pass 1: Checking inodes, blocks, and sizes */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index fad05c56..86cb6144 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -274,6 +274,12 @@ struct problem_context { /* Error initializing quota context */ #define PR_0_QUOTA_INIT_CTX 0x00004C +/* Bad s_min_extra_isize in superblock */ +#define PR_0_BAD_MIN_EXTRA_ISIZE 0x00004D + +/* Bad s_want_extra_isize in superblock */ +#define PR_0_BAD_WANT_EXTRA_ISIZE 0x00004E + /* * Pass 1 errors diff --git a/e2fsck/super.c b/e2fsck/super.c index dec70bd4..d2fd9225 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -578,7 +578,35 @@ void check_super_block(e2fsck_t ctx) ext2fs_mark_super_dirty(fs); } } - + if (EXT2_INODE_SIZE(sb) > EXT2_GOOD_OLD_INODE_SIZE) { + unsigned min = + sizeof(((struct ext2_inode_large *) 0)->i_extra_isize) + + sizeof(((struct ext2_inode_large *) 0)->i_checksum_hi); + unsigned max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; + pctx.num = sb->s_min_extra_isize; + if (sb->s_min_extra_isize && + (sb->s_min_extra_isize < min || + sb->s_min_extra_isize > max || + sb->s_min_extra_isize & 3) && + fix_problem(ctx, PR_0_BAD_MIN_EXTRA_ISIZE, &pctx)) { + sb->s_min_extra_isize = + (sizeof(struct ext2_inode_large) - + EXT2_GOOD_OLD_INODE_SIZE); + ext2fs_mark_super_dirty(fs); + } + pctx.num = sb->s_want_extra_isize; + if (sb->s_want_extra_isize && + (sb->s_want_extra_isize < min || + sb->s_want_extra_isize > max || + sb->s_want_extra_isize & 3) && + fix_problem(ctx, PR_0_BAD_WANT_EXTRA_ISIZE, &pctx)) { + sb->s_want_extra_isize = + (sizeof(struct ext2_inode_large) - + EXT2_GOOD_OLD_INODE_SIZE); + ext2fs_mark_super_dirty(fs); + } + } + /* Are metadata_csum and uninit_bg both set? */ if (ext2fs_has_feature_metadata_csum(fs->super) && ext2fs_has_feature_gdt_csum(fs->super) && diff --git a/tests/f_sb_extra_isize/expect.1 b/tests/f_sb_extra_isize/expect.1 new file mode 100644 index 00000000..75e239b1 --- /dev/null +++ b/tests/f_sb_extra_isize/expect.1 @@ -0,0 +1,13 @@ +Bad required extra isize in superblock (1). Fix? yes + +Bad desired extra isize in superblock (1024). Fix? yes + +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 11/32 files (0.0% non-contiguous), 28/200 blocks +Exit status is 1 diff --git a/tests/f_sb_extra_isize/expect.2 b/tests/f_sb_extra_isize/expect.2 new file mode 100644 index 00000000..c7e0e5fd --- /dev/null +++ b/tests/f_sb_extra_isize/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 11/32 files (0.0% non-contiguous), 28/200 blocks +Exit status is 0 diff --git a/tests/f_sb_extra_isize/image.gz b/tests/f_sb_extra_isize/image.gz new file mode 100644 index 0000000000000000000000000000000000000000..a7cb8279236658e0eee6dfd99cab8de7c97e565f GIT binary patch literal 719 zcmb2|=HM{tKNHTxoSB=Lp33m{uCIqkq73_k^7QLG*Ml`Y0wh=i8zm(oV!3R>SX?g| zcIdUrnXtS}xU|r_jMJ!tW#Q!5))yD9pFG5|UNKIoL!;}>1;rcpZeCR~ZC>+d#`DJi zHE+%sd_H&Xed;qKVWtV8y&I1uT|Kf(dbM3x-aD?|se!AW-m0kPSbFIr|ISZUw@-f- z-F#a#JuT|-3s0d#JDoVh{qwV`e|&v$Zgn-gx!=4h({K4vlcP&s{#|!*VdpO8>-ju( zJ1lK~{qWM0;n`|@+KsJl%VT{x-^7K=UiEk0TuPp4$}{JO$YRM?Nx9n3_uHu~42Ux; zeEs(AuM5?m!f)TJ-j{kxlBMD5$`GwK{i~nr-)l2w$JW^NpFgm3iDsYnWzS1jLMq$l zpSiB`+5K-yIcI-x8w z>sf1p|NLEOp`ml-U(L_z6N+o}`LmZ5zs$P-G$~ZK@c!XyrwpFGKX?9j4qLagZ(&aQ zyQ1uExBu&$Ec-3Zr~lvZOKey3GpEG5|KE%2zpI=5Nvk~lddvUcH|Adbmv8e}|K98S z)8BrRe;xTRxnjz_|0en+|0lP!xxTB