From 7bb83e12891a0ed2bf55ede31051d7c3a7545f4e Mon Sep 17 00:00:00 2001
From: Gordon Ross <gwr@nexenta.com>
Date: Mon, 14 Oct 2019 16:13:59 -0400
Subject: [PATCH 1/5] Be far more judicious in the use of curzone-using macros.
(Merge and extra asserts by danmcd.)
---
 usr/src/uts/common/fs/nfs/nfs3_srv.c      |  2 ++
 usr/src/uts/common/fs/nfs/nfs4_srv.c      | 27 ++++++++++++++---------
 usr/src/uts/common/fs/nfs/nfs4_srv_attr.c | 18 ++++++++++++---
 usr/src/uts/common/fs/nfs/nfs4_srv_ns.c   |  3 +++
 usr/src/uts/common/fs/nfs/nfs_export.c    | 18 +++++++++++----
 usr/src/uts/common/fs/nfs/nfs_server.c    |  2 ++
 usr/src/uts/common/sys/zone.h             |  7 ++++++
 7 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index 7c63789325..d2b0f7627c 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -411,6 +411,7 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 	 * location of the public filehandle.
 	 */
 	if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
+		ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 		dvp = ZONE_ROOTVP();
 		VN_HOLD(dvp);
 
@@ -2674,6 +2675,7 @@ rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
 		goto err1;
 	}
 
+	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 	error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
 
 	if (name != args->object.name)
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index e628abd9eb..8e7a216e10 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -953,7 +953,7 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 {
 	int error, different_export = 0;
 	vnode_t *dvp, *vp;
-	struct exportinfo *exi = NULL;
+	struct exportinfo *exi;
 	fid_t fid;
 	uint_t count, i;
 	secinfo4 *resok_val;
@@ -964,6 +964,8 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 	nfs_export_t *ne = nfs_get_export();
 
 	dvp = cs->vp;
+	exi = cs->exi;
+	ASSERT(exi != NULL);
 	dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
 
 	/*
@@ -971,13 +973,13 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 	 * root of a filesystem, or above an export point.
 	 */
 	if (dotdot) {
-
+		ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 		/*
 		 * If dotdotting at the root of a filesystem, then
 		 * need to traverse back to the mounted-on filesystem
 		 * and do the dotdot lookup there.
 		 */
-		if ((cs->vp->v_flag & VROOT) || VN_IS_CURZONEROOT(cs->vp)) {
+		if ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp)) {
 
 			/*
 			 * If at the system root, then can
@@ -989,7 +991,7 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 			/*
 			 * Traverse back to the mounted-on filesystem
 			 */
-			dvp = untraverse(cs->vp);
+			dvp = untraverse(dvp);
 
 			/*
 			 * Set the different_export flag so we remember
@@ -1003,7 +1005,7 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 			 * If dotdotting above an export point then set
 			 * the different_export to get new export info.
 			 */
-			different_export = nfs_exported(cs->exi, cs->vp);
+			different_export = nfs_exported(exi, dvp);
 		}
 	}
 
@@ -1022,9 +1024,9 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 	 * check whether this vnode is visible.
 	 */
 	if (!different_export &&
-	    (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
+	    (PSEUDO(exi) || !is_exported_sec(cs->nfsflavor, exi) ||
 	    cs->access & CS_ACCESS_LIMITED)) {
-		if (! nfs_visible(cs->exi, vp, &different_export)) {
+		if (! nfs_visible(exi, vp, &different_export)) {
 			VN_RELE(vp);
 			return (puterrno4(ENOENT));
 		}
@@ -1066,6 +1068,7 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 			return (puterrno4(error));
 		}
 
+		/* We'll need to reassign "exi". */
 		if (dotdot)
 			exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
 		else
@@ -1086,8 +1089,6 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 				return (puterrno4(EACCES));
 			}
 		}
-	} else {
-		exi = cs->exi;
 	}
 	ASSERT(exi != NULL);
 
@@ -2718,7 +2719,8 @@ do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs)
 	 * export point.
 	 */
 	if (dotdot) {
-
+		ASSERT(cs->exi != NULL);
+		ASSERT3U(cs->exi->exi_zoneid, ==, curzone->zone_id);
 		/*
 		 * If dotdotting at the root of a filesystem, then
 		 * need to traverse back to the mounted-on filesystem
@@ -3676,6 +3678,9 @@ rfs4_op_putrootfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
 
 	cs->cr = crdup(cs->basecr);
 
+	ASSERT(cs->exi != NULL);
+	ASSERT3U(cs->exi->exi_zoneid, ==, curzone->zone_id);
+
 	/*
 	 * Using rootdir, the system root vnode,
 	 * get its fid.
@@ -4257,6 +4262,8 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
 			 * NFS4ERR_EXIST to NFS4ERR_NOTEMPTY to
 			 * transmit over the wire.
 			 */
+			ASSERT(cs->exi != NULL);
+			ASSERT3U(cs->exi->exi_zoneid, ==, curzone->zone_id);
 			if ((error = VOP_RMDIR(dvp, name, ZONE_ROOTVP(), cs->cr,
 			    NULL, 0)) == EEXIST)
 				error = ENOTEMPTY;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
index 9ae5132353..8042732c86 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -135,7 +135,12 @@ rfs4_attr_init()
 	struct statvfs64 sb;
 
 	rfs4_init_compound_state(&cs);
-	cs.vp = ZONE_ROOTVP();
+	/*
+	 * This is global state checking, called once. We might be in
+	 * non-global-zone context here (say a modload happens from a zone
+	 * process) so in this case, we want the global-zone root vnode.
+	 */
+	cs.vp = rootvp;
 	cs.fh.nfs_fh4_val = NULL;
 	cs.cr = kcred;
 
@@ -1303,7 +1308,14 @@ rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
 	vp = sarg->cs->vp;
 	sarg->mntdfid_set = FALSE;
 
-	/* VROOT object or zone's root, must untraverse */
+	/*
+	 * VROOT object or zone's root, must untraverse.
+	 *
+	 * NOTE: Not doing reality checks on curzone vs. compound
+	 * state vnode because it will mismatch once at initialization
+	 * if a non-global-zone triggers the module load, BUT in that case
+	 * the vp is literally "/" which has VROOT set.
+	 */
 	if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
 
 		/* extra hold for vp since untraverse might rele */
@@ -1318,7 +1330,7 @@ rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
 		 * another getattr -- just use the one in sarg.
 		 */
 		if (VN_CMP(vp, stubvp)) {
-			ASSERT(VN_CMP(vp, ZONE_ROOTVP()));
+			ASSERT(VN_IS_CURZONEROOT(vp));
 			vap = sarg->vap;
 		} else {
 			va.va_mask = AT_NODEID;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
index 3c43aa3e0e..1d2b018755 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
@@ -660,6 +660,7 @@ treeclimb_export(struct exportinfo *exip)
 		if (error)
 			break;
 
+		ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
 		/*
 		 * The root of the file system, or the zone's root for
 		 * in-zone NFS service needs special handling
@@ -907,6 +908,8 @@ treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
  * Traverse backward across mountpoint from the
  * root vnode of a filesystem to its mounted-on
  * vnode.
+ *
+ * Callers to this function have confirmed the use of curzone is safe here.
  */
 vnode_t *
 untraverse(vnode_t *vp)
diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c
index 4b13116de4..fcb9190d7f 100644
--- a/usr/src/uts/common/fs/nfs/nfs_export.c
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c
@@ -719,13 +719,14 @@ vis2exi(treenode_t *tnode)
  * Add or remove the newly exported or unexported security flavors of the
  * given exportinfo from its ancestors upto the system root.
  */
-void
+static void
 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
     int seccnt, bool_t isadd)
 {
 	treenode_t *tnode;
 
 	ASSERT(RW_WRITE_HELD(&ne->exported_lock));
+	ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
 
 	/*
 	 * exi_tree can be null for the zone root
@@ -900,6 +901,7 @@ nfs_export_zone_init(nfs_globals_t *ng)
 {
 	int i;
 	nfs_export_t *ne;
+	zone_t *zone;
 
 	ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 
@@ -924,9 +926,16 @@ nfs_export_zone_init(nfs_globals_t *ng)
 	ne->exi_root->exi_count = 1;
 	mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 
-	ASSERT(curzone->zone_id == ng->nfs_zoneid);
-	ne->exi_root->exi_vp = ZONE_ROOTVP();
-	ne->exi_root->exi_zoneid = ng->nfs_zoneid;
+	/*
+	 * Because we cannot:
+	 *	ASSERT(curzone->zone_id == ng->nfs_zoneid);
+	 * We grab the zone pointer explicitly (like netstacks do) and
+	 * set the rootvp here.
+	 */
+	zone = zone_find_by_id_nolock(ng->nfs_zoneid);
+	ne->exi_root->exi_vp = zone->zone_rootvp;
+	ne->exi_root->exi_zone = zone;	/* XXX KEBE SAYS lose me, and... */
+	/* ne->exi_root->exi_zoneid = ng->nfs_zoneid; */ /* use me instead! */
 
 	/*
 	 * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
@@ -2189,6 +2198,7 @@ nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
 		 * If we're at the root of this filesystem, then
 		 * it's time to stop (with failure).
 		 */
+		ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
 		if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
 			error = EINVAL;
 			break;
diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c
index d4955f5d08..2d5a1323ab 100644
--- a/usr/src/uts/common/fs/nfs/nfs_server.c
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c
@@ -2978,6 +2978,8 @@ rfs_pathname(
 	struct pathname pn;
 	int error;
 
+	ASSERT3U(crgetzoneid(cr), ==, curzone->zone_id);
+
 	/*
 	 * If pathname starts with '/', then set startdvp to root.
 	 */
diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h
index 9fdc2639ec..b07336cd88 100644
--- a/usr/src/uts/common/sys/zone.h
+++ b/usr/src/uts/common/sys/zone.h
@@ -934,6 +934,12 @@ struct zsd_entry {
 
 /*
  * The root vnode of the current zone.
+ *
+ * NOTE: It may be necessary (initialization time for file sharing where an
+ * NGZ loads a file-sharing kernel module that does zsd initialization) to NOT
+ * use this macro. One should ASSERT() that curzone == active ZSD (an
+ * ASSERTion that's not always true at ZSD initialization time) during regular
+ * use of this macro.
  */
 #define	ZONE_ROOTVP()	(curzone->zone_rootvp)
 
@@ -942,6 +948,7 @@ struct zsd_entry {
  * (i.e. VROOT may not be set on zone->zone_rootvp) we need to not assume it.
  * This macro helps in checking if a vnode is the current zone's rootvp.
  * NOTE:  Using the VN_ prefix, even though it's defined here in zone.h.
+ * NOTE2: See above warning about ZONE_ROOTVP().
  */
 #define	VN_IS_CURZONEROOT(vp)	(VN_CMP(vp, ZONE_ROOTVP()))
 
-- 
2.21.0 (Apple Git-122)

