Module Name:    src
Committed By:   msaitoh
Date:           Thu Apr 12 01:45:58 UTC 2018

Modified Files:
        src/external/bsd/nvi/dist/common [netbsd-8]: recover.c
        src/lib/libc/stdio [netbsd-8]: fdopen.c flags.c fopen.c freopen.c
        src/lib/libc/sys [netbsd-8]: open.2
        src/sys/kern [netbsd-8]: vfs_vnops.c
        src/sys/sys [netbsd-8]: fcntl.h

Log Message:
Pull up following revision(s) (requested by christos in ticket #741):
        lib/libc/stdio/flags.c: revision 1.19
        lib/libc/stdio/fdopen.c: revision 1.18
        sys/kern/vfs_vnops.c: revision 1.196
        lib/libc/stdio/freopen.c: revision 1.20
        lib/libc/stdio/fopen.c: revision 1.17
        external/bsd/nvi/dist/common/recover.c: revision 1.10
        external/bsd/nvi/dist/common/recover.c: revision 1.11
        lib/libc/sys/open.2: revision 1.58
        sys/sys/fcntl.h: revision 1.49
make the checkok test stricter to avoid races, and use O_REGULAR.
Instead of opening the file and using popen(3), pass the file descriptor
to sendmail directory. Idea and code from Todd Miller.
Add O_REGULAR to enforce opening of only regular files
(like we have O_DIRECTORY for directories).
This is better than open(, O_NONBLOCK), fstat()+S_ISREG() because opening
devices can have side effects.


To generate a diff of this commit:
cvs rdiff -u -r1.5.22.1 -r1.5.22.2 src/external/bsd/nvi/dist/common/recover.c
cvs rdiff -u -r1.17 -r1.17.6.1 src/lib/libc/stdio/fdopen.c
cvs rdiff -u -r1.17 -r1.17.22.1 src/lib/libc/stdio/flags.c
cvs rdiff -u -r1.15 -r1.15.24.1 src/lib/libc/stdio/fopen.c
cvs rdiff -u -r1.19 -r1.19.24.1 src/lib/libc/stdio/freopen.c
cvs rdiff -u -r1.57 -r1.57.2.1 src/lib/libc/sys/open.2
cvs rdiff -u -r1.195 -r1.195.6.1 src/sys/kern/vfs_vnops.c
cvs rdiff -u -r1.48.8.1 -r1.48.8.2 src/sys/sys/fcntl.h

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

Modified files:

Index: src/external/bsd/nvi/dist/common/recover.c
diff -u src/external/bsd/nvi/dist/common/recover.c:1.5.22.1 src/external/bsd/nvi/dist/common/recover.c:1.5.22.2
--- src/external/bsd/nvi/dist/common/recover.c:1.5.22.1	Mon Nov  6 09:37:24 2017
+++ src/external/bsd/nvi/dist/common/recover.c	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: recover.c,v 1.5.22.1 2017/11/06 09:37:24 snj Exp $ */
+/*	$NetBSD: recover.c,v 1.5.22.2 2018/04/12 01:45:57 msaitoh Exp $ */
 /*-
  * Copyright (c) 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -16,12 +16,13 @@
 static const char sccsid[] = "Id: recover.c,v 10.31 2001/11/01 15:24:44 skimo Exp  (Berkeley) Date: 2001/11/01 15:24:44 ";
 #endif /* not lint */
 #else
-__RCSID("$NetBSD: recover.c,v 1.5.22.1 2017/11/06 09:37:24 snj Exp $");
+__RCSID("$NetBSD: recover.c,v 1.5.22.2 2018/04/12 01:45:57 msaitoh Exp $");
 #endif
 
 #include <sys/param.h>
 #include <sys/types.h>		/* XXX: param.h may not have included types.h */
 #include <sys/queue.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 
 /*
@@ -116,11 +117,15 @@ __RCSID("$NetBSD: recover.c,v 1.5.22.1 2
 #define	VI_PHEADER	"X-vi-recover-path: "
 
 static int	 rcv_copy(SCR *, int, char *);
-static void	 rcv_email(SCR *, const char *);
+static void	 rcv_email(SCR *, int fd);
 static char	*rcv_gets(char *, size_t, int);
 static int	 rcv_mailfile(SCR *, int, char *);
 static int	 rcv_mktemp(SCR *, char *, const char *, int);
 
+#ifndef O_REGULAR
+#define O_REGULAR O_NONBLOCK
+#endif
+
 /*
  * rcv_tmp --
  *	Build a file name that will be used as the recovery file.
@@ -286,7 +291,7 @@ rcv_sync(SCR *sp, u_int flags)
 
 		/* REQUEST: send email. */
 		if (LF_ISSET(RCV_EMAIL))
-			rcv_email(sp, ep->rcv_mpath);
+			rcv_email(sp, ep->rcv_fd);
 	}
 
 	/*
@@ -466,7 +471,7 @@ wout:		*t2++ = '\n';
 	}
 
 	if (issync) {
-		rcv_email(sp, mpath);
+		rcv_email(sp, fd);
 		if (close(fd)) {
 werr:			msgq(sp, M_SYSERR, "065|Recovery file");
 			goto err;
@@ -487,14 +492,19 @@ err:	if (!issync)
  * This is simpler than checking for getuid() == st.st_uid and we want
  * to preserve the functionality that root can recover anything which
  * means that root should know better and be careful.
+ *
+ * Checking the mode is racy though (someone can chmod between the
+ * open and the stat call, so also check for uid match or root.
  */
 static int
 checkok(int fd)
 {
 	struct stat sb;
+	uid_t uid = getuid();
 
 	return fstat(fd, &sb) != -1 && S_ISREG(sb.st_mode) &&
-	    (sb.st_mode & (S_IRWXG|S_IRWXO)) == 0;
+	    (sb.st_mode & (S_IRWXG|S_IRWXO)) == 0 &&
+	    (uid == 0 || uid == sb.st_uid);
 }
 
 /*
@@ -659,7 +669,7 @@ rcv_read(SCR *sp, FREF *frp)
 		 * if we're using fcntl(2), there's no way to lock a file
 		 * descriptor that's not open for writing.
 		 */
-		if ((fd = open(recpath, O_RDWR|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC,
+		if ((fd = open(recpath, O_RDWR|O_REGULAR|O_NOFOLLOW|O_CLOEXEC,
 		    0)) == -1)
 			continue;
 
@@ -876,12 +886,10 @@ rcv_mktemp(SCR *sp, char *path, const ch
  *	Send email.
  */
 static void
-rcv_email(SCR *sp, const char *fname)
+rcv_email(SCR *sp, int fd)
 {
 	struct stat sb;
-	char buf[BUFSIZ];
-	FILE *fin, *fout;
-	size_t l;
+	pid_t pid;
 
 	if (_PATH_SENDMAIL[0] != '/' || stat(_PATH_SENDMAIL, &sb) == -1) {
 		msgq_str(sp, M_SYSERR,
@@ -896,28 +904,26 @@ rcv_email(SCR *sp, const char *fname)
 	 * for the recipients instead of specifying them some other
 	 * way.
 	 */
-	if ((fin = fopen(fname, "refl")) == NULL) {
-		msgq_str(sp, M_SYSERR,
-		    fname, "325|cannot open: %s");
-		return;
-	}
-
-	if (!checkok(fileno(fin))) {
-		(void)fclose(fin);
-		return;
-	}
-
-	fout = popen(_PATH_SENDMAIL " -t", "w");
-	if (fout == NULL) {
-		msgq_str(sp, M_SYSERR,
-		    _PATH_SENDMAIL, "326|cannot execute sendmail: %s");
-		fclose(fin);
-		return;
+	switch (pid = fork()) {
+	case -1:                /* Error. */
+		msgq(sp, M_SYSERR, "fork");
+		break;
+	case 0:                 /* Sendmail. */
+		if (lseek(fd, 0, SEEK_SET) == -1) {
+			msgq(sp, M_SYSERR, "lseek");
+			_exit(127);
+		}
+		if (fd != STDIN_FILENO) {
+			(void)dup2(fd, STDIN_FILENO);
+			(void)close(fd);
+		}
+		execl(_PATH_SENDMAIL, "sendmail", "-t", NULL);
+		msgq(sp, M_SYSERR, _PATH_SENDMAIL);
+		_exit(127);
+	default:                /* Parent. */
+		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
+			continue;
+		break;
 	}
 
-	while ((l = fread(buf, 1, sizeof(buf), fin)) != 0)
-		(void)fwrite(buf, 1, l, fout);
-
-	(void)fclose(fin);
-	(void)pclose(fout);
 }

Index: src/lib/libc/stdio/fdopen.c
diff -u src/lib/libc/stdio/fdopen.c:1.17 src/lib/libc/stdio/fdopen.c:1.17.6.1
--- src/lib/libc/stdio/fdopen.c:1.17	Tue Jan 10 17:00:58 2017
+++ src/lib/libc/stdio/fdopen.c	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: fdopen.c,v 1.17 2017/01/10 17:00:58 christos Exp $	*/
+/*	$NetBSD: fdopen.c,v 1.17.6.1 2018/04/12 01:45:57 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)fdopen.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: fdopen.c,v 1.17 2017/01/10 17:00:58 christos Exp $");
+__RCSID("$NetBSD: fdopen.c,v 1.17.6.1 2018/04/12 01:45:57 msaitoh Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -92,7 +92,7 @@ fdopen(int fd, const char *mode)
 		return NULL;
 	}
 
-	if (oflags & O_NONBLOCK) {
+	if (oflags & O_REGULAR) {
 		struct stat st;
 		if (fstat(fd, &st) == -1) {
 			return NULL;

Index: src/lib/libc/stdio/flags.c
diff -u src/lib/libc/stdio/flags.c:1.17 src/lib/libc/stdio/flags.c:1.17.22.1
--- src/lib/libc/stdio/flags.c:1.17	Thu Nov 15 03:50:36 2012
+++ src/lib/libc/stdio/flags.c	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: flags.c,v 1.17 2012/11/15 03:50:36 christos Exp $	*/
+/*	$NetBSD: flags.c,v 1.17.22.1 2018/04/12 01:45:57 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)flags.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: flags.c,v 1.17 2012/11/15 03:50:36 christos Exp $");
+__RCSID("$NetBSD: flags.c,v 1.17.22.1 2018/04/12 01:45:57 msaitoh Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -99,7 +99,7 @@ __sflags(const char *mode, int *optr)
 			m = O_RDWR;
 			break;
 		case 'f':
-			o |= O_NONBLOCK;
+			o |= O_REGULAR;
 			break;
 		case 'e':
 			o |= O_CLOEXEC;

Index: src/lib/libc/stdio/fopen.c
diff -u src/lib/libc/stdio/fopen.c:1.15 src/lib/libc/stdio/fopen.c:1.15.24.1
--- src/lib/libc/stdio/fopen.c:1.15	Thu Mar 15 18:22:30 2012
+++ src/lib/libc/stdio/fopen.c	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: fopen.c,v 1.15 2012/03/15 18:22:30 christos Exp $	*/
+/*	$NetBSD: fopen.c,v 1.15.24.1 2018/04/12 01:45:57 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)fopen.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: fopen.c,v 1.15 2012/03/15 18:22:30 christos Exp $");
+__RCSID("$NetBSD: fopen.c,v 1.15.24.1 2018/04/12 01:45:57 msaitoh Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -66,20 +66,6 @@ fopen(const char *file, const char *mode
 		return NULL;
 	if ((f = open(file, oflags, DEFFILEMODE)) < 0)
 		goto release;
-	if (oflags & O_NONBLOCK) {
-		struct stat st;
-		if (fstat(f, &st) == -1) {
-			int sverrno = errno;
-			(void)close(f);
-			errno = sverrno;
-			goto release;
-		}
-		if (!S_ISREG(st.st_mode)) {
-			(void)close(f);
-			errno = EFTYPE;
-			goto release;
-		}
-	}
 	/*
 	 * File descriptors are a full int, but _file is only a short.
 	 * If we get a valid file descriptor that is greater or equal to

Index: src/lib/libc/stdio/freopen.c
diff -u src/lib/libc/stdio/freopen.c:1.19 src/lib/libc/stdio/freopen.c:1.19.24.1
--- src/lib/libc/stdio/freopen.c:1.19	Tue Mar 27 15:05:42 2012
+++ src/lib/libc/stdio/freopen.c	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: freopen.c,v 1.19 2012/03/27 15:05:42 christos Exp $	*/
+/*	$NetBSD: freopen.c,v 1.19.24.1 2018/04/12 01:45:57 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)freopen.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: freopen.c,v 1.19 2012/03/27 15:05:42 christos Exp $");
+__RCSID("$NetBSD: freopen.c,v 1.19.24.1 2018/04/12 01:45:57 msaitoh Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -141,21 +141,6 @@ freopen(const char *file, const char *mo
 		return NULL;
 	}
 
-	if (oflags & O_NONBLOCK) {
-		struct stat st;
-		if (fstat(f, &st) == -1) {
-			sverrno = errno;
-			(void)close(f);
-			errno = sverrno;
-			return NULL;
-		}
-		if (!S_ISREG(st.st_mode)) {
-			(void)close(f);
-			errno = EFTYPE;
-			return NULL;
-		}
-	}
-
 	/*
 	 * If reopening something that was open before on a real file, try
 	 * to maintain the descriptor.  Various C library routines (perror)

Index: src/lib/libc/sys/open.2
diff -u src/lib/libc/sys/open.2:1.57 src/lib/libc/sys/open.2:1.57.2.1
--- src/lib/libc/sys/open.2:1.57	Sun May 14 12:30:37 2017
+++ src/lib/libc/sys/open.2	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-.\"	$NetBSD: open.2,v 1.57 2017/05/14 12:30:37 wiz Exp $
+.\"	$NetBSD: open.2,v 1.57.2.1 2018/04/12 01:45:57 msaitoh Exp $
 .\"
 .\" Copyright (c) 1980, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"     @(#)open.2	8.2 (Berkeley) 11/16/93
 .\"
-.Dd July 29, 2013
+.Dd November 9, 2017
 .Dt OPEN 2
 .Os
 .Sh NAME
@@ -188,6 +188,8 @@ using an interface that supports scatter
 element of the request must meet the above alignment constraints.
 .It Dv O_DIRECTORY
 Fail if the file is not a directory.
+.It Dv O_REGULAR
+Fail if the path does not refer to a regular file.
 .It Dv O_ASYNC
 Enable the
 .Dv SIGIO

Index: src/sys/kern/vfs_vnops.c
diff -u src/sys/kern/vfs_vnops.c:1.195 src/sys/kern/vfs_vnops.c:1.195.6.1
--- src/sys/kern/vfs_vnops.c:1.195	Thu Mar 30 09:13:37 2017
+++ src/sys/kern/vfs_vnops.c	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnops.c,v 1.195 2017/03/30 09:13:37 hannken Exp $	*/
+/*	$NetBSD: vfs_vnops.c,v 1.195.6.1 2018/04/12 01:45:57 msaitoh 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.195 2017/03/30 09:13:37 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.195.6.1 2018/04/12 01:45:57 msaitoh Exp $");
 
 #include "veriexec.h"
 
@@ -299,6 +299,9 @@ vn_openchk(struct vnode *vp, kauth_cred_
 	if ((fflags & O_DIRECTORY) != 0 && vp->v_type != VDIR)
 		return ENOTDIR;
 
+	if ((fflags & O_REGULAR) != 0 && vp->v_type != VREG)
+		return EFTYPE;
+
 	if ((fflags & FREAD) != 0) {
 		permbits = VREAD;
 	}

Index: src/sys/sys/fcntl.h
diff -u src/sys/sys/fcntl.h:1.48.8.1 src/sys/sys/fcntl.h:1.48.8.2
--- src/sys/sys/fcntl.h:1.48.8.1	Sun Feb 25 23:57:51 2018
+++ src/sys/sys/fcntl.h	Thu Apr 12 01:45:57 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: fcntl.h,v 1.48.8.1 2018/02/25 23:57:51 snj Exp $	*/
+/*	$NetBSD: fcntl.h,v 1.48.8.2 2018/04/12 01:45:57 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 1983, 1990, 1993
@@ -120,6 +120,7 @@
 #endif
 #if defined(_NETBSD_SOURCE)
 #define	O_NOSIGPIPE	0x01000000	/* don't deliver sigpipe */
+#define	O_REGULAR	0x02000000	/* fail if not a regular file */
 #endif
 
 #ifdef _KERNEL
@@ -131,7 +132,7 @@
 #define	O_MASK		(O_ACCMODE|O_NONBLOCK|O_APPEND|O_SHLOCK|O_EXLOCK|\
 			 O_ASYNC|O_SYNC|O_CREAT|O_TRUNC|O_EXCL|O_DSYNC|\
 			 O_RSYNC|O_NOCTTY|O_ALT_IO|O_NOFOLLOW|O_DIRECT|\
-			 O_DIRECTORY|O_CLOEXEC|O_NOSIGPIPE)
+			 O_DIRECTORY|O_CLOEXEC|O_NOSIGPIPE|O_REGULAR)
 
 #define	FMARK		0x00001000	/* mark during gc() */
 #define	FDEFER		0x00002000	/* defer for next gc pass */

Reply via email to