[Bug 271354] reachable directory with zero link count can cause fsck to deref NULL

From: <bugzilla-noreply_at_freebsd.org>
Date: Wed, 10 May 2023 19:09:49 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=271354

            Bug ID: 271354
           Summary: reachable directory with zero link count can cause
                    fsck to deref NULL
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: bin
          Assignee: bugs@FreeBSD.org
          Reporter: rtm@lcs.mit.edu

Created attachment 242111
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=242111&action=edit
ffs image with reachable directory with zero link count causes fsck to deref
NULL

If a directory inode's link count is zero, then pass1.c's checkinode()
doesn't call cacheino() to enter it into inphash[]:

     if (mode == IFDIR) {
        if (DIP(dp, di_size) == 0) {
            inoinfo(inumber)->ino_state = DCLEAR;
        } else if (DIP(dp, di_nlink) <= 0) {
            inoinfo(inumber)->ino_state = DZLINK;
        } else {
            inoinfo(inumber)->ino_state = DSTATE;  
            cacheino(dp, inumber);

Then in pass2check(), if the directory is reachable, the fall-through
path from DZLINK calls getinoinfo(), which returns NULL, causing
inp->i_parent to crash:

                case DZLINK:
                        if (inoinfo(idesc->id_number)->ino_state == DFOUND)
                                inoinfo(dirp->d_ino)->ino_state = DFOUND;
                        /* FALLTHROUGH */

                case DFOUND:
                        inp = getinoinfo(dirp->d_ino);
                        if (idesc->id_entryno > 2) {
                                if (inp->i_parent == 0) {

I've attached a file system image in which i-node 3 (/.snap) has a 0
link count, and which yields this fsck_ffs backtrace:

Program received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
0x000000000021f412 in pass2check (idesc=0x7fffffffe7b8) at pass2.c:554
554                                     if (inp->i_parent == 0) {
(gdb) where
#0  0x000000000021f412 in pass2check (idesc=0x7fffffffe7b8) at pass2.c:554
#1  0x00000000002093e7 in dirscan (idesc=0x7fffffffe7b8) at dir.c:211
#2  0x000000000021318b in ckinode (dp=0x7fffffffe6b8, idesc=0x7fffffffe7b8)
    at inode.c:126
#3  0x000000000021e130 in pass2 () at pass2.c:202
#4  0x0000000000219a7d in checkfilesys (filesys=0x7fffffffed71 "junk")
    at main.c:468
#5  0x0000000000218f42 in main (argc=1, argv=0x7fffffffea20) at main.c:210

-- 
You are receiving this mail because:
You are the assignee for the bug.