NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/56080 (tar(1) dumps core on nfs volume)



Synopsis: tar(1) dumps core on nfs volume

Responsible-Changed-From-To: bin-bug-people->lukem
Responsible-Changed-By: lukem%NetBSD.org@localhost
Responsible-Changed-When: Sun, 28 May 2023 19:52:15 +0000
Responsible-Changed-Why:


State-Changed-From-To: open->analyzed
State-Changed-By: lukem%NetBSD.org@localhost
State-Changed-When: Sun, 28 May 2023 19:52:15 +0000
State-Changed-Why:

I read the thread about this issue, including RVP's proposed fix to
ensure that the struct filesystem.name_max field isn't 0 to fallback
to NAME_MAX.

I think libarchive's implementation for NetBSD could be simplified to
just allocate the backing store for sizeof(struct dirent) when using
readdir_r() on platforms where dirent.d_name has a known size (e.g.,
d_name).  Or use the existing logic modified to check at startup to use
NAME_MAX if defined and pathconf as a fallback?

(I see that macOS/Darwin and Linux/glibc both claim readdir_r() is
deprecated because NAME_MAX may be undefined, but NetBSD doesn't claim
that it's deprecated, and AFAICT, neither does POSIX.1-2017).

Looking into more detail in how libarchive uses the filesystem.name_max field:

- Relevant parts of struct filesystem:
        struct filesystem {
        // ...
        #if defined(USE_READDIR_R)
                size_t          name_max;
        #endif
        // ...
        };

- There's a lot of system-specific complexity to determine name_max
  as the length of a path name.

- Relevant parts of struct tree:
        struct tree {
        //...
        #if defined(USE_READDIR_R)
                struct dirent           *dirent;
                size_t                   dirent_allocated;
        #endif
        //...
        };

- In tree_dir_next_posix(), filesystem.name_max is used to determine
  how much space to allocate for struct tree.dirent:
        #if defined(USE_READDIR_R)
                dirent_size = offsetof(struct dirent, d_name) +
                  t->filesystem_table[t->current->filesystem_id].name_max + 1;
                if (t->dirent == NULL || t->dirent_allocated < dirent_size) {
                        free(t->dirent);
                        t->dirent = malloc(dirent_size);


Why does libarchive go to so much effort to determine how much space to
use for the backing store for readdir_r()'s struct dirent in a
system-specific manner?

Why isn't libarchive just allocating sizeof(struct dirent) for those
systems where struct dirent is known to be a fixed size (where
dirent.d_name is fixed), and avoid this complicated
per-current-filesystem statvfs (etc) logic?

It strikes me that this complex logic could potentially fail with memory
overruns if a kernel returns the wrong value for "maximum length of a
path for that filesystem", and given dirent has a fixed upper size at
compile time on most platforms (see above).






Home | Main Index | Thread Index | Old Index