summaryrefslogtreecommitdiff
path: root/scripts/objdiff
diff options
context:
space:
mode:
authorZhan Xusheng <zhanxusheng@xiaomi.com>2026-08-11 10:43:36 +0800
committerAndrew Morton <akpm@linux-foundation.org>2026-08-19 19:55:06 -0700
commitbec0eed29b41a4e1b922d9ce40a748216496ed6e (patch)
tree7e6c640bce08df56786841e4ef5ac48e413e2ac1 /scripts/objdiff
parentf6f47a9ca82b3943c136494143f41366f83a2584 (diff)
downloadlinux-bec0eed29b41a4e1b922d9ce40a748216496ed6e.tar.gz
linux-bec0eed29b41a4e1b922d9ce40a748216496ed6e.zip
ocfs2: bound-check dir entries in the readdir re-validation scan
Patch series "ocfs2: bound-check both readdir re-validation scans", v2. This patch (of 2): When the inode version changed since the last readdir(), ocfs2_dir_foreach_blk_el() re-scans the directory block from its start to relocate the current position: for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ocfs2_dir_entry *)(bh->b_data + i); if (le16_to_cpu(de->rec_len) < OCFS2_DIR_REC_LEN(1)) break; i += le16_to_cpu(de->rec_len); } i walks the block on rec_len values taken from the block itself and the only thing tested is that rec_len is not too small, so a single bogus rec_len leaves i anywhere in the block, including its last OCFS2_DIR_REC_LEN(1) - 1 bytes. @offset comes from ctx->pos, which userspace moves with lseek() on the directory fd, and decides how far the walk gets. Two bounds are missing, both of which ocfs2_check_dir_entry() applies for the emit loop below. de->rec_len sits at byte offset 8 within the entry, so dereferencing de in that tail reads past the s_blocksize buffer. ocfs2_check_dir_entry() declines to look at an entry that close to the end: size - buf_offset < OCFS2_DIR_REC_LEN(1) Nothing bounds i += rec_len either, so i can end up past the block. The emit loop that follows is guarded by offset < sb->s_blocksize and does not run, but offset = i; ctx->pos = (ctx->pos & ~((loff_t)sb->s_blocksize - 1)) | offset; runs first and ORs a value with bits above the block mask into ctx->pos, corrupting the block number readdir() resumes from. ocfs2_check_dir_entry() rejects that as "directory entry overrun": next_offset = buf_offset + rlen; ... next_offset > size Apply both bounds. For a consistent directory this changes nothing: entries are at least OCFS2_DIR_REC_LEN(1) bytes and do not cross the end of the block, so no valid entry is skipped. Found by the sashiko review tool; fix approach suggested by Joseph Qi. Link: https://lore.kernel.org/20260811024337.3972976-1-zhanxusheng@xiaomi.com Link: https://sashiko.dev/#/patchset/20260806022044.167962-1-zhanxusheng@xiaomi.com Link: https://lore.kernel.org/20260811024337.3972976-2-zhanxusheng@xiaomi.com Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com> Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'scripts/objdiff')
0 files changed, 0 insertions, 0 deletions