Subject: Re: CVS commit: src/sys/secmodel/bsd44
To: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
From: Elad Efrat <elad@NetBSD.org>
List: tech-kern
Date: 11/02/2006 00:54:43
This is a multi-part message in MIME format.

--Boundary_(ID_8u1eivK7FyA78gY8EimS4Q)
Content-type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: 7BIT

initial diff attached does the following:

  - rawio stuff moves to device scope out of system scope,
  - isdevkmem() exported in sys/conf.h, (arbitrary)
  - kauth_authorize_device(cred, action, req, dev, void *),
  - unified handling of disk/memory access in bsd44 secmodel,
  - somewhat "unified" handling of vchr/vblk (please review.)

keep in mind this is just a first revision. :) probably needs some
cleanup (I think some unused attributes there are incorrect, I just
did copy/paste) and probably the disk/memory handling code could be
refactored to be smaller.

comments?

-e.

-- 
Elad Efrat

--Boundary_(ID_8u1eivK7FyA78gY8EimS4Q)
Content-type: text/plain; name=rawio.diff
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=rawio.diff

Index: sys/kauth.h
===================================================================
RCS file: /cvsroot/src/sys/sys/kauth.h,v
retrieving revision 1.16
diff -u -p -r1.16 kauth.h
--- sys/kauth.h	25 Oct 2006 22:49:23 -0000	1.16
+++ sys/kauth.h	1 Nov 2006 22:47:49 -0000
@@ -86,7 +86,6 @@ enum {
 	KAUTH_SYSTEM_FILEHANDLE,
 	KAUTH_SYSTEM_LKM,
 	KAUTH_SYSTEM_MKNOD,
-	KAUTH_SYSTEM_RAWIO,
 	KAUTH_SYSTEM_REBOOT,
 	KAUTH_SYSTEM_SETIDCORE,
 	KAUTH_SYSTEM_SWAPCTL,
@@ -101,11 +100,6 @@ enum kauth_system_req {
 	KAUTH_REQ_SYSTEM_CHROOT_CHROOT=1,
 	KAUTH_REQ_SYSTEM_CHROOT_FCHROOT,
 	KAUTH_REQ_SYSTEM_DEBUG_IPKDB,
-	KAUTH_REQ_SYSTEM_RAWIO_DISK,
-	KAUTH_REQ_SYSTEM_RAWIO_MEMORY,
-	KAUTH_REQ_SYSTEM_RAWIO_READ,
-	KAUTH_REQ_SYSTEM_RAWIO_RW,
-	KAUTH_REQ_SYSTEM_RAWIO_WRITE,
 	KAUTH_REQ_SYSTEM_SYSCTL_ADD,
 	KAUTH_REQ_SYSTEM_SYSCTL_DELETE,
 	KAUTH_REQ_SYSTEM_SYSCTL_DESC,
@@ -201,7 +195,18 @@ enum kauth_machdep_req {
  */
 enum {
 	KAUTH_DEVICE_TTY_OPEN=1,
-	KAUTH_DEVICE_TTY_PRIVSET
+	KAUTH_DEVICE_TTY_PRIVSET,
+	KAUTH_DEVICE_RAWIO
+};
+
+/*
+ * Device scope - sub-actions.
+ */
+enum kauth_device_req {
+	KAUTH_REQ_DEVICE_RAWIO_READ,
+	KAUTH_REQ_DEVICE_RAWIO_WRITE,
+	KAUTH_REQ_DEVICE_RAWIO_RW,
+	KAUTH_REQ_DEVICE_RAWIO_PASSTHRU
 };
 
 #define NOCRED ((kauth_cred_t)-1)	/* no credential available */
@@ -228,6 +233,8 @@ int kauth_authorize_network(kauth_cred_t
     enum kauth_network_req, void *, void *, void *);
 int kauth_authorize_machdep(kauth_cred_t, kauth_action_t,
     enum kauth_machdep_req, void *, void *, void *);
+int kauth_authorize_device(kauth_cred_t, kauth_action_t,
+    enum kauth_device_req, dev_t, void *);
 int kauth_authorize_device_tty(kauth_cred_t, kauth_action_t, struct tty *);
 
 /* Kauth credentials management routines. */
Index: sys/conf.h
===================================================================
RCS file: /cvsroot/src/sys/sys/conf.h,v
retrieving revision 1.124
diff -u -p -r1.124 conf.h
--- sys/conf.h	9 Oct 2006 07:56:33 -0000	1.124
+++ sys/conf.h	1 Nov 2006 22:47:49 -0000
@@ -192,6 +192,8 @@ void	       ttyldisc_release(struct line
 
 int	ttyerrpoll (struct tty *, int, struct lwp *);
 int	ttynullioctl(struct tty *, u_long, caddr_t, int, struct lwp *);
+
+int	iskmemdev(dev_t);
 #endif
 
 #ifdef _KERNEL
Index: kern/kern_auth.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_auth.c,v
retrieving revision 1.29
diff -u -p -r1.29 kern_auth.c
--- kern/kern_auth.c	22 Oct 2006 13:07:15 -0000	1.29
+++ kern/kern_auth.c	1 Nov 2006 22:47:51 -0000
@@ -812,6 +812,14 @@ kauth_authorize_machdep(kauth_cred_t cre
 }
 
 int
+kauth_authorize_device(kauth_cred_t cred, kauth_action_t action,
+    enum kauth_device_req req, dev_t dev, void *arg2)
+{
+	return (kauth_authorize_action(kauth_builtin_scope_device, cred,
+	    action, (void *)req, (void *)(u_long)dev, arg2, NULL));
+}
+
+int
 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action,
     struct tty *tty)
 {
Index: miscfs/specfs/spec_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v
retrieving revision 1.94
diff -u -p -r1.94 spec_vnops.c
--- miscfs/specfs/spec_vnops.c	1 Nov 2006 09:37:28 -0000	1.94
+++ miscfs/specfs/spec_vnops.c	1 Nov 2006 22:47:51 -0000
@@ -154,7 +154,7 @@ spec_lookup(v)
 /*
  * Returns true if dev is /dev/mem or /dev/kmem.
  */
-static int
+int
 iskmemdev(dev_t dev)
 {
 	/* mem_no is emitted by config(8) to generated devsw.c */
@@ -182,10 +182,11 @@ spec_open(v)
 	struct vnode *vp = ap->a_vp;
 	const struct bdevsw *bdev;
 	const struct cdevsw *cdev;
-	dev_t dev = (dev_t)vp->v_rdev;
+	dev_t  dev = (dev_t)vp->v_rdev;
 	int error;
 	struct partinfo pi;
 	int (*d_ioctl)(dev_t, u_long, caddr_t, int, struct lwp *);
+	enum kauth_device_req req;
 
 	/*
 	 * Don't allow open if fs is mounted -nodev.
@@ -193,9 +194,9 @@ spec_open(v)
 	if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
 		return (ENXIO);
 
-#define M2K(m)	(((m) & FREAD) && ((m) & FWRITE) ? KAUTH_REQ_SYSTEM_RAWIO_RW : \
-		 (m) & FWRITE ? KAUTH_REQ_SYSTEM_RAWIO_WRITE : \
-		 KAUTH_REQ_SYSTEM_RAWIO_READ)
+#define M2K(m)	(((m) & FREAD) && ((m) & FWRITE) ? KAUTH_REQ_DEVICE_RAWIO_RW : \
+		 (m) & FWRITE ? KAUTH_REQ_DEVICE_RAWIO_WRITE : \
+		 KAUTH_REQ_DEVICE_RAWIO_READ)
 
 	switch (vp->v_type) {
 
@@ -204,47 +205,39 @@ spec_open(v)
 		if (cdev == NULL)
 			return (ENXIO);
 
-		if (ap->a_cred != FSCRED) {
-			u_long rw;
-
-			rw = M2K(ap->a_mode);
-			error = 0;
+		req = M2K(ap->a_mode);
 
-			/* XXX we're holding a vnode lock here */
-			if (iskmemdev(dev)) {
-				error = kauth_authorize_system(ap->a_cred,
-				    KAUTH_SYSTEM_RAWIO,
-				    KAUTH_REQ_SYSTEM_RAWIO_MEMORY,
-				    (void *)rw, NULL, NULL);
-			} else {
-				error = kauth_authorize_system(ap->a_cred,
-				    KAUTH_SYSTEM_RAWIO,
-				    KAUTH_REQ_SYSTEM_RAWIO_DISK,
-				    (void *)rw, vp, (void *)(u_long)dev);
-			}
+		error = kauth_authorize_device(ap->a_cred,
+		    KAUTH_DEVICE_RAWIO, req, dev, NULL);
+		if (error) {
+			if (ap->a_cred == FSCRED)
+				printf("wtf? FSCRED\n");
 
-			if (error)
-				return (error);
+			printf("VCHR returning EPERM\n");
+			return (error);
+		}
 
 #if NVERIEXEC > 0
-			if (veriexec_strict >= VERIEXEC_IPS &&
-			    iskmemdev(dev) && (ap->a_mode & FWRITE)) {
-				return (error);
-			} else {
-				struct vnode *bvp;
-				dev_t blkdev;
-
-				blkdev = devsw_chr2blk(dev);
-				if (blkdev != NODEV) {
-					bvp = NULL;
-					vfinddev(blkdev, VBLK, &bvp);
-					error = veriexec_rawchk(bvp);
-					if (error)
-						return (error);
-				}
+		/*
+		 * XXX this should be a listener on the device scope
+		 */
+		if (veriexec_strict >= VERIEXEC_IPS &&
+		    iskmemdev(dev) && (ap->a_mode & FWRITE)) {
+			return (error);
+		} else {
+			struct vnode *bvp;
+			dev_t blkdev;
+
+			blkdev = devsw_chr2blk(dev);
+			if (blkdev != NODEV) {
+				bvp = NULL;
+				vfinddev(blkdev, VBLK, &bvp);
+				error = veriexec_rawchk(bvp);
+				if (error)
+					return (error);
 			}
-#endif /* NVERIEXEC > 0 */
 		}
+#endif /* NVERIEXEC > 0 */
 
 		if (cdev->d_type == D_TTY)
 			vp->v_flag |= VISTTY;
@@ -265,20 +258,17 @@ spec_open(v)
 		 * When running in very secure mode, do not allow
 		 * opens for writing of any disk block devices.
 		 */
-		if (ap->a_cred != FSCRED) {
-			u_long rw;
-
-			if ((error = vfs_mountedon(vp)) != 0)
-				return (error);
+		if ((ap->a_cred != FSCRED) &&
+		    (error = vfs_mountedon(vp)) != 0)
+			return (error);
 
-			rw = M2K(ap->a_mode);
+		req = M2K(ap->a_mode);
 
-			error = kauth_authorize_system(ap->a_cred,
-			    KAUTH_SYSTEM_RAWIO,
-			    KAUTH_REQ_SYSTEM_RAWIO_DISK,
-			    (void *)rw, vp, (void *)(u_long)dev);
-			if (error)
-				return (error);
+		error = kauth_authorize_device(ap->a_cred,
+		    KAUTH_DEVICE_RAWIO, req, dev, NULL);
+		if (error) {
+			printf("VBLK returning EPERM\n");
+			return (error);
 		}
 
 #if NVERIEXEC > 0
Index: secmodel/bsd44/secmodel_bsd44_securelevel.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/bsd44/secmodel_bsd44_securelevel.c,v
retrieving revision 1.9
diff -u -p -r1.9 secmodel_bsd44_securelevel.c
--- secmodel/bsd44/secmodel_bsd44_securelevel.c	12 Oct 2006 01:32:50 -0000	1.9
+++ secmodel/bsd44/secmodel_bsd44_securelevel.c	1 Nov 2006 22:47:52 -0000
@@ -126,6 +126,8 @@ secmodel_bsd44_securelevel_start(void)
 	    secmodel_bsd44_securelevel_network_cb, NULL);
 	kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
 	    secmodel_bsd44_securelevel_machdep_cb, NULL);
+	kauth_listen_scope(KAUTH_SCOPE_DEVICE,
+	    secmodel_bsd44_securelevel_device_cb, NULL);
 }
 
 /*
@@ -147,127 +149,6 @@ secmodel_bsd44_securelevel_system_cb(kau
 	req = (enum kauth_system_req)arg0;
 
 	switch (action) {
-	case KAUTH_SYSTEM_RAWIO: {
-		u_int rw;
-
-		rw = (u_int)(u_long)arg1;
-
-		switch (req) {
-		case KAUTH_REQ_SYSTEM_RAWIO_MEMORY: {
-			switch (rw) {
-			case KAUTH_REQ_SYSTEM_RAWIO_READ:
-				result = KAUTH_RESULT_ALLOW;
-				break;
-
-			case KAUTH_REQ_SYSTEM_RAWIO_WRITE:
-			case KAUTH_REQ_SYSTEM_RAWIO_RW:
-				if (securelevel < 1)
-					result = KAUTH_RESULT_ALLOW;
-				break;
-
-			default:
-				result = KAUTH_RESULT_DEFER;
-				break;
-			}
-
-			break;
-			}
-
-		case KAUTH_REQ_SYSTEM_RAWIO_DISK: {
-			struct vnode *vp = arg2;
-			dev_t dev = (dev_t)(u_long)arg3;
-
-			if (vp == NULL || dev == NODEV) {
-				switch (rw) {
-				case KAUTH_REQ_SYSTEM_RAWIO_READ:
-					result = KAUTH_RESULT_ALLOW;
-					break;
-
-				case KAUTH_REQ_SYSTEM_RAWIO_RW:
-				case KAUTH_REQ_SYSTEM_RAWIO_WRITE:
-					if (securelevel < 1)
-						result = KAUTH_RESULT_ALLOW;
-					break;
-
-				default:
-					result = KAUTH_RESULT_DEFER;
-					break;
-				}
-
-				break;
-			}
-
-			switch (vp->v_type) {
-			case VCHR: {
-				const struct cdevsw *cdev;
-				struct vnode *bvp;
-
-				switch (rw) {
-				case KAUTH_REQ_SYSTEM_RAWIO_READ:
-					result = KAUTH_RESULT_ALLOW;
-					break;
-
-				case KAUTH_REQ_SYSTEM_RAWIO_WRITE:
-				case KAUTH_REQ_SYSTEM_RAWIO_RW:
-					cdev = cdevsw_lookup(dev);
-					if (cdev == NULL)
-						break;
-
-					if (cdev->d_type == D_DISK &&
-					    securelevel > 1)
-						break;
-
-					bvp = NULL;
-					vfinddev(devsw_chr2blk(dev), VBLK, &bvp);
-					if (bvp != NULL) {
-						if (vfs_mountedon(bvp) &&
-						    securelevel > 0)
-							break;
-					}
-
-					result = KAUTH_RESULT_ALLOW;
-
-					break;
-
-				default:
-					result = KAUTH_RESULT_DEFER;
-					break;
-				}
-
-				break;
-				}
-
-			case VBLK: {
-				const struct bdevsw *bdev;
-
-				bdev = bdevsw_lookup(dev);
-				if (bdev == NULL)
-					break;
-
-				if (bdev->d_type == D_DISK &&
-				    rw != KAUTH_REQ_SYSTEM_RAWIO_READ &&
-				    securelevel > 1)
-					break;
-
-				result = KAUTH_RESULT_ALLOW;
-
-				break;
-				}
-
-			default:
-				result = KAUTH_RESULT_DEFER;
-				break;
-			}
-			break;
-			}
-
-		default:
-			result = KAUTH_RESULT_DEFER;
-			break;
-		}
-		break;
-		}
-	
 	case KAUTH_SYSTEM_TIME:
 		switch (req) {
 		case KAUTH_REQ_SYSTEM_TIME_BACKWARDS:
@@ -448,3 +329,111 @@ secmodel_bsd44_securelevel_machdep_cb(ka
 
 	return (result);
 }
+
+/*
+ * kauth(9) listener
+ *
+ * Security model: Traditional NetBSD
+ * Scope: Device 
+ * Responsibility: Securelevel
+ */
+int
+secmodel_bsd44_securelevel_device_cb(kauth_cred_t cred __unused,
+    kauth_action_t action, void *cookie __unused, void *arg0 __unused,
+    void *arg1 __unused, void *arg2 __unused, void *arg3 __unused)
+{
+	int result;
+	enum kauth_device_req req;
+	const struct bdevsw *bdev;
+	dev_t dev;
+
+	result = KAUTH_RESULT_DENY;
+	req = (enum kauth_device_req)arg0;
+	dev = (dev_t)(u_long)arg1;
+
+	switch (action) {
+	case KAUTH_DEVICE_RAWIO:
+		if (dev == NODEV) {
+			result = KAUTH_RESULT_ALLOW;
+			break;
+		}
+
+		/* Handle /dev/{mem,kmem} */
+		if (iskmemdev(dev)) {
+			switch (req) {
+			case KAUTH_REQ_DEVICE_RAWIO_READ:
+				result = KAUTH_RESULT_ALLOW;
+				break;
+
+			case KAUTH_REQ_DEVICE_RAWIO_WRITE:
+			case KAUTH_REQ_DEVICE_RAWIO_RW:
+				if (securelevel < 1)
+					result = KAUTH_RESULT_ALLOW;
+				break;
+
+			default:
+				result = KAUTH_RESULT_DEFER;
+				break;
+			}
+
+			break;
+		}
+
+		switch (req) {
+		case KAUTH_REQ_DEVICE_RAWIO_READ:
+			result = KAUTH_RESULT_ALLOW;
+			break;
+
+		case KAUTH_REQ_DEVICE_RAWIO_WRITE:
+		case KAUTH_REQ_DEVICE_RAWIO_RW:
+			bdev = bdevsw_lookup(dev);
+			if (bdev == NULL) {
+				dev = devsw_chr2blk(dev);
+				bdev = bdevsw_lookup(dev);
+				if (bdev == NULL) {
+					result = KAUTH_RESULT_ALLOW;
+					break;
+				}
+			}
+
+			if (bdev->d_type != D_DISK)
+				result = KAUTH_RESULT_ALLOW;
+			else {
+				struct vnode *vp = NULL;
+
+				vfinddev(dev, VBLK, &vp);
+
+				if (vp == NULL) {
+					result = KAUTH_RESULT_ALLOW;
+					break;
+				}
+
+				if (vfs_mountedon(vp) &&
+				    (securelevel > 0))
+					break;
+
+				if (securelevel < 2)
+					result = KAUTH_RESULT_ALLOW;
+			}
+
+			break;
+
+		case KAUTH_REQ_DEVICE_RAWIO_PASSTHRU:
+			if (securelevel < 1)
+				result = KAUTH_RESULT_ALLOW;
+			break;
+
+		default:
+			result = KAUTH_RESULT_DEFER;
+			break;
+		}
+
+		break;
+
+	default:
+		result = KAUTH_RESULT_DEFER;
+		break;
+	}
+
+	return (result);
+}

--Boundary_(ID_8u1eivK7FyA78gY8EimS4Q)--