Synopsis: noexec mount flag is not properly handled by non-root mount
NetBSD versions: NetBSD 1.3.3 and prior; NetBSD-current until 19990318
Thanks to: Manuel Bouyer
Reported in NetBSD Security Advisory: SA1999-007

This patch fixes the non-root mount problem described in the NetBSD-SA1999-007
security advisory. For it to apply, make sure you have NetBSD 1.3.3 kernel 
sources unpacked in /usr/src, then do:
    % cd /usr/src/sys
    % patch <19990317-mount
    % cd arch/`uname -m`/conf
    % config GENERIC
    % cd ../compile/GENERIC
    % make depend && make
    % su root
    # mv /netbsd /netbsd.old
    # cp netbsd /
    # chmod 444 /netbsd
    # sync; reboot


Index: kern/vfs_syscalls.c
===================================================================
RCS file: /archive/cvs/cvsroot/NetBSD/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 vfs_syscalls.c
--- vfs_syscalls.c	1997/12/15 16:49:57	1.1.1.1
+++ vfs_syscalls.c	1999/03/17 16:29:35
@@ -163,8 +163,9 @@
 			return (error);
 		}
 		/*
-		 * Do not allow NFS export by non-root users. Silently
-		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
+		 * Do not allow NFS export by non-root users. For non-root
+		 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
+		 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
 		 */
 		if (p->p_ucred->cr_uid != 0) {
 			if (SCARG(uap, flags) & MNT_EXPORTED) {
@@ -172,6 +173,8 @@
 				return (EPERM);
 			}
 			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
+			if (flag & MNT_NOEXEC)
+				SCARG(uap, flags) |= MNT_NOEXEC;
 		}
 		VOP_UNLOCK(vp);
 		goto update;
@@ -187,8 +190,9 @@
 		return (error);
 	}
 	/*
-	 * Do not allow NFS export by non-root users. Silently
-	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
+	 * Do not allow NFS export by non-root users. For non-root users,
+	 * silently enforce MNT_NOSUID and MNT_NODEV, and MNT_NOEXEC if the
+	 * mount point is already MNT_NOEXEC.
 	 */
 	if (p->p_ucred->cr_uid != 0) {
 		if (SCARG(uap, flags) & MNT_EXPORTED) {
@@ -196,6 +200,8 @@
 			return (EPERM);
 		}
 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
+		if (vp->v_mount->mnt_flag & MNT_NOEXEC)
+			SCARG(uap, flags) |= MNT_NOEXEC;
 	}
 	if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
 		return (error);