aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/vmm/vmm_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/vmm/vmm_dev.c')
-rw-r--r--sys/dev/vmm/vmm_dev.c93
1 files changed, 65 insertions, 28 deletions
diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c
index a5322f05d28f..a2775023838a 100644
--- a/sys/dev/vmm/vmm_dev.c
+++ b/sys/dev/vmm/vmm_dev.c
@@ -8,6 +8,8 @@
#include <sys/param.h>
#include <sys/conf.h>
+#define EXTERR_CATEGORY EXTERR_CAT_VMM
+#include <sys/exterrvar.h>
#include <sys/fcntl.h>
#include <sys/ioccom.h>
#include <sys/jail.h>
@@ -91,7 +93,7 @@ static bool vmm_initialized = false;
static SLIST_HEAD(, vmmdev_softc) head;
-static unsigned pr_allow_flag;
+static unsigned int pr_allow_vmm_flag, pr_allow_vmm_ppt_flag;
static struct sx vmmdev_mtx;
SX_SYSINIT(vmmdev_mtx, &vmmdev_mtx, "vmm device mutex");
@@ -112,10 +114,10 @@ static int devmem_create_cdev(struct vmmdev_softc *sc, int id, char *devmem);
static void vmmdev_destroy(struct vmmdev_softc *sc);
static int
-vmm_priv_check(struct ucred *ucred)
+vmm_jail_priv_check(struct ucred *ucred)
{
if (jailed(ucred) &&
- !(ucred->cr_prison->pr_allow & pr_allow_flag))
+ (ucred->cr_prison->pr_allow & pr_allow_vmm_flag) == 0)
return (EPERM);
return (0);
@@ -369,7 +371,7 @@ vmmdev_open(struct cdev *dev, int flags, int fmt, struct thread *td)
* A jail without vmm access shouldn't be able to access vmm device
* files at all, but check here just to be thorough.
*/
- error = vmm_priv_check(td->td_ucred);
+ error = vmm_jail_priv_check(td->td_ucred);
if (error != 0)
return (error);
@@ -459,8 +461,11 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
if (ioctl == NULL)
return (ENOTTY);
- if ((ioctl->flags & VMMDEV_IOCTL_PRIV_CHECK_DRIVER) != 0) {
- error = priv_check(td, PRIV_DRIVER);
+ if ((ioctl->flags & VMMDEV_IOCTL_PPT) != 0) {
+ if (jailed(td->td_ucred) && (td->td_ucred->cr_prison->pr_allow &
+ pr_allow_vmm_ppt_flag) == 0)
+ return (EPERM);
+ error = priv_check(td, PRIV_VMM_PPTDEV);
if (error != 0)
return (error);
}
@@ -876,8 +881,7 @@ vmmdev_destroy(struct vmmdev_softc *sc)
free(dsc, M_VMMDEV);
}
- if (sc->vm != NULL)
- vm_destroy(sc->vm);
+ vm_destroy(sc->vm);
chgvmmcnt(sc->ucred->cr_ruidinfo, -1, 0);
crfree(sc->ucred);
@@ -896,6 +900,7 @@ vmmdev_lookup_and_destroy(const char *name, struct ucred *cred)
{
struct cdev *cdev;
struct vmmdev_softc *sc;
+ int error;
sx_xlock(&vmmdev_mtx);
sc = vmmdev_lookup(name, cred);
@@ -905,6 +910,16 @@ vmmdev_lookup_and_destroy(const char *name, struct ucred *cred)
}
/*
+ * Only the creator of a VM or a privileged user can destroy it.
+ */
+ if ((cred->cr_uid != sc->ucred->cr_uid ||
+ cred->cr_prison != sc->ucred->cr_prison) &&
+ (error = priv_check_cred(cred, PRIV_VMM_DESTROY)) != 0) {
+ sx_xunlock(&vmmdev_mtx);
+ return (error);
+ }
+
+ /*
* Setting 'sc->cdev' to NULL is used to indicate that the VM
* is scheduled for destruction.
*/
@@ -925,7 +940,7 @@ sysctl_vmm_destroy(SYSCTL_HANDLER_ARGS)
char *buf;
int error, buflen;
- error = vmm_priv_check(req->td->td_ucred);
+ error = vmm_jail_priv_check(req->td->td_ucred);
if (error)
return (error);
@@ -990,9 +1005,32 @@ vmmdev_create(const char *name, uint32_t flags, struct ucred *cred)
return (EEXIST);
}
+ /*
+ * Unprivileged users can only create VMs that will be automatically
+ * destroyed when the creating descriptor is closed.
+ */
+ if ((flags & VMMCTL_CREATE_DESTROY_ON_CLOSE) == 0 &&
+ (error = priv_check_cred(cred, PRIV_VMM_CREATE)) != 0) {
+ sx_xunlock(&vmmdev_mtx);
+ return (EXTERROR(error,
+ "An unprivileged user must run VMs in monitor mode"));
+ }
+
+ if ((error = vmm_jail_priv_check(cred)) != 0) {
+ sx_xunlock(&vmmdev_mtx);
+ return (EXTERROR(error,
+ "VMs cannot be created in the current jail"));
+ }
+
+ if (!chgvmmcnt(cred->cr_ruidinfo, 1, vm_maxvmms)) {
+ sx_xunlock(&vmmdev_mtx);
+ return (ENOMEM);
+ }
+
error = vm_create(name, &vm);
if (error != 0) {
sx_xunlock(&vmmdev_mtx);
+ (void)chgvmmcnt(cred->cr_ruidinfo, -1, 0);
return (error);
}
sc = vmmdev_alloc(vm, cred);
@@ -1004,8 +1042,8 @@ vmmdev_create(const char *name, uint32_t flags, struct ucred *cred)
make_dev_args_init(&mda);
mda.mda_devsw = &vmmdevsw;
mda.mda_cr = sc->ucred;
- mda.mda_uid = UID_ROOT;
- mda.mda_gid = GID_WHEEL;
+ mda.mda_uid = cred->cr_uid;
+ mda.mda_gid = GID_VMM;
mda.mda_mode = 0600;
mda.mda_si_drv1 = sc;
mda.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
@@ -1015,12 +1053,6 @@ vmmdev_create(const char *name, uint32_t flags, struct ucred *cred)
vmmdev_destroy(sc);
return (error);
}
- if (!chgvmmcnt(cred->cr_ruidinfo, 1, vm_maxvmms)) {
- sx_xunlock(&vmmdev_mtx);
- destroy_dev(cdev);
- vmmdev_destroy(sc);
- return (ENOMEM);
- }
sc->cdev = cdev;
sx_xunlock(&vmmdev_mtx);
return (0);
@@ -1035,7 +1067,7 @@ sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
if (!vmm_initialized)
return (ENXIO);
- error = vmm_priv_check(req->td->td_ucred);
+ error = vmm_jail_priv_check(req->td->td_ucred);
if (error != 0)
return (error);
@@ -1100,7 +1132,7 @@ vmmctl_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
int error;
struct vmmctl_priv *priv;
- error = vmm_priv_check(td->td_ucred);
+ error = vmm_jail_priv_check(td->td_ucred);
if (error != 0)
return (error);
@@ -1178,10 +1210,13 @@ vmmdev_init(void)
sx_xlock(&vmmdev_mtx);
error = make_dev_p(MAKEDEV_CHECKNAME, &vmmctl_cdev, &vmmctlsw, NULL,
- UID_ROOT, GID_WHEEL, 0600, "vmmctl");
- if (error == 0)
- pr_allow_flag = prison_add_allow(NULL, "vmm", NULL,
- "Allow use of vmm in a jail.");
+ UID_ROOT, GID_VMM, 0660, "vmmctl");
+ if (error == 0) {
+ pr_allow_vmm_flag = prison_add_allow(NULL, "vmm", NULL,
+ "Allow use of vmm in a jail");
+ pr_allow_vmm_ppt_flag = prison_add_allow(NULL, "vmm_ppt", NULL,
+ "Allow use of vmm with ppt devices in a jail");
+ }
sx_xunlock(&vmmdev_mtx);
return (error);
@@ -1228,9 +1263,11 @@ vmm_handler(module_t mod, int what, void *arg)
if (error == 0)
vmm_initialized = true;
else {
- error = vmmdev_cleanup();
- KASSERT(error == 0,
- ("%s: vmmdev_cleanup failed: %d", __func__, error));
+ int error1 __diagused;
+
+ error1 = vmmdev_cleanup();
+ KASSERT(error1 == 0,
+ ("%s: vmmdev_cleanup failed: %d", __func__, error1));
}
break;
case MOD_UNLOAD:
@@ -1329,8 +1366,8 @@ devmem_create_cdev(struct vmmdev_softc *sc, int segid, char *devname)
make_dev_args_init(&mda);
mda.mda_devsw = &devmemsw;
mda.mda_cr = sc->ucred;
- mda.mda_uid = UID_ROOT;
- mda.mda_gid = GID_WHEEL;
+ mda.mda_uid = sc->ucred->cr_uid;
+ mda.mda_gid = GID_VMM;
mda.mda_mode = 0600;
mda.mda_si_drv1 = dsc;
mda.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;