From 1fddfc6dccb0fb435b1d9609f88ee45521dc2d03 Mon Sep 17 00:00:00 2001 From: t_jeang Date: Tue, 6 Jan 2009 12:06:04 +0000 Subject: [PATCH] Add a RESTRICT ioctl to /proc/xen/privcmd, which allows a privcommand file descriptor to be restricted to only work with one domain. Certain difficult operations, like hypercalls, are prohibited completely on restricted handles. --- drivers/xen/privcmd/privcmd.c | 52 +++++++++++++++++++++++++++++++++++ include/xen/public/privcmd.h | 6 ++++ 2 files changed, 58 insertions(+) diff --git a/drivers/xen/privcmd/privcmd.c b/drivers/xen/privcmd/privcmd.c index 845406e4..5f659567 100644 --- a/drivers/xen/privcmd/privcmd.c +++ b/drivers/xen/privcmd/privcmd.c @@ -33,6 +33,12 @@ static struct proc_dir_entry *privcmd_intf; static struct proc_dir_entry *capabilities_intf; +struct privcmd_filp_data { + domid_t restrict_domid; +}; + +#define UNRESTRICTED_DOMID ((domid_t)-1) + #ifndef HAVE_ARCH_PRIVCMD_MMAP static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); #endif @@ -42,11 +48,15 @@ static long privcmd_ioctl(struct file *file, { int ret = -ENOSYS; void __user *udata = (void __user *) data; + struct privcmd_filp_data *fdata = file->private_data; switch (cmd) { case IOCTL_PRIVCMD_HYPERCALL: { privcmd_hypercall_t hypercall; + if (fdata->restrict_domid != UNRESTRICTED_DOMID) + return -EACCES; + if (copy_from_user(&hypercall, udata, sizeof(hypercall))) return -EFAULT; @@ -110,6 +120,10 @@ static long privcmd_ioctl(struct file *file, if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) return -EFAULT; + if (fdata->restrict_domid != UNRESTRICTED_DOMID && + fdata->restrict_domid != mmapcmd.dom) + return -EACCES; + p = mmapcmd.entry; for (i = 0; i < mmapcmd.num;) { int nr = min(mmapcmd.num - i, MMAP_NR_PER_PAGE); @@ -204,6 +218,10 @@ static long privcmd_ioctl(struct file *file, if (copy_from_user(&m, udata, sizeof(m))) return -EFAULT; + if (fdata->restrict_domid != UNRESTRICTED_DOMID && + fdata->restrict_domid != m.dom) + return -EACCES; + nr_pages = m.num; if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT))) return -EINVAL; @@ -279,6 +297,20 @@ static long privcmd_ioctl(struct file *file, } break; + case IOCTL_PRIVCMD_RESTRICT_DOMID: { + privcmd_restrict_domid_t prd; + + if (fdata->restrict_domid != UNRESTRICTED_DOMID) + return -EACCES; + if (copy_from_user(&prd, udata, sizeof(prd))) + return -EFAULT; + if (prd.domid >= DOMID_FIRST_RESERVED) + return -EINVAL; + fdata->restrict_domid = prd.domid; + ret = 0; + } + break; + default: ret = -EINVAL; break; @@ -319,9 +351,29 @@ static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) } #endif +static int privcmd_open(struct inode *ino, struct file *filp) +{ + struct privcmd_filp_data *fd; + fd = kmalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) + return -ENOMEM; + fd->restrict_domid = UNRESTRICTED_DOMID; + filp->private_data = fd; + return 0; +} + +static int privcmd_release(struct inode *ino, struct file *filp) +{ + struct privcmd_filp_data *fd = filp->private_data; + kfree(fd); + return 0; +} + static const struct file_operations privcmd_file_ops = { .unlocked_ioctl = privcmd_ioctl, .mmap = privcmd_mmap, + .open = privcmd_open, + .release = privcmd_release }; static int capabilities_read(char *page, char **start, off_t off, diff --git a/include/xen/public/privcmd.h b/include/xen/public/privcmd.h index d1162eeb..1d196569 100644 --- a/include/xen/public/privcmd.h +++ b/include/xen/public/privcmd.h @@ -64,6 +64,10 @@ typedef struct privcmd_mmapbatch { xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */ } privcmd_mmapbatch_t; +typedef struct privcmd_restrict_domid { + domid_t domid; +} privcmd_restrict_domid_t; + /* * @cmd: IOCTL_PRIVCMD_HYPERCALL * @arg: &privcmd_hypercall_t @@ -75,5 +79,7 @@ typedef struct privcmd_mmapbatch { _IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t)) #define IOCTL_PRIVCMD_MMAPBATCH \ _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) +#define IOCTL_PRIVCMD_RESTRICT_DOMID \ + _IOC(_IOC_NONE, 'P', 4, sizeof(privcmd_restrict_domid_t)) #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ -- 2.39.5