The branch main has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a6d57f312f18bbeeda8a34e99d0a662b0db9a190

commit a6d57f312f18bbeeda8a34e99d0a662b0db9a190
Author:     Rick Macklem <[email protected]>
AuthorDate: 2026-01-08 16:27:32 +0000
Commit:     Rick Macklem <[email protected]>
CommitDate: 2026-01-08 16:27:32 +0000

    nfsd: Fix handling of hidden/system during Open/Create
    
    When an NFSv4.n client specifies settings for the archive,
    hidden and/or system attributes during a Open/Create, the
    Open/Create fails for ZFS.  This is caused by ZFS doing
    a secpolicy_xvattr() call, which fails for non-root.
    If this check is bypassed, ZFS panics.
    
    This patch resolves the problem by disabling va_flags
    for the VOP_CREATE() call in the NFSv4.n server and
    then setting the flags with a subsequent VOP_SETATTR().
    
    This problem only affects FreeBSD-15 and main, since the
    archive, system and hidden attributes are not enabled
    for FreeBSD-14.
    
    I think a similar problem exists for the NFSv4.n
    Open/Create/Exclusive_41, but that will be resolved
    in a future commit.
    
    Note that the Linux, Solaris and FreeBSD clients
    do not set archive, hidden or system for Open/Create,
    so the bug does not affect mounts from those clients.
    
    PR:     292283
    Reported by:    Aurelien Couderc <[email protected]>
    Tested by:      Aurelien Couderc <[email protected]>
    MFC after:      2 weeks
---
 sys/fs/nfsserver/nfs_nfsdport.c | 11 +++++++++++
 sys/fs/nfsserver/nfs_nfsdsubs.c | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 7d64f211b058..1e215b52e835 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1977,6 +1977,7 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidata 
*ndp,
        struct nfsexstuff nes;
        struct thread *p = curthread;
        uint32_t oldrepstat;
+       u_long savflags;
 
        if (ndp->ni_vp == NULL) {
                /*
@@ -1991,6 +1992,15 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidata 
*ndp,
        }
        if (!nd->nd_repstat) {
                if (ndp->ni_vp == NULL) {
+                       /*
+                        * Most file systems ignore va_flags for
+                        * VOP_CREATE(), however setting va_flags
+                        * for VOP_CREATE() causes problems for ZFS.
+                        * So disable them and let nfsrv_fixattr()
+                        * do them, as required.
+                        */
+                       savflags = nvap->na_flags;
+                       nvap->na_flags = VNOVAL;
                        nd->nd_repstat = VOP_CREATE(ndp->ni_dvp,
                            &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
                        /* For a pNFS server, create the data file on a DS. */
@@ -2003,6 +2013,7 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidata 
*ndp,
                                nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr,
                                    cred, p);
                        }
+                       nvap->na_flags = savflags;
                        VOP_VPUT_PAIR(ndp->ni_dvp, nd->nd_repstat == 0 ?
                            &ndp->ni_vp : NULL, false);
                        nfsvno_relpathbuf(ndp);
diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c
index ea8382e4282a..c8c78d98be72 100644
--- a/sys/fs/nfsserver/nfs_nfsdsubs.c
+++ b/sys/fs/nfsserver/nfs_nfsdsubs.c
@@ -1697,6 +1697,44 @@ nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
                        NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP);
                }
        }
+
+       /*
+        * For archive, ZFS sets it by default for new files,
+        * so if specified, it must be set or cleared.
+        * For hidden and system, no file system sets them
+        * by default upon creation, so they only need to be
+        * set and not cleared.
+        */
+       if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ARCHIVE)) {
+               if (nva.na_flags == VNOVAL)
+                       nva.na_flags = 0;
+               if ((nvap->na_flags & UF_ARCHIVE) != 0)
+                       nva.na_flags |= UF_ARCHIVE;
+               change++;
+               NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_ARCHIVE);
+       }
+       if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN)) {
+               if ((nvap->na_flags & UF_HIDDEN) != 0) {
+                       if (nva.na_flags == VNOVAL)
+                               nva.na_flags = 0;
+                       nva.na_flags |= UF_HIDDEN;
+                       change++;
+                       NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_HIDDEN);
+               } else {
+                       NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN);
+               }
+       }
+       if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SYSTEM)) {
+               if ((nvap->na_flags & UF_SYSTEM) != 0) {
+                       if (nva.na_flags == VNOVAL)
+                               nva.na_flags = 0;
+                       nva.na_flags |= UF_SYSTEM;
+                       change++;
+                       NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_SYSTEM);
+               } else {
+                       NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_SYSTEM);
+               }
+       }
        if (change) {
                error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
                if (error) {

Reply via email to