Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys - Add usermount_common_policy() that implements some com...



details:   https://anonhg.NetBSD.org/src/rev/d487456e69ae
branches:  trunk
changeset: 747900:d487456e69ae
user:      elad <elad%NetBSD.org@localhost>
date:      Mon Oct 05 04:20:13 2009 +0000

description:
- 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.

diffstat:

 sys/kern/vfs_init.c                 |   60 +++++++++++++++++-
 sys/secmodel/suser/secmodel_suser.c |  117 ++++++++++++++++-------------------
 sys/sys/mount.h                     |    4 +-
 3 files changed, 114 insertions(+), 67 deletions(-)

diffs (288 lines):

diff -r ba456a76da2d -r d487456e69ae sys/kern/vfs_init.c
--- a/sys/kern/vfs_init.c       Mon Oct 05 03:54:17 2009 +0000
+++ b/sys/kern/vfs_init.c       Mon Oct 05 04:20:13 2009 +0000
@@ -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.
diff -r ba456a76da2d -r d487456e69ae sys/secmodel/suser/secmodel_suser.c
--- a/sys/secmodel/suser/secmodel_suser.c       Mon Oct 05 03:54:17 2009 +0000
+++ b/sys/secmodel/suser/secmodel_suser.c       Mon Oct 05 04:20:13 2009 +0000
@@ -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 <elad%NetBSD.org@localhost>
  * 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,83 +302,72 @@
 
                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 (!dovfsusermount)
+                               break;
+
+                       if (usermount_common_policy(mp, flags) != 0)
+                               break;
 
-                               if (!(flags & MNT_NODEV) ||
-                                   !(flags & MNT_NOSUID))
-                                       break;
+                       result = KAUTH_RESULT_ALLOW;
+                       
+                       break;
+                       }
+
+               case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT: {
+                       struct mount *mp = arg1;
 
-                               if ((vp->v_mount->mnt_flag & MNT_NOEXEC) &&
-                                   !(flags & MNT_NOEXEC))
-                                       break;
+                       if (isroot) {
+                               result = KAUTH_RESULT_ALLOW;
+                               break;
+                       }
 
-                               result = KAUTH_RESULT_ALLOW;
-                       }
+                       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_UNMOUNT:
-                       if (isroot)
+               case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: {
+                       struct mount *mp = arg1;
+                       u_long flags = (u_long)arg2;
+
+                       if (isroot) {
                                result = KAUTH_RESULT_ALLOW;
-                       else {
-                               struct mount *mp = arg1;
+                               break;
+                       }
+
+                       if (!dovfsusermount)
+                               break;
 
-                               if (mp->mnt_stat.f_owner ==
-                                   kauth_cred_geteuid(cred))
-                                       result = KAUTH_RESULT_ALLOW;
-                       }
+                       /* 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;
-
-               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;
-
-                               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;
diff -r ba456a76da2d -r d487456e69ae sys/sys/mount.h
--- a/sys/sys/mount.h   Mon Oct 05 03:54:17 2009 +0000
+++ b/sys/sys/mount.h   Mon Oct 05 04:20:13 2009 +0000
@@ -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;
 



Home | Main Index | Thread Index | Old Index