Subject: Re: mount(2) on kauth(9)
To: None <tech-kern@NetBSD.org>
From: Elad Efrat <elad@NetBSD.org>
List: tech-kern
Date: 01/02/2007 00:47:06
This is a multi-part message in MIME format.
--------------020608020207080308040701
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
attached is a diff that makes mount(2) use kauth(9).
the only difference between this and the original diff is that the
flags are no longer passed as pointer -- apart from requiring certain
order if we introduce logging listeners, this also breaks the kauth(9)
restrictive policy, as a malicious listener can modify the flags.
the MNT_NOSUID/MNT_NODEV/MNT_NOEXEC enforcement is done inside the
secmodel, simply preventing non-root users from doing what earlier
would be silently enforced. (this is a compromise we'll have to make.)
if there are no objections, I'll commit this.
-e.
--------------020608020207080308040701
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 29 Dec 2006 10:44: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,10 @@ 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_UNMOUNT,
+ 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.289
diff -u -p -r1.289 vfs_syscalls.c
--- kern/vfs_syscalls.c 31 Dec 2006 10:05:52 -0000 1.289
+++ kern/vfs_syscalls.c 31 Dec 2006 12:10:01 -0000
@@ -170,39 +170,12 @@ 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;
- goto out;
- }
- /*
- * Only root, or the user that did the original mount is
- * permitted to update it.
- */
- if (mp->mnt_stat.f_owner != kauth_cred_geteuid(l->l_cred) &&
- (error = kauth_authorize_generic(l->l_cred,
- KAUTH_GENERIC_ISSUSER, NULL)) != 0) {
+
+ error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
+ KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data);
+ if (error)
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,9 +246,9 @@ mount_domount(struct lwp *l, struct vnod
char fstypename[MFSNAMELEN];
int error;
- /* XXX secmodel stuff. */
- if (securelevel >= 2) {
- error = EPERM;
+ error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
+ KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data);
+ if (error) {
vput(vp);
goto out;
}
@@ -306,13 +279,6 @@ mount_domount(struct lwp *l, struct vnod
}
/*
- * 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.
*/
error = copyinstr(fstype, fstypename, MFSNAMELEN, NULL);
@@ -439,6 +405,12 @@ mount_getargs(struct lwp *l, struct vnod
mp = vp->v_mount;
+ /* 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 ((vp->v_flag & VROOT) == 0) {
error = EINVAL;
goto out;
@@ -473,12 +445,6 @@ sys_mount(struct lwp *l, void *v, regist
struct nameidata nd;
int error;
- /* 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
*/
Index: secmodel/bsd44/secmodel_bsd44_securelevel.c
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/bsd44/secmodel_bsd44_securelevel.c,v
retrieving revision 1.21
diff -u -p -r1.21 secmodel_bsd44_securelevel.c
--- secmodel/bsd44/secmodel_bsd44_securelevel.c 31 Dec 2006 10:38:18 -0000 1.21
+++ secmodel/bsd44/secmodel_bsd44_securelevel.c 31 Dec 2006 11:33:51 -0000
@@ -170,6 +170,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;
+ u_long flags = (u_long)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:
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 31 Dec 2006 12:09:31 -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,83 @@ 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) {
+ 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:
+ 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;
+
+ 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:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
case KAUTH_SYSTEM_TIME:
switch (req) {
case KAUTH_REQ_SYSTEM_TIME_ADJTIME:
--------------020608020207080308040701--