The branch main has been updated by royger:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a7650787905d36ac01297aa699d3009da6cfaaa9

commit a7650787905d36ac01297aa699d3009da6cfaaa9
Author:     Roger Pau Monne <[email protected]>
AuthorDate: 2020-06-25 17:16:04 +0000
Commit:     Roger Pau Monné <[email protected]>
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__ */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to