- 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.
This commit is contained in:
elad 2009-10-05 04:20:13 +00:00
parent 94ebcd4993
commit 4c9fcb77c3
3 changed files with 115 additions and 68 deletions

View File

@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.44 2009/05/03 21:25:44 elad Exp $");
#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 @@ const struct vnodeopv_desc * const vfs_special_vnodeopv_descs[] = {
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
@ -331,6 +334,56 @@ vfs_op_check(void)
}
#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.
*/
@ -382,6 +435,9 @@ vfsinit(void)
*/
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.

View File

@ -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>
* 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 @@ void
secmodel_suser_init(void)
{
secmodel_suser_curtain = 0;
dovfsusermount = 0;
}
void
@ -303,82 +302,71 @@ secmodel_suser_system_cb(kauth_cred_t cred, kauth_action_t action,
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:
case KAUTH_REQ_SYSTEM_MOUNT_NEW: {
struct mount *mp = ((struct vnode *)arg1)->v_mount;
u_long flags = (u_long)arg2;
if (isroot) {
result = KAUTH_RESULT_ALLOW;
break;
}
if (!dovfsusermount)
break;
if (usermount_common_policy(mp, flags) != 0)
break;
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_SYSTEM_MOUNT_NEW:
if (isroot)
result = KAUTH_RESULT_ALLOW;
else if (dovfsusermount) {
struct vnode *vp = arg1;
u_long flags = (u_long)arg2;
if (!(flags & MNT_NODEV) ||
!(flags & MNT_NOSUID))
break;
if ((vp->v_mount->mnt_flag & MNT_NOEXEC) &&
!(flags & MNT_NOEXEC))
break;
result = KAUTH_RESULT_ALLOW;
}
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;
result = KAUTH_RESULT_ALLOW;
}
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 @@ secmodel_suser_system_cb(kauth_cred_t cred, kauth_action_t action,
case KAUTH_SYSTEM_MKNOD:
case KAUTH_SYSTEM_SETIDCORE:
case KAUTH_SYSTEM_MODULE:
case KAUTH_SYSTEM_FS_RESERVEDSPACE:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;

View File

@ -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_finispecific(struct mount *);
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;