Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Nov 2018 01:46:17 +0200
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Vladimir Kondratyev <vladimir@kondratyev.su>
Cc:        current@freebsd.org, peter@holm.cc
Subject:   Re: r340343 triggers kernel assertion if file is opened with O_BENEATH flag set through symlink
Message-ID:  <20181127234617.GE2378@kib.kiev.ua>
In-Reply-To: <d8fd4b5d-b6c7-c56e-79f3-504daceb2a51@kondratyev.su>
References:  <d8fd4b5d-b6c7-c56e-79f3-504daceb2a51@kondratyev.su>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, Nov 28, 2018 at 12:54:21AM +0300, Vladimir Kondratyev wrote:
> Following test case triggers assertion after r340343:
> 
> 
> #include <fcntl.h>
> 
> int
> main(int argc, char **argv)
> {
>         openat(open("/etc", O_RDONLY), "termcap", O_RDONLY | O_BENEATH);
> }
> 
> It results in:
> 
> panic: Assertion (ndp->ni_lcf & NI_LCF_LATCH) != 0 failed at
> /usr/src/sys/kern/vfs_lookup.c:182
> 

The following should fix it. Problem was that the topping directory was
only latched when the initial path was absolute. Since your example
switched from the relative argument to the absolute symlink, the BENEATH
tracker rightfully complained that there were no recorded top.

I also added some asserts I used during the debugging.

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 78893c4f2bd..7a80775d91d 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -202,8 +202,10 @@ nameicap_cleanup(struct nameidata *ndp, bool clean_latch)
 		vdrop(nt->dp);
 		uma_zfree(nt_zone, nt);
 	}
-	if (clean_latch && (ndp->ni_lcf & NI_LCF_LATCH) != 0)
+	if (clean_latch && (ndp->ni_lcf & NI_LCF_LATCH) != 0) {
+		ndp->ni_lcf &= ~NI_LCF_LATCH;
 		vrele(ndp->ni_beneath_latch);
+	}
 }
 
 /*
@@ -264,6 +266,7 @@ namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
 		return (ENOTCAPABLE);
 	}
 	if ((cnp->cn_flags & BENEATH) != 0) {
+		MPASS((ndp->ni_lcf & NI_LCF_LATCH) != 0);
 		ndp->ni_lcf |= NI_LCF_BENEATH_ABS;
 		ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED;
 		nameicap_cleanup(ndp, false);
@@ -446,7 +449,7 @@ namei(struct nameidata *ndp)
 		if (error == 0 && dp->v_type != VDIR)
 			error = ENOTDIR;
 	}
-	if (error == 0 && (ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) {
+	if (error == 0 && (cnp->cn_flags & BENEATH) != 0) {
 		if (ndp->ni_dirfd == AT_FDCWD) {
 			ndp->ni_beneath_latch = fdp->fd_cdir;
 			vrefact(ndp->ni_beneath_latch);
@@ -471,6 +474,8 @@ namei(struct nameidata *ndp)
 			vrele(dp);
 		goto out;
 	}
+	MPASS((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | NI_LCF_LATCH)) !=
+	    NI_LCF_BENEATH_ABS);
 	if (((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 &&
 	    lookup_cap_dotdot != 0) ||
 	    ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0 &&



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20181127234617.GE2378>