git: a6d57f312f18 - main - nfsd: Fix handling of hidden/system during Open/Create
Date: Fri, 09 Jan 2026 00:33:27 UTC
The branch main has been updated by rmacklem:
URL: https://cgit.FreeBSD.org/src/commit/?id=a6d57f312f18bbeeda8a34e99d0a662b0db9a190
commit a6d57f312f18bbeeda8a34e99d0a662b0db9a190
Author: Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2026-01-08 16:27:32 +0000
Commit: Rick Macklem <rmacklem@FreeBSD.org>
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 <aurelien.couderc2002@gmail.com>
Tested by: Aurelien Couderc <aurelien.couderc2002@gmail.com>
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) {