Date: Mon, 11 Jan 2021 15:36:11 GMT From: Roger Pau Monné <royger@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: a7650787905d - main - xen/privcmd: implement the restrict ioctl Message-ID: <202101111536.10BFaBtH026688@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@citrix.com> AuthorDate: 2020-06-25 17:16:04 +0000 Commit: Roger Pau Monné <royger@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__ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101111536.10BFaBtH026688>