nfsd: Fix handling of hidden/system during Open/Create
Some checks are pending
Cross-build Kernel / amd64 ubuntu-22.04 (clang-15) (push) Waiting to run
Cross-build Kernel / aarch64 ubuntu-22.04 (clang-15) (push) Waiting to run
Cross-build Kernel / amd64 ubuntu-24.04 (clang-18) (push) Waiting to run
Cross-build Kernel / aarch64 ubuntu-24.04 (clang-18) (push) Waiting to run
Cross-build Kernel / amd64 macos-latest (clang-18) (push) Waiting to run
Cross-build Kernel / aarch64 macos-latest (clang-18) (push) Waiting to run

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
This commit is contained in:
Rick Macklem 2026-01-08 08:27:32 -08:00
parent 0aaa95ae02
commit a6d57f312f
2 changed files with 49 additions and 0 deletions

View file

@ -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);

View file

@ -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) {