Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 08 May 2023 08:55:23 +0000
From:      bugzilla-noreply@freebsd.org
To:        bugs@FreeBSD.org
Subject:   [Bug 271310] potential NULL dereference in fsck_ffs's changeino()
Message-ID:  <bug-271310-227@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D271310

            Bug ID: 271310
           Summary: potential NULL dereference in fsck_ffs's changeino()
           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 242049
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=3D242049&action=
=3Dedit
a broken FS image that causes a NULL dereference in fsck's changeino()

Running fsck_ffs -y on the attached image causes this line in
sbin/fsck_ffs/dir.c changeino() to dereference NULL:

                getinoinfo(dir)->i_depth =3D depth;

I think the reason is that the link count of the i-node in question
(i-number 3, a directory) has its high bit set, so that it looks
negative in di_nlink (which is int16_t) in this code in checkinode()
in pass1.c:

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

As a result, ino_state is set to DZLINK, and cacheino() is not called,
which is why getinoinfo() eventually returns NULL.

Later, in pass4(), I think the expectation is that ino_linkcnt will be
zero, and clri() will be called. But in fact ino_linkcnt is not zero
(it's negative), so adjust() is called, which effectively expects
cacheino() to have been called.

                        case DZLINK:
                                if (inoinfo(inumber)->ino_linkcnt =3D=3D 0)=
 {
                                        clri(&idesc, "UNREF", 1);
                                        break;
                                }
                                /* fall through */

                        case FSTATE:
                        case DFOUND:
                                n =3D inoinfo(inumber)->ino_linkcnt;
                                if (n) {
                                        adjust(&idesc, (short)n);

A backtrace from fsck_ffs -y fsck13a.img :

Program received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
0x000000000020b165 in changeino (dir=3D3, name=3D0x201ecf "..", newnum=3D4,=
 depth=3D2)
at dir.c:712
712                     getinoinfo(dir)->i_depth =3D depth;
(gdb) where
#0  0x000000000020b165 in changeino (dir=3D3, name=3D0x201ecf "..", newnum=
=3D4,=20
    depth=3D2) at dir.c:712
#1  0x000000000020a553 in linkup (orphan=3D3, parentdir=3D0, name=3D0x0) at=
 dir.c:664
#2  0x0000000000209acd in adjust (idesc=3D0x7fffffffe7d0, lcnt=3D-32765)
    at dir.c:470
#3  0x000000000022025e in pass4 () at pass4.c:94
#4  0x0000000000219ae9 in checkfilesys (filesys=3D0x7fffffffed79 "junk")
    at main.c:484
#5  0x0000000000218f42 in main (argc=3D1, argv=3D0x7fffffffea28) at main.c:=
210

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-271310-227>