nftw: fix use of uninitialized struct stat
authorAlexey Izbyshev <izbyshev@ispras.ru>
Fri, 10 Mar 2023 14:00:50 +0000 (17:00 +0300)
committerRich Felker <dalias@aerifal.cx>
Tue, 11 Apr 2023 13:18:01 +0000 (09:18 -0400)
If lstat/stat fails with EACCES, st is left uninitialized, but its
st_dev/st_ino fields are then used in several places:

* for FTW_MOUNT check (in practice typically results in a false
  positive and an early return)
* for copying to the new struct history (though the struct is not used
  afterwards since we don't recurse in this case)
* for cycle detection check (could theoretically result in a false
  positive and an early return)

To avoid adding FTW_NS checks to all these places, fix this by
zero-initializing st_dev/st_ino (which can never match an existing
dentry due to zero inode being reserved in Linux), and check for FTW_NS
only when handling FTW_MOUNT since we need two valid dentries there.

src/misc/nftw.c

index fcd25a7..71bc62e 100644 (file)
@@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
        int err;
        struct FTW lev;
 
+       st.st_dev = st.st_ino = 0;
+
        if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
                if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
                        type = FTW_SLN;
@@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
                type = FTW_F;
        }
 
-       if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
+       if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev)
                return 0;
        
        new.chain = h;