NDFREE(): Fix unlocking for LOCKPARENT|LOCKLEAF and ndp->ni_dvp == ndp->ni_vp.

NDFREE() calculates unlock_dvp after ndp->ni_vp is unlocked and zeroed
out. This makes the comparision of ni_dvp with ni_vp always fail.
Move the calculation of unlock_dvp right after unlock_vp, so that the
code sees correct ni_vp value.

Reproduced by
	   chdir("/usr");
	   open("/..", O_BENEATH | O_RDONLY);

Reported by:	syzkaller
Reviewed by:	markj, mckusick
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D20304
This commit is contained in:
Konstantin Belousov 2019-05-21 15:12:13 +00:00
parent 1177d38ce1
commit e28fa55a08
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=348052

View File

@ -1332,6 +1332,10 @@ NDFREE(struct nameidata *ndp, const u_int flags)
if (!(flags & NDF_NO_VP_UNLOCK) &&
(ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp)
unlock_vp = 1;
if (!(flags & NDF_NO_DVP_UNLOCK) &&
(ndp->ni_cnd.cn_flags & LOCKPARENT) &&
ndp->ni_dvp != ndp->ni_vp)
unlock_dvp = 1;
if (!(flags & NDF_NO_VP_RELE) && ndp->ni_vp) {
if (unlock_vp) {
vput(ndp->ni_vp);
@ -1342,10 +1346,6 @@ NDFREE(struct nameidata *ndp, const u_int flags)
}
if (unlock_vp)
VOP_UNLOCK(ndp->ni_vp, 0);
if (!(flags & NDF_NO_DVP_UNLOCK) &&
(ndp->ni_cnd.cn_flags & LOCKPARENT) &&
ndp->ni_dvp != ndp->ni_vp)
unlock_dvp = 1;
if (!(flags & NDF_NO_DVP_RELE) &&
(ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) {
if (unlock_dvp) {