From 039b3f78070fc6e79870ba3f99b96952cdb103a0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 18 Apr 2018 11:56:59 -0400 Subject: [PATCH] add patch prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS --- ...nt-right-shifting-extents-beyond-EXT_MAX_BLOCKS | 69 ++++++++++++++++++++++ series | 2 + timestamps | 8 ++- 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS diff --git a/prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS b/prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS new file mode 100644 index 00000000..1cdc6eea --- /dev/null +++ b/prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS @@ -0,0 +1,69 @@ +ext4: prevent right-shifting extents beyond EXT_MAX_BLOCKS + +From: Eric Biggers + +During the "insert range" fallocate operation, extents starting at the +range offset are shifted "right" (to a higher file offset) by the range +length. But, as shown by syzbot, it's not validated that this doesn't +cause extents to be shifted beyond EXT_MAX_BLOCKS. In that case +->ee_block can wrap around, corrupting the extent tree. + +Fix it by returning an error if the space between the end of the last +extent and EXT4_MAX_BLOCKS is smaller than the range being inserted. + +This bug can be reproduced by running the following commands when the +current directory is on an ext4 filesystem with a 4k block size: + + fallocate -l 8192 file + fallocate --keep-size -o 0xfffffffe000 -l 4096 -n file + fallocate --insert-range -l 8192 file + +Then after unmounting the filesystem, e2fsck reports corruption. + +Reported-by: syzbot+06c885be0edcdaeab40c@syzkaller.appspotmail.com +Fixes: 331573febb6a ("ext4: Add support FALLOC_FL_INSERT_RANGE for fallocate") +Cc: # v4.2+ +Signed-off-by: Eric Biggers +Signed-off-by: Theodore Ts'o +--- + fs/ext4/extents.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 0a7315961bac6..c969275ce3ee7 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -5329,8 +5329,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, + stop = le32_to_cpu(extent->ee_block); + + /* +- * In case of left shift, Don't start shifting extents until we make +- * sure the hole is big enough to accommodate the shift. ++ * For left shifts, make sure the hole on the left is big enough to ++ * accommodate the shift. For right shifts, make sure the last extent ++ * won't be shifted beyond EXT_MAX_BLOCKS. + */ + if (SHIFT == SHIFT_LEFT) { + path = ext4_find_extent(inode, start - 1, &path, +@@ -5350,9 +5351,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, + + if ((start == ex_start && shift > ex_start) || + (shift > start - ex_end)) { +- ext4_ext_drop_refs(path); +- kfree(path); +- return -EINVAL; ++ ret = -EINVAL; ++ goto out; ++ } ++ } else { ++ if (shift > EXT_MAX_BLOCKS - ++ (stop + ext4_ext_get_actual_len(extent))) { ++ ret = -EINVAL; ++ goto out; + } + } + +-- +2.17.0 + + diff --git a/series b/series index f398f5da..ef9fb32b 100644 --- a/series +++ b/series @@ -1,5 +1,7 @@ # e40ff2138985 +prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS + #################################################### # unstable patches #################################################### diff --git a/timestamps b/timestamps index d488691f..706c3e8a 100755 --- a/timestamps +++ b/timestamps @@ -28,12 +28,14 @@ touch -d @1522639443 jbd2-suppress-extra-newline-in-jbd2_debug touch -d @1522639503 jbd2-dont-double-bump-transaction-number touch -d @1522639563 journal-superblock-changes touch -d @1522639623 add-journal-no-cleanup-option -touch -d @1523241663 series -touch -d @1523241706 timestamps touch -d @1523242005 add-support-for-log-metadata-block-tracking-in-log touch -d @1523242044 add-indirection-to-metadata-block-read-paths touch -d @1523242121 cleaner touch -d @1523242124 disable-writeback touch -d @1523242124 load-jmap-from-journal touch -d @1523242125 add-ext4-journal-lazy-mount-option -touch -d @1523242592 status +touch -d @1523548089 prevent-right-shifting-extents-beyond-EXT_MAX_BLOCKS +touch -d @1524066571 set-h_journal-if-reserved-handle-fails-to-start +touch -d @1524066571 status +touch -d @1524067007 series +touch -d @1524067010 timestamps -- 2.11.4.GIT