git: a7650787905d - main - xen/privcmd: implement the restrict ioctl
Roger Pau Monné
royger at FreeBSD.org
Mon Jan 11 15:36:17 UTC 2021
The branch main has been updated by royger:
URL: https://cgit.FreeBSD.org/src/commit/?id=a7650787905d36ac01297aa699d3009da6cfaaa9
commit a7650787905d36ac01297aa699d3009da6cfaaa9
Author: Roger Pau Monne <roger.pau at citrix.com>
AuthorDate: 2020-06-25 17:16:04 +0000
Commit: Roger Pau Monné <royger at FreeBSD.org>
CommitDate: 2021-01-11 15:33:27 +0000
xen/privcmd: implement the restrict ioctl
Use an interface compatible with the Linux one so that the user-space
libraries already using the Linux interface can be used without much
modifications.
This allows an open privcmd instance to limit against which domains it
can act upon.
Sponsored by: Citrix Systems R&D
---
sys/dev/xen/privcmd/privcmd.c | 82 +++++++++++++++++++++++++++++++++++++++++++
sys/xen/privcmd.h | 2 ++
2 files changed, 84 insertions(+)
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;
@@ -472,6 +511,24 @@ mmap_out:
free(hbufs, M_PRIVCMD);
+ 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:
@@ -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)
diff --git a/sys/xen/privcmd.h b/sys/xen/privcmd.h
index cd0bc7d550d9..55a1cdc86471 100644
--- a/sys/xen/privcmd.h
+++ b/sys/xen/privcmd.h
@@ -82,5 +82,7 @@ struct ioctl_privcmd_dmop {
_IOW('E', 2, struct ioctl_privcmd_mmapresource)
#define IOCTL_PRIVCMD_DM_OP \
_IOW('E', 3, struct ioctl_privcmd_dmop)
+#define IOCTL_PRIVCMD_RESTRICT \
+ _IOW('E', 4, domid_t)
#endif /* !__XEN_PRIVCMD_H__ */
More information about the dev-commits-src-all
mailing list