x86/domctl: Implement XEN_DOMCTL_set_cpumsr_policy

This hypercall allows the toolstack to present one combined CPUID and MSR
policy for a domain, which can be audited in one go by Xen, which is necessary
for correctness of the auditing.

Reuse the existing set_cpuid XSM access vector, as this is logically the same
operation.

As x86_cpu_policies_are_compatible() is still only a stub, retain the call to
recalculate_cpuid_policy() to discard unsafe toolstack settings.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
Andrew Cooper committed 2019-09-26 13:40:18 +01:00
1 parent 205f3b6380
commit 14ba07e6f8
6 files changed
+151 -4

No files matched your search

+5
View File
@@ -2530,6 +2530,11 @@ int xc_get_system_cpu_policy(xc_interface *xch, uint32_t index,
int xc_get_domain_cpu_policy(xc_interface *xch, uint32_t domid,
uint32_t *nr_leaves, xen_cpuid_leaf_t *leaves,
uint32_t *nr_msrs, xen_msr_entry_t *msrs);
int xc_set_domain_cpu_policy(xc_interface *xch, uint32_t domid,
uint32_t nr_leaves, xen_cpuid_leaf_t *leaves,
uint32_t nr_msrs, xen_msr_entry_t *msrs,
uint32_t *err_leaf_p, uint32_t *err_subleaf_p,
uint32_t *err_msr_p);
uint32_t xc_get_cpu_featureset_size(void);
+53
View File
@@ -229,6 +229,59 @@ int xc_get_domain_cpu_policy(xc_interface *xch, uint32_t domid,
return ret;
}
int xc_set_domain_cpu_policy(xc_interface *xch, uint32_t domid,
uint32_t nr_leaves, xen_cpuid_leaf_t *leaves,
uint32_t nr_msrs, xen_msr_entry_t *msrs,
uint32_t *err_leaf_p, uint32_t *err_subleaf_p,
uint32_t *err_msr_p)
{
DECLARE_DOMCTL;
DECLARE_HYPERCALL_BOUNCE(leaves,
nr_leaves * sizeof(*leaves),
XC_HYPERCALL_BUFFER_BOUNCE_IN);
DECLARE_HYPERCALL_BOUNCE(msrs,
nr_msrs * sizeof(*msrs),
XC_HYPERCALL_BUFFER_BOUNCE_IN);
int ret;
if ( err_leaf_p )
*err_leaf_p = -1;
if ( err_subleaf_p )
*err_subleaf_p = -1;
if ( err_msr_p )
*err_msr_p = -1;
if ( xc_hypercall_bounce_pre(xch, leaves) )
return -1;
if ( xc_hypercall_bounce_pre(xch, msrs) )
return -1;
domctl.cmd = XEN_DOMCTL_set_cpu_policy;
domctl.domain = domid;
domctl.u.cpu_policy.nr_leaves = nr_leaves;
set_xen_guest_handle(domctl.u.cpu_policy.cpuid_policy, leaves);
domctl.u.cpu_policy.nr_msrs = nr_msrs;
set_xen_guest_handle(domctl.u.cpu_policy.msr_policy, msrs);
domctl.u.cpu_policy.err_leaf = -1;
domctl.u.cpu_policy.err_subleaf = -1;
domctl.u.cpu_policy.err_msr = -1;
ret = do_domctl(xch, &domctl);
xc_hypercall_bounce_post(xch, leaves);
xc_hypercall_bounce_post(xch, msrs);
if ( err_leaf_p )
*err_leaf_p = domctl.u.cpu_policy.err_leaf;
if ( err_subleaf_p )
*err_subleaf_p = domctl.u.cpu_policy.err_subleaf;
if ( err_msr_p )
*err_msr_p = domctl.u.cpu_policy.err_msr;
return ret;
}
struct cpuid_domain_info
{
unsigned int vendor; /* X86_VENDOR_* */
+80
View File
@@ -294,6 +294,65 @@ static int update_domain_cpuid_info(struct domain *d,
return 0;
}
static int update_domain_cpu_policy(struct domain *d,
xen_domctl_cpu_policy_t *xdpc)
{
struct cpu_policy new = {};
const struct cpu_policy *sys = is_pv_domain(d)
? &system_policies[XEN_SYSCTL_cpu_policy_pv_max]
: &system_policies[XEN_SYSCTL_cpu_policy_hvm_max];
struct cpu_policy_errors err = INIT_CPU_POLICY_ERRORS;
int ret = -ENOMEM;
/* Start by copying the domain's existing policies. */
if ( !(new.cpuid = xmemdup(d->arch.cpuid)) ||
!(new.msr = xmemdup(d->arch.msr)) )
goto out;
/* Merge the toolstack provided data. */
if ( (ret = x86_cpuid_copy_from_buffer(
new.cpuid, xdpc->cpuid_policy, xdpc->nr_leaves,
&err.leaf, &err.subleaf)) ||
(ret = x86_msr_copy_from_buffer(
new.msr, xdpc->msr_policy, xdpc->nr_msrs, &err.msr)) )
goto out;
/* Trim any newly-stale out-of-range leaves. */
x86_cpuid_policy_clear_out_of_range_leaves(new.cpuid);
/* Audit the combined dataset. */
ret = x86_cpu_policies_are_compatible(sys, &new, &err);
if ( ret )
goto out;
/*
* Audit was successful. Replace existing policies, leaving the old
* policies to be freed.
*/
SWAP(new.cpuid, d->arch.cpuid);
SWAP(new.msr, d->arch.msr);
/* TODO: Drop when x86_cpu_policies_are_compatible() is completed. */
recalculate_cpuid_policy(d);
/* Recalculate relevant dom/vcpu state now the policy has changed. */
domain_cpu_policy_changed(d);
out:
/* Free whichever cpuid/msr structs are not installed in struct domain. */
xfree(new.cpuid);
xfree(new.msr);
if ( ret )
{
xdpc->err_leaf = err.leaf;
xdpc->err_subleaf = err.subleaf;
xdpc->err_msr = err.msr;
}
return ret;
}
static int vcpu_set_vmce(struct vcpu *v,
const struct xen_domctl_ext_vcpucontext *evc)
{
@@ -1476,6 +1535,27 @@ long arch_do_domctl(
copyback = true;
break;
case XEN_DOMCTL_set_cpu_policy:
if ( d == currd ) /* No domain_pause() */
{
ret = -EINVAL;
break;
}
domain_pause(d);
if ( d->creation_finished )
ret = -EEXIST; /* No changing once the domain is running. */
else
{
ret = update_domain_cpu_policy(d, &domctl->u.cpu_policy);
if ( ret ) /* Copy domctl->u.cpu_policy.err_* to guest. */
copyback = true;
}
domain_unpause(d);
break;
default:
ret = iommu_do_domctl(domctl, d, u_domctl);
break;
+11 -4
View File
@@ -669,17 +669,23 @@ struct xen_domctl_cpuid {
};
/*
* XEN_DOMCTL_get_cpu_policy (x86 specific)
* XEN_DOMCTL_{get,set}_cpu_policy (x86 specific)
*
* Query the CPUID and MSR policies for a specific domain.
* Query or set the CPUID and MSR policies for a specific domain.
*/
struct xen_domctl_cpu_policy {
uint32_t nr_leaves; /* IN/OUT: Number of leaves in/written to
* 'cpuid_policy'. */
uint32_t nr_msrs; /* IN/OUT: Number of MSRs in/written to
* 'msr_domain_policy' */
XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_policy; /* OUT */
XEN_GUEST_HANDLE_64(xen_msr_entry_t) msr_policy; /* OUT */
XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_policy; /* IN/OUT */
XEN_GUEST_HANDLE_64(xen_msr_entry_t) msr_policy; /* IN/OUT */
/*
* OUT, set_policy only. Written in some (but not all) error cases to
* identify the CPUID leaf/subleaf and/or MSR which auditing objects to.
*/
uint32_t err_leaf, err_subleaf, err_msr;
};
typedef struct xen_domctl_cpu_policy xen_domctl_cpu_policy_t;
DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpu_policy_t);
@@ -1204,6 +1210,7 @@ struct xen_domctl {
/* #define XEN_DOMCTL_set_gnttab_limits 80 - Moved into XEN_DOMCTL_createdomain */
#define XEN_DOMCTL_vuart_op 81
#define XEN_DOMCTL_get_cpu_policy 82
#define XEN_DOMCTL_set_cpu_policy 83
#define XEN_DOMCTL_gdbsx_guestmemio 1000
#define XEN_DOMCTL_gdbsx_pausevcpu 1001
#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
+1
View File
@@ -715,6 +715,7 @@ static int flask_domctl(struct domain *d, int cmd)
case XEN_DOMCTL_set_virq_handler:
return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SET_VIRQ_HANDLER);
case XEN_DOMCTL_set_cpu_policy:
case XEN_DOMCTL_set_cpuid:
return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID);
+1
View File
@@ -207,6 +207,7 @@ class domain2
# source = the domain making the hypercall
# target = the new target domain
set_as_target
# XEN_DOMCTL_set_cpu_policy
# XEN_DOMCTL_set_cpuid
set_cpuid
# XEN_DOMCTL_gettscinfo
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.