Skip site navigation (1)Skip section navigation (2)
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>