Date: Wed, 30 May 2018 20:16:18 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r334396 - head/sys/fs/nfsserver Message-ID: <201805302016.w4UKGInM068733@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rmacklem Date: Wed May 30 20:16:17 2018 New Revision: 334396 URL: https://svnweb.freebsd.org/changeset/base/334396 Log: Strengthen locking for the NFSv4.1 server DestroySession operation. If a client did a DestroySession on a session while it was still in use, the server might try to use the session structure after it is free'd. I think the client has violated RFC5661 if it does this, but this patch makes DestroySession block all other nfsd threads so no thread could be using the session when it is free'd. After the DestroySession, nfsd threads will not be able to find the session. The patch also adds a check for nd_sessionid being set, although if that was not the case it would have been all 0s and unlikely to have a false match. This might fix the crashes described in PR#228497 for the FreeNAS server. PR: 228497 MFC after: 1 week Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdstate.c Wed May 30 19:58:36 2018 (r334395) +++ head/sys/fs/nfsserver/nfs_nfsdstate.c Wed May 30 20:16:17 2018 (r334396) @@ -6006,17 +6006,32 @@ nfsrv_findsession(uint8_t *sessionid) int nfsrv_destroysession(struct nfsrv_descript *nd, uint8_t *sessionid) { - int error, samesess; + int error, igotlock, samesess; samesess = 0; - if (!NFSBCMP(sessionid, nd->nd_sessionid, NFSX_V4SESSIONID)) { + if (!NFSBCMP(sessionid, nd->nd_sessionid, NFSX_V4SESSIONID) && + (nd->nd_flag & ND_HASSEQUENCE) != 0) { samesess = 1; if ((nd->nd_flag & ND_LASTOP) == 0) return (NFSERR_BADSESSION); } + + /* Lock out other nfsd threads */ + NFSLOCKV4ROOTMUTEX(); + nfsv4_relref(&nfsv4rootfs_lock); + do { + igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, + NFSV4ROOTLOCKMUTEXPTR, NULL); + } while (igotlock == 0); + NFSUNLOCKV4ROOTMUTEX(); + error = nfsrv_freesession(NULL, sessionid); if (error == 0 && samesess != 0) nd->nd_flag &= ~ND_HASSEQUENCE; + + NFSLOCKV4ROOTMUTEX(); + nfsv4_unlock(&nfsv4rootfs_lock, 1); + NFSUNLOCKV4ROOTMUTEX(); return (error); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201805302016.w4UKGInM068733>