Module Name: src Committed By: bouyer Date: Fri Apr 10 19:04:14 UTC 2009
Modified Files: src/sys/nfs: nfs_syscalls.c Log Message: PR kern/41154: possible races in NFS server code Fix some of the races (but probably not all of them) in the NFS server code. nfssvc_nfsd(): change a splsoftclock()/spx() to mutex_enter/exit(&nfsd_lock) (I guess it was forgotten when the nfsd code was made SMP safe) m_freem(nd_nam) in nfsrv_slpderef() instead of nfsrv_zapsock() to avoid possible use after free in nfssvc_nfsd() Fix nfsrv_slpderef() to not release nfsd_lock before testing SLP_VALID and reaquiring it just after. This could cause a use after free of the slp if one thread is in nfsrv_slpderef() and the other one grabs slp from nfssvc_sockpending and zap it. To generate a diff of this commit: cvs rdiff -u -r1.146 -r1.147 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_syscalls.c diff -u src/sys/nfs/nfs_syscalls.c:1.146 src/sys/nfs/nfs_syscalls.c:1.147 --- src/sys/nfs/nfs_syscalls.c:1.146 Sun Mar 15 17:20:10 2009 +++ src/sys/nfs/nfs_syscalls.c Fri Apr 10 19:04:14 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: nfs_syscalls.c,v 1.146 2009/03/15 17:20:10 cegger Exp $ */ +/* $NetBSD: nfs_syscalls.c,v 1.147 2009/04/10 19:04:14 bouyer Exp $ */ /* * Copyright (c) 1989, 1993 @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.146 2009/03/15 17:20:10 cegger Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.147 2009/04/10 19:04:14 bouyer Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -432,7 +432,6 @@ u_quad_t cur_usec; int error = 0, cacherep, siz, sotype, writes_todo; struct proc *p = l->l_proc; - int s; bool doreinit; #ifndef nolint @@ -682,14 +681,14 @@ getmicrotime(&tv); cur_usec = (u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec; - s = splsoftclock(); + mutex_enter(&nfsd_lock); if (LIST_FIRST(&slp->ns_tq) && LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) { cacherep = RC_DOIT; writes_todo = 1; } else writes_todo = 0; - splx(s); + mutex_exit(&nfsd_lock); } while (writes_todo); if (nfsrv_dorec(slp, nfsd, &nd, &dummy)) { nfsd->nfsd_slp = NULL; @@ -748,8 +747,6 @@ soshutdown(so, SHUT_RDWR); sounlock(so); - if (slp->ns_nam) - m_free(slp->ns_nam); m_freem(slp->ns_raw); m = slp->ns_rec; while (m != NULL) { @@ -759,6 +756,7 @@ m_freem(m); m = n; } + /* XXX what about freeing ns_frag ? */ for (nuidp = TAILQ_FIRST(&slp->ns_uidlruhead); nuidp != 0; nuidp = nnuidp) { nnuidp = TAILQ_NEXT(nuidp, nu_lru); @@ -790,11 +788,9 @@ mutex_enter(&nfsd_lock); KASSERT(slp->ns_sref > 0); ref = --slp->ns_sref; - mutex_exit(&nfsd_lock); if (ref == 0 && (slp->ns_flags & SLP_VALID) == 0) { file_t *fp; - mutex_enter(&nfsd_lock); KASSERT((slp->ns_gflags & SLP_G_DOREC) == 0); TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); mutex_exit(&nfsd_lock); @@ -808,9 +804,12 @@ closef(fp); slp->ns_so = NULL; } - + + if (slp->ns_nam) + m_free(slp->ns_nam); nfsrv_sockfree(slp); - } + } else + mutex_exit(&nfsd_lock); } /*