bfs_move_block() uses sb_getblk() to obtain a buffer for the destination
block, copies data into it via memcpy(), and then calls mark_buffer_dirty().
However, sb_getblk() only allocates a buffer head without reading the block
from disk, leaving BH_Uptodate unset. This causes mark_buffer_dirty() to
trigger a warning:
WARNING: fs/buffer.c:1180 at mark_buffer_dirty+0x299/0x410
!buffer_uptodate(bh)
Since bfs_move_block() fully overwrites the destination buffer via memcpy(),
reading the block from disk is unnecessary. Instead, call
set_buffer_uptodate() after the copy to indicate the buffer contains valid
data before marking it dirty.
Additionally, sb_getblk() can return NULL but the original code never
checked for this, which would cause a NULL pointer dereference. Add a
proper NULL check with cleanup of the source buffer on failure.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+d083fd809394eab229a8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d083fd809394eab229a8
Tested-by: syzbot+d083fd809394eab229a8@syzkaller.appspotmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/bfs/file.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index d33d6bde992b..0a9b12b73324 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -40,7 +40,12 @@ static int bfs_move_block(unsigned long from, unsigned long to,
if (!bh)
return -EIO;
new = sb_getblk(sb, to);
+ if (!new) {
+ brelse(bh);
+ return -EIO;
+ }
memcpy(new->b_data, bh->b_data, bh->b_size);
+ set_buffer_uptodate(new);
mark_buffer_dirty(new);
bforget(bh);
brelse(new);
--
2.43.0