DF-0884 / fix.diff
diff --git a/sys/vfs/smbfs/smbfs_io.c b/sys/vfs/smbfs/smbfs_io.c --- a/sys/vfs/smbfs/smbfs_io.c +++ b/sys/vfs/smbfs/smbfs_io.c @@ -199,7 +199,18 @@ return EINVAL; td = uiop->uio_td; if (vp->v_type == VDIR) { - lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, td);*/ + /* + * vn_read() acquires the vnode SHARED, but smbfs_readvdir() + * mutates per-vnode directory-iteration state (np->n_dirseq, + * np->n_dirofs). Two concurrent read(2) on the same directory + * vnode would race smbfs_findnext() against smbfs_findclose() + * and use-after-free the smbfs_fctx, so upgrade to exclusive + * when we currently hold it shared (the normal read(2) path). + * smbfs_readdir() already holds it exclusively, so detect the + * current state rather than hardcoding LK_EXCLUSIVE (which left + * the upgrade as dead code and the race open). + */ + lks = vn_islocked(vp); if (lks == LK_SHARED) vn_lock(vp, LK_UPGRADE | LK_RETRY); error = smbfs_readvdir(vp, uiop, cred); |