diff --git a/sys/rpc/rpc_generic.c.vnet b/sys/rpc/rpc_generic.c --- a/sys/rpc/rpc_generic.c.vnet +++ b/sys/rpc/rpc_generic.c @@ -45,10 +45,12 @@ #include "opt_inet6.h" #include +#include #include #include #include #include +#include #include #include #include @@ -958,6 +960,10 @@ return (mhead); } +#ifdef VNET_NFSD +int rpctls_prison_cleanup(void *obj, void *data __unused); +#endif + /* * Kernel module glue */ @@ -965,10 +971,19 @@ krpc_modevent(module_t mod, int type, void *data) { int error = 0; +#ifdef VNET_NFSD + osd_method_t methods[PR_MAXMETHOD] = { + [PR_METHOD_REMOVE] = rpctls_prison_cleanup, + }; +#endif switch (type) { case MOD_LOAD: error = rpctls_init(); +#ifdef VNET_NFSD + /* XXX-BZ OSD to VNET? */ + osd_jail_register(NULL, methods); +#endif break; case MOD_UNLOAD: /* diff --git a/sys/rpc/rpcsec_tls.h.vnet b/sys/rpc/rpcsec_tls.h --- a/sys/rpc/rpcsec_tls.h.vnet +++ b/sys/rpc/rpcsec_tls.h @@ -86,6 +86,35 @@ /* ssl refno value to indicate TLS handshake being done. */ #define RPCTLS_REFNO_HANDSHAKE 0xFFFFFFFFFFFFFFFFULL +/* Macros for VNET_NFSD. */ +#ifdef VNET_NFSD +#if !defined(VIMAGE) +options VNET_NFSD also requires options VIMAGE +#endif +/* Just define the VNET_KRPCxxx() macros as VNETxxx() macros. */ +#define KRPC_VNET_DEFINE(t, n) VNET_DEFINE(t, n) +#define KRPC_VNET_DEFINE_STATIC(t, n) VNET_DEFINE_STATIC(t, n) +#define KRPC_VNET(n) VNET(n) + +#define KRPC_CURVNET_SET(n) CURVNET_SET(n) +#define KRPC_CURVNET_SET_QUIET(n) CURVNET_SET_QUIET(n) +#define KRPC_CURVNET_RESTORE() CURVNET_RESTORE() +#define KRPC_TD_TO_VNET(n) TD_TO_VNET(n) + +/* Jail OSD cleanup function. */ +int rpctls_prison_cleanup(void *obj, void *data __unused); +#else /* !VNET_NFSD */ +/* Define the KRPC_VNET macros similar to !VIMAGE. */ +#define KRPC_VNET_DEFINE(t, n) t n +#define KRPC_VNET_DEFINE_STATIC(t, n) static t n +#define KRPC_VNET(n) (n) + +#define KRPC_CURVNET_SET(n) +#define KRPC_CURVNET_SET_QUIET(n) +#define KRPC_CURVNET_RESTORE() +#define KRPC_TD_TO_VNET(n) NULL +#endif /* VNET_NFSD */ + #endif /* _KERNEL */ #endif /* _RPC_RPCSEC_TLS_H_ */ diff --git a/sys/rpc/rpcsec_tls/rpctls_impl.c.vnet b/sys/rpc/rpcsec_tls/rpctls_impl.c --- a/sys/rpc/rpcsec_tls/rpctls_impl.c.vnet +++ b/sys/rpc/rpcsec_tls/rpctls_impl.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,8 @@ #include #include +#include + #include #include #include @@ -74,15 +77,16 @@ static struct mtx rpctls_connect_lock; static struct socket *rpctls_connect_so = NULL; static CLIENT *rpctls_connect_cl = NULL; -static CLIENT *rpctls_server_handle[RPCTLS_SRV_MAXNPROCS]; static struct mtx rpctls_server_lock; -static struct socket *rpctls_server_so = NULL; -static SVCXPRT *rpctls_server_xprt = NULL; -static bool rpctls_srv_newdaemon = false; -static int rpctls_srv_prevproc = 0; -static bool rpctls_server_busy[RPCTLS_SRV_MAXNPROCS]; static struct opaque_auth rpctls_null_verf; +KRPC_VNET_DEFINE_STATIC(CLIENT **, rpctls_server_handle); +KRPC_VNET_DEFINE_STATIC(struct socket *, rpctls_server_so) = NULL; +KRPC_VNET_DEFINE_STATIC(SVCXPRT *, rpctls_server_xprt) = NULL; +KRPC_VNET_DEFINE_STATIC(bool, rpctls_srv_newdaemon) = false; +KRPC_VNET_DEFINE_STATIC(int, rpctls_srv_prevproc) = 0; +KRPC_VNET_DEFINE_STATIC(bool *, rpctls_server_busy); + static CLIENT *rpctls_connect_client(void); static CLIENT *rpctls_server_client(int procpos); static enum clnt_stat rpctls_server(SVCXPRT *xprt, struct socket *so, @@ -90,10 +94,27 @@ uid_t *uid, int *ngrps, gid_t **gids, int *procposp); +static void +rpctls_vnetinit(const void *unused __unused) +{ + int i; + + KRPC_VNET(rpctls_server_handle) = malloc(sizeof(CLIENT *) * + RPCTLS_SRV_MAXNPROCS, M_RPC, M_WAITOK | M_ZERO); + KRPC_VNET(rpctls_server_busy) = malloc(sizeof(bool) * + RPCTLS_SRV_MAXNPROCS, M_RPC, M_WAITOK | M_ZERO); + for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) + KRPC_VNET(rpctls_server_busy)[i] = false; +} +#ifdef VNET_NFSD +VNET_SYSINIT(rpctls_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY, + rpctls_vnetinit, NULL); +#endif + int rpctls_init(void) { - int error, i; + int error; error = syscall_helper_register(rpctls_syscalls, SY_THR_STATIC_KLD); if (error != 0) { @@ -107,8 +128,9 @@ rpctls_null_verf.oa_flavor = AUTH_NULL; rpctls_null_verf.oa_base = RPCTLS_START_STRING; rpctls_null_verf.oa_length = strlen(RPCTLS_START_STRING); - for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) - rpctls_server_busy[i] = false; +#ifndef VNET_NFSD + rpctls_vnetinit(NULL); +#endif return (0); } @@ -133,27 +155,36 @@ if (error != 0) return (error); + KRPC_CURVNET_SET(KRPC_TD_TO_VNET(td)); switch (uap->op) { case RPCTLS_SYSC_SRVSTARTUP: - /* Get rid of all old CLIENTs. */ - mtx_lock(&rpctls_server_lock); - for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { - oldcl[i] = rpctls_server_handle[i]; - rpctls_server_handle[i] = NULL; - rpctls_server_busy[i] = false; - } - rpctls_srv_newdaemon = true; - rpctls_srv_prevproc = 0; - mtx_unlock(&rpctls_server_lock); - for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { - if (oldcl[i] != NULL) { - CLNT_CLOSE(oldcl[i]); - CLNT_RELEASE(oldcl[i]); + if (jailed(curthread->td_ucred) && + !prison_check_nfsd(curthread->td_ucred)) + error = EPERM; + if (error == 0) { + /* Get rid of all old CLIENTs. */ + mtx_lock(&rpctls_server_lock); + for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { + oldcl[i] = KRPC_VNET(rpctls_server_handle)[i]; + KRPC_VNET(rpctls_server_handle)[i] = NULL; + KRPC_VNET(rpctls_server_busy)[i] = false; } + KRPC_VNET(rpctls_srv_newdaemon) = true; + KRPC_VNET(rpctls_srv_prevproc) = 0; + mtx_unlock(&rpctls_server_lock); + for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { + if (oldcl[i] != NULL) { + CLNT_CLOSE(oldcl[i]); + CLNT_RELEASE(oldcl[i]); + } + } } break; case RPCTLS_SYSC_CLSETPATH: - error = copyinstr(uap->path, path, sizeof(path), NULL); + if (jailed(curthread->td_ucred)) + error = EPERM; + if (error == 0) + error = copyinstr(uap->path, path, sizeof(path), NULL); if (error == 0) { error = ENXIO; #ifdef KERN_TLS @@ -209,7 +240,11 @@ } break; case RPCTLS_SYSC_SRVSETPATH: - error = copyinstr(uap->path, path, sizeof(path), NULL); + if (jailed(curthread->td_ucred) && + !prison_check_nfsd(curthread->td_ucred)) + error = EPERM; + if (error == 0) + error = copyinstr(uap->path, path, sizeof(path), NULL); if (error == 0) { error = ENXIO; #ifdef KERN_TLS @@ -254,14 +289,14 @@ for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) oldcl[i] = NULL; mtx_lock(&rpctls_server_lock); - if (rpctls_srv_newdaemon) { + if (KRPC_VNET(rpctls_srv_newdaemon)) { /* * For a new daemon, the rpctls_srv_handles have * already been cleaned up by RPCTLS_SYSC_SRVSTARTUP. * Scan for an available array entry to use. */ for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { - if (rpctls_server_handle[i] == NULL) + if (KRPC_VNET(rpctls_server_handle)[i] == NULL) break; } if (i == RPCTLS_SRV_MAXNPROCS && error == 0) @@ -269,14 +304,14 @@ } else { /* For an old daemon, clear out old CLIENTs. */ for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { - oldcl[i] = rpctls_server_handle[i]; - rpctls_server_handle[i] = NULL; - rpctls_server_busy[i] = false; + oldcl[i] = KRPC_VNET(rpctls_server_handle)[i]; + KRPC_VNET(rpctls_server_handle)[i] = NULL; + KRPC_VNET(rpctls_server_busy)[i] = false; } i = 0; /* Set to use rpctls_server_handle[0]. */ } if (error == 0) - rpctls_server_handle[i] = cl; + KRPC_VNET(rpctls_server_handle)[i] = cl; mtx_unlock(&rpctls_server_lock); for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { @@ -300,10 +335,10 @@ case RPCTLS_SYSC_SRVSHUTDOWN: mtx_lock(&rpctls_server_lock); for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { - oldcl[i] = rpctls_server_handle[i]; - rpctls_server_handle[i] = NULL; + oldcl[i] = KRPC_VNET(rpctls_server_handle)[i]; + KRPC_VNET(rpctls_server_handle)[i] = NULL; } - rpctls_srv_newdaemon = false; + KRPC_VNET(rpctls_srv_newdaemon) = false; mtx_unlock(&rpctls_server_lock); for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { @@ -342,10 +377,10 @@ break; case RPCTLS_SYSC_SRVSOCKET: mtx_lock(&rpctls_server_lock); - so = rpctls_server_so; - rpctls_server_so = NULL; - xprt = rpctls_server_xprt; - rpctls_server_xprt = NULL; + so = KRPC_VNET(rpctls_server_so); + KRPC_VNET(rpctls_server_so) = NULL; + xprt = KRPC_VNET(rpctls_server_xprt); + KRPC_VNET(rpctls_server_xprt) = NULL; mtx_unlock(&rpctls_server_lock); if (so != NULL) { error = falloc(td, &fp, &fd, 0); @@ -370,6 +405,7 @@ default: error = EINVAL; } + KRPC_CURVNET_RESTORE(); return (error); } @@ -400,11 +436,13 @@ { CLIENT *cl; + KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); mtx_lock(&rpctls_server_lock); - cl = rpctls_server_handle[procpos]; + cl = KRPC_VNET(rpctls_server_handle)[procpos]; if (cl != NULL) CLNT_ACQUIRE(cl); mtx_unlock(&rpctls_server_lock); + KRPC_CURVNET_RESTORE(); return (cl); } @@ -611,33 +649,37 @@ uint32_t *gidv; int i, procpos; + KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); cl = NULL; procpos = -1; mtx_lock(&rpctls_server_lock); - for (i = (rpctls_srv_prevproc + 1) % RPCTLS_SRV_MAXNPROCS; - i != rpctls_srv_prevproc; i = (i + 1) % RPCTLS_SRV_MAXNPROCS) { - if (rpctls_server_handle[i] != NULL) + for (i = (KRPC_VNET(rpctls_srv_prevproc) + 1) % RPCTLS_SRV_MAXNPROCS; + i != KRPC_VNET(rpctls_srv_prevproc); + i = (i + 1) % RPCTLS_SRV_MAXNPROCS) { + if (KRPC_VNET(rpctls_server_handle)[i] != NULL) break; } - if (i == rpctls_srv_prevproc) { - if (rpctls_server_handle[i] != NULL) + if (i == KRPC_VNET(rpctls_srv_prevproc)) { + if (KRPC_VNET(rpctls_server_handle)[i] != NULL) procpos = i; } else - rpctls_srv_prevproc = procpos = i; + KRPC_VNET(rpctls_srv_prevproc) = procpos = i; mtx_unlock(&rpctls_server_lock); if (procpos >= 0) cl = rpctls_server_client(procpos); - if (cl == NULL) + if (cl == NULL) { + KRPC_CURVNET_RESTORE(); return (RPC_SYSTEMERROR); + } /* Serialize the server upcalls. */ mtx_lock(&rpctls_server_lock); - while (rpctls_server_busy[procpos]) - msleep(&rpctls_server_busy[procpos], &rpctls_server_lock, PVFS, - "rtlssn", 0); - rpctls_server_busy[procpos] = true; - rpctls_server_so = so; - rpctls_server_xprt = xprt; + while (KRPC_VNET(rpctls_server_busy)[procpos]) + msleep(&KRPC_VNET(rpctls_server_busy)[procpos], + &rpctls_server_lock, PVFS, "rtlssn", 0); + KRPC_VNET(rpctls_server_busy)[procpos] = true; + KRPC_VNET(rpctls_server_so) = so; + KRPC_VNET(rpctls_server_xprt) = xprt; mtx_unlock(&rpctls_server_lock); /* Do the server upcall. */ @@ -672,11 +714,12 @@ /* Once the upcall is done, the daemon is done with the fp and so. */ mtx_lock(&rpctls_server_lock); - rpctls_server_so = NULL; - rpctls_server_xprt = NULL; - rpctls_server_busy[procpos] = false; - wakeup(&rpctls_server_busy[procpos]); + KRPC_VNET(rpctls_server_so) = NULL; + KRPC_VNET(rpctls_server_xprt) = NULL; + KRPC_VNET(rpctls_server_busy)[procpos] = false; + wakeup(&KRPC_VNET(rpctls_server_busy)[procpos]); mtx_unlock(&rpctls_server_lock); + KRPC_CURVNET_RESTORE(); return (stat); } @@ -795,9 +838,30 @@ return (false); if (rpctlscd_run && rpctls_connect_handle == NULL) return (false); - if (rpctlssd_run && rpctls_server_handle[0] == NULL) + KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); + if (rpctlssd_run && KRPC_VNET(rpctls_server_handle)[0] == NULL) { + KRPC_CURVNET_RESTORE(); return (false); + } + KRPC_CURVNET_RESTORE(); *maxlenp = maxlen; return (enable); } + +#ifdef VNET_NFSD +/* Osd entry for prison cleanup. */ +int +rpctls_prison_cleanup(void *obj, void *data __unused) +{ + struct prison *pr = obj; + + if ((pr->pr_flags & PR_VNET) == 0) + return (0); + KRPC_CURVNET_SET(pr->pr_vnet); + free(KRPC_VNET(rpctls_server_handle), M_RPC); + free(KRPC_VNET(rpctls_server_busy), M_RPC); + KRPC_CURVNET_RESTORE(); + return (0); +} +#endif