Re: r340343 triggers kernel assertion if file is opened with O_BENEATH flag set through symlink

From: Konstantin Belousov <kostikbel_at_gmail.com>
Date: Wed, 28 Nov 2018 01:46:17 +0200
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
_at__at_ -202,8 +202,10 _at__at_ 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);
+	}
 }
 
 /*
_at__at_ -264,6 +266,7 _at__at_ 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);
_at__at_ -446,7 +449,7 _at__at_ 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);
_at__at_ -471,6 +474,8 _at__at_ 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 &&
Received on Tue Nov 27 2018 - 22:46:30 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:41:19 UTC