Module Name:    src
Committed By:   martin
Date:           Mon Jun 21 14:50:57 UTC 2021

Modified Files:
        src/sys/kern [netbsd-9]: vfs_lookup.c vfs_vnops.c
        src/sys/sys [netbsd-9]: namei.src

Log Message:
Pull up following revision(s) (requested by dholland in ticket #1296):

        sys/sys/namei.src: revision 1.59        (via patch)
        sys/kern/vfs_vnops.c: revision 1.215
        sys/kern/vfs_lookup.c: revision 1.226

Add a new namei flag NONEXCLHACK for open with O_CREAT and not O_EXCL.
This case needs to be distinguished from the other CREATE operations
because it is supposed to successfully return (and open) the target if
it exists. In the case where that target is the root, or a mount
point, such that there's no parent dir, "real" CREATE operations fail,
but O_CREAT without O_EXCL needs to succeed.

So (a) add the flag, (b) test for it in namei in the situation
described above, (c) set it in open under the appropriate
circumstances, and (d) because this can result in namei returning
ni_dvp of NULL, cope with that case.

Should get into -9 and maybe even -8, because it was prompted by
issues with 3rd-party code. The use of a flag (vs. adding an
additional nameiop, which would be more appropriate) was deliberate to
make the patch small and noninvasive.


To generate a diff of this commit:
cvs rdiff -u -r1.212 -r1.212.2.1 src/sys/kern/vfs_lookup.c
cvs rdiff -u -r1.200 -r1.200.4.1 src/sys/kern/vfs_vnops.c
cvs rdiff -u -r1.42 -r1.42.2.1 src/sys/sys/namei.src

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/vfs_lookup.c
diff -u src/sys/kern/vfs_lookup.c:1.212 src/sys/kern/vfs_lookup.c:1.212.2.1
--- src/sys/kern/vfs_lookup.c:1.212	Thu Jul 18 09:39:40 2019
+++ src/sys/kern/vfs_lookup.c	Mon Jun 21 14:50:57 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.212 2019/07/18 09:39:40 hannken Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.212.2.1 2021/06/21 14:50:57 martin Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.212 2019/07/18 09:39:40 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.212.2.1 2021/06/21 14:50:57 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_magiclinks.h"
@@ -1434,10 +1434,33 @@ namei_oneroot(struct namei_state *state,
 		 * a CREATE, DELETE, or RENAME), and we don't have one
 		 * (because this is the root directory, or we crossed
 		 * a mount point), then we must fail.
+		 *
+		 * 20210604 dholland when NONEXCLHACK is set (open
+		 * with O_CREAT but not O_EXCL) skip this logic. Since
+		 * we have a foundobj, open will not be creating, so
+		 * it doesn't actually need or use the searchdir, so
+		 * it's ok to return it even if it's on a different
+		 * volume, and it's also ok to return NULL; by setting
+		 * NONEXCLHACK the open code promises to cope with
+		 * those cases correctly. (That is, it should do what
+		 * it would do anyway, that is, just release the
+		 * searchdir, except not crash if it's null.) This is
+		 * needed because otherwise opening mountpoints with
+		 * O_CREAT but not O_EXCL fails... which is a silly
+		 * thing to do but ought to work. (This whole issue
+		 * came to light because 3rd party code wanted to open
+		 * certain procfs nodes with O_CREAT for some 3rd
+		 * party reason, and it failed.)
+		 *
+		 * Note that NONEXCLHACK is properly a different
+		 * nameiop (it is partway between LOOKUP and CREATE)
+		 * but it was stuffed in as a flag instead to make the
+		 * resulting patch less invasive for pullup. Blah.
 		 */
 		if (cnp->cn_nameiop != LOOKUP &&
 		    (searchdir == NULL ||
-		     searchdir->v_mount != foundobj->v_mount)) {
+		     searchdir->v_mount != foundobj->v_mount) &&
+		    (cnp->cn_flags & NONEXCLHACK) == 0) {
 			if (searchdir) {
 				vput(searchdir);
 			}

Index: src/sys/kern/vfs_vnops.c
diff -u src/sys/kern/vfs_vnops.c:1.200 src/sys/kern/vfs_vnops.c:1.200.4.1
--- src/sys/kern/vfs_vnops.c:1.200	Thu Mar  7 11:09:48 2019
+++ src/sys/kern/vfs_vnops.c	Mon Jun 21 14:50:57 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnops.c,v 1.200 2019/03/07 11:09:48 hannken Exp $	*/
+/*	$NetBSD: vfs_vnops.c,v 1.200.4.1 2021/06/21 14:50:57 martin Exp $	*/
 
 /*-
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.200 2019/03/07 11:09:48 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.200.4.1 2021/06/21 14:50:57 martin Exp $");
 
 #include "veriexec.h"
 
@@ -161,6 +161,8 @@ vn_open(struct nameidata *ndp, int fmode
 		if ((fmode & O_EXCL) == 0 &&
 		    ((fmode & O_NOFOLLOW) == 0))
 			ndp->ni_cnd.cn_flags |= FOLLOW;
+		if ((fmode & O_EXCL) == 0)
+			ndp->ni_cnd.cn_flags |= NONEXCLHACK;
 	} else {
 		ndp->ni_cnd.cn_nameiop = LOOKUP;
 		ndp->ni_cnd.cn_flags |= LOCKLEAF;
@@ -183,7 +185,12 @@ vn_open(struct nameidata *ndp, int fmode
 	error = veriexec_openchk(l, ndp->ni_vp, pathstring, fmode);
 	if (error) {
 		/* We have to release the locks ourselves */
-		if (fmode & O_CREAT) {
+		/*
+		 * 20210604 dholland passing NONEXCLHACK means we can
+		 * get ni_dvp == NULL back if ni_vp exists, and we should
+		 * treat that like the non-O_CREAT case.
+		 */
+		if ((fmode & O_CREAT) != 0 && ndp->ni_dvp != NULL) {
 			if (vp == NULL) {
 				vput(ndp->ni_dvp);
 			} else {
@@ -202,7 +209,10 @@ vn_open(struct nameidata *ndp, int fmode
 	}
 #endif /* NVERIEXEC > 0 */
 
-	if (fmode & O_CREAT) {
+	/*
+	 * 20210604 dholland ditto
+	 */
+	if ((fmode & O_CREAT) != 0 && ndp->ni_dvp != NULL) {
 		if (ndp->ni_vp == NULL) {
 			vattr_null(&va);
 			va.va_type = VREG;
@@ -233,6 +243,17 @@ vn_open(struct nameidata *ndp, int fmode
 			}
 			fmode &= ~O_CREAT;
 		}
+	} else if ((fmode & O_CREAT) != 0) {
+		/*
+		 * 20210606 dholland passing NONEXCLHACK means this
+		 * case exists; it is the same as the following one
+		 * but also needs to do things in the second (exists)
+		 * half of the following block. (Besides handle
+		 * ni_dvp, anyway.)
+		 */
+		vp = ndp->ni_vp;
+		KASSERT((fmode & O_EXCL) == 0);
+		fmode &= ~O_CREAT;
 	} else {
 		vp = ndp->ni_vp;
 	}

Index: src/sys/sys/namei.src
diff -u src/sys/sys/namei.src:1.42 src/sys/sys/namei.src:1.42.2.1
--- src/sys/sys/namei.src:1.42	Mon Jun  3 06:04:21 2019
+++ src/sys/sys/namei.src	Mon Jun 21 14:50:57 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: namei.src,v 1.42 2019/06/03 06:04:21 msaitoh Exp $	*/
+/*	$NetBSD: namei.src,v 1.42.2.1 2021/06/21 14:50:57 martin Exp $	*/
 
 /*
  * Copyright (c) 1985, 1989, 1991, 1993
@@ -152,7 +152,8 @@ NAMEIFL	NOFOLLOW	0x00000000	/* do not fo
 NAMEIFL	EMULROOTSET	0x00000080	/* emulation root already
 					   in ni_erootdir */
 NAMEIFL	NOCHROOT	0x01000000	/* no chroot on abs path lookups */
-NAMEIFL	MODMASK		0x010000fc	/* mask of operational modifiers */
+NAMEIFL	NONEXCLHACK	0x02000000	/* open wwith O_CREAT but not O_EXCL */
+NAMEIFL	MODMASK		0x030000fc	/* mask of operational modifiers */
 /*
  * Namei parameter descriptors.
  */

Reply via email to