Subject: mount(2) on kauth(9)
To: None <tech-kern@NetBSD.org>
From: Elad Efrat <elad@NetBSD.org>
List: tech-kern
Date: 12/28/2006 18:04:49
This is a multi-part message in MIME format.
--------------000606070401000105060001
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

hi,

attached diff makes mount(2) use kauth(9) to do some stuff previously
done by checking securelevel/euid.

if there are no objections, I'll commit.

-e.

--------------000606070401000105060001
Content-Type: text/plain;
 name="mount.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="mount.diff"

Index: sys/kauth.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/kauth.h,v
retrieving revision 1.29
diff -u -p -r1.29 kauth.h
--- sys/kauth.h	26 Dec 2006 10:43:44 -0000	1.29
+++ sys/kauth.h	27 Dec 2006 13:58:15 -0000
@@ -87,6 +87,7 @@ enum {
 	KAUTH_SYSTEM_FILEHANDLE,
 	KAUTH_SYSTEM_LKM,
 	KAUTH_SYSTEM_MKNOD,
+	KAUTH_SYSTEM_MOUNT,
 	KAUTH_SYSTEM_REBOOT,
 	KAUTH_SYSTEM_SETIDCORE,
 	KAUTH_SYSTEM_SWAPCTL,
@@ -101,6 +102,9 @@ enum kauth_system_req {
 	KAUTH_REQ_SYSTEM_CHROOT_CHROOT=1,
 	KAUTH_REQ_SYSTEM_CHROOT_FCHROOT,
 	KAUTH_REQ_SYSTEM_DEBUG_IPKDB,
+	KAUTH_REQ_SYSTEM_MOUNT_GET,
+	KAUTH_REQ_SYSTEM_MOUNT_NEW,
+	KAUTH_REQ_SYSTEM_MOUNT_UPDATE,
 	KAUTH_REQ_SYSTEM_SYSCTL_ADD,
 	KAUTH_REQ_SYSTEM_SYSCTL_DELETE,
 	KAUTH_REQ_SYSTEM_SYSCTL_DESC,
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.288
diff -u -p -r1.288 vfs_syscalls.c
--- kern/vfs_syscalls.c	28 Dec 2006 14:33:41 -0000	1.288
+++ kern/vfs_syscalls.c	27 Dec 2006 14:43:09 -0000
@@ -170,39 +170,23 @@ mount_update(struct lwp *l, struct vnode
 		error = EOPNOTSUPP;	/* Needs translation */
 		goto out;
 	}
-	/*
-	 * In "highly secure" mode, don't let the caller do anything
-	 * but downgrade a filesystem from read-write to read-only.
-	 */
-	if (securelevel >= 2 &&
-	    flags !=
-	    (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) {
-		error = EPERM;
+
+	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
+	    KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, &flags, data);
+	if (error)
 		goto out;
-	}
+
 	/*
 	 * Only root, or the user that did the original mount is
 	 * permitted to update it.
+	 *
+	 * XXX: kauth(9) vnode scope.
 	 */
  	if (mp->mnt_stat.f_owner != kauth_cred_geteuid(l->l_cred) &&
 	    (error = kauth_authorize_generic(l->l_cred,
 	    KAUTH_GENERIC_ISSUSER, NULL)) != 0) {
 		goto out;
 	}
-	/*
-	 * 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 (kauth_cred_geteuid(l->l_cred) != 0) {
-		if (flags & MNT_EXPORTED) {
-			error = EPERM;
-			goto out;
-		}
-		flags |= MNT_NOSUID | MNT_NODEV;
-		if (saved_flags & MNT_NOEXEC)
-			flags |= MNT_NOEXEC;
-	}
 	if (vfs_busy(mp, LK_NOWAIT, 0)) {
 		error = EPERM;
 		goto out;
@@ -273,16 +257,15 @@ mount_domount(struct lwp *l, struct vnod
 	char fstypename[MFSNAMELEN];
 	int error;
 
-	/* XXX secmodel stuff. */
-	if (securelevel >= 2) {
-		error = EPERM;
+	/* Can't make a non-dir a mount-point (from here anyway). */
+	if (vp->v_type != VDIR) {
+		error = ENOTDIR;
 		vput(vp);
 		goto out;
 	}
 
-	/* Can't make a non-dir a mount-point (from here anyway). */
-	if (vp->v_type != VDIR) {
-		error = ENOTDIR;
+	if (flags & MNT_EXPORTED) {
+		error = EINVAL;
 		vput(vp);
 		goto out;
 	}
@@ -290,6 +273,8 @@ mount_domount(struct lwp *l, struct vnod
 	/*
 	 * If the user is not root, ensure that they own the directory
 	 * onto which we are attempting to mount.
+	 *
+	 * XXX: kauth(9) vnode scope.
 	 */
 	if ((error = VOP_GETATTR(vp, &va, l->l_cred, l)) != 0 ||
 	    (va.va_uid != kauth_cred_geteuid(l->l_cred) &&
@@ -299,19 +284,6 @@ mount_domount(struct lwp *l, struct vnod
 		goto out;
 	}
 
-	if (flags & MNT_EXPORTED) {
-		error = EINVAL;
-		vput(vp);
-		goto out;
-	}
-
-	/*
-	 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV.
-	 */
-	if (kauth_cred_geteuid(l->l_cred) != 0) {
-		flags |= MNT_NOSUID | MNT_NODEV;
-	}
-
 	/*
 	 * Copy file-system type from userspace.
 	 */
@@ -344,6 +316,13 @@ mount_domount(struct lwp *l, struct vnod
 		strlcpy(fstypename, "ffs", sizeof(fstypename));
 #endif
 
+	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
+	    KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, &flags, data);
+	if (error) {
+		vput(vp);
+		goto out;
+	}
+
 	if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0) {
 		vput(vp);
 		goto out;
@@ -438,6 +417,12 @@ mount_getargs(struct lwp *l, struct vnod
 		goto out;
 	}
 
+	/* XXX: probably some notion of "can see" here if we want isolation. */
+	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
+	    KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL);
+	if (error)
+		goto out;
+
 	if (vfs_busy(mp, LK_NOWAIT, 0)) {
 		error = EPERM;
 		goto out;
@@ -475,17 +460,10 @@ sys_mount(struct lwp *l, void *v, regist
 		return EINVAL;
 	}
 
-	/* XXX secmodel stuff. */
-	if (dovfsusermount == 0 && (SCARG(uap, flags) & MNT_GETARGS) == 0 &&
-	    (error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
-	    &l->l_acflag)))
-		return (error);
-
 	/*
 	 * Get vnode to be covered
 	 */
-	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
-	    SCARG(uap, path), l);
+	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	vp = nd.ni_vp;
Index: secmodel/bsd44/secmodel_bsd44_suser.c
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/bsd44/secmodel_bsd44_suser.c,v
retrieving revision 1.23
diff -u -p -r1.23 secmodel_bsd44_suser.c
--- secmodel/bsd44/secmodel_bsd44_suser.c	27 Dec 2006 10:02:46 -0000	1.23
+++ secmodel/bsd44/secmodel_bsd44_suser.c	27 Dec 2006 14:04:36 -0000
@@ -60,6 +60,8 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_bsd
 
 #include <secmodel/bsd44/suser.h>
 
+extern int dovfsusermount;
+
 void
 secmodel_bsd44_suser_start(void)
 {
@@ -138,6 +140,54 @@ secmodel_bsd44_suser_system_cb(kauth_cre
 	req = (enum kauth_system_req)arg0;
 
 	switch (action) {
+	case KAUTH_SYSTEM_MOUNT:
+		switch (req) {
+		case KAUTH_REQ_SYSTEM_MOUNT_GET:
+			result = KAUTH_RESULT_ALLOW;
+			break;
+
+		case KAUTH_REQ_SYSTEM_MOUNT_NEW:
+			if (isroot) {
+				result = KAUTH_RESULT_ALLOW;
+			} else if (dovfsusermount) {
+				int *flags = arg2;
+
+				/* Enforce 'nodev', 'nosuid', for non-root */
+				*flags |= MNT_NODEV | MNT_NOSUID;
+
+				result = KAUTH_RESULT_ALLOW;
+			}
+
+			break;
+
+		case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
+			if (isroot) {
+				result = KAUTH_RESULT_ALLOW;
+			} else if (dovfsusermount) {
+				struct mount *mp = arg1;
+				int *flags = arg2;
+
+				/* No exporting for non-root. */
+				if (*flags & MNT_EXPORTED)
+					break;
+
+				/* Enforce 'nodev', 'nosuid', for non-root */
+				*flags |= MNT_NODEV | MNT_NOSUID;
+
+				/* Retain 'noexec'. */
+				if (mp->mnt_flag & MNT_NOEXEC)
+					*flags |= MNT_NOEXEC;
+
+				result = KAUTH_RESULT_ALLOW;
+			}
+
+			break;
+
+		default:
+			result = KAUTH_RESULT_DEFER;
+			break;
+		}
+
 	case KAUTH_SYSTEM_TIME:
 		switch (req) {
 		case KAUTH_REQ_SYSTEM_TIME_ADJTIME:
Index: secmodel/bsd44/secmodel_bsd44_securelevel.c
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/bsd44/secmodel_bsd44_securelevel.c,v
retrieving revision 1.20
diff -u -p -r1.20 secmodel_bsd44_securelevel.c
--- secmodel/bsd44/secmodel_bsd44_securelevel.c	26 Dec 2006 10:43:44 -0000	1.20
+++ secmodel/bsd44/secmodel_bsd44_securelevel.c	27 Dec 2006 14:33:25 -0000
@@ -174,6 +174,37 @@ secmodel_bsd44_securelevel_system_cb(kau
 			result = KAUTH_RESULT_ALLOW;
 		break;
 
+	case KAUTH_SYSTEM_MOUNT:
+		switch (req) {
+		case KAUTH_REQ_SYSTEM_MOUNT_NEW:
+			if (securelevel > 1)
+				break;
+
+			result = KAUTH_RESULT_ALLOW;
+			break;
+
+		case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
+			if (securelevel > 1) {
+				struct mount *mp = arg1;
+				int *flags = arg2;
+
+				/* Can only degrade from read/write to read-only. */
+				if (*flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD |
+				    MNT_FORCE | MNT_UPDATE))
+					break;
+			}
+
+			result = KAUTH_RESULT_ALLOW;
+
+			break;
+
+		default:
+			result = KAUTH_RESULT_DEFER;
+			break;
+		}
+
+		break;
+
 	case KAUTH_SYSTEM_SYSCTL:
 		switch (req) {
 		case KAUTH_REQ_SYSTEM_SYSCTL_ADD:

--------------000606070401000105060001--