kernel BUG at fs/ext4/extents.c:LINE!

71 views
Skip to first unread message

syzbot

unread,
Apr 1, 2018, 1:01:03 PM4/1/18
to adilger...@dilger.ca, linux...@vger.kernel.org, linux-...@vger.kernel.org, syzkall...@googlegroups.com, ty...@mit.edu
Hello,

syzbot hit the following crash on upstream commit
10b84daddbec72c6b440216a69de9a9605127f7a (Sat Mar 31 17:59:00 2018 +0000)
Merge branch 'perf-urgent-for-linus' of
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
syzbot dashboard link:
https://syzkaller.appspot.com/bug?extid=06c885be0edcdaeab40c

C reproducer: https://syzkaller.appspot.com/x/repro.c?id=6721172100087808
syzkaller reproducer:
https://syzkaller.appspot.com/x/repro.syz?id=4701086711545856
Raw console output:
https://syzkaller.appspot.com/x/log.txt?id=6392087410900992
Kernel config:
https://syzkaller.appspot.com/x/.config?id=-2760467897697295172
compiler: gcc (GCC) 7.1.1 20170620

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+06c885...@syzkaller.appspotmail.com
It will help syzbot understand when the bug is fixed. See footer for
details.
If you forward the report, please keep this part and the footer.

------------[ cut here ]------------
kernel BUG at fs/ext4/extents.c:3190!
invalid opcode: 0000 [#1] SMP KASAN
Dumping ftrace buffer:
(ftrace buffer empty)
Modules linked in:
CPU: 0 PID: 4422 Comm: syzkaller152353 Not tainted 4.16.0-rc7+ #9
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
RIP: 0010:ext4_split_extent_at+0x75d/0x1160 fs/ext4/extents.c:3190
RSP: 0018:ffff8801c6b8e290 EFLAGS: 00010293
RAX: ffff8801acdc0080 RBX: ffff8801b425b018 RCX: ffffffff81e959ad
RDX: 0000000000000000 RSI: ffff8801a79c11f0 RDI: ffff8801d96ce940
RBP: ffff8801c6b8e3f8 R08: 0000000000000010 R09: 0000000000000425
R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801d96ce930
R13: 0000000000003010 R14: 1ffff10038d71c5e R15: 0000000000000010
FS: 00000000014a2880(0000) GS:ffff8801db000000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f8298ddf000 CR3: 00000001ad57f002 CR4: 00000000001606f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
ext4_split_extent.isra.36+0x2b6/0x490 fs/ext4/extents.c:3364
ext4_ext_convert_to_initialized fs/ext4/extents.c:3619 [inline]
ext4_ext_handle_unwritten_extents+0x1acd/0x3940 fs/ext4/extents.c:4081
ext4_ext_map_blocks+0x12d1/0x4410 fs/ext4/extents.c:4339
ext4_map_blocks+0xc90/0x1830 fs/ext4/inode.c:636
mpage_map_one_extent fs/ext4/inode.c:2452 [inline]
mpage_map_and_submit_extent fs/ext4/inode.c:2505 [inline]
ext4_writepages+0x2035/0x3c30 fs/ext4/inode.c:2875
do_writepages+0xff/0x170 mm/page-writeback.c:2340
__filemap_fdatawrite_range+0x32f/0x460 mm/filemap.c:444
file_write_and_wait_range+0x8a/0x100 mm/filemap.c:752
ext4_sync_file+0x4fb/0x1260 fs/ext4/fsync.c:128
vfs_fsync_range+0x110/0x260 fs/sync.c:196
generic_write_sync include/linux/fs.h:2680 [inline]
ext4_file_write_iter+0x919/0x10c0 fs/ext4/file.c:270
call_write_iter include/linux/fs.h:1782 [inline]
do_iter_readv_writev+0x55c/0x830 fs/read_write.c:653
do_iter_write+0x154/0x540 fs/read_write.c:932
vfs_iter_write+0x77/0xb0 fs/read_write.c:945
iter_file_splice_write+0x7db/0xf30 fs/splice.c:749
do_splice_from fs/splice.c:851 [inline]
direct_splice_actor+0x125/0x180 fs/splice.c:1018
splice_direct_to_actor+0x2c1/0x820 fs/splice.c:973
do_splice_direct+0x29b/0x3c0 fs/splice.c:1061
do_sendfile+0x5c9/0xe80 fs/read_write.c:1413
SYSC_sendfile64 fs/read_write.c:1468 [inline]
SyS_sendfile64+0xbd/0x160 fs/read_write.c:1460
do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287
entry_SYSCALL_64_after_hwframe+0x42/0xb7
RIP: 0033:0x440029
RSP: 002b:00007fff87fd7e68 EFLAGS: 00000217 ORIG_RAX: 0000000000000028
RAX: ffffffffffffffda RBX: 00000fffffeff000 RCX: 0000000000440029
RDX: 0000000020000000 RSI: 0000000000000004 RDI: 0000000000000003
RBP: 00000000006cb018 R08: 00007fff87fd7e80 R09: 00007fff87fd7e80
R10: 0000000100000001 R11: 0000000000000217 R12: 0000000000401860
R13: 00000000004018f0 R14: 0000000000000000 R15: 0000000000000000
Code: fe ff ff 48 c7 c7 c0 9c 56 87 0f b7 43 08 4c 8d 04 40 49 c1 e0 04 49
01 d8 e8 a0 66 ff ff 41 89 c7 e9 f8 fd ff ff e8 93 0b 88 ff <0f> 0b e8 8c
0b 88 ff 48 8b 8d b8 fe ff ff 48 b8 00 00 00 00 00
RIP: ext4_split_extent_at+0x75d/0x1160 fs/ext4/extents.c:3190 RSP:
ffff8801c6b8e290
---[ end trace d3416668281344cc ]---


---
This bug is generated by a dumb bot. It may contain errors.
See https://goo.gl/tpsmEJ for details.
Direct all questions to syzk...@googlegroups.com.

syzbot will keep track of this bug report.
If you forgot to add the Reported-by tag, once the fix for this bug is
merged
into any tree, please reply to this email with:
#syz fix: exact-commit-title
If you want to test a patch for this bug, please reply with:
#syz test: git://repo/address.git branch
and provide the patch inline or as an attachment.
To mark this as a duplicate of another syzbot report, please reply with:
#syz dup: exact-subject-of-another-report
If it's a one-off invalid bug report, please reply with:
#syz invalid
Note: if the crash happens again, it will cause creation of a new bug
report.
Note: all commands must start from beginning of the line in the email body.

Theodore Y. Ts'o

unread,
Apr 2, 2018, 12:45:28 AM4/2/18
to syzbot, adilger...@dilger.ca, linux...@vger.kernel.org, syzkall...@googlegroups.com
Here's a simplified reproducer. Run this script with the current
directory in an ext4 directory. Then unmount the file sytsem, and run
fsck on it. The file system corruption is.... impressive.

I'm pretty sure the problem is being caused by bad/missing
error/sanity checking in handling of FALLOC_FL_INSERT_RANGE.

- Ted

---------------- repro.c
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
int fd = 0;

fd = open("bus", O_RDWR|O_CREAT|O_SYNC|O_NOATIME, 0x644);
fallocate(fd, 0, 0, 4);
fallocate(fd, FALLOC_FL_KEEP_SIZE, 0x200002, 0x10000101);
fallocate(fd, FALLOC_FL_INSERT_RANGE, 0, 0xfffffeff000);
close(fd);
return 0;
}
----------------- fsck output

e2fsck 1.44.0 (7-Mar-2018)
Pass 1: Checking inodes, blocks, and sizes
Inode 12 has out of order extents
(invalid logical block 255, physical block 33921, len 30208)
Clear? yes

Failed to iterate extents in inode 12
(op ext2fs_extent_fix_parents, blk 33921, lblk 255): Extent not found
Clear inode? yes

Inode 12, i_size is 17592184991748, should be 17592184995840. Fix? yes

Restarting e2fsck from the beginning...
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Entry 'bus' in / (2) has deleted/unused inode 12. Clear? yes

Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Block bitmap differences: -33409 -(33920--64128) -(65536--98303) -(100352--102912)
Fix? yes

Free blocks count wrong for group #1 (1917, counted=32127).
Fix? yes

Free blocks count wrong for group #2 (0, counted=32768).
Fix? yes

Free blocks count wrong for group #3 (29566, counted=32127).
Fix? yes

Free blocks count wrong (1203103, counted=1268642).
Fix? yes

Inode bitmap differences: -12
Fix? yes

Free inodes count wrong for group #0 (8180, counted=8181).
Fix? yes

Free inodes count wrong (327668, counted=327669).
Fix? yes


/dev/vdc: ***** FILE SYSTEM WAS MODIFIED *****
/dev/vdc: 11/327680 files (0.0% non-contiguous), 42078/1310720 blocks

Eric Biggers

unread,
Apr 10, 2018, 3:02:35 AM4/10/18
to linux...@vger.kernel.org, Theodore Ts'o, Andreas Dilger, syzkall...@googlegroups.com
From: Eric Biggers <ebig...@google.com>

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+06c885...@syzkaller.appspotmail.com
Fixes: 331573febb6a ("ext4: Add support FALLOC_FL_INSERT_RANGE for fallocate")
Cc: <sta...@vger.kernel.org> # v4.2+
Signed-off-by: Eric Biggers <ebig...@google.com>
---
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

Darrick J. Wong

unread,
Apr 10, 2018, 10:43:35 AM4/10/18
to Eric Biggers, linux...@vger.kernel.org, Theodore Ts'o, Andreas Dilger, syzkall...@googlegroups.com
On Tue, Apr 10, 2018 at 12:01:04AM -0700, Eric Biggers wrote:
> From: Eric Biggers <ebig...@google.com>
>
> 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.

Could you please wrap this up into a xfstest for regression testing?

--D

Theodore Y. Ts'o

unread,
Apr 12, 2018, 11:53:06 AM4/12/18
to Eric Biggers, linux...@vger.kernel.org, Andreas Dilger, syzkall...@googlegroups.com
On Tue, Apr 10, 2018 at 12:01:04AM -0700, Eric Biggers wrote:
> From: Eric Biggers <ebig...@google.com>
>
> 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.
>

Applied, thanks.

- Ted
Reply all
Reply to author
Forward
0 new messages