Bug 259024 - ext2_search_dirblock() loops forever if e2d_reclen is zero
Summary: ext2_search_dirblock() loops forever if e2d_reclen is zero
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-10-09 11:22 UTC by Robert Morris
Modified: 2022-01-06 07:48 UTC (History)
2 users (show)

See Also:


Attachments
An ext3 disk image that causes ext2_search_dirblock() to loop forever. (1.50 KB, application/x-gzip)
2021-10-09 11:22 UTC, Robert Morris
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Morris 2021-10-09 11:22:39 UTC
Created attachment 228539 [details]
An ext3 disk image that causes ext2_search_dirblock() to loop forever.

The code in ext2_search_dirblock() that handles e2d_reclen == 0
doesn't increment ep, and thus loops forever. 

I've attached a demo:

% gunzip ext34.img.gz
% sudo mdconfig -f ext34.img
% sudo mount -t ext2fs -o ro /dev/md0 /mnt
% sudo cp /mnt/a /dev/null
<the lookup never finishes>

FreeBSD unmatched 14.0-CURRENT FreeBSD 14.0-CURRENT #0 main-n249571-b5f90655ea3: Thu Sep 23 06:10:05 UTC 2021     root@releng1.nyi.freebsd.org:/usr/obj/usr/src/riscv.riscv64/sys/GENERIC  riscv
Comment 1 Fedor Uporov freebsd_committer freebsd_triage 2021-10-18 16:03:29 UTC
Hi, Robert.

Thanks a lot for reports and images for reproduction.

I successfully reproduced current issue on amd64 with crash instead of infinity loop:
#14 0xffffffff810f1927 in trap (frame=0xfffffe00af5eb7b0) at /usr/src/sys/amd64/amd64/trap.c:443
#15 <signal handler called>
#16 ext2_search_dirblock (ip=<optimized out>, ip@entry=0xfffff80004d73900, data=<optimized out>,
    foundp=foundp@entry=0xfffffe00af5eb990, name=0xfffff80004c87805 "a", namelen=1, entryoffsetinblockp=<optimized out>,
    entryoffsetinblockp@entry=0xfffffe00af5eb9dc, offp=0xfffffe00af5eb9e4, prevoffp=0xfffffe00af5eb9ac,
    endusefulp=0xfffffe00af5eb9d4, ssp=0xfffffe00af5eb978) at /usr/src/sys/fs/ext2fs/ext2_lookup.c:743
#17 0xffffffff82746852 in ext2_lookup_ino (vdp=<optimized out>, vpp=0xfffffe00af5ebc28, cnp=0xfffffe00af5ebc50, dd_ino=0x0)
    at /usr/src/sys/fs/ext2fs/ext2_lookup.c:455
#18 0xffffffff80cf9f16 in VOP_CACHEDLOOKUP (dvp=0xfffff800b50d3700, vpp=0xfffffe00af5ebc28, cnp=0xfffffe00af5ebc50)
    at ./vnode_if.h:103
#19 vfs_cache_lookup (ap=<optimized out>) at /usr/src/sys/kern/vfs_cache.c:3068
#20 0xffffffff80d0b1e1 in VOP_LOOKUP (dvp=0xfffff800b50d3700, vpp=0xfffffe00af5ebc28, cnp=0xfffffe00af5ebc50) at ./vnode_if.h:69
#21 lookup (ndp=ndp@entry=0xfffffe00af5ebbd0) at /usr/src/sys/kern/vfs_lookup.c:1128
--Type <RET> for more, q to quit, c to continue without paging--
#22 0xffffffff80d0a0de in namei (ndp=ndp@entry=0xfffffe00af5ebbd0) at /usr/src/sys/kern/vfs_lookup.c:658
#23 0xffffffff80d29ba2 in kern_statat (td=0xfffffe0094b47e40, flag=<optimized out>, fd=-100,
    path=0x8018182f8 <error: Cannot access memory at address 0x8018182f8>, pathseg=pathseg@entry=UIO_USERSPACE,
    sbp=sbp@entry=0xfffffe00af5ebd18, hook=0x0) at /usr/src/sys/kern/vfs_syscalls.c:2441

Issues 259105, 259107, 259112 were successfully reproduced too.

The problem with these sort of issues, I mean malicious images with bad/corrupted metadata, that it is too difficult to make
crosscheck of metadata values read from disk. The only way to avoid it, is to format drive with ext4 metadata_csum (RO_COMPAT_METADATA_CSUM) feature turned on.

Need to find a way, how the metadata values, which cause a crashes, could be verified.
Comment 2 commit-hook freebsd_committer freebsd_triage 2021-12-30 06:16:00 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=bb9f1ba4b55c1f566d59cc7c7d1d28dd37715984

commit bb9f1ba4b55c1f566d59cc7c7d1d28dd37715984
Author:     Fedor Uporov <fsu@FreeBSD.org>
AuthorDate: 2021-10-29 12:45:50 +0000
Commit:     Fedor Uporov <fsu@FreeBSD.org>
CommitDate: 2021-12-30 06:14:44 +0000

    Add more accurate directory entries check

    Rename ext2_dirbadentry() to ext2_check_direntry(). Add directory
    entry inode value check, and call ext2_check_direntry() in all cases.
    The dirchk sysctl is removed.

    PR:                     259024,259041
    Reported by:            Robert Morris
    Reviewed by:            pfg
    MFC after:              2 weeks
    Differential Revision:  https://reviews.freebsd.org/D33374

 sys/fs/ext2fs/ext2_lookup.c | 39 ++++++++++-----------------------------
 1 file changed, 10 insertions(+), 29 deletions(-)