[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 3/3] xen/privcmd: add IOCTL_PRIVCMD_RESTRICT
The purpose if this ioctl is to allow a user of privcmd to restrict its operation such that it will no longer service arbitrary hypercalls via IOCTL_PRIVCMD_HYPERCALL, and will check for a matching domid when servicing IOCTL_PRIVCMD_DM_OP. The aim of this is to limit the attack surface for a compromised device model. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- Cc: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx> Cc: Juergen Gross <jgross@xxxxxxxx> v2: - Make sure that a restriction cannot be cleared --- drivers/xen/privcmd.c | 67 +++++++++++++++++++++++++++++++++++++++++++--- include/uapi/xen/privcmd.h | 2 ++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index d5cf042..e372aae 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -44,16 +44,25 @@ MODULE_LICENSE("GPL"); #define PRIV_VMA_LOCKED ((void *)1) +struct privcmd_data { + domid_t domid; +}; + static int privcmd_vma_range_is_mapped( struct vm_area_struct *vma, unsigned long addr, unsigned long nr_pages); -static long privcmd_ioctl_hypercall(void __user *udata) +static long privcmd_ioctl_hypercall(struct file *file, void __user *udata) { + struct privcmd_data *data = file->private_data; struct privcmd_hypercall hypercall; long ret; + /* Disallow arbitrary hypercalls if restricted */ + if (data->domid != DOMID_INVALID) + return -EPERM; + if (copy_from_user(&hypercall, udata, sizeof(hypercall))) return -EFAULT; @@ -591,8 +600,9 @@ static void unlock_pages(struct page *pages[], unsigned int nr_pages) } } -static long privcmd_ioctl_dm_op(void __user *udata) +static long privcmd_ioctl_dm_op(struct file *file, void __user *udata) { + struct privcmd_data *data = file->private_data; struct privcmd_dm_op kdata; struct privcmd_dm_op_buf *kbufs; unsigned int nr_pages = 0; @@ -604,6 +614,10 @@ static long privcmd_ioctl_dm_op(void __user *udata) if (copy_from_user(&kdata, udata, sizeof(kdata))) return -EFAULT; + /* If restriction is in place, check the domid matches */ + if (data->domid != DOMID_INVALID && data->domid != kdata.dom) + return -EPERM; + if (kdata.num == 0) return 0; @@ -682,6 +696,23 @@ static long privcmd_ioctl_dm_op(void __user *udata) return rc; } +static long privcmd_ioctl_restrict(struct file *file, void __user *udata) +{ + struct privcmd_data *data = file->private_data; + domid_t dom; + + if (copy_from_user(&dom, udata, sizeof(dom))) + return -EFAULT; + + /* Set restriction to the specified domain, or check it matches */ + if (data->domid == DOMID_INVALID) + data->domid = dom; + else if (data->domid != dom) + return -EINVAL; + + return 0; +} + static long privcmd_ioctl(struct file *file, unsigned int cmd, unsigned long data) { @@ -690,7 +721,7 @@ static long privcmd_ioctl(struct file *file, switch (cmd) { case IOCTL_PRIVCMD_HYPERCALL: - ret = privcmd_ioctl_hypercall(udata); + ret = privcmd_ioctl_hypercall(file, udata); break; case IOCTL_PRIVCMD_MMAP: @@ -706,7 +737,11 @@ static long privcmd_ioctl(struct file *file, break; case IOCTL_PRIVCMD_DM_OP: - ret = privcmd_ioctl_dm_op(udata); + ret = privcmd_ioctl_dm_op(file, udata); + break; + + case IOCTL_PRIVCMD_RESTRICT: + ret = privcmd_ioctl_restrict(file, udata); break; default: @@ -716,6 +751,28 @@ static long privcmd_ioctl(struct file *file, return ret; } +static int privcmd_open(struct inode *ino, struct file *file) +{ + struct privcmd_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + + if (!data) + return -ENOMEM; + + /* DOMID_INVALID implies no restriction */ + data->domid = DOMID_INVALID; + + file->private_data = data; + return 0; +} + +static int privcmd_release(struct inode *ino, struct file *file) +{ + struct privcmd_data *data = file->private_data; + + kfree(data); + return 0; +} + static void privcmd_close(struct vm_area_struct *vma) { struct page **pages = vma->vm_private_data; @@ -784,6 +841,8 @@ static int privcmd_vma_range_is_mapped( const struct file_operations xen_privcmd_fops = { .owner = THIS_MODULE, .unlocked_ioctl = privcmd_ioctl, + .open = privcmd_open, + .release = privcmd_release, .mmap = privcmd_mmap, }; EXPORT_SYMBOL_GPL(xen_privcmd_fops); diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h index f8c5d75..63ee95c 100644 --- a/include/uapi/xen/privcmd.h +++ b/include/uapi/xen/privcmd.h @@ -111,5 +111,7 @@ struct privcmd_dm_op { _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2)) #define IOCTL_PRIVCMD_DM_OP \ _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op)) +#define IOCTL_PRIVCMD_RESTRICT \ + _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t)) #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |