| From 270ef41094e9fa95273f288d7d785313ceab2ff3 Mon Sep 17 00:00:00 2001 |
| From: Eric Biggers <ebiggers@google.com> |
| Date: Tue, 11 Aug 2020 18:35:30 -0700 |
| Subject: fs/minix: reject too-large maximum file size |
| |
| From: Eric Biggers <ebiggers@google.com> |
| |
| commit 270ef41094e9fa95273f288d7d785313ceab2ff3 upstream. |
| |
| If the minix filesystem tries to map a very large logical block number to |
| its on-disk location, block_to_path() can return offsets that are too |
| large, causing out-of-bounds memory accesses when accessing indirect index |
| blocks. This should be prevented by the check against the maximum file |
| size, but this doesn't work because the maximum file size is read directly |
| from the on-disk superblock and isn't validated itself. |
| |
| Fix this by validating the maximum file size at mount time. |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Reported-by: syzbot+c7d9ec7a1a7272dd71b3@syzkaller.appspotmail.com |
| Reported-by: syzbot+3b7b03a0c28948054fb5@syzkaller.appspotmail.com |
| Reported-by: syzbot+6e056ee473568865f3e6@syzkaller.appspotmail.com |
| Signed-off-by: Eric Biggers <ebiggers@google.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Alexander Viro <viro@zeniv.linux.org.uk> |
| Cc: Qiujun Huang <anenbupt@gmail.com> |
| Cc: <stable@vger.kernel.org> |
| Link: http://lkml.kernel.org/r/20200628060846.682158-4-ebiggers@kernel.org |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/minix/inode.c | 22 ++++++++++++++++++++-- |
| 1 file changed, 20 insertions(+), 2 deletions(-) |
| |
| --- a/fs/minix/inode.c |
| +++ b/fs/minix/inode.c |
| @@ -150,6 +150,23 @@ static int minix_remount (struct super_b |
| return 0; |
| } |
| |
| +static bool minix_check_superblock(struct minix_sb_info *sbi) |
| +{ |
| + if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0) |
| + return false; |
| + |
| + /* |
| + * s_max_size must not exceed the block mapping limitation. This check |
| + * is only needed for V1 filesystems, since V2/V3 support an extra level |
| + * of indirect blocks which places the limit well above U32_MAX. |
| + */ |
| + if (sbi->s_version == MINIX_V1 && |
| + sbi->s_max_size > (7 + 512 + 512*512) * BLOCK_SIZE) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| static int minix_fill_super(struct super_block *s, void *data, int silent) |
| { |
| struct buffer_head *bh; |
| @@ -228,11 +245,12 @@ static int minix_fill_super(struct super |
| } else |
| goto out_no_fs; |
| |
| + if (!minix_check_superblock(sbi)) |
| + goto out_illegal_sb; |
| + |
| /* |
| * Allocate the buffer map to keep the superblock small. |
| */ |
| - if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0) |
| - goto out_illegal_sb; |
| i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh); |
| map = kzalloc(i, GFP_KERNEL); |
| if (!map) |