Re: [PATCH] ocfs2: fix boundary check in ocfs2_check_dir_entry() to use buffer offset
Dmitry Antipov <[email protected]> Fri, 10 Jul 2026 10:52:27 +0300
| Newsgroups | dev.linux.lists.ocfs2-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 7/10/26 7:05 AM, Joseph Qi wrote:
> Commit 390ac56cf0f6 ("ocfs2: add boundary check to ocfs2_check_dir_entry()")
> added an out-of-bounds guard using the caller-supplied 'offset' argument:
>
> if (offset > size - OCFS2_DIR_REC_LEN(1))
> return 0;
>
> However, 'offset' and 'size' are not measured against the same base for
> all callers. In the block-based lookup path, ocfs2_find_entry_el() passes
> 'offset' as an absolute offset into the whole directory:
>
> i = ocfs2_search_dirblock(bh, dir, name, namelen,
> block << sb->s_blocksize_bits,
> bh->b_data, sb->s_blocksize, res_dir);
>
> while 'size' is a single block size (sb->s_blocksize). For any directory
> entry located in the second or later block, 'offset' is >= sb->s_blocksize,
> so the guard rejects every such entry even though it is perfectly valid and
> lies entirely within its block buffer.
>
> This makes mounting fail for filesystems whose system directory spans more
> than one block, e.g. a volume formatted with a small block size:
>
> mkfs.ocfs2 -b 512 -C 4096 -N 2 -T datafiles --fs-features=usrquota,grpquota
>
> ocfs2_check_dir_entry:314 ERROR: directory entry (#18: offset=512) too close to end or out-of-bounds
> ocfs2_init_local_system_inodes:496 ERROR: status=-22, sysfile=12, slot=0
> ocfs2_mount_volume:1757 ERROR: status = -22
>
> The dirent's position within the buffer being validated is
> ((char *)de - buf), which is what the rest of the function already uses
> (via next_offset) and what must be bounds-checked against 'size'. Compute
> that buffer-relative offset and use it for the guard. The subtraction is
> reordered to size - buf_offset < OCFS2_DIR_REC_LEN(1) to avoid an unsigned
> underflow when size is smaller than the minimal record length.
>
> Fixes: 390ac56cf0f6 ("ocfs2: add boundary check to ocfs2_check_dir_entry()")
> Cc: [email protected]
> Signed-off-by: Joseph Qi <[email protected]>
Reviewed-and-tested-by: Dmitry Antipov <[email protected]>
> ---
> fs/ocfs2/dir.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
> index 8e6b032383278..d7fc3cccf2f4b 100644
> --- a/fs/ocfs2/dir.c
> +++ b/fs/ocfs2/dir.c
> @@ -302,10 +302,11 @@ static int ocfs2_check_dir_entry(struct inode *dir,
> unsigned long offset)
> {
> const char *error_msg = NULL;
> + unsigned long buf_offset = (char *)de - buf;
> unsigned long next_offset;
> int rlen;
>
> - if (offset > size - OCFS2_DIR_REC_LEN(1)) {
> + if (buf_offset > size || size - buf_offset < OCFS2_DIR_REC_LEN(1)) {
> /* Dirent is (maybe partially) beyond the buffer
> * boundaries so touching 'de' members is unsafe.
> */
> @@ -316,7 +317,7 @@ static int ocfs2_check_dir_entry(struct inode *dir,
> }
>
> rlen = le16_to_cpu(de->rec_len);
> - next_offset = ((char *) de - buf) + rlen;
> + next_offset = buf_offset + rlen;
>
> if (unlikely(rlen < OCFS2_DIR_REC_LEN(1)))
> error_msg = "rec_len is smaller than minimal";