diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-01-23 13:21:44 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-01-23 13:21:44 +0000 |
commit | 47fcfcb75b5d5ece1bba1aeca8e2d99b0103d6c4 (patch) | |
tree | 7f798956328c11549823567152ffb71698fc062b | |
parent | d352a2fb4de6720cc11376bebf3ced95f4f18c17 (diff) | |
download | xen-47fcfcb75b5d5ece1bba1aeca8e2d99b0103d6c4.tar.gz xen-47fcfcb75b5d5ece1bba1aeca8e2d99b0103d6c4.tar.bz2 xen-47fcfcb75b5d5ece1bba1aeca8e2d99b0103d6c4.zip |
New XEN_DOMCTL_set_target
Stubdomains (and probably other domain disagregation elements too)
need to be able to tinker with another domain. This adds IS_PRIV_FOR
that extends IS_PRIV by allowing domains to have privileges over a
given "target" domain. XEN_DOMCTL_set_target permits to set this
"target". A new 'target' configuration option makes the domain builder
use it.
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
-rw-r--r-- | tools/libxc/xc_domain.c | 14 | ||||
-rw-r--r-- | tools/libxc/xenctrl.h | 5 | ||||
-rw-r--r-- | tools/python/xen/lowlevel/xc/xc.c | 13 | ||||
-rw-r--r-- | tools/python/xen/xend/XendConfig.py | 7 | ||||
-rw-r--r-- | tools/python/xen/xend/XendDomainInfo.py | 3 | ||||
-rw-r--r-- | tools/python/xen/xm/create.py | 6 | ||||
-rw-r--r-- | xen/arch/ia64/vmx/vmx_hypercall.c | 22 | ||||
-rw-r--r-- | xen/arch/ia64/xen/dom0_ops.c | 46 | ||||
-rw-r--r-- | xen/arch/ia64/xen/hypercall.c | 7 | ||||
-rw-r--r-- | xen/arch/ia64/xen/mm.c | 12 | ||||
-rw-r--r-- | xen/arch/ia64/xen/xensetup.c | 1 | ||||
-rw-r--r-- | xen/arch/powerpc/setup.c | 1 | ||||
-rw-r--r-- | xen/arch/x86/hvm/hvm.c | 34 | ||||
-rw-r--r-- | xen/arch/x86/mm.c | 74 | ||||
-rw-r--r-- | xen/arch/x86/mm/shadow/multi.c | 4 | ||||
-rw-r--r-- | xen/arch/x86/setup.c | 1 | ||||
-rw-r--r-- | xen/common/domain.c | 3 | ||||
-rw-r--r-- | xen/common/domctl.c | 173 | ||||
-rw-r--r-- | xen/common/event_channel.c | 58 | ||||
-rw-r--r-- | xen/common/grant_table.c | 54 | ||||
-rw-r--r-- | xen/common/memory.c | 40 | ||||
-rw-r--r-- | xen/common/schedule.c | 9 | ||||
-rw-r--r-- | xen/include/public/domctl.h | 12 | ||||
-rw-r--r-- | xen/include/xen/sched.h | 3 | ||||
-rw-r--r-- | xen/xsm/acm/acm_simple_type_enforcement_hooks.c | 10 |
25 files changed, 426 insertions, 186 deletions
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 8be00d1ab6..f75955c577 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -875,6 +875,20 @@ int xc_domain_ioport_mapping( return do_domctl(xc_handle, &domctl); } +int xc_domain_set_target( + int xc_handle, + uint32_t domid, + uint32_t target) +{ + DECLARE_DOMCTL; + + domctl.cmd = XEN_DOMCTL_set_target; + domctl.domain = domid; + domctl.u.set_target.target = target; + + return do_domctl(xc_handle, &domctl); +} + /* * Local variables: * mode: C diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index d9c6bace54..f6778dd946 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -952,4 +952,9 @@ int xc_domain_bind_pt_isa_irq(int xc_handle, uint32_t domid, uint8_t machine_irq); +/* Set the target domain */ +int xc_domain_set_target(int xc_handle, + uint32_t domid, + uint32_t target); + #endif /* XENCTRL_H */ diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 1f1421e487..29a1bc0fd2 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -96,17 +96,17 @@ static PyObject *pyxc_domain_create(XcObject *self, PyObject *args, PyObject *kwds) { - uint32_t dom = 0, ssidref = 0, flags = 0; + uint32_t dom = 0, ssidref = 0, flags = 0, target = 0; int ret, i, hvm = 0; PyObject *pyhandle = NULL; xen_domain_handle_t handle = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef }; - static char *kwd_list[] = { "domid", "ssidref", "handle", "hvm", NULL }; + static char *kwd_list[] = { "domid", "ssidref", "handle", "hvm", "target", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiOi", kwd_list, - &dom, &ssidref, &pyhandle, &hvm)) + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiOii", kwd_list, + &dom, &ssidref, &pyhandle, &hvm, &target)) return NULL; if ( pyhandle != NULL ) @@ -131,6 +131,11 @@ static PyObject *pyxc_domain_create(XcObject *self, handle, flags, &dom)) < 0 ) return pyxc_error_to_exception(); + if ( target ) + if ( (ret = xc_domain_set_target(self->xc_handle, dom, target)) < 0 ) + return pyxc_error_to_exception(); + + return PyInt_FromLong(dom); out_exception: diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 0e970b6293..67803517eb 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -170,6 +170,7 @@ XENAPI_CFG_TYPES = { 'platform': dict, 'tools_version': dict, 'other_config': dict, + 'target': int, 'security_label': str, 'pci': str, } @@ -336,7 +337,8 @@ class XendConfig(dict): 'vbd_refs': [], 'vtpm_refs': [], 'other_config': {}, - 'platform': {} + 'platform': {}, + 'target': 0, } return defaults @@ -1585,6 +1587,9 @@ class XendConfig(dict): def is_hvm(self): return self['HVM_boot_policy'] != '' + def target(self): + return self['target'] + def image_type(self): stored_type = self['platform'].get('image_type') return stored_type or (self.is_hvm() and 'hvm' or 'linux') diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 052258ec55..38d276748a 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1640,7 +1640,8 @@ class XendDomainInfo: domid = 0, ssidref = ssidref, handle = uuid.fromString(self.info['uuid']), - hvm = int(hvm)) + hvm = int(hvm), + target = self.info.target()) except Exception, e: # may get here if due to ACM the operation is not permitted if security.on(): diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 440b7d4fe9..b201c548db 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -521,6 +521,10 @@ gopts.var('on_xend_stop', val='ignore|shutdown|suspend', - suspend: Domain is suspended; """) +gopts.var('target', val='TARGET', + fn=set_int, default=0, + use="Set domain target.") + def err(msg): """Print an error to stderr and exit. """ @@ -748,7 +752,7 @@ def make_config(vals): map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory', 'restart', 'on_poweroff', 'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features', - 'on_xend_start', 'on_xend_stop']) + 'on_xend_start', 'on_xend_stop', 'target']) if vals.uuid is not None: config.append(['uuid', vals.uuid]) diff --git a/xen/arch/ia64/vmx/vmx_hypercall.c b/xen/arch/ia64/vmx/vmx_hypercall.c index 5f79cb59d1..b9c5b52568 100644 --- a/xen/arch/ia64/vmx/vmx_hypercall.c +++ b/xen/arch/ia64/vmx/vmx_hypercall.c @@ -47,9 +47,6 @@ static int hvmop_set_isa_irq_level( if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( op.isa_irq > 15 ) return -EINVAL; @@ -57,6 +54,10 @@ static int hvmop_set_isa_irq_level( if ( d == NULL ) return -ESRCH; + rc = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto out; + rc = -EINVAL; if ( !is_hvm_domain(d) ) goto out; @@ -79,9 +80,6 @@ static int hvmop_set_pci_intx_level( if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( (op.domain > 0) || (op.bus > 0) || (op.device > 31) || (op.intx > 3) ) return -EINVAL; @@ -89,6 +87,10 @@ static int hvmop_set_pci_intx_level( if ( d == NULL ) return -ESRCH; + rc = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto out; + rc = -EINVAL; if ( !is_hvm_domain(d) ) goto out; @@ -124,13 +126,15 @@ do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if (a.domid == DOMID_SELF) { d = rcu_lock_current_domain(); } - else if (IS_PRIV(current->domain)) { + else { d = rcu_lock_domain_by_id(a.domid); if (d == NULL) return -ESRCH; + if (!IS_PRIV_FOR(current->domain, d)) { + rcu_unlock_domain(d); + return -EPERM; + } } - else - return -EPERM; if (op == HVMOP_set_param) { struct vmx_ioreq_page *iorp; diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index 85f8eaf7ee..525ed28d54 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -37,9 +37,6 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) { long ret = 0; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - switch ( op->cmd ) { case XEN_DOMCTL_getmemlist: @@ -54,6 +51,13 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = -EINVAL; break; } + + if ( !IS_PRIV_FOR(current->domain, d) ) { + ret = -EPERM; + rcu_unlock_domain(d); + break; + } + for (i = 0 ; i < nr_pages ; i++) { pte_t *pte; @@ -87,6 +91,12 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) break; } + if ( !IS_PRIV_FOR(current->domain, d) ) { + ret = -EPERM; + rcu_unlock_domain(d); + break; + } + if (ds->flags & XEN_DOMAINSETUP_query) { /* Set flags. */ if (is_hvm_domain(d)) @@ -153,6 +163,12 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) d = rcu_lock_domain_by_id(op->domain); if ( d != NULL ) { + if ( !IS_PRIV_FOR(current->domain, d) ) { + ret = -EPERM; + rcu_unlock_domain(d); + break; + } + ret = shadow_mode_control(d, &op->u.shadow_op); rcu_unlock_domain(d); if (copy_to_guest(u_domctl, op, 1)) @@ -173,6 +189,12 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if (unlikely(d == NULL)) break; + if ( !IS_PRIV_FOR(current->domain, d) ) { + ret = -EPERM; + rcu_unlock_domain(d); + break; + } + if (np == 0) ret = 0; else { @@ -196,6 +218,11 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) { + goto sendtrigger_out; + } + ret = -EINVAL; if ( op->u.sendtrigger.vcpu >= MAX_VIRT_CPUS ) goto sendtrigger_out; @@ -239,6 +266,10 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if (d == NULL) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto sethvmcontext_out; + #ifdef CONFIG_X86 ret = xsm_hvmcontext(d, op->cmd); if (ret) @@ -280,6 +311,10 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if (d == NULL) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto gethvmcontext_out; + #ifdef CONFIG_X86 ret = xsm_hvmcontext(d, op->cmd); if (ret) @@ -341,7 +376,10 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) break; } - ret = domain_opt_feature(d, optf); + ret = -EPERM; + if ( IS_PRIV_FOR(current->domain, d) ) + ret = domain_opt_feature(d, optf); + rcu_unlock_domain(d); } break; diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index c2879f7c9a..9ef8ca8de1 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -500,13 +500,15 @@ do_ia64_debug_op(unsigned long cmd, unsigned long domain, struct domain *d; long ret = 0; - if (!IS_PRIV(current->domain)) - return -EPERM; if (copy_from_guest(op, u_debug_op, 1)) return -EFAULT; d = rcu_lock_domain_by_id(domain); if (d == NULL) return -ESRCH; + if (!IS_PRIV_FOR(current->domain, d)) { + ret = -EPERM; + goto out; + } switch (cmd) { case XEN_IA64_DEBUG_OP_SET_FLAGS: @@ -520,6 +522,7 @@ do_ia64_debug_op(unsigned long cmd, unsigned long domain, default: ret = -ENOSYS; } +out: rcu_unlock_domain(d); return ret; } diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 9c80393372..782d12ae97 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -2787,10 +2787,14 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) if (xatp.domid == DOMID_SELF) d = rcu_lock_current_domain(); - else if (!IS_PRIV(current->domain)) - return -EPERM; - else if ((d = rcu_lock_domain_by_id(xatp.domid)) == NULL) - return -ESRCH; + else { + if ((d = rcu_lock_domain_by_id(xatp.domid)) == NULL) + return -ESRCH; + if (!IS_PRIV_FOR(current->domain,d)) { + rcu_lock_domain(d); + return -EPERM; + } + } /* This hypercall is used for VT-i domain only */ if (!VMX_DOMAIN(d->vcpu[0])) { diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index ede498abab..fb806af049 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -642,6 +642,7 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); panic("Cannot allocate dom0 vcpu 0\n"); dom0->is_privileged = 1; + dom0->target = NULL; /* * We're going to setup domain0 using the module(s) that we stashed safely diff --git a/xen/arch/powerpc/setup.c b/xen/arch/powerpc/setup.c index 6abf10cf17..7f2f5d2572 100644 --- a/xen/arch/powerpc/setup.c +++ b/xen/arch/powerpc/setup.c @@ -375,6 +375,7 @@ static void __init __start_xen(void) dom0->vcpu[0]->cpu_affinity = cpumask_of_cpu(0); dom0->is_privileged = 1; + dom0->target = NULL; /* scrub_heap_pages() requires IRQs enabled, and we're post IRQ setup... */ local_irq_enable(); diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index c812982140..9f88fd0cdd 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1740,9 +1740,6 @@ static int hvmop_set_pci_intx_level( if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( (op.domain > 0) || (op.bus > 0) || (op.device > 31) || (op.intx > 3) ) return -EINVAL; @@ -1750,6 +1747,10 @@ static int hvmop_set_pci_intx_level( if ( d == NULL ) return -ESRCH; + rc = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto out; + rc = -EINVAL; if ( !is_hvm_domain(d) ) goto out; @@ -1787,9 +1788,6 @@ static int hvmop_set_isa_irq_level( if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( op.isa_irq > 15 ) return -EINVAL; @@ -1797,6 +1795,10 @@ static int hvmop_set_isa_irq_level( if ( d == NULL ) return -ESRCH; + rc = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto out; + rc = -EINVAL; if ( !is_hvm_domain(d) ) goto out; @@ -1834,9 +1836,6 @@ static int hvmop_set_pci_link_route( if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( (op.link > 3) || (op.isa_irq > 15) ) return -EINVAL; @@ -1844,6 +1843,10 @@ static int hvmop_set_pci_link_route( if ( d == NULL ) return -ESRCH; + rc = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto out; + rc = -EINVAL; if ( !is_hvm_domain(d) ) goto out; @@ -1921,13 +1924,16 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( a.domid == DOMID_SELF ) d = rcu_lock_current_domain(); - else if ( IS_PRIV(current->domain) ) + else { d = rcu_lock_domain_by_id(a.domid); - else - return -EPERM; + if ( d == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rc = -EPERM; + goto param_fail; + } + } - if ( d == NULL ) - return -ESRCH; rc = -EINVAL; if ( !is_hvm_domain(d) ) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index baea82118b..efd077ae6d 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2056,38 +2056,35 @@ static int set_foreigndom(domid_t domid) MEM_LOG("Cannot mix foreign mappings with translated domains"); okay = 0; } - else if ( !IS_PRIV(d) ) + else switch ( domid ) { - switch ( domid ) - { - case DOMID_IO: - info->foreign = rcu_lock_domain(dom_io); - break; - default: + case DOMID_IO: + info->foreign = rcu_lock_domain(dom_io); + break; + case DOMID_XEN: + if (!IS_PRIV(d)) { MEM_LOG("Cannot set foreign dom"); okay = 0; break; } - } - else - { - info->foreign = e = rcu_lock_domain_by_id(domid); + info->foreign = rcu_lock_domain(dom_xen); + break; + default: + e = rcu_lock_domain_by_id(domid); if ( e == NULL ) { - switch ( domid ) - { - case DOMID_XEN: - info->foreign = rcu_lock_domain(dom_xen); - break; - case DOMID_IO: - info->foreign = rcu_lock_domain(dom_io); - break; - default: - MEM_LOG("Unknown domain '%u'", domid); - okay = 0; - break; - } + MEM_LOG("Unknown domain '%u'", domid); + okay = 0; + break; + } + if (!IS_PRIV_FOR(d, e)) { + MEM_LOG("Cannot set foreign dom"); + okay = 0; + rcu_unlock_domain(e); + break; } + info->foreign = e; + break; } out: @@ -3043,9 +3040,6 @@ int do_update_va_mapping_otherdomain(unsigned long va, u64 val64, { int rc; - if ( unlikely(!IS_PRIV(current->domain)) ) - return -EPERM; - if ( !set_foreigndom(domid) ) return -ESRCH; @@ -3222,10 +3216,15 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) if ( xatp.domid == DOMID_SELF ) d = rcu_lock_current_domain(); - else if ( !IS_PRIV(current->domain) ) - return -EPERM; - else if ( (d = rcu_lock_domain_by_id(xatp.domid)) == NULL ) - return -ESRCH; + else { + d = rcu_lock_domain_by_id(xatp.domid); + if ( d == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rcu_unlock_domain(d); + return -EPERM; + } + } if ( xsm_add_to_physmap(current->domain, d) ) { @@ -3313,10 +3312,15 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) if ( fmap.domid == DOMID_SELF ) d = rcu_lock_current_domain(); - else if ( !IS_PRIV(current->domain) ) - return -EPERM; - else if ( (d = rcu_lock_domain_by_id(fmap.domid)) == NULL ) - return -ESRCH; + else { + d = rcu_lock_domain_by_id(fmap.domid); + if ( d == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rcu_unlock_domain(d); + return -EPERM; + } + } rc = xsm_domain_memory_map(d); if ( rc ) diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 1c4e7fad70..5a460d9de2 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -993,11 +993,11 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d) // not own, we let it succeed anyway. // if ( unlikely(!res) && - IS_PRIV(d) && !shadow_mode_translate(d) && mfn_valid(mfn = shadow_l1e_get_mfn(sl1e)) && (owner = page_get_owner(mfn_to_page(mfn))) && - (d != owner) ) + (d != owner) && + IS_PRIV_FOR(d, owner)) { res = get_page_from_l1e(sl1e, owner); SHADOW_PRINTK("privileged domain %d installs map of mfn %05lx " diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 095ee91116..031feb12a2 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -959,6 +959,7 @@ void __init __start_xen(unsigned long mbi_p) panic("Error creating domain 0\n"); dom0->is_privileged = 1; + dom0->target = NULL; /* Grab the DOM0 command line. */ cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL); diff --git a/xen/common/domain.c b/xen/common/domain.c index 6c26363c65..a888d88d79 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -502,6 +502,9 @@ static void complete_domain_destroy(struct rcu_head *head) if ( (v = d->vcpu[i]) != NULL ) free_vcpu_struct(v); + if (d->target) + put_domain(d->target); + free_domain(d); send_guest_global_virq(dom0, VIRQ_DOM_EXC); diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 3f87a73c84..83d191d93a 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -182,9 +182,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) struct xen_domctl curop, *op = &curop; static DEFINE_SPINLOCK(domctl_lock); - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( copy_from_guest(op, u_domctl, 1) ) return -EFAULT; @@ -207,6 +204,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto svc_out; + ret = xsm_setvcpucontext(d); if ( ret ) goto svc_out; @@ -258,6 +259,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = -ESRCH; if ( d != NULL ) { + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto pausedomain_out; + ret = xsm_pausedomain(d); if ( ret ) goto pausedomain_out; @@ -282,16 +287,18 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto unpausedomain_out; + ret = xsm_unpausedomain(d); if ( ret ) - { - rcu_unlock_domain(d); - break; - } + goto unpausedomain_out; domain_unpause_by_systemcontroller(d); - rcu_unlock_domain(d); ret = 0; +unpausedomain_out: + rcu_unlock_domain(d); } break; @@ -303,16 +310,18 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto resumedomain_out; + ret = xsm_resumedomain(d); if ( ret ) - { - rcu_unlock_domain(d); - break; - } + goto resumedomain_out; domain_resume(d); - rcu_unlock_domain(d); ret = 0; +resumedomain_out: + rcu_unlock_domain(d); } break; @@ -323,6 +332,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) static domid_t rover = 0; unsigned int domcr_flags; + ret = -EPERM; + if ( !IS_PRIV(current->domain) ) + break; + ret = -EINVAL; if ( supervisor_mode_kernel || (op->u.createdomain.flags & ~XEN_DOMCTL_CDF_hvm_guest) ) @@ -385,12 +398,13 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto maxvcpu_out2; + ret = xsm_max_vcpus(d); if ( ret ) - { - rcu_unlock_domain(d); - break; - } + goto maxvcpu_out2; /* Needed, for example, to ensure writable p.t. state is synced. */ domain_pause(d); @@ -418,6 +432,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) maxvcpu_out: domain_unpause(d); + maxvcpu_out2: rcu_unlock_domain(d); } break; @@ -428,7 +443,9 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = -ESRCH; if ( d != NULL ) { - ret = xsm_destroydomain(d) ? : domain_kill(d); + ret = -EPERM; + if ( IS_PRIV_FOR(current->domain, d) ) + ret = xsm_destroydomain(d) ? : domain_kill(d); rcu_unlock_domain(d); } } @@ -446,6 +463,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto vcpuaffinity_out; + ret = xsm_vcpuaffinity(op->cmd, d); if ( ret ) goto vcpuaffinity_out; @@ -484,6 +505,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto scheduler_op_out; + ret = xsm_scheduler(d); if ( ret ) goto scheduler_op_out; @@ -505,7 +530,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) rcu_read_lock(&domlist_read_lock); for_each_domain ( d ) - if ( d->domain_id >= dom ) + if ( d->domain_id >= dom && IS_PRIV_FOR(current->domain, d)) break; if ( d == NULL ) @@ -540,6 +565,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto getvcpucontext_out; + ret = xsm_getvcpucontext(d); if ( ret ) goto getvcpucontext_out; @@ -600,6 +629,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto getvcpuinfo_out; + ret = xsm_getvcpuinfo(d); if ( ret ) goto getvcpuinfo_out; @@ -639,6 +672,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto max_mem_out; + ret = xsm_setdomainmaxmem(d); if ( ret ) goto max_mem_out; @@ -655,6 +692,8 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) d->max_pages = new_max; ret = 0; } + else + printk("new max %ld, tot pages %d\n", new_max, d->tot_pages); spin_unlock(&d->page_alloc_lock); max_mem_out: @@ -671,17 +710,19 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto setdomainhandle_out; + ret = xsm_setdomainhandle(d); if ( ret ) - { - rcu_unlock_domain(d); - break; - } + goto setdomainhandle_out; memcpy(d->handle, op->u.setdomainhandle.handle, sizeof(xen_domain_handle_t)); - rcu_unlock_domain(d); ret = 0; +setdomainhandle_out: + rcu_unlock_domain(d); } break; @@ -694,18 +735,20 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto setdebugging_out; + ret = xsm_setdebugging(d); if ( ret ) - { - rcu_unlock_domain(d); - break; - } + goto setdebugging_out; domain_pause(d); d->debugger_attached = !!op->u.setdebugging.enable; domain_unpause(d); /* causes guest to latch new status */ - rcu_unlock_domain(d); ret = 0; +setdebugging_out: + rcu_unlock_domain(d); } break; @@ -723,6 +766,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto irq_permission_out; + ret = xsm_irq_permission(d, pirq, op->u.irq_permission.allow_access); if ( ret ) goto irq_permission_out; @@ -752,6 +799,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto iomem_permission_out; + ret = xsm_iomem_permission(d, mfn, op->u.iomem_permission.allow_access); if ( ret ) goto iomem_permission_out; @@ -772,19 +823,61 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = -ESRCH; d = rcu_lock_domain_by_id(op->domain); - if ( d != NULL ) - { - ret = xsm_domain_settime(d); - if ( ret ) - { - rcu_unlock_domain(d); - break; - } + if ( d == NULL ) + break; - d->time_offset_seconds = op->u.settimeoffset.time_offset_seconds; - rcu_unlock_domain(d); - ret = 0; + ret = -EPERM; + if ( !IS_PRIV_FOR(current->domain, d) ) + goto settimeoffset_out; + + ret = xsm_domain_settime(d); + if ( ret ) + goto settimeoffset_out; + + d->time_offset_seconds = op->u.settimeoffset.time_offset_seconds; + + ret = 0; +settimeoffset_out: + rcu_unlock_domain(d); + } + break; + + case XEN_DOMCTL_set_target: + { + struct domain *d, *e; + + ret = -ESRCH; + d = rcu_lock_domain_by_id(op->domain); + if ( d == NULL ) + break; + + ret = -EPERM; + if (!IS_PRIV_FOR(current->domain, d)) + goto set_target_out; + + ret = -ESRCH; + e = get_domain_by_id(op->u.set_target.target); + if ( e == NULL ) + goto set_target_out; + + if ( d == e ) { + ret = -EINVAL; + put_domain(e); + goto set_target_out; } + + if (!IS_PRIV_FOR(current->domain, e)) { + ret = -EPERM; + put_domain(e); + goto set_target_out; + } + + d->target = e; + /* and we keep the reference on e, released when destroying d */ + ret = 0; + +set_target_out: + rcu_unlock_domain(d); } break; diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 3a82e7c6aa..7777822fb6 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -130,12 +130,15 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc) long rc; if ( dom == DOMID_SELF ) - dom = current->domain->domain_id; - else if ( !IS_PRIV(current->domain) ) - return -EPERM; - - if ( (d = rcu_lock_domain_by_id(dom)) == NULL ) - return -ESRCH; + d = current->domain; + else { + if ( (d = rcu_lock_domain_by_id(dom)) == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rc = -EPERM; + goto out2; + } + } spin_lock(&d->evtchn_lock); @@ -156,6 +159,7 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc) out: spin_unlock(&d->evtchn_lock); + out2: rcu_unlock_domain(d); return rc; @@ -197,7 +201,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) ERROR_EXIT_DOM(-EINVAL, rd); rchn = evtchn_from_port(rd, rport); if ( (rchn->state != ECS_UNBOUND) || - (rchn->u.unbound.remote_domid != ld->domain_id) ) + (rchn->u.unbound.remote_domid != ld->domain_id && !IS_PRIV_FOR(ld, rd))) ERROR_EXIT_DOM(-EINVAL, rd); rc = xsm_evtchn_interdomain(ld, lchn, rd, rchn); @@ -628,12 +632,15 @@ static long evtchn_status(evtchn_status_t *status) long rc = 0; if ( dom == DOMID_SELF ) - dom = current->domain->domain_id; - else if ( !IS_PRIV(current->domain) ) - return -EPERM; - - if ( (d = rcu_lock_domain_by_id(dom)) == NULL ) - return -ESRCH; + d = current->domain; + else { + if ( (d = rcu_lock_domain_by_id(dom)) == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rc = -EPERM; + goto out2; + } + } spin_lock(&d->evtchn_lock); @@ -684,6 +691,7 @@ static long evtchn_status(evtchn_status_t *status) out: spin_unlock(&d->evtchn_lock); + out2: rcu_unlock_domain(d); return rc; } @@ -782,26 +790,28 @@ static long evtchn_reset(evtchn_reset_t *r) int rc; if ( dom == DOMID_SELF ) - dom = current->domain->domain_id; - else if ( !IS_PRIV(current->domain) ) - return -EPERM; - - if ( (d = rcu_lock_domain_by_id(dom)) == NULL ) - return -ESRCH; + d = current->domain; + else { + if ( (d = rcu_lock_domain_by_id(dom)) == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rc = -EPERM; + goto out; + } + } rc = xsm_evtchn_reset(current->domain, d); if ( rc ) - { - rcu_unlock_domain(d); - return rc; - } + goto out; for ( i = 0; port_is_valid(d, i); i++ ) (void)__evtchn_close(d, i); + rc = 0; +out: rcu_unlock_domain(d); - return 0; + return rc; } diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 7aaad6417c..6f402832f5 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -834,19 +834,19 @@ gnttab_setup_table( dom = op.dom; if ( dom == DOMID_SELF ) { - dom = current->domain->domain_id; + d = current->domain; } - else if ( unlikely(!IS_PRIV(current->domain)) ) - { - op.status = GNTST_permission_denied; - goto out; - } - - if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) - { - gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); - op.status = GNTST_bad_domain; - goto out; + else { + if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) + { + gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); + op.status = GNTST_bad_domain; + goto out; + } + if ( unlikely(!IS_PRIV_FOR(current->domain, d)) ) { + op.status = GNTST_permission_denied; + goto setup_unlock_out2; + } } if ( xsm_grant_setup(current->domain, d) ) @@ -880,6 +880,7 @@ gnttab_setup_table( setup_unlock_out: spin_unlock(&d->grant_table->lock); + setup_unlock_out2: rcu_unlock_domain(d); out: @@ -910,27 +911,26 @@ gnttab_query_size( dom = op.dom; if ( dom == DOMID_SELF ) { - dom = current->domain->domain_id; + d = current->domain; } - else if ( unlikely(!IS_PRIV(current->domain)) ) - { - op.status = GNTST_permission_denied; - goto query_out; - } - - if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) - { - gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); - op.status = GNTST_bad_domain; - goto query_out; + else { + if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) + { + gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); + op.status = GNTST_bad_domain; + goto query_out; + } + if ( unlikely(!IS_PRIV_FOR(current->domain, d)) ) { + op.status = GNTST_permission_denied; + goto query_out_unlock; + } } rc = xsm_grant_query_size(current->domain, d); if ( rc ) { - rcu_unlock_domain(d); op.status = GNTST_permission_denied; - goto query_out; + goto query_out_unlock; } spin_lock(&d->grant_table->lock); @@ -941,6 +941,8 @@ gnttab_query_size( spin_unlock(&d->grant_table->lock); + + query_out_unlock: rcu_unlock_domain(d); query_out: diff --git a/xen/common/memory.c b/xen/common/memory.c index 849e2c1cd8..a3c2ad65e6 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -232,12 +232,17 @@ static long translate_gpfn_list( return -EFAULT; if ( op.domid == DOMID_SELF ) - op.domid = current->domain->domain_id; - else if ( !IS_PRIV(current->domain) ) - return -EPERM; + d = current->domain; + else { + d = rcu_lock_domain_by_id(op.domid); + if ( d == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rcu_unlock_domain(d); + return -EPERM; + } + } - if ( (d = rcu_lock_domain_by_id(op.domid)) == NULL ) - return -ESRCH; if ( !paging_mode_translate(d) ) { @@ -535,9 +540,15 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( likely(reservation.domid == DOMID_SELF) ) d = current->domain; - else if ( !IS_PRIV(current->domain) || - ((d = rcu_lock_domain_by_id(reservation.domid)) == NULL) ) - return start_extent; + else { + d = rcu_lock_domain_by_id(reservation.domid); + if ( d == NULL) + return start_extent; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rcu_unlock_domain(d); + return start_extent; + } + } args.domain = d; rc = xsm_memory_adjust_reservation(current->domain, d); @@ -589,10 +600,15 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( likely(domid == DOMID_SELF) ) d = current->domain; - else if ( !IS_PRIV(current->domain) ) - return -EPERM; - else if ( (d = rcu_lock_domain_by_id(domid)) == NULL ) - return -ESRCH; + else { + d = rcu_lock_domain_by_id(domid); + if ( d == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) { + rcu_unlock_domain(d); + return -EPERM; + } + } rc = xsm_memory_stat_reservation(current->domain, d); if ( rc ) diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 9c70b97030..8af024f2de 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -461,9 +461,6 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE(void) arg) struct domain *d; struct sched_remote_shutdown sched_remote_shutdown; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - ret = -EFAULT; if ( copy_from_guest(&sched_remote_shutdown, arg, 1) ) break; @@ -473,6 +470,12 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE(void) arg) if ( d == NULL ) break; + if ( !IS_PRIV_FOR(current->domain, d) ) + { + rcu_unlock_domain(d); + return -EPERM; + } + ret = xsm_schedop_shutdown(current->domain, d); if ( ret ) { diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index a0d3673af8..99822e3d46 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -554,6 +554,17 @@ struct xen_domctl_set_opt_feature { typedef struct xen_domctl_set_opt_feature xen_domctl_set_opt_feature_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_opt_feature_t); +/* + * Set the target domain for a domain + */ +#define XEN_DOMCTL_set_target 46 +struct xen_domctl_set_target { + domid_t target; +}; +typedef struct xen_domctl_set_target xen_domctl_set_target_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_target_t); + + struct xen_domctl { uint32_t cmd; uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */ @@ -590,6 +601,7 @@ struct xen_domctl { struct xen_domctl_pin_mem_cacheattr pin_mem_cacheattr; struct xen_domctl_ext_vcpucontext ext_vcpucontext; struct xen_domctl_set_opt_feature set_opt_feature; + struct xen_domctl_set_target set_target; uint8_t pad[128]; } u; }; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 85cdb6e9a5..a2983aed6a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -187,6 +187,8 @@ struct domain bool_t is_hvm; /* Is this guest fully privileged (aka dom0)? */ bool_t is_privileged; + /* Which guest this guest has privileges on */ + struct domain *target; /* Is this guest being debugged by dom0? */ bool_t debugger_attached; /* Are any VCPUs polling event channels (SCHEDOP_poll)? */ @@ -493,6 +495,7 @@ static inline void vcpu_unblock(struct vcpu *v) } #define IS_PRIV(_d) ((_d)->is_privileged) +#define IS_PRIV_FOR(_d, _t) (IS_PRIV(_d) || ((_d)->target && (_d)->target == (_t))) #ifndef IS_COMPAT #define IS_COMPAT(d) 0 diff --git a/xen/xsm/acm/acm_simple_type_enforcement_hooks.c b/xen/xsm/acm/acm_simple_type_enforcement_hooks.c index 652351ab05..d58c49fcd4 100644 --- a/xen/xsm/acm/acm_simple_type_enforcement_hooks.c +++ b/xen/xsm/acm/acm_simple_type_enforcement_hooks.c @@ -817,17 +817,19 @@ ste_pre_grant_setup (domid_t id) return ACM_ACCESS_PERMITTED; } atomic_inc(&ste_bin_pol.gt_eval_count); + subj = current->domain; + obj = rcu_lock_domain_by_id(id); + /* a) check authorization (eventually use specific capabilities) */ - if ( !IS_PRIV(current->domain) ) + if ( obj && !IS_PRIV_FOR(current->domain, obj) ) { printk("%s: Grant table management authorization denied ERROR!\n", __func__); + rcu_unlock_domain(obj); return ACM_ACCESS_DENIED; } - /* b) check types */ - subj = current->domain; - obj = rcu_lock_domain_by_id(id); + /* b) check types */ if ( share_common_type(subj, obj) ) { cache_result(subj, obj); |