qnx6: validate di_filelevels in qnx6_iget() - #2647
Open
vfsci-bot[bot] wants to merge 6 commits into
Open
vfsci-bot[bot] wants to merge 6 commits into
vfsci-bot[bot] wants to merge 6 commits into
Conversation
In qnx6_iget(), raw_inode->di_filelevels is copied directly from the on-disk inode without checking whether it exceeds QNX6_PTR_MAX_LEVELS (5) (unlike sb1->Inode.levels and sb1->Longfile.levels, which qnx6_fill_super() explicitly checks against QNX6_PTR_MAX_LEVELS). When qnx6_block_map() later computes bitdelta = ptrbits * ei->di_filelevels, a crafted di_filelevels value (e.g. 20, giving bitdelta = 200) causes a shift-out-of-bounds in (no >> bitdelta) and out-of-bounds indirect block traversal: qnx6: superblock #1 active Buffer I/O error on dev loop0, logical block 4099, async page read qnx6: Error reading block (4099) qnx6: error reading root directory. Validate that ei->di_filelevels <= QNX6_PTR_MAX_LEVELS in qnx6_iget() and fail with -EIO if exceeded. Tested in QEMU against Linux 7.3.0-rc3 by mounting a crafted QNX6 filesystem image with root inode di_filelevels = 20 on /dev/loop0: on the unfixed kernel qnx6_iget() accepts the inode and qnx6_block_map() walks invalid indirect blocks ("qnx6: Error reading block (4099)"), whereas on the fixed kernel qnx6_iget() logs "qnx6: invalid filelevels (20) in inode 1" and fails immediately with -EIO. Fixes: 5d026c7 ("fs: initial qnx6fs addition") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com>
In qnx6_block_map(), when qnx6_check_blockptr(ptr) fails ("qnx6: hit
unused blockpointer.") inside the indirect block traversal loop, the
buffer_head bh read by sb_bread() is not released before returning 0,
leaving bh->b_count elevated and pinning the backing blockdev folio in
memory. Call brelse(bh) on that error path before returning 0.
Tested in QEMU against Linux 7.3.0-rc3 by mounting a crafted QNX6 image on
/dev/loop0 with a file (di_filelevels = 1) whose indirect block (block 5)
contains an unused block pointer (~0U), reading the file to trigger
"qnx6: hit unused blockpointer.", and then flushing per-CPU bh_lrus and
pagecache via /proc/sys/vm/drop_caches and POSIX_FADV_DONTNEED: on the
unfixed kernel indirect block 5 remains pinned in bd_mapping
(indirect_page5_leaked = 1), whereas on the fixed kernel indirect block 5
is released and evicted cleanly (indirect_page5_leaked = 0).
Fixes: 5d026c7 ("fs: initial qnx6fs addition")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
In qnx6_fill_super(), when selecting the active superblock, the inactive superblock buffer_head (bh2 when superblock #1 is active, or bh1 when superblock #2 is active) is released immediately via brelse() without clearing the local pointer to NULL. If a subsequent mount step fails and jumps to out, out1, out2, or out3, qnx6_fill_super() unconditionally calls brelse(bh1) and brelse(bh2), causing a second brelse() on the already released buffer_head. Because the extra brelse() drops the per-CPU bh_lru reference to 0, freeing the buffer_head while it remains in bh_lru, this triggers a KASAN slab-use-after-free and VFS buffer refcount warning: qnx6: superblock #1 active qnx6: error reading root directory. BUG: KASAN: slab-use-after-free in invalidate_bh_lrus_cpu+0x9f/0x120 Read of size 4 at addr ffff88800151e658 by task kworker/1:1/69 ... VFS: brelse: Trying to free [already] free buffer WARNING: fs/buffer.c:1051 at invalidate_bh_lru+0x4c/0x160, CPU#0: init/1 Clear bh2/bh1 to NULL immediately after releasing the inactive buffer_head. Tested in QEMU against Linux 7.3.0-rc3 by mounting a crafted QNX6 image on /dev/loop0 that activates superblock #1 and then fails root directory validation: on the unfixed kernel, mount failure triggers the double-brelse VFS warning, WARNING at fs/buffer.c:1051, and KASAN slab-use-after-free in invalidate_bh_lrus_cpu(), whereas on the fixed kernel mount fails cleanly with 0 warnings or KASAN faults. Fixes: 5d026c7 ("fs: initial qnx6fs addition") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com>
When mounting with "-o mmi_fs" (QNX6_MOUNT_MMI_FS), qnx6_mmi_fill_super() allocates the active superblock buffer_head and stores it in qs->sb_buf (QNX6_SB(s)->sb_buf), while qnx6_fill_super()'s local bh1 and bh2 pointers remain NULL, and jumps to mmi_success. If a subsequent validation or inode initialization check after mmi_success fails and jumps to out, out1, out2, or out3, the error cleanup at out only calls brelse(bh1) and brelse(bh2) (both NULL), leaking the qs->sb_buf buffer_head reference. Release qs->sb_buf at out when it is distinct from bh1 and bh2 (using qs->sb_buf rather than sbi->sb_buf because sbi is not yet initialized if mmi_success jumps to out on superblock level validation failure). Tested in QEMU against Linux 7.3.0-rc3 by mounting a crafted QNX6 mmi_fs image on /dev/loop0 that succeeds in qnx6_mmi_fill_super() (allocating qs->sb_buf at block 0) and then fails root directory validation, followed by flushing per-CPU bh_lrus and pagecache via /proc/sys/vm/drop_caches and POSIX_FADV_DONTNEED: on the unfixed kernel block 0 remains pinned in bd_mapping by the leaked qs->sb_buf buffer_head (sb_buf_page0_leaked = 1), whereas on the fixed kernel qs->sb_buf is released and evicted cleanly (sb_buf_page0_leaked = 0). Fixes: 5d026c7 ("fs: initial qnx6fs addition") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com>
In qnx6_mmi_fill_super(), when the superblock #1 magic check fails and the silent mount flag (SB_SILENT) is set, the goto out statement is inside the if (!silent) block, so execution continues past the magic check with an invalid superblock (unlike superblock #2 at line 93 where goto out is outside if (!silent)). Move goto out outside the if (!silent) block. Tested in QEMU against Linux 7.3.0-rc3 by mounting a crafted QNX6 mmi_fs image on /dev/loop0 with sb1->sb_magic = 0xdeadbeef (!= QNX6_SUPER_MAGIC) using MS_SILENT | MS_RDONLY and "-o mmi_fs": on the unfixed kernel qnx6_mmi_fill_super() ignores the magic mismatch when MS_SILENT is set, logs "qnx6: superblock #1 active", and mounts the invalid-magic filesystem (mount returns 0), whereas on the fixed kernel qnx6_mmi_fill_super() immediately aborts at the magic check and rejects the mount with -EINVAL. Fixes: 5d026c7 ("fs: initial qnx6fs addition") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com>
In qnx6_mmi_fill_super(), QNX6_SUPERBLOCK_AREA / fs32_to_cpu(sbi, sb1->sb_blocksize) is evaluated before sb_set_blocksize() validates that sb1->sb_blocksize is a non-zero power of two, risking a divide-by-zero when sb1->sb_blocksize is 0 on disk. Move the offset calculation after sb_set_blocksize() (matching qnx6_fill_super() in fs/qnx6/inode.c). Tested in QEMU against Linux 7.3.0-rc3 by mounting a crafted QNX6 mmi_fs image with sb_blocksize = 0 on /dev/loop0 and verifying that sb_set_blocksize() logs "qnx6: unable to set blocksize" and rejects the mount with -EINVAL before any division takes place. Fixes: 5d026c7 ("fs: initial qnx6fs addition") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Hui Peng <benquike@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Series: https://patchwork.kernel.org/project/linux-fsdevel/list/?series=1169988
Submitter: Hui Peng
Version: 2
Patches: 6/6
Message-ID:
<20260921042511.1473629-1-benquike@gmail.com>Base: vfs.base.ci
Lore: https://lore.kernel.org/linux-fsdevel/20260921042511.1473629-1-benquike@gmail.com
Automated by ml2pr