From patchwork Wed Sep 11 20:04:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrew Cooper X-Patchwork-Id: 11141847 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2BB8914E5 for ; Wed, 11 Sep 2019 20:07:10 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EF5D520838 for ; Wed, 11 Sep 2019 20:07:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="Y/qAtP5R" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EF5D520838 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i88rk-00030w-Ct; Wed, 11 Sep 2019 20:05:24 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i88rj-00030Q-4o for xen-devel@lists.xenproject.org; Wed, 11 Sep 2019 20:05:23 +0000 X-Inumbo-ID: 77962363-d4cf-11e9-83dd-12813bfff9fa Received: from esa2.hc3370-68.iphmx.com (unknown [216.71.145.153]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 77962363-d4cf-11e9-83dd-12813bfff9fa; Wed, 11 Sep 2019 20:05:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568232314; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BIbnzCREkG77hGwoxZ3RMjH/adLjjec/0WbuotSainY=; b=Y/qAtP5RizTiEL+UN51Iu/6u8CO7vCdLHLmv9aMbKbOrRnEhQOztzP/8 6P3ROA2fhQMvTlyB/ugiIRDwoijFXQocIHgmnYagkOtnF+KYok1e1QGJ/ NhdWYL8o8Yrg8MQQYZplsMGvBEIMPll/s4aHJ3QT0drRygk74uEV1FKtV 4=; Authentication-Results: esa2.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=andrew.cooper3@citrix.com; spf=Pass smtp.mailfrom=Andrew.Cooper3@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa2.hc3370-68.iphmx.com: no sender authenticity information available from domain of andrew.cooper3@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa2.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="andrew.cooper3@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa2.hc3370-68.iphmx.com: domain of Andrew.Cooper3@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa2.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="Andrew.Cooper3@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa2.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa2.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: iC/85lOS97iYbHxeP+m/voeXswq+JeYqBhLHZ/p93Cik7QXsMus2dDB8dA9+Yiyd4153Ec55UB 9ppGVUz3JoKeb6+ox7U6TOrlfKkAWjWAVmcXkIabxGL5lrTSCV56+Y1iSaFN45k60gWgU/4A2r vqtyNGrbzeL+OxXgXTMtTrkyVatnTfu+vxvbINgD1ytNMJEZNu8biYVsNUjYaAG1XSDqrydOKR gSK9pYZgEGQ2JK3aqAyUOCMJOoDznNrVdvbqcwe/AMLgy9bsXPW1Bsp6ddbEvWK3b57SH1+xoI 7jI= X-SBRS: 2.7 X-MesageID: 5451848 X-Ironport-Server: esa2.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,494,1559534400"; d="scan'208";a="5451848" From: Andrew Cooper To: Xen-devel Date: Wed, 11 Sep 2019 21:04:59 +0100 Message-ID: <20190911200504.5693-4-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190911200504.5693-1-andrew.cooper3@citrix.com> References: <20190911200504.5693-1-andrew.cooper3@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH 3/8] x86/domctl: Implement XEN_DOMCTL_set_cpumsr_policy X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Sergey Dyasli , Wei Liu , Andrew Cooper , Ian Jackson , Jan Beulich , Daniel De Graaf , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" 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 Signed-off-by: Sergey Dyasli Signed-off-by: Roger Pau Monné Reviewed-by: Jan Beulich --- CC: Jan Beulich CC: Ian Jackson CC: Wei Liu CC: Roger Pau Monné CC: Daniel De Graaf --- tools/libxc/include/xenctrl.h | 5 +++ tools/libxc/xc_cpuid_x86.c | 49 +++++++++++++++++++++++ xen/arch/x86/domctl.c | 80 +++++++++++++++++++++++++++++++++++++ xen/include/public/domctl.h | 15 +++++-- xen/xsm/flask/hooks.c | 1 + xen/xsm/flask/policy/access_vectors | 1 + 6 files changed, 147 insertions(+), 4 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 7559e1bc69..e47778535d 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -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_idx_p); uint32_t xc_get_cpu_featureset_size(void); diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index b829336082..33b9e9fc85 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -229,6 +229,55 @@ 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_idx_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 ( 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 = ~0; + domctl.u.cpu_policy.err_subleaf = ~0; + domctl.u.cpu_policy.err_msr_idx = ~0; + + ret = do_domctl(xch, &domctl); + + xc_hypercall_bounce_post(xch, leaves); + xc_hypercall_bounce_post(xch, msrs); + + if ( ret ) + { + 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_idx_p ) + *err_msr_idx_p = domctl.u.cpu_policy.err_msr_idx; + } + + return ret; +} + struct cpuid_domain_info { unsigned int vendor; /* X86_VENDOR_* */ diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index d15ae066c3..99bc2fb10d 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -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_idx = 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; diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 77f546cbb8..0471d3c680 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -658,17 +658,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 */ + uint32_t err_leaf, err_subleaf; /* OUT, set_policy only. If not ~0, + * indicates the leaf/subleaf which + * auditing objected to. */ + uint32_t err_msr_idx; /* OUT, set_policy only. If not ~0, + * indicates the MSR idx which + * auditing objected to. */ }; typedef struct xen_domctl_cpu_policy xen_domctl_cpu_policy_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpu_policy_t); @@ -1193,6 +1199,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 diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6800f2d9a0..b23772786a 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -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); diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index 76f3d60ddd..6f3f9493f8 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -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