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;