[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220315191545.187366-1-tadeusz.struk@linaro.org>
Date: Tue, 15 Mar 2022 12:15:45 -0700
From: Tadeusz Struk <tadeusz.struk@...aro.org>
To: Theodore Ts'o <tytso@....edu>
Cc: Tadeusz Struk <tadeusz.struk@...aro.org>,
Andreas Dilger <adilger.kernel@...ger.ca>,
Ritesh Harjani <riteshh@...ux.ibm.com>,
linux-ext4@...r.kernel.org, stable@...r.kernel.org,
linux-kernel@...r.kernel.org,
syzbot+7a806094edd5d07ba029@...kaller.appspotmail.com
Subject: [PATCH] ext4: check if offset+length is within a valid range in fallocate
Syzbot found an issue [1] in ext4_fallocate().
The C reproducer [2] calls fallocate(), passing size 0xffeffeff000ul,
and offset 0x1000000ul, which, when added together exceed the disk size,
and trigger a BUG in ext4_ind_remove_space() [3].
According to the comment doc in ext4_ind_remove_space() the 'end'
parameter needs to be one block after the last block to remove.
In the case when the BUG is triggered it points to the last block on
a 4GB virtual disk image. This is calculated in
ext4_ind_remove_space() in [4].
This patch adds a check that ensure the length + offest to be
within the valid range and returns -ENOSPC error code in case
it is invalid.
LINK: [1] https://syzkaller.appspot.com/bug?id=b80bd9cf348aac724a4f4dff251800106d721331
LINK: [2] https://syzkaller.appspot.com/text?tag=ReproC&x=14ba0238700000
LINK: [3] https://elixir.bootlin.com/linux/v5.17-rc8/source/fs/ext4/indirect.c#L1244
LINK: [4] https://elixir.bootlin.com/linux/v5.17-rc8/source/fs/ext4/indirect.c#L1234
Cc: Theodore Ts'o <tytso@....edu>
Cc: Andreas Dilger <adilger.kernel@...ger.ca>
Cc: Ritesh Harjani <riteshh@...ux.ibm.com>
Cc: <linux-ext4@...r.kernel.org>
Cc: <stable@...r.kernel.org>
Cc: <linux-kernel@...r.kernel.org>
Fixes: a4bb6b64e39a ("ext4: enable "punch hole" functionality")
Reported-by: syzbot+7a806094edd5d07ba029@...kaller.appspotmail.com
Signed-off-by: Tadeusz Struk <tadeusz.struk@...aro.org>
---
fs/ext4/inode.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 01c9e4f743ba..dd9c35113efe 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3924,7 +3924,8 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
struct super_block *sb = inode->i_sb;
ext4_lblk_t first_block, stop_block;
struct address_space *mapping = inode->i_mapping;
- loff_t first_block_offset, last_block_offset;
+ loff_t first_block_offset, last_block_offset, max_length;
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
handle_t *handle;
unsigned int credits;
int ret = 0, ret2 = 0;
@@ -3967,6 +3968,16 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
offset;
}
+ /*
+ * For punch hole the length + offset needs to be at least within
+ * one block before last
+ */
+ max_length = sbi->s_bitmap_maxbytes - sbi->s_blocksize;
+ if (offset + length >= max_length) {
+ ret = -ENOSPC;
+ goto out_mutex;
+ }
+
if (offset & (sb->s_blocksize - 1) ||
(offset + length) & (sb->s_blocksize - 1)) {
/*
--
2.35.1
Powered by blists - more mailing lists