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;