aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/privcmd.c88
-rw-r--r--include/uapi/xen/privcmd.h2
2 files changed, 81 insertions, 9 deletions
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 1a6f1860e008..2077a3ac7c0c 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -56,16 +56,25 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
56MODULE_PARM_DESC(dm_op_buf_max_size, 56MODULE_PARM_DESC(dm_op_buf_max_size,
57 "Maximum size of a dm_op hypercall buffer"); 57 "Maximum size of a dm_op hypercall buffer");
58 58
59struct privcmd_data {
60 domid_t domid;
61};
62
59static int privcmd_vma_range_is_mapped( 63static int privcmd_vma_range_is_mapped(
60 struct vm_area_struct *vma, 64 struct vm_area_struct *vma,
61 unsigned long addr, 65 unsigned long addr,
62 unsigned long nr_pages); 66 unsigned long nr_pages);
63 67
64static long privcmd_ioctl_hypercall(void __user *udata) 68static long privcmd_ioctl_hypercall(struct file *file, void __user *udata)
65{ 69{
70 struct privcmd_data *data = file->private_data;
66 struct privcmd_hypercall hypercall; 71 struct privcmd_hypercall hypercall;
67 long ret; 72 long ret;
68 73
74 /* Disallow arbitrary hypercalls if restricted */
75 if (data->domid != DOMID_INVALID)
76 return -EPERM;
77
69 if (copy_from_user(&hypercall, udata, sizeof(hypercall))) 78 if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
70 return -EFAULT; 79 return -EFAULT;
71 80
@@ -242,8 +251,9 @@ static int mmap_gfn_range(void *data, void *state)
242 return 0; 251 return 0;
243} 252}
244 253
245static long privcmd_ioctl_mmap(void __user *udata) 254static long privcmd_ioctl_mmap(struct file *file, void __user *udata)
246{ 255{
256 struct privcmd_data *data = file->private_data;
247 struct privcmd_mmap mmapcmd; 257 struct privcmd_mmap mmapcmd;
248 struct mm_struct *mm = current->mm; 258 struct mm_struct *mm = current->mm;
249 struct vm_area_struct *vma; 259 struct vm_area_struct *vma;
@@ -258,6 +268,10 @@ static long privcmd_ioctl_mmap(void __user *udata)
258 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) 268 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
259 return -EFAULT; 269 return -EFAULT;
260 270
271 /* If restriction is in place, check the domid matches */
272 if (data->domid != DOMID_INVALID && data->domid != mmapcmd.dom)
273 return -EPERM;
274
261 rc = gather_array(&pagelist, 275 rc = gather_array(&pagelist,
262 mmapcmd.num, sizeof(struct privcmd_mmap_entry), 276 mmapcmd.num, sizeof(struct privcmd_mmap_entry),
263 mmapcmd.entry); 277 mmapcmd.entry);
@@ -429,8 +443,10 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
429 443
430static const struct vm_operations_struct privcmd_vm_ops; 444static const struct vm_operations_struct privcmd_vm_ops;
431 445
432static long privcmd_ioctl_mmap_batch(void __user *udata, int version) 446static long privcmd_ioctl_mmap_batch(
447 struct file *file, void __user *udata, int version)
433{ 448{
449 struct privcmd_data *data = file->private_data;
434 int ret; 450 int ret;
435 struct privcmd_mmapbatch_v2 m; 451 struct privcmd_mmapbatch_v2 m;
436 struct mm_struct *mm = current->mm; 452 struct mm_struct *mm = current->mm;
@@ -459,6 +475,10 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
459 return -EINVAL; 475 return -EINVAL;
460 } 476 }
461 477
478 /* If restriction is in place, check the domid matches */
479 if (data->domid != DOMID_INVALID && data->domid != m.dom)
480 return -EPERM;
481
462 nr_pages = DIV_ROUND_UP(m.num, XEN_PFN_PER_PAGE); 482 nr_pages = DIV_ROUND_UP(m.num, XEN_PFN_PER_PAGE);
463 if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT))) 483 if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
464 return -EINVAL; 484 return -EINVAL;
@@ -603,8 +623,9 @@ static void unlock_pages(struct page *pages[], unsigned int nr_pages)
603 } 623 }
604} 624}
605 625
606static long privcmd_ioctl_dm_op(void __user *udata) 626static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
607{ 627{
628 struct privcmd_data *data = file->private_data;
608 struct privcmd_dm_op kdata; 629 struct privcmd_dm_op kdata;
609 struct privcmd_dm_op_buf *kbufs; 630 struct privcmd_dm_op_buf *kbufs;
610 unsigned int nr_pages = 0; 631 unsigned int nr_pages = 0;
@@ -616,6 +637,10 @@ static long privcmd_ioctl_dm_op(void __user *udata)
616 if (copy_from_user(&kdata, udata, sizeof(kdata))) 637 if (copy_from_user(&kdata, udata, sizeof(kdata)))
617 return -EFAULT; 638 return -EFAULT;
618 639
640 /* If restriction is in place, check the domid matches */
641 if (data->domid != DOMID_INVALID && data->domid != kdata.dom)
642 return -EPERM;
643
619 if (kdata.num == 0) 644 if (kdata.num == 0)
620 return 0; 645 return 0;
621 646
@@ -683,6 +708,23 @@ out:
683 return rc; 708 return rc;
684} 709}
685 710
711static long privcmd_ioctl_restrict(struct file *file, void __user *udata)
712{
713 struct privcmd_data *data = file->private_data;
714 domid_t dom;
715
716 if (copy_from_user(&dom, udata, sizeof(dom)))
717 return -EFAULT;
718
719 /* Set restriction to the specified domain, or check it matches */
720 if (data->domid == DOMID_INVALID)
721 data->domid = dom;
722 else if (data->domid != dom)
723 return -EINVAL;
724
725 return 0;
726}
727
686static long privcmd_ioctl(struct file *file, 728static long privcmd_ioctl(struct file *file,
687 unsigned int cmd, unsigned long data) 729 unsigned int cmd, unsigned long data)
688{ 730{
@@ -691,23 +733,27 @@ static long privcmd_ioctl(struct file *file,
691 733
692 switch (cmd) { 734 switch (cmd) {
693 case IOCTL_PRIVCMD_HYPERCALL: 735 case IOCTL_PRIVCMD_HYPERCALL:
694 ret = privcmd_ioctl_hypercall(udata); 736 ret = privcmd_ioctl_hypercall(file, udata);
695 break; 737 break;
696 738
697 case IOCTL_PRIVCMD_MMAP: 739 case IOCTL_PRIVCMD_MMAP:
698 ret = privcmd_ioctl_mmap(udata); 740 ret = privcmd_ioctl_mmap(file, udata);
699 break; 741 break;
700 742
701 case IOCTL_PRIVCMD_MMAPBATCH: 743 case IOCTL_PRIVCMD_MMAPBATCH:
702 ret = privcmd_ioctl_mmap_batch(udata, 1); 744 ret = privcmd_ioctl_mmap_batch(file, udata, 1);
703 break; 745 break;
704 746
705 case IOCTL_PRIVCMD_MMAPBATCH_V2: 747 case IOCTL_PRIVCMD_MMAPBATCH_V2:
706 ret = privcmd_ioctl_mmap_batch(udata, 2); 748 ret = privcmd_ioctl_mmap_batch(file, udata, 2);
707 break; 749 break;
708 750
709 case IOCTL_PRIVCMD_DM_OP: 751 case IOCTL_PRIVCMD_DM_OP:
710 ret = privcmd_ioctl_dm_op(udata); 752 ret = privcmd_ioctl_dm_op(file, udata);
753 break;
754
755 case IOCTL_PRIVCMD_RESTRICT:
756 ret = privcmd_ioctl_restrict(file, udata);
711 break; 757 break;
712 758
713 default: 759 default:
@@ -717,6 +763,28 @@ static long privcmd_ioctl(struct file *file,
717 return ret; 763 return ret;
718} 764}
719 765
766static int privcmd_open(struct inode *ino, struct file *file)
767{
768 struct privcmd_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
769
770 if (!data)
771 return -ENOMEM;
772
773 /* DOMID_INVALID implies no restriction */
774 data->domid = DOMID_INVALID;
775
776 file->private_data = data;
777 return 0;
778}
779
780static int privcmd_release(struct inode *ino, struct file *file)
781{
782 struct privcmd_data *data = file->private_data;
783
784 kfree(data);
785 return 0;
786}
787
720static void privcmd_close(struct vm_area_struct *vma) 788static void privcmd_close(struct vm_area_struct *vma)
721{ 789{
722 struct page **pages = vma->vm_private_data; 790 struct page **pages = vma->vm_private_data;
@@ -785,6 +853,8 @@ static int privcmd_vma_range_is_mapped(
785const struct file_operations xen_privcmd_fops = { 853const struct file_operations xen_privcmd_fops = {
786 .owner = THIS_MODULE, 854 .owner = THIS_MODULE,
787 .unlocked_ioctl = privcmd_ioctl, 855 .unlocked_ioctl = privcmd_ioctl,
856 .open = privcmd_open,
857 .release = privcmd_release,
788 .mmap = privcmd_mmap, 858 .mmap = privcmd_mmap,
789}; 859};
790EXPORT_SYMBOL_GPL(xen_privcmd_fops); 860EXPORT_SYMBOL_GPL(xen_privcmd_fops);
diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h
index f8c5d75b99e1..63ee95c9dabb 100644
--- a/include/uapi/xen/privcmd.h
+++ b/include/uapi/xen/privcmd.h
@@ -111,5 +111,7 @@ struct privcmd_dm_op {
111 _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2)) 111 _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
112#define IOCTL_PRIVCMD_DM_OP \ 112#define IOCTL_PRIVCMD_DM_OP \
113 _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op)) 113 _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op))
114#define IOCTL_PRIVCMD_RESTRICT \
115 _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t))
114 116
115#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ 117#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */