qnx4_block_map() follows the on-disk extent chain. For each extent block (struct qnx4_xblk, one 512-byte QNX4 block) it walks xblk->xblk_xtnts[ix] using xblk->xblk_num_xtnts as the loop bound: block = try_extent(&xblk->xblk_xtnts[ix], &offset); ... if (++ix >= xblk->xblk_num_xtnts) { ... ix = 0; } xblk_xtnts[] is a fixed QNX4_MAX_XTNTS_PER_XBLK (60) array, but xblk_num_xtnts is an on-disk u8 (up to 255) that is never validated. A crafted image with xblk_num_xtnts > 60 makes ix walk past xblk_xtnts[60], reading past the end of the 512-byte extent block (an out-of-bounds read of the buffer_head data). Reject an extent count larger than the array, right after the "IamXblk" signature check. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas --- Everything below the --- is dropped by git am. Class / impact: CWE-125 out-of-bounds read (root CWE-129). Reachable only by mounting a crafted qnx4 image (CAP_SYS_ADMIN; not unprivileged-userns mountable) and reading a file with a long extent chain. Read-only, no write primitive; on a live mount the 512-byte block shares a 4096-byte page-cache page so the read lands in adjacent in-page data of the same image -> a robustness/hardening fix. Affected: present since fs/qnx4/inode.c entered git at v2.6.12-rc2 (the extent walk predates git). Verified at mainline v7.1-rc6 and stable v6.12.92. Reproducer: a qnx4 image whose file uses an indirect extent block ("IamXblk") with xblk_num_xtnts > 60 (e.g. 255); mount and read that file. A/B verification (CONFIG_KASAN_GENERIC=y, kasan.fault=report, x86-64). The on-disk extent block is exactly 512 bytes; reproduced on a kmalloc(512) copy of the walk so KASAN sees the boundary: - Without this patch (xblk_num_xtnts = 255): BUG: KASAN: slab-out-of-bounds in Read of size 4 ... located 4 bytes to the right of the 512-byte region (cache kmalloc-512) - Control (xblk_num_xtnts = 5): no report. - With this patch (xblk_num_xtnts = 255): no report, block rejected -EIO. Also an ABI-invariant AddressSanitizer extraction (-m64 and -m32): heap-buffer-overflow read without the patch, clean with it. fs/qnx4/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 3828ba7d4492..f244e197e2df 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -112,6 +112,12 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) brelse(bh); return -EIO; } + if (xblk->xblk_num_xtnts > QNX4_MAX_XTNTS_PER_XBLK) { + QNX4DEBUG((KERN_ERR "qnx4: bad xtnt count %u\n", + xblk->xblk_num_xtnts)); + brelse(bh); + return -EIO; + } } block = try_extent(&xblk->xblk_xtnts[ix], &offset); if (block) { -- 2.43.0