#409272 nfsmount: incompatible with nfsv4

Package:
klibc-utils
Source:
klibc
Description:
small utilities built with klibc for early boot
Submitter:
John Goerzen
Date:
2023-07-07 13:21:03 UTC
Severity:
wishlist
Tags:
#409272#5
Date:
2007-02-01 15:30:26 UTC
From:
To:
nfsmount is incapable of mounting NFSv4 filesystems.  It seems to have
support for v3 and maybe v2, but not v4.

#409272#14
Date:
2021-11-16 23:19:31 UTC
From:
To:
Short version:

  1. nfsmount(8klibc) is still explicitly broken for NFSv4.
  2. mount.nfs(8nfs-utils) works in the ramdisk.
  3. A single mount(2) call also works!


Boring detailed version follows.

John Goerzen wrote:

This is still the case in Debian 11, klibc-utils=2.0.8-6.1.
A workaround is to copy nfs-utils 1.3's mount.nfs into the initrd:

    /usr/share/initramfs-tools/hooks/zz-nfs4:

        #!/bin/sh
        [ prereqs = "$1" ] && exit
        . /usr/share/initramfs-tools/hook-functions
        copy_exec /sbin/mount.nfs /bin/nfsmount

Here are some specific errors I saw, with an NFSv4-only server on 10.0.2.100 port 2049/tcp

    # Normal nfs-common=1:1.3.4-6 works fine
    root@main:~# mount.nfs 10.0.2.100:/srv/netboot/images /mnt
    root@main:~# umount /mnt

    root@main:~# /usr/lib/klibc/bin/nfsmount -o nfsvers=4.2,sec=sys 10.0.2.100:/srv/netboot/images /mnt
    4.2: invalid value for nfsvers
https://sources.debian.org/src/klibc/2.0.8-6.1/usr/kinit/nfsmount/main.c/#L145

    root@main:~# /usr/lib/klibc/bin/nfsmount -o nfsvers=4,sec=sys 10.0.2.100:/srv/netboot/images /mnt
    /usr/lib/klibc/bin/nfsmount: bad option 'sec'

    # This hangs because NFSv3 ports (inc. portmap) are not allowed AT ALL by 10.0.2.100.
    # klibc-utils is hard-coded to *EXPLICITLY* ask for a NFSv3 mount.
    root@main:~# /usr/lib/klibc/bin/nfsmount 10.0.2.100:/srv/netboot/images /mnt
    connect: Connection timed out



It is quite annoying that we need *anything* special in userland, because
a nfsvers=4.2,sec=sys mount requires only 2049/tcp (no other ports/services), and
the actual filesystem is in-kernel, so
really all that should be needed is enough of a C program to issue a single mount(2)!

As an experiment, I tried do compile in EXACTLY that, and it works for me:

    root@main:~# apt install build-essential strace
    root@main:~# strace -s99999 -emount mount.nfs 10.0.2.100:/srv/netboot /mnt
    mount("10.0.2.100:/srv/netboot", "/mnt", "nfs", 0, "vers=4.2,addr=10.0.2.100,clientaddr=10.0.2.15") = 0
    root@main:~# umount /mnt

    root@main:~# journalctl -kfn0 &
    root@main:~# cc -x c - <<< 'int main() {exit(mount("10.0.2.100:/srv/netboot", "/mnt", "nfs", 0, "vers=4.2,addr=10.0.2.100,clientaddr=10.0.2.15"));}' && ./a.out; echo $?
    <stdin>: In function ‘main’:
    <stdin>:1:13: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
    <stdin>:1:13: warning: incompatible implicit declaration of built-in function ‘exit’
    <stdin>:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
    <stdin>:1:18: warning: implicit declaration of function ‘mount’ [-Wimplicit-function-declaration]
    0
    root@main:~# umount /mnt

Can I do the same thing with klibc instead of glibc?
Well, the compiler wrapper is a bit confused...

    root@main:~# apt install libklibc-dev
    root@main:~# klcc -x c - <<< 'int main() {exit(mount("10.0.2.100:/srv/netboot", "/mnt", "nfs", 0, "vers=4.2,addr=10.0.2.100,clientaddr=10.0.2.15"));}' && ./a.out; echo $?
    <ot", "/mnt", "nfs", 0, "vers=4.2,addr=10.0.2.100,clientaddr=10.0.2.15"));}' && ./a.out; echo $?
    Died at /usr/bin/klcc line 294.
    25

But if I write the C program to a file, it works perfectly:

    root@main:~# >nfsmount.c printf '#include <stdlib.h>\n#include <sys/mount.h>\nint main() {exit(mount("10.0.2.100:/srv/netboot", "/mnt", "nfs", 0, "vers=4.2,addr=10.0.2.100,clientaddr=10.0.2.15"));}'
    root@main:~# klcc -o nfsmount nfsmount.c
    root@main:~# ./nfsmount; echo $?
    ./nfsmount; echo $?
    Nov 17 10:11:31 main.lan kernel: process '/root/nfsmount' started with executable stack
    0

So for current-generation NFS, without kerberos, all we *REALLY* need
is something to getopts from

    nfsmount -t nfs -o nfsvers=4.2,sec=sys example.com:/srv /srv

into

    mount("example.com:/srv", "/srv", 0, "nfsvers=4.2,sec=sys");

This is pretty narrow in scope and is probably achievable.
It allows you to boot off NFSv4, without putting glibc into the initrd.

#409272#19
Date:
2021-11-17 00:39:22 UTC
From:
To:
Trent W. Buck wrote:

I had a go at actually packaging this (attached), but
it turns out to be slightly harder than I thought (see comments in mount.nfs.c).
I don't have time to pursue this further.

#409272#24
Date:
2022-11-29 01:50:09 UTC
From:
To:
Earlier in this bug, Trent Buck suggested an initramfs hook zz-nfs4 to work
around the problem.  I tried it, but I still can't get an NFS 4 mount.

I think the problem is that the script did not copy mount.nfs to nfsmount,
since the 2 files have completely different sizes.  I'm not familiar enough
with the details of hooks for initramfs to understand why.

I installed the script zz-nfs4 and made it executable, then ran
update-initramfs -u -v
and copied the result to where my tftp server could find it.  My server
continues to recieve MNT3 NFS requests, which it denied.

I used unkminitramfs to inspect the initrd.  Here is the file the script wants
to copy, followed by the target:

root@barley:~# ls -l /sbin/mount.nfs
- -rwsr-xr-x 1 root root 114784 Jun 28  2021 /sbin/mount.nfs
root@barley:~# ls -l initramfs/bin/nfs*
- -rwxr-xr-x 1 root root 15232 May 26  2021 initramfs/bin/nfsmount

Obviously different.

I ran update-initramfs within a chroot on the file system (direct, not NFS
mounted) and then used a virtual machine with bridged networking to try to PXE
boot.  I also tried earlier with a physical machine and got similar errors.

I have tried with and without vers as an option on nfsroot for the kernel
invocation, and vers=4 and vers=4.2.  Explicit specification just gets me an
error about an unrecognized option.  I saw some people suggesting this on the
internet, but I note the kernel documentation does *not* list vers as an
available option:
https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt.  Possibly
the documentation is dated.

Onward to making my server respond to NFSv3, I guess


- -- System Information:
Debian Release: 11.5
  APT prefers stable-security
  APT policy: (500, 'stable-security'), (500, 'stable-debug'), (500, 'proposed-
updates-debug'), (500, 'proposed-updates'), (500, 'stable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.10.0-19-amd64 (SMP w/8 CPU threads)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE,
TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not
set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages klibc-utils depends on:
ii  libklibc  2.0.8-6.1

klibc-utils recommends no packages.

klibc-utils suggests no packages.
-----BEGIN PGP SIGNATURE-----

iQFSBAEBCgA8FiEEreS674/HIyV9gBfdnAYPmOsbK2AFAmOFZT8eHHJvc3Nib3ls
YW5Ac3RhbmZvcmRhbHVtbmkub3JnAAoJEJwGD5jrGytg8m4H/RCxhrS5TGI5QLXu
oNVqTif6+msKN9pCKs7SUBTY18ExwL3+sFBcxq+5bTn0m0ZSvda6sQsXeqg22+I1
FAUo1gX8Xu5Hx3+LtTZpHUzSscjdGcyiCE/Zx7WIYeIwN0uDcXDuJrQWU60S5I1s
vMhQiHxO2tGSww3MS6tbCL+7aFqcwPLFUvIHJcvffl0GvlDkutAUtQdKdp4qpX1/
bNv8fwyWtbIsaB6ThuDoUWUPgCMV+g1MSaSZtJYnc1Ti8hLKyZBGt4+7SM6+FaeW
IVbISwHhaJk+hEsurhXwslYNUe847vFKvQVsuVg7q64tkWnYpGuY6osBkNrDhd1i
YoSOvz4=
=czY4
-----END PGP SIGNATURE-----

#409272#29
Date:
2023-07-07 13:18:44 UTC
From:
To:
Hi Ross,

Following up with the zz-nfs4 hook workaround, I found that it didn't work
because copy_exec won't overwrite an existing file. I do not know if this
was always the case, or perhaps it changed since the original workaround
was posted.

My zz-nfs4 looks like this now and does replace /bin/nfsmount

#!/bin/sh
[ prereqs = "$1" ] && exit
. /usr/share/initramfs-tools/hook-functions
echo "Deleting of nfsmount (${DESTDIR}/bin/nfsmount) so that copy_exec will
overwrite"
rm -f ${DESTDIR}/bin/nfsmount
copy_exec /sbin/mount.nfs /bin/nfsmount


Also, the vers parameter is documented in the nfs(5) man page (eg.
https://linux.die.net/man/5/nfs) as an alias of nfsvers.

It'd be great to get the bug fixed, but in the mean time hopefully this
small change to the hook will help someone else who finds the bug.