On Wed, Mar 05, 2025 at 06:45:13PM -0600, Tim Chase wrote:
> 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.
Looks like a pointer into kernel mem. Dereffing it will cause a
segfault. If anything, it should probably be cleared in the kernel
before copying out, there are also other pointers in export_args. The
mount helpers do use fspec and a few fields of export_info as an input
argument, check mount_ffs.c.
-Otto
>
> -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;
> }
>
>
>
>
>