udf: reject extents past EOF when extending a file udf_extend_file() warns when inode_bmap() reports the last extent as longer than the block the file is being extended in: WARN_ON_ONCE(within_last_ext && elen > ((loff_t)offset + 1) << inode->i_blkbits); A corrupted image can trigger this, as syzbot reports for udf_setsize(): WARNING: CPU: 1 PID: 6098 at fs/udf/inode.c:684 udf_extend_file fs/udf/inode.c:683 [inline] WARNING: CPU: 1 PID: 6098 at fs/udf/inode.c:684 udf_setsize+0xd5a/0x1010 fs/udf/inode.c:1300 The extent really is invalid, so there is nothing to warn about: report it with udf_err() and fail the truncate with -EFSCORRUPTED instead of tainting the kernel. Reported-by: syzbot+db6df8c0f578bc11e50e@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=db6df8c0f578bc11e50e Fixes: 16d055656814 ("udf: Discard preallocation before extending file with a hole") Signed-off-by: xujiahao <xujiahao@cmss.chinamobile.com> Link: https://patch.msgid.link/20261109013952.449019-1-xujiahao@cmss.chinamobile.com Signed-off-by: Jan Kara <jack@suse.cz>
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index c425096..78a3451 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c
@@ -687,9 +687,14 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) if (err < 0) goto out; within_last_ext = (err == 1); - /* We don't expect extents past EOF... */ - WARN_ON_ONCE(within_last_ext && - elen > ((loff_t)offset + 1) << inode->i_blkbits); + if (within_last_ext && + elen > ((loff_t)offset + 1) << inode->i_blkbits) { + udf_err(sb, "(ino %llu) extent past EOF: length %u, expected at most %lld\n", + inode->i_ino, elen, + ((loff_t)offset + 1) << inode->i_blkbits); + err = -EFSCORRUPTED; + goto out; + } if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {