From 756638cf9587770daab9a23d7d778f524160adb2 Mon Sep 17 00:00:00 2001 From: elad Date: Tue, 6 Oct 2009 04:28:10 +0000 Subject: [PATCH] Factor out a block of code that appears in three places (Veriexec, keylock, and securelevel) so that others can use it as well. --- sys/kern/kern_verifiedexec.c | 53 ++----------- sys/kern/vfs_subr.c | 77 ++++++++++++++++++- sys/miscfs/specfs/spec_vnops.c | 11 ++- sys/miscfs/specfs/specdev.h | 4 +- sys/secmodel/keylock/secmodel_keylock.c | 57 ++------------ .../securelevel/secmodel_securelevel.c | 65 ++++------------ sys/sys/vnode.h | 3 +- 7 files changed, 116 insertions(+), 154 deletions(-) diff --git a/sys/kern/kern_verifiedexec.c b/sys/kern/kern_verifiedexec.c index 98b42332983c..a52b5631d81d 100644 --- a/sys/kern/kern_verifiedexec.c +++ b/sys/kern/kern_verifiedexec.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_verifiedexec.c,v 1.116 2009/10/03 21:03:55 elad Exp $ */ +/* $NetBSD: kern_verifiedexec.c,v 1.117 2009/10/06 04:28:10 elad Exp $ */ /*- * Copyright (c) 2005, 2006 Elad Efrat @@ -29,7 +29,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.116 2009/10/03 21:03:55 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.117 2009/10/06 04:28:10 elad Exp $"); #include "opt_veriexec.h" @@ -1030,8 +1030,7 @@ veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, switch (action) { case KAUTH_DEVICE_RAWIO_SPEC: { struct vnode *vp, *bvp; - dev_t dev; - int d_type; + int error; if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) { result = KAUTH_RESULT_DEFER; @@ -1041,60 +1040,22 @@ veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, vp = arg1; KASSERT(vp != NULL); - dev = vp->v_rdev; - d_type = D_OTHER; - bvp = NULL; - /* Handle /dev/mem and /dev/kmem. */ - if ((vp->v_type == VCHR) && iskmemdev(dev)) { + if (iskmemvp(vp)) { if (veriexec_strict < VERIEXEC_IPS) result = KAUTH_RESULT_DEFER; break; } - switch (vp->v_type) { - case VCHR: { - const struct cdevsw *cdev; - - cdev = cdevsw_lookup(dev); - if (cdev != NULL) { - dev_t blkdev; - - blkdev = devsw_chr2blk(dev); - if (blkdev != NODEV) { - vfinddev(blkdev, VBLK, &bvp); - if (bvp != NULL) - d_type = cdev->d_flag & - D_TYPEMASK; - } - } - - break; - } - case VBLK: { - const struct bdevsw *bdev; - - bdev = bdevsw_lookup(dev); - if (bdev != NULL) - d_type = bdev->d_flag & D_TYPEMASK; - - bvp = vp; - - break; - } - default: - result = KAUTH_RESULT_DEFER; - break; - } - - if (d_type != D_DISK) { + error = rawdev_mounted(vp, &bvp); + if (error == EINVAL) { result = KAUTH_RESULT_DEFER; break; } /* - * XXX: See vfs_mountedon() comment in secmodel/securelevel. + * XXX: See vfs_mountedon() comment in rawdev_mounted(). */ vte = veriexec_table_lookup(bvp->v_mount); if (vte == NULL) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index e7ab1c3e5165..1b6221b68af2 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_subr.c,v 1.384 2009/09/19 16:20:41 jmcneill Exp $ */ +/* $NetBSD: vfs_subr.c,v 1.385 2009/10/06 04:28:10 elad Exp $ */ /*- * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc. @@ -91,7 +91,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.384 2009/09/19 16:20:41 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.385 2009/10/06 04:28:10 elad Exp $"); #include "opt_ddb.h" #include "opt_compat_netbsd.h" @@ -3289,3 +3289,76 @@ vfs_mount_print(struct mount *mp, int full, void (*pr)(const char *, ...)) } #endif /* DDB || DEBUGPRINT */ +/* + * Check if a device pointed to by vp is mounted. + * + * Returns: + * EINVAL if it's not a disk + * EBUSY if it's a disk and mounted + * 0 if it's a disk and not mounted + */ +int +rawdev_mounted(struct vnode *vp, struct vnode **bvpp) +{ + struct vnode *bvp; + dev_t dev; + int d_type; + + bvp = NULL; + dev = vp->v_rdev; + d_type = D_OTHER; + + if (iskmemvp(vp)) + return EINVAL; + + switch (vp->v_type) { + case VCHR: { + const struct cdevsw *cdev; + + cdev = cdevsw_lookup(dev); + if (cdev != NULL) { + dev_t blkdev; + + blkdev = devsw_chr2blk(dev); + if (blkdev != NODEV) { + vfinddev(blkdev, VBLK, &bvp); + if (bvp != NULL) + d_type = (cdev->d_flag & D_TYPEMASK); + } + } + + break; + } + + case VBLK: { + const struct bdevsw *bdev; + + bdev = bdevsw_lookup(dev); + if (bdev != NULL) + d_type = (bdev->d_flag & D_TYPEMASK); + + bvp = vp; + + break; + } + + default: + break; + } + + if (d_type != D_DISK) + return EINVAL; + + if (bvpp != NULL) + *bvpp = bvp; + + /* + * XXX: This is bogus. We should be failing the request + * XXX: not only if this specific slice is mounted, but + * XXX: if it's on a disk with any other mounted slice. + */ + if (vfs_mountedon(bvp)) + return EBUSY; + + return 0; +} diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index 52fc2ec410f6..a44758426458 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -1,4 +1,4 @@ -/* $NetBSD: spec_vnops.c,v 1.125 2009/10/04 06:23:58 tsutsui Exp $ */ +/* $NetBSD: spec_vnops.c,v 1.126 2009/10/06 04:28:10 elad Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.125 2009/10/04 06:23:58 tsutsui Exp $"); +__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.126 2009/10/06 04:28:10 elad Exp $"); #include #include @@ -151,6 +151,13 @@ const struct vnodeopv_entry_desc spec_vnodeop_entries[] = { const struct vnodeopv_desc spec_vnodeop_opv_desc = { &spec_vnodeop_p, spec_vnodeop_entries }; +/* Returns true if vnode is /dev/mem or /dev/kmem. */ +bool +iskmemvp(struct vnode *vp) +{ + return ((vp->v_type == VCHR) && iskmemdev(vp->v_rdev)); +} + /* * Returns true if dev is /dev/mem or /dev/kmem. */ diff --git a/sys/miscfs/specfs/specdev.h b/sys/miscfs/specfs/specdev.h index 9bcf1d790add..e3df9b673e51 100644 --- a/sys/miscfs/specfs/specdev.h +++ b/sys/miscfs/specfs/specdev.h @@ -1,4 +1,4 @@ -/* $NetBSD: specdev.h,v 1.37 2008/12/29 17:41:19 pooka Exp $ */ +/* $NetBSD: specdev.h,v 1.38 2009/10/06 04:28:11 elad Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -155,4 +155,6 @@ int spec_advlock(void *); #define spec_getpages genfs_getpages #define spec_putpages genfs_putpages +bool iskmemvp(struct vnode *); + #endif /* _MISCFS_SPECFS_SPECDEV_H_ */ diff --git a/sys/secmodel/keylock/secmodel_keylock.c b/sys/secmodel/keylock/secmodel_keylock.c index d155597a4598..c8a49f1bb3d7 100644 --- a/sys/secmodel/keylock/secmodel_keylock.c +++ b/sys/secmodel/keylock/secmodel_keylock.c @@ -1,4 +1,4 @@ -/* $NetBSD: secmodel_keylock.c,v 1.3 2009/10/03 20:48:42 elad Exp $ */ +/* $NetBSD: secmodel_keylock.c,v 1.4 2009/10/06 04:28:10 elad Exp $ */ /*- * Copyright (c) 2009 Marc Balmer * Copyright (c) 2006 Elad Efrat @@ -54,7 +54,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: secmodel_keylock.c,v 1.3 2009/10/03 20:48:42 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: secmodel_keylock.c,v 1.4 2009/10/06 04:28:10 elad Exp $"); #include #include @@ -421,22 +421,16 @@ secmodel_keylock_device_cb(kauth_cred_t cred, switch (action) { case KAUTH_DEVICE_RAWIO_SPEC: { - struct vnode *vp, *bvp; + struct vnode *vp; enum kauth_device_req req; - dev_t dev; - int d_type; req = (enum kauth_device_req)arg0; vp = arg1; KASSERT(vp != NULL); - dev = vp->v_rdev; - d_type = D_OTHER; - bvp = NULL; - /* Handle /dev/mem and /dev/kmem. */ - if ((vp->v_type == VCHR) && iskmemdev(dev)) { + if (iskmemvp(vp)) { switch (req) { case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: break; @@ -458,49 +452,12 @@ secmodel_keylock_device_cb(kauth_cred_t cred, case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: - switch (vp->v_type) { - case VCHR: { - const struct cdevsw *cdev; + error = rawdev_mounted(vp, NULL); - cdev = cdevsw_lookup(dev); - if (cdev != NULL) { - dev_t blkdev; - - blkdev = devsw_chr2blk(dev); - if (blkdev != NODEV) { - vfinddev(blkdev, VBLK, &bvp); - if (bvp != NULL) - d_type = (cdev->d_flag - & D_TYPEMASK); - } - } - - break; - } - case VBLK: { - const struct bdevsw *bdev; - - bdev = bdevsw_lookup(dev); - if (bdev != NULL) - d_type = (bdev->d_flag & D_TYPEMASK); - - bvp = vp; - - break; - } - default: - break; - } - - if (d_type != D_DISK) + if (error == EINVAL) break; - /* - * XXX: This is bogus. We should be failing the request - * XXX: not only if this specific slice is mounted, but - * XXX: if it's on a disk with any other mounted slice. - */ - if (vfs_mountedon(bvp) && (kstate != KEYLOCK_OPEN)) + if (error && (kstate != KEYLOCK_OPEN)) break; if (kstate == KEYLOCK_CLOSE) diff --git a/sys/secmodel/securelevel/secmodel_securelevel.c b/sys/secmodel/securelevel/secmodel_securelevel.c index 56a2e252603c..1f02a2b5e4f3 100644 --- a/sys/secmodel/securelevel/secmodel_securelevel.c +++ b/sys/secmodel/securelevel/secmodel_securelevel.c @@ -1,4 +1,4 @@ -/* $NetBSD: secmodel_securelevel.c,v 1.16 2009/10/03 20:48:42 elad Exp $ */ +/* $NetBSD: secmodel_securelevel.c,v 1.17 2009/10/06 04:28:10 elad Exp $ */ /*- * Copyright (c) 2006 Elad Efrat * All rights reserved. @@ -35,7 +35,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.16 2009/10/03 20:48:42 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.17 2009/10/06 04:28:10 elad Exp $"); #ifdef _KERNEL_OPT #include "opt_insecure.h" @@ -480,22 +480,16 @@ secmodel_securelevel_device_cb(kauth_cred_t cred, switch (action) { case KAUTH_DEVICE_RAWIO_SPEC: { - struct vnode *vp, *bvp; + struct vnode *vp; enum kauth_device_req req; - dev_t dev; - int d_type; req = (enum kauth_device_req)arg0; vp = arg1; KASSERT(vp != NULL); - dev = vp->v_rdev; - d_type = D_OTHER; - bvp = NULL; - /* Handle /dev/mem and /dev/kmem. */ - if ((vp->v_type == VCHR) && iskmemdev(dev)) { + if (iskmemvp(vp)) { switch (req) { case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: break; @@ -504,6 +498,7 @@ secmodel_securelevel_device_cb(kauth_cred_t cred, case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: if (securelevel > 0) result = KAUTH_RESULT_DENY; + break; default: @@ -518,57 +513,23 @@ secmodel_securelevel_device_cb(kauth_cred_t cred, break; case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: - case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: - switch (vp->v_type) { - case VCHR: { - const struct cdevsw *cdev; + case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: { + int error; - cdev = cdevsw_lookup(dev); - if (cdev != NULL) { - dev_t blkdev; + error = rawdev_mounted(vp, NULL); - blkdev = devsw_chr2blk(dev); - if (blkdev != NODEV) { - vfinddev(blkdev, VBLK, &bvp); - if (bvp != NULL) - d_type = (cdev->d_flag - & D_TYPEMASK); - } - } - - break; - } - case VBLK: { - const struct bdevsw *bdev; - - bdev = bdevsw_lookup(dev); - if (bdev != NULL) - d_type = (bdev->d_flag & D_TYPEMASK); - - bvp = vp; - - break; - } - - default: - break; - } - - if (d_type != D_DISK) + /* Not a disk. */ + if (error == EINVAL) break; - /* - * XXX: This is bogus. We should be failing the request - * XXX: not only if this specific slice is mounted, but - * XXX: if it's on a disk with any other mounted slice. - */ - if (vfs_mountedon(bvp) && (securelevel > 0)) - break; + if (error && securelevel > 0) + result = KAUTH_RESULT_DENY; if (securelevel > 1) result = KAUTH_RESULT_DENY; break; + } default: break; diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 510bacfd33b7..a34bf039013e 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1,4 +1,4 @@ -/* $NetBSD: vnode.h,v 1.209 2009/08/16 10:51:21 yamt Exp $ */ +/* $NetBSD: vnode.h,v 1.210 2009/10/06 04:28:10 elad Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -658,6 +658,7 @@ int speedup_syncer(void); int dorevoke(struct vnode *, kauth_cred_t); int vlockmgr(struct vnlock *, int); int vlockstatus(struct vnlock *); +int rawdev_mounted(struct vnode *, struct vnode **); /* see vfssubr(9) */ void vfs_getnewfsid(struct mount *);