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;
> }
> 
> 
> 
> 
> 

Reply via email to