aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/xen
diff options
context:
space:
mode:
authorRoger Pau Monne <roger.pau@citrix.com>2020-06-25 17:16:04 +0000
committerRoger Pau Monné <royger@FreeBSD.org>2021-01-11 15:33:27 +0000
commita7650787905d36ac01297aa699d3009da6cfaaa9 (patch)
tree7a950c884c680643e386019836ff68cb4ebea595 /sys/dev/xen
parented78016d005c9ec97883a33c4468052ca9880c4f (diff)
Diffstat (limited to 'sys/dev/xen')
-rw-r--r--sys/dev/xen/privcmd/privcmd.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/sys/dev/xen/privcmd/privcmd.c b/sys/dev/xen/privcmd/privcmd.c
index d9f11aa0fe7a..0ef6737df64f 100644
--- a/sys/dev/xen/privcmd/privcmd.c
+++ b/sys/dev/xen/privcmd/privcmd.c
@@ -78,12 +78,14 @@ struct privcmd_map {
};
static d_ioctl_t privcmd_ioctl;
+static d_open_t privcmd_open;
static d_mmap_single_t privcmd_mmap_single;
static struct cdevsw privcmd_devsw = {
.d_version = D_VERSION,
.d_ioctl = privcmd_ioctl,
.d_mmap_single = privcmd_mmap_single,
+ .d_open = privcmd_open,
.d_name = "privcmd",
};
@@ -99,6 +101,10 @@ static struct cdev_pager_ops privcmd_pg_ops = {
.cdev_pg_dtor = privcmd_pg_dtor,
};
+struct per_user_data {
+ domid_t dom;
+};
+
static device_t privcmd_dev = NULL;
/*------------------------- Privcmd Pager functions --------------------------*/
@@ -259,12 +265,30 @@ privcmd_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg,
{
int error;
unsigned int i;
+ void *data;
+ const struct per_user_data *u;
+
+ error = devfs_get_cdevpriv(&data);
+ if (error != 0)
+ return (EINVAL);
+ /*
+ * Constify user-data to prevent unintended changes to the restriction
+ * limits.
+ */
+ u = data;
switch (cmd) {
case IOCTL_PRIVCMD_HYPERCALL: {
struct ioctl_privcmd_hypercall *hcall;
hcall = (struct ioctl_privcmd_hypercall *)arg;
+
+ /* Forbid hypercalls if restricted. */
+ if (u->dom != DOMID_INVALID) {
+ error = EPERM;
+ break;
+ }
+
#ifdef __amd64__
/*
* The hypervisor page table walker will refuse to access
@@ -301,6 +325,11 @@ privcmd_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg,
mmap = (struct ioctl_privcmd_mmapbatch *)arg;
+ if (u->dom != DOMID_INVALID && u->dom != mmap->dom) {
+ error = EPERM;
+ break;
+ }
+
umap = setup_virtual_area(td, mmap->addr, mmap->num);
if (umap == NULL) {
error = EINVAL;
@@ -382,6 +411,11 @@ mmap_out:
mmap = (struct ioctl_privcmd_mmapresource *)arg;
+ if (u->dom != DOMID_INVALID && u->dom != mmap->dom) {
+ error = EPERM;
+ break;
+ }
+
bzero(&adq, sizeof(adq));
adq.domid = mmap->dom;
@@ -434,6 +468,11 @@ mmap_out:
dmop = (struct ioctl_privcmd_dmop *)arg;
+ if (u->dom != DOMID_INVALID && u->dom != dmop->dom) {
+ error = EPERM;
+ break;
+ }
+
if (dmop->num == 0)
break;
@@ -474,6 +513,24 @@ mmap_out:
break;
}
+ case IOCTL_PRIVCMD_RESTRICT: {
+ struct per_user_data *u;
+ domid_t dom;
+
+ dom = *(domid_t *)arg;
+
+ error = devfs_get_cdevpriv((void **)&u);
+ if (error != 0)
+ break;
+
+ if (u->dom != DOMID_INVALID && u->dom != dom) {
+ error = -EINVAL;
+ break;
+ }
+ u->dom = dom;
+
+ break;
+ }
default:
error = ENOSYS;
break;
@@ -482,6 +539,31 @@ mmap_out:
return (error);
}
+static void
+user_release(void *arg)
+{
+
+ free(arg, M_PRIVCMD);
+}
+
+static int
+privcmd_open(struct cdev *dev, int flag, int otyp, struct thread *td)
+{
+ struct per_user_data *u;
+ int error;
+
+ u = malloc(sizeof(*u), M_PRIVCMD, M_WAITOK);
+ u->dom = DOMID_INVALID;
+
+ /* Assign the allocated per_user_data to this open instance. */
+ error = devfs_set_cdevpriv(u, user_release);
+ if (error != 0) {
+ free(u, M_PRIVCMD);
+ }
+
+ return (error);
+}
+
/*------------------ Private Device Attachment Functions --------------------*/
static void
privcmd_identify(driver_t *driver, device_t parent)