Module Name:    src
Committed By:   elad
Date:           Mon Oct  5 04:20:13 UTC 2009

Modified Files:
        src/sys/kern: vfs_init.c
        src/sys/secmodel/suser: secmodel_suser.c
        src/sys/sys: mount.h

Log Message:
- Add usermount_common_policy() that implements some common (everything
  but access control) user mounting policies: enforced MNT_NOSUID and
  MNT_NODEV, no MNT_EXPORT, MNT_EXEC propagation. This can be useful for
  secmodels that are interested in simply adding finer grained user mount
  support.

- Add a mount subsystem listener for KAUTH_REQ_SYSTEM_MOUNT_GET.


To generate a diff of this commit:
cvs rdiff -u -r1.44 -r1.45 src/sys/kern/vfs_init.c
cvs rdiff -u -r1.26 -r1.27 src/sys/secmodel/suser/secmodel_suser.c
cvs rdiff -u -r1.191 -r1.192 src/sys/sys/mount.h

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_init.c
diff -u src/sys/kern/vfs_init.c:1.44 src/sys/kern/vfs_init.c:1.45
--- src/sys/kern/vfs_init.c:1.44	Sun May  3 21:25:44 2009
+++ src/sys/kern/vfs_init.c	Mon Oct  5 04:20:13 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_init.c,v 1.44 2009/05/03 21:25:44 elad Exp $	*/
+/*	$NetBSD: vfs_init.c,v 1.45 2009/10/05 04:20:13 elad Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.44 2009/05/03 21:25:44 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.45 2009/10/05 04:20:13 elad Exp $");
 
 #include <sys/param.h>
 #include <sys/mount.h>
@@ -83,6 +83,7 @@
 #include <sys/module.h>
 #include <sys/dirhash.h>
 #include <sys/sysctl.h>
+#include <sys/kauth.h>
 
 /*
  * Sigh, such primitive tools are these...
@@ -119,6 +120,8 @@
 struct vfs_list_head vfs_list =			/* vfs list */
     LIST_HEAD_INITIALIZER(vfs_list);
 
+static kauth_listener_t mount_listener;
+
 /*
  * This code doesn't work if the defn is **vnodop_defns with cc.
  * The problem is because of the compiler sometimes putting in an
@@ -332,6 +335,56 @@
 #endif /* DEBUG */
 
 /*
+ * Common routine to check if an unprivileged mount is allowed.
+ *
+ * We export just this part (i.e., without the access control) so that if a
+ * secmodel wants to implement finer grained user mounts it can do so without
+ * copying too much code. More elaborate policies (i.e., specific users allowed
+ * to also create devices and/or introduce set-id binaries, or export
+ * file-systems) will require a different implementation.
+ *
+ * This routine is intended to be called from listener context, and as such
+ * does not take credentials as an argument.
+ */
+int
+usermount_common_policy(struct mount *mp, u_long flags)
+{
+
+	/* No exporting if unprivileged. */
+	if (flags & MNT_EXPORTED)
+		return EPERM;
+
+	/* Must have 'nosuid' and 'nodev'. */
+	if ((flags & MNT_NODEV) == 0 || (flags & MNT_NOSUID) == 0)
+		return EPERM;
+
+	/* Retain 'noexec'. */
+	if ((mp->mnt_flag & MNT_NOEXEC) && (flags & MNT_NOEXEC) == 0)
+		return EPERM;
+
+	return 0;
+}
+
+static int
+mount_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
+    void *arg0, void *arg1, void *arg2, void *arg3)
+{
+	int result;
+	enum kauth_system_req req;
+
+	result = KAUTH_RESULT_DEFER;
+	req = (enum kauth_system_req)arg0;
+
+	if ((action != KAUTH_SYSTEM_MOUNT) ||
+	    (req != KAUTH_REQ_SYSTEM_MOUNT_GET))
+		return result;
+
+	result = KAUTH_RESULT_ALLOW;
+
+	return result;
+}
+
+/*
  * Initialize the vnode structures and initialize each file system type.
  */
 void
@@ -382,6 +435,9 @@
 	 */
 	vfs_hooks_init();
 
+	mount_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
+	    mount_listener_cb, NULL);
+
 	/*
 	 * Establish each file system which was statically
 	 * included in the kernel.

Index: src/sys/secmodel/suser/secmodel_suser.c
diff -u src/sys/secmodel/suser/secmodel_suser.c:1.26 src/sys/secmodel/suser/secmodel_suser.c:1.27
--- src/sys/secmodel/suser/secmodel_suser.c:1.26	Sat Oct  3 03:59:39 2009
+++ src/sys/secmodel/suser/secmodel_suser.c	Mon Oct  5 04:20:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: secmodel_suser.c,v 1.26 2009/10/03 03:59:39 elad Exp $ */
+/* $NetBSD: secmodel_suser.c,v 1.27 2009/10/05 04:20:13 elad Exp $ */
 /*-
  * Copyright (c) 2006 Elad Efrat <e...@netbsd.org>
  * All rights reserved.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.26 2009/10/03 03:59:39 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.27 2009/10/05 04:20:13 elad Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -152,7 +152,6 @@
 secmodel_suser_init(void)
 {
 	secmodel_suser_curtain = 0;
-	dovfsusermount = 0;
 }
 
 void
@@ -303,82 +302,71 @@
 
 		break;
 
-	case KAUTH_SYSTEM_FS_RESERVEDSPACE:
-		if (isroot)
-			result = KAUTH_RESULT_ALLOW;
-		break;
-
 	case KAUTH_SYSTEM_MOUNT:
 		switch (req) {
-		case KAUTH_REQ_SYSTEM_MOUNT_GET:
-			result = KAUTH_RESULT_ALLOW;
-			break;
+		case KAUTH_REQ_SYSTEM_MOUNT_NEW: {
+			struct mount *mp = ((struct vnode *)arg1)->v_mount;
+			u_long flags = (u_long)arg2;
 
-		case KAUTH_REQ_SYSTEM_MOUNT_NEW:
-			if (isroot)
+			if (isroot) {
 				result = KAUTH_RESULT_ALLOW;
-			else if (dovfsusermount) {
-				struct vnode *vp = arg1;
-				u_long flags = (u_long)arg2;
+				break;
+			}
 
-				if (!(flags & MNT_NODEV) ||
-				    !(flags & MNT_NOSUID))
-					break;
+			if (!dovfsusermount)
+				break;
 
-				if ((vp->v_mount->mnt_flag & MNT_NOEXEC) &&
-				    !(flags & MNT_NOEXEC))
-					break;
+			if (usermount_common_policy(mp, flags) != 0)
+				break;
 
-				result = KAUTH_RESULT_ALLOW;
+			result = KAUTH_RESULT_ALLOW;
+			
+			break;
 			}
 
-			break;
+		case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT: {
+			struct mount *mp = arg1;
 
-		case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT:
-			if (isroot)
+			if (isroot) {
 				result = KAUTH_RESULT_ALLOW;
-			else {
-				struct mount *mp = arg1;
-
-				if (mp->mnt_stat.f_owner ==
-				    kauth_cred_geteuid(cred))
-					result = KAUTH_RESULT_ALLOW;
+				break;
 			}
 
+			if (!dovfsusermount)
+				break;
+
+			/* Must own the mount. */
+			if (mp->mnt_stat.f_owner != kauth_cred_geteuid(cred))
+				break;
+
+			result = KAUTH_RESULT_ALLOW;
+
 			break;
+			}
 
-		case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
-			if (isroot)
-				result = KAUTH_RESULT_ALLOW;
-			else if (dovfsusermount) {
-				struct mount *mp = arg1;
-				u_long flags = (u_long)arg2;
-
-				/* No exporting for non-root. */
-				if (flags & MNT_EXPORTED)
-					break;
-
-				if (!(flags & MNT_NODEV) ||
-				    !(flags & MNT_NOSUID))
-					break;
-
-				/*
-				 * Only super-user, or user that did the mount,
-				 * can update.
-				 */
-				if (mp->mnt_stat.f_owner !=
-				    kauth_cred_geteuid(cred))
-					break;
-
-				/* Retain 'noexec'. */
-				if ((mp->mnt_flag & MNT_NOEXEC) &&
-				    !(flags & MNT_NOEXEC))
-					break;
+		case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: {
+			struct mount *mp = arg1;
+			u_long flags = (u_long)arg2;
 
+			if (isroot) {
 				result = KAUTH_RESULT_ALLOW;
+				break;
 			}
 
+			if (!dovfsusermount)
+				break;
+
+			/* Must own the mount. */
+			if (mp->mnt_stat.f_owner != kauth_cred_geteuid(cred))
+				break;
+
+			if (usermount_common_policy(mp, flags) != 0)
+				break;
+
+			result = KAUTH_RESULT_ALLOW;
+
 			break;
+			}
 
 		default:
 			break;
@@ -444,6 +432,7 @@
 	case KAUTH_SYSTEM_MKNOD:
 	case KAUTH_SYSTEM_SETIDCORE:
 	case KAUTH_SYSTEM_MODULE:
+	case KAUTH_SYSTEM_FS_RESERVEDSPACE:
 		if (isroot)
 			result = KAUTH_RESULT_ALLOW;
 		break;

Index: src/sys/sys/mount.h
diff -u src/sys/sys/mount.h:1.191 src/sys/sys/mount.h:1.192
--- src/sys/sys/mount.h:1.191	Sat Jul 18 16:31:43 2009
+++ src/sys/sys/mount.h	Mon Oct  5 04:20:13 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: mount.h,v 1.191 2009/07/18 16:31:43 reinoud Exp $	*/
+/*	$NetBSD: mount.h,v 1.192 2009/10/05 04:20:13 elad Exp $	*/
 
 /*
  * Copyright (c) 1989, 1991, 1993
@@ -433,6 +433,8 @@
 void *	mount_getspecific(struct mount *, specificdata_key_t);
 void	mount_setspecific(struct mount *, specificdata_key_t, void *);
 
+int	usermount_common_policy(struct mount *, u_long);
+
 LIST_HEAD(vfs_list_head, vfsops);
 extern struct vfs_list_head vfs_list;
 

Reply via email to