Merge tag 'for-linus-4.8-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / xen / evtchn.c
index f4edd6d..e8c7f09 100644 (file)
@@ -55,6 +55,7 @@
 #include <xen/xen.h>
 #include <xen/events.h>
 #include <xen/evtchn.h>
+#include <xen/xen-ops.h>
 #include <asm/xen/hypervisor.h>
 
 struct per_user_data {
@@ -73,8 +74,12 @@ struct per_user_data {
        wait_queue_head_t evtchn_wait;
        struct fasync_struct *evtchn_async_queue;
        const char *name;
+
+       domid_t restrict_domid;
 };
 
+#define UNRESTRICTED_DOMID ((domid_t)-1)
+
 struct user_evtchn {
        struct rb_node node;
        struct per_user_data *user;
@@ -443,12 +448,16 @@ static long evtchn_ioctl(struct file *file,
                struct ioctl_evtchn_bind_virq bind;
                struct evtchn_bind_virq bind_virq;
 
+               rc = -EACCES;
+               if (u->restrict_domid != UNRESTRICTED_DOMID)
+                       break;
+
                rc = -EFAULT;
                if (copy_from_user(&bind, uarg, sizeof(bind)))
                        break;
 
                bind_virq.virq = bind.virq;
-               bind_virq.vcpu = 0;
+               bind_virq.vcpu = xen_vcpu_nr(0);
                rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
                                                 &bind_virq);
                if (rc != 0)
@@ -468,6 +477,11 @@ static long evtchn_ioctl(struct file *file,
                if (copy_from_user(&bind, uarg, sizeof(bind)))
                        break;
 
+               rc = -EACCES;
+               if (u->restrict_domid != UNRESTRICTED_DOMID &&
+                   u->restrict_domid != bind.remote_domain)
+                       break;
+
                bind_interdomain.remote_dom  = bind.remote_domain;
                bind_interdomain.remote_port = bind.remote_port;
                rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
@@ -485,6 +499,10 @@ static long evtchn_ioctl(struct file *file,
                struct ioctl_evtchn_bind_unbound_port bind;
                struct evtchn_alloc_unbound alloc_unbound;
 
+               rc = -EACCES;
+               if (u->restrict_domid != UNRESTRICTED_DOMID)
+                       break;
+
                rc = -EFAULT;
                if (copy_from_user(&bind, uarg, sizeof(bind)))
                        break;
@@ -553,6 +571,27 @@ static long evtchn_ioctl(struct file *file,
                break;
        }
 
+       case IOCTL_EVTCHN_RESTRICT_DOMID: {
+               struct ioctl_evtchn_restrict_domid ierd;
+
+               rc = -EACCES;
+               if (u->restrict_domid != UNRESTRICTED_DOMID)
+                       break;
+
+               rc = -EFAULT;
+               if (copy_from_user(&ierd, uarg, sizeof(ierd)))
+                   break;
+
+               rc = -EINVAL;
+               if (ierd.domid == 0 || ierd.domid >= DOMID_FIRST_RESERVED)
+                       break;
+
+               u->restrict_domid = ierd.domid;
+               rc = 0;
+
+               break;
+       }
+
        default:
                rc = -ENOSYS;
                break;
@@ -601,6 +640,8 @@ static int evtchn_open(struct inode *inode, struct file *filp)
        mutex_init(&u->ring_cons_mutex);
        spin_lock_init(&u->ring_prod_lock);
 
+       u->restrict_domid = UNRESTRICTED_DOMID;
+
        filp->private_data = u;
 
        return nonseekable_open(inode, filp);