Module Name:    src
Committed By:   riastradh
Date:           Thu Jan 25 17:14:36 UTC 2018

Modified Files:
        src/sys/nfs: nfs.h nfs_syscalls.c

Log Message:
Use a random opaque cookie, not kva pointer, for nfssvc(2).

(What were they smoking?!)

I suspect most of this is actually dead code that wasn't properly
amputated along with the rest of the gangrene of NFSKERB a decade
ago, but I'm out of time to investigate further.  If someone else
wants to kill NFSSVC_AUTHIN/NFSSVC_AUTHINFAIL and the rest of the
tentacular kerberosity, be my guest.

Noted by Silvio Cesare of InfoSect.


To generate a diff of this commit:
cvs rdiff -u -r1.76 -r1.77 src/sys/nfs/nfs.h
cvs rdiff -u -r1.158 -r1.159 src/sys/nfs/nfs_syscalls.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/nfs/nfs.h
diff -u src/sys/nfs/nfs.h:1.76 src/sys/nfs/nfs.h:1.77
--- src/sys/nfs/nfs.h:1.76	Sun Jan 21 20:36:49 2018
+++ src/sys/nfs/nfs.h	Thu Jan 25 17:14:36 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs.h,v 1.76 2018/01/21 20:36:49 christos Exp $	*/
+/*	$NetBSD: nfs.h,v 1.77 2018/01/25 17:14:36 riastradh Exp $	*/
 /*
  * Copyright (c) 1989, 1993, 1995
  *	The Regents of the University of California.  All rights reserved.
@@ -41,6 +41,7 @@
 #include <sys/fstypes.h>
 #include <sys/mbuf.h>
 #include <sys/mutex.h>
+#include <sys/rbtree.h>
 #endif
 
 /*
@@ -486,7 +487,7 @@ extern int nfssvc_sockhead_flag;
  * One of these structures is allocated for each nfsd.
  */
 struct nfsd {
-	TAILQ_ENTRY(nfsd) nfsd_chain;	/* List of all nfsd's */
+	struct rb_node	nfsd_node;	/* Tree of all nfsd's */
 	SLIST_ENTRY(nfsd) nfsd_idle;	/* List of idle nfsd's */
 	kcondvar_t	nfsd_cv;
 	int		nfsd_flag;	/* NFSD_ flags */
@@ -497,6 +498,7 @@ struct nfsd {
 	u_char		nfsd_verfstr[RPCVERF_MAXSIZ];
 	struct proc	*nfsd_procp;	/* Proc ptr */
 	struct nfsrv_descript *nfsd_nd;	/* Associated nfsrv_descript */
+	uint32_t	nfsd_cookie;	/* Userland cookie, fits 32bit ptr */
 };
 
 /* Bits for "nfsd_flag" */
@@ -557,7 +559,6 @@ struct nfsrv_descript {
 
 extern kmutex_t nfsd_lock;
 extern kcondvar_t nfsd_initcv;
-extern TAILQ_HEAD(nfsdhead, nfsd) nfsd_head;
 extern SLIST_HEAD(nfsdidlehead, nfsd) nfsd_idle_head;
 extern int nfsd_head_flag;
 #define	NFSD_CHECKSLP	0x01

Index: src/sys/nfs/nfs_syscalls.c
diff -u src/sys/nfs/nfs_syscalls.c:1.158 src/sys/nfs/nfs_syscalls.c:1.159
--- src/sys/nfs/nfs_syscalls.c:1.158	Sun Feb 12 18:24:31 2017
+++ src/sys/nfs/nfs_syscalls.c	Thu Jan 25 17:14:36 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_syscalls.c,v 1.158 2017/02/12 18:24:31 maxv Exp $	*/
+/*	$NetBSD: nfs_syscalls.c,v 1.159 2018/01/25 17:14:36 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.158 2017/02/12 18:24:31 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.159 2018/01/25 17:14:36 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -61,6 +61,8 @@ __KERNEL_RCSID(0, "$NetBSD: nfs_syscalls
 #include <sys/kthread.h>
 #include <sys/kauth.h>
 #include <sys/syscallargs.h>
+#include <sys/cprng.h>
+#include <sys/rbtree.h>
 
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -87,9 +89,11 @@ kmutex_t nfsd_lock;
 struct nfssvc_sockhead nfssvc_sockhead;
 kcondvar_t nfsd_initcv;
 struct nfssvc_sockhead nfssvc_sockpending;
-struct nfsdhead nfsd_head;
 struct nfsdidlehead nfsd_idle_head;
 
+static rb_tree_t nfsd_tree;
+static const rb_tree_ops_t nfsd_tree_ops;
+
 int nfssvc_sockhead_flag;
 int nfsd_head_flag;
 
@@ -102,12 +106,118 @@ static void nfsd_rt(int, struct nfsrv_de
 static int nfssvc_nfsd(struct nfssvc_copy_ops *, struct nfsd_srvargs *, void *,
 		struct lwp *);
 
+static int nfsd_compare_nodes(void *, const void *, const void *);
+static int nfsd_compare_key(void *, const void *, const void *);
+
+static struct nfsd *nfsd_bake_cookie(struct nfsd *);
+static void nfsd_toss_cookie(struct nfsd *);
+static struct nfsd *nfsd_get(struct nfsd *);
+
 static int nfssvc_addsock_in(struct nfsd_args *, const void *);
 static int nfssvc_setexports_in(struct mountd_exports_list *, const void *);
 static int nfssvc_nsd_in(struct nfsd_srvargs *, const void *);
 static int nfssvc_nsd_out(void *, const struct nfsd_srvargs *);
 static int nfssvc_exp_in(struct export_args *, const void *, size_t);
 
+static const rb_tree_ops_t nfsd_tree_ops = {
+	.rbto_compare_nodes = nfsd_compare_nodes,
+	.rbto_compare_key = nfsd_compare_key,
+	.rbto_node_offset = offsetof(struct nfsd, nfsd_node),
+};
+
+static int
+nfsd_compare_nodes(void *cookie, const void *va, const void *vb)
+{
+	const struct nfsd *na = va;
+	const struct nfsd *nb = vb;
+
+	if (na->nfsd_cookie < nb->nfsd_cookie)
+		return -1;
+	if (na->nfsd_cookie > nb->nfsd_cookie)
+		return +1;
+	return 0;
+}
+
+static int
+nfsd_compare_key(void *cookie, const void *vn, const void *vk)
+{
+	const struct nfsd *n = vn;
+	const uint32_t *k = vk;
+
+	if (n->nfsd_cookie < *k)
+		return -1;
+	if (n->nfsd_cookie > *k)
+		return +1;
+	return 0;
+}
+
+/*
+ * nfsd_bake_cookie(nfsd)
+ *
+ *	Bake a cookie for nfsd, hang it on the tree of nfsds, and
+ *	return a userland-safe pointer nfsdu neatly packed for
+ *	transport in struct nfsd_srvargs::nsd_nfsd.
+ */
+static struct nfsd *
+nfsd_bake_cookie(struct nfsd *nfsd)
+{
+
+	KASSERT(mutex_owned(&nfsd_lock));
+
+	do {
+		nfsd->nfsd_cookie = cprng_fast32();
+	} while (nfsd->nfsd_cookie == 0 ||
+	    rb_tree_insert_node(&nfsd_tree, nfsd) != nfsd);
+
+	return (struct nfsd *)(uintptr_t)nfsd->nfsd_cookie;
+}
+
+/*
+ * nfsd_toss_cookie(nfsd)
+ *
+ *	Toss nfsd's cookie.
+ */
+static void
+nfsd_toss_cookie(struct nfsd *nfsd)
+{
+
+	KASSERT(mutex_owned(&nfsd_lock));
+	KASSERT(nfsd->nfsd_cookie != 0);
+
+	rb_tree_remove_node(&nfsd_tree, nfsd);
+	nfsd->nfsd_cookie = 0;	/* paranoia */
+}
+
+/*
+ * nfsd_get(nfsdu)
+ *
+ *	Return the struct nfsd pointer for the userland nfsdu cookie,
+ *	as stored in struct nfsd_srvargs::nsd_nfsd, or NULL if nfsdu is
+ *	not a current valid nfsd cookie.
+ *
+ *	Caller MUST NOT hold nfsd_lock.  Caller MUST NOT pass (struct
+ *	nfsd *)(uintptr_t)0, which is the sentinel value for no nfsd
+ *	cookie, for which the caller should check first.
+ */
+static struct nfsd *
+nfsd_get(struct nfsd *nfsdu)
+{
+	uintptr_t cookie = (uintptr_t)nfsdu;
+	uint32_t key;
+	struct nfsd *nfsd;
+
+	KASSERT(cookie != 0);
+	if (cookie > UINT32_MAX)
+		return NULL;
+	key = cookie;
+
+	mutex_enter(&nfsd_lock);
+	nfsd = rb_tree_find_node(&nfsd_tree, &key);
+	mutex_exit(&nfsd_lock);
+
+	return nfsd;
+}
+
 static int
 nfssvc_addsock_in(struct nfsd_args *nfsdarg, const void *argp)
 {
@@ -184,7 +294,7 @@ do_nfssvc(struct nfssvc_copy_ops *ops, s
 	struct mbuf *nam;
 	struct nfsd_args nfsdarg;
 	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
-	struct nfsd *nfsd;
+	struct nfsd *nfsd = NULL;
 	struct nfssvc_sock *slp;
 	struct nfsuid *nuidp;
 
@@ -254,8 +364,11 @@ do_nfssvc(struct nfssvc_copy_ops *ops, s
 		error = ops->nsd_in(nsd, argp);
 		if (error)
 			return (error);
+		if ((uintptr_t)nsd->nsd_nfsd != 0 &&
+		    (nfsd = nfsd_get(nsd->nsd_nfsd)) == NULL)
+			return (EINVAL);
 		if ((flag & NFSSVC_AUTHIN) &&
-		    ((nfsd = nsd->nsd_nfsd)) != NULL &&
+		    nfsd != NULL &&
 		    (nfsd->nfsd_slp->ns_flags & SLP_VALID)) {
 			slp = nfsd->nfsd_slp;
 
@@ -340,7 +453,7 @@ do_nfssvc(struct nfssvc_copy_ops *ops, s
 			}
 		}
 		if ((flag & NFSSVC_AUTHINFAIL) &&
-		    (nfsd = nsd->nsd_nfsd))
+		    nfsd != NULL)
 			nfsd->nfsd_flag |= NFSD_AUTHFAIL;
 		error = nfssvc_nfsd(ops, nsd, argp, l);
 	}
@@ -481,7 +594,7 @@ nfssvc_nfsd(struct nfssvc_copy_ops *ops,
 	struct timeval tv;
 	struct mbuf *m;
 	struct nfssvc_sock *slp;
-	struct nfsd *nfsd = nsd->nsd_nfsd;
+	struct nfsd *nfsd;
 	struct nfsrv_descript *nd = NULL;
 	struct mbuf *mreq;
 	u_quad_t cur_usec;
@@ -493,8 +606,12 @@ nfssvc_nfsd(struct nfssvc_copy_ops *ops,
 	cacherep = RC_DOIT;
 	writes_todo = 0;
 #endif
-	if (nfsd == NULL) {
-		nsd->nsd_nfsd = nfsd = kmem_alloc(sizeof(*nfsd), KM_SLEEP);
+	/*
+	 * If userland didn't provide an nfsd cookie, bake a fresh one;
+	 * if they did provide one, look it up.
+	 */
+	if ((uintptr_t)nsd->nsd_nfsd == 0) {
+		nfsd = kmem_alloc(sizeof(*nfsd), KM_SLEEP);
 		memset(nfsd, 0, sizeof (struct nfsd));
 		cv_init(&nfsd->nfsd_cv, "nfsd");
 		nfsd->nfsd_procp = p;
@@ -503,10 +620,15 @@ nfssvc_nfsd(struct nfssvc_copy_ops *ops,
 			KASSERT(nfs_numnfsd == 0);
 			cv_wait(&nfsd_initcv, &nfsd_lock);
 		}
-		TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
+		nsd->nsd_nfsd = nfsd_bake_cookie(nfsd);
 		nfs_numnfsd++;
 		mutex_exit(&nfsd_lock);
+	} else if ((nfsd = nfsd_get(nsd->nsd_nfsd)) == NULL) {
+		return (EINVAL);
 	}
+	KASSERT(nfsd != NULL);
+	KASSERT(nsd->nsd_nfsd != (struct nfsd *)(uintptr_t)0);
+
 	/*
 	 * Loop getting rpc requests until SIGKILL.
 	 */
@@ -759,14 +881,15 @@ nfssvc_nfsd(struct nfssvc_copy_ops *ops,
 	}
 done:
 	mutex_enter(&nfsd_lock);
-	TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
+	nfsd_toss_cookie(nfsd);
 	doreinit = --nfs_numnfsd == 0;
 	if (doreinit)
 		nfssvc_sockhead_flag |= SLP_INIT;
 	mutex_exit(&nfsd_lock);
 	cv_destroy(&nfsd->nfsd_cv);
 	kmem_free(nfsd, sizeof(*nfsd));
-	nsd->nsd_nfsd = NULL;
+	KASSERT(nsd->nsd_nfsd != (struct nfsd *)(uintptr_t)0);
+	nsd->nsd_nfsd = (struct nfsd *)(uintptr_t)0;
 	if (doreinit)
 		nfsrv_init(true);	/* Reinitialize everything */
 	return (error);
@@ -895,7 +1018,7 @@ nfsrv_init(int terminating)
 
 	if (terminating) {
 		KASSERT(SLIST_EMPTY(&nfsd_idle_head));
-		KASSERT(TAILQ_EMPTY(&nfsd_head));
+		KASSERT(RB_TREE_MIN(&nfsd_tree) == NULL);
 		while ((slp = TAILQ_FIRST(&nfssvc_sockhead)) != NULL) {
 			mutex_exit(&nfsd_lock);
 			KASSERT(slp->ns_sref == 0);
@@ -915,7 +1038,7 @@ nfsrv_init(int terminating)
 	TAILQ_INIT(&nfssvc_sockhead);
 	TAILQ_INIT(&nfssvc_sockpending);
 
-	TAILQ_INIT(&nfsd_head);
+	rb_tree_init(&nfsd_tree, &nfsd_tree_ops);
 	SLIST_INIT(&nfsd_idle_head);
 	nfsd_head_flag &= ~NFSD_CHECKSLP;
 

Reply via email to