An issue came up on Reddit today

https://www.reddit.com/r/openbsd/comments/1j45t16/openbsd_statfs/

that seems to be a bug in getmntinfo(3) wherein it doesn't populate
the corresponding mount_info values with a valid pointer.

I was able to reproduce the OP's segfault with the demonstration
code below.  

If I don't dereference ufs_args.fspec (the commented-out UFS printf()
statements), the code properly iterates over all my mounts and dumps the
corresponding info.

However, when I dereference ufs_args.fspec (change the corresponding
`#if 0`), my first mountpoint comes back with proper output until I
reach the dereferencing at which point it segfaults :

  f_fstypename: ffs
  f_mntonname: /
  f_mntfromname: /dev/sd0a
  f_mntfromspec: 0aa7ddd292874c57.a
  UFS: fspec 0x7684154ce733
  Segmentation fault (core dumped)

The f_fstypename is indeed "ffs" (MOUNT_UFS/MOUNT_FFS), and the value
of ufs_args.fspec is NOT null (in the output above, it comes back as
0x7684154ce733), so I would expect fspec to be a valid pointer.

I don't see anything in the man-pages for getmntinfo(3), statfs(2), or
mount(2) about it NOT populating the mount_info fields with valid data.

It might be a misunderstanding of what that value should be, but that
value isn't well-documented beyond "block special file to mount" (which,
as a char*, sounds like it should be a string I could dump), and
statfs(2) describes the union as "per-filesystem mount options".

If it's an opaque object for kernel-use-only, the documentation should
advise about the hazards of dereferencing (or modifying?) that pointer.

-tkc

#include <err.h>
#include <stdio.h>
#include <string.h>
#include <sys/mount.h>
int main() {
    int mntsize, i;
    struct statfs *mntbuf;
    if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
        err(1, "getmntinfo");
    for (i = 0; i < mntsize; i++) {
        printf(
            "f_fstypename: %s\n"
            "f_mntonname: %s\n"
            "f_mntfromname: %s\n"
            "f_mntfromspec: %s\n"
            ,
            mntbuf[i].f_fstypename,
            mntbuf[i].f_mntonname,
            mntbuf[i].f_mntfromname,
            mntbuf[i].f_mntfromspec
            );
        if (strcmp(mntbuf[i].f_fstypename, MOUNT_UFS) == 0) {
            if (mntbuf[i].mount_info.ufs_args.fspec) {
                printf("UFS: fspec %p\n", mntbuf[i].mount_info.ufs_args.fspec);
                /* segfaults here: */
#if 0
                printf("UFS: *fspec %s\n", mntbuf[i].mount_info.ufs_args.fspec);
#endif
                /* even dereferencing the pointer causes a segfault: */
#if 0
                printf("UFS: fspec[0] %c\n", 
*mntbuf[i].mount_info.ufs_args.fspec);
#endif
            } else {
                printf("UFS: fpsec NULL\n");
            }
        }
        putchar('\n');
    }
    return 0;
}





Reply via email to