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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user