Bug 271354 - reachable directory with zero link count can cause fsck to deref NULL
Summary: reachable directory with zero link count can cause fsck to deref NULL
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-fs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-05-10 19:09 UTC by Robert Morris
Modified: 2023-06-08 17:20 UTC (History)
3 users (show)

See Also:


Attachments
ffs image with reachable directory with zero link count causes fsck to deref NULL (800.00 KB, application/octet-stream)
2023-05-10 19:09 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 2023-05-10 19:09:49 UTC
Created attachment 242111 [details]
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
Comment 1 commit-hook freebsd_committer freebsd_triage 2023-05-27 05:44:36 UTC
A commit in branch main references this bug:

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

commit 03a8680202ef7d7e68adc70625633c490b4ed637
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-27 05:41:57 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-05-27 05:43:21 +0000

    Correct two bugs in fsck_ffs(8) triggered by corrupted filesystems.

    Always create a directory inode structure when a directory inode is
    found in Pass 1 as it is not known whether it will be saved or removed
    in later passes. If it is to be saved the directory inode structure
    is needed to track its status and fsck_ffs(8) will segment fault if
    it does not exist.

    Reported-by:  Robert Morris
    PR:           271310
    PR:           271354
    MFC-after:    1 week
    Sponsored-by: The FreeBSD Foundation

 sbin/fsck_ffs/pass1.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
Comment 2 Kirk McKusick freebsd_committer freebsd_triage 2023-05-27 05:47:50 UTC
Fix checked in. Will close when MFC'ed to 13.
Comment 3 commit-hook freebsd_committer freebsd_triage 2023-06-07 23:16:15 UTC
A commit in branch stable/13 references this bug:

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

commit 52f50301aaabddc6e3c1bc8c354101cfd7ea0463
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2023-05-27 05:41:57 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2023-06-07 22:40:35 +0000

    Correct two bugs in fsck_ffs(8) triggered by corrupted filesystems.

    Reported-by:  Robert Morris
    PR:           271310
    PR:           271354
    Sponsored-by: The FreeBSD Foundation

    (cherry picked from commit 03a8680202ef7d7e68adc70625633c490b4ed637)

 sbin/fsck_ffs/pass1.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
Comment 4 Kirk McKusick freebsd_committer freebsd_triage 2023-06-08 17:20:03 UTC
MFC'ed to 13.