Add the domctl, libxc wrapper and XSM permission used by libxl to turn a paused Arm guest into a Realm. RMI failures are reported back as-is.
Signed-off-by: Koichiro Den <[email protected]> --- tools/flask/policy/modules/xen.if | 1 + tools/include/xenctrl.h | 12 ++++++ tools/libs/ctrl/xc_domain.c | 37 ++++++++++++++++++ xen/arch/arm/domctl.c | 60 +++++++++++++++++++++++++++++ xen/include/public/domctl.h | 12 ++++++ xen/xsm/flask/hooks.c | 3 ++ xen/xsm/flask/policy/access_vectors | 2 + 7 files changed, 127 insertions(+) diff --git a/tools/flask/policy/modules/xen.if b/tools/flask/policy/modules/xen.if index ef7d8f438c65..5eb2d98341e9 100644 --- a/tools/flask/policy/modules/xen.if +++ b/tools/flask/policy/modules/xen.if @@ -98,6 +98,7 @@ define(`create_domain_common', ` vuart_op set_llc_colors get_domain_state + arm_cca_op }; allow $1 $2:security check_context; allow $1 $2:shadow enable; diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index d5dbf69c8968..149e15f7c531 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -808,6 +808,18 @@ int xc_dom_vuart_init(xc_interface *xch, xen_pfn_t gfn, evtchn_port_t *evtchn); +/* + * Finalize a paused ARM domain as a Realm backed by RMM. The toolstack is + * expected to have already built a normal ARM guest image in the domain RAM. + * + * Returns 0 on success, or -1 with errno set. If Xen receives an RMI error + * result from RMM, libxc logs the raw RMI result and reports EPROTO. + */ +int xc_arm_cca_init_realm(xc_interface *xch, + uint32_t domid, + xen_pfn_t base_gfn, + uint64_t nr_pages); + /** * This function returns information about the XSAVE state of a particular * vcpu of a domain. If extstate->size and extstate->xfeature_mask are 0, diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c index 01c0669c8863..3cb8da9cc07d 100644 --- a/tools/libs/ctrl/xc_domain.c +++ b/tools/libs/ctrl/xc_domain.c @@ -345,6 +345,43 @@ int xc_dom_vuart_init(xc_interface *xch, return rc; } +int xc_arm_cca_init_realm(xc_interface *xch, + uint32_t domid, + xen_pfn_t base_gfn, + uint64_t nr_pages) +{ + struct xen_domctl domctl = {}; + int rc; + + memset(&domctl, 0, sizeof(domctl)); + + domctl.cmd = XEN_DOMCTL_arm_cca_op; + domctl.domain = domid; + domctl.u.arm_cca_op.cmd = XEN_DOMCTL_ARM_CCA_OP_INIT_REALM; + domctl.u.arm_cca_op.flags = 0; + domctl.u.arm_cca_op.base_gfn = base_gfn; + domctl.u.arm_cca_op.nr_pages = nr_pages; + + rc = do_domctl(xch, &domctl); + if ( rc < 0 ) + { + if ( domctl.u.arm_cca_op.rmi_result ) + { + xc_report_error(xch, XC_INTERNAL_ERROR, + "xc_arm_cca_init_realm failed with raw RMI " + "result 0x%llx", + (unsigned long long) + domctl.u.arm_cca_op.rmi_result); + errno = EPROTO; + return -1; + } + + return rc; + } + + return rc; +} + int xc_domain_getinfo_single(xc_interface *xch, uint32_t domid, xc_domaininfo_t *info) diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index ad914c915f81..36461eeda633 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -16,6 +16,7 @@ #include <xen/types.h> #include <xsm/xsm.h> #include <public/domctl.h> +#include <public/sched.h> void arch_get_domain_info(const struct domain *d, struct xen_domctl_getdomaininfo *info) @@ -49,6 +50,42 @@ static int handle_vuart_init(struct domain *d, return rc; } +static int handle_arm_cca_init_realm(struct domain *d, + struct xen_domctl_arm_cca_op *cca_op) +{ +#ifdef CONFIG_ARM_CCA + uint64_t rmi_result = 0; + int rc; +#endif + + if ( cca_op->flags ) + return -EINVAL; + + cca_op->rmi_result = 0; + +#ifdef CONFIG_ARM_CCA + rc = arm_cca_domain_finalize(d, _gfn(cca_op->base_gfn), + cca_op->nr_pages, &rmi_result); + + /* + * Once Realm data conversion starts, the original guest RAM image can no + * longer be trusted after a failed finalization attempt. + */ + if ( rc == -EIO ) + domain_shutdown(d, SHUTDOWN_crash); + + if ( rc == -EIO && rmi_result ) + { + cca_op->rmi_result = rmi_result; + return rc; + } + + return rc; +#else + return -EOPNOTSUPP; +#endif +} + long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { @@ -177,6 +214,29 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, return rc; } + case XEN_DOMCTL_arm_cca_op: + { + struct xen_domctl_arm_cca_op *cca_op = &domctl->u.arm_cca_op; + + switch ( cca_op->cmd ) + { + case XEN_DOMCTL_ARM_CCA_OP_INIT_REALM: + { + long rc = handle_arm_cca_init_realm(d, cca_op); + + if ( rc == -ERESTART ) + rc = hypercall_create_continuation(__HYPERVISOR_domctl, + "h", u_domctl); + else if ( rc == -EIO && cca_op->rmi_result && + copy_to_guest(u_domctl, domctl, 1) ) + rc = -EFAULT; + + return rc; + } + default: + return -EINVAL; + } + } case XEN_DOMCTL_dt_overlay: return dt_overlay_domctl(d, &domctl->u.dt_overlay); default: diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 8f6708c0a7cd..2562647d93d3 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -1201,6 +1201,16 @@ struct xen_domctl_vuart_op { */ }; +/* XEN_DOMCTL_arm_cca_op */ +struct xen_domctl_arm_cca_op { +#define XEN_DOMCTL_ARM_CCA_OP_INIT_REALM 0 + uint32_t cmd; /* IN - XEN_DOMCTL_ARM_CCA_OP_* */ + uint32_t flags; /* IN - reserved, must be zero */ + uint64_aligned_t base_gfn; /* IN - first guest RAM gfn to protect */ + uint64_aligned_t nr_pages; /* IN - number of 4K pages to protect */ + uint64_aligned_t rmi_result; /* OUT - raw RMI result on -EIO */ +}; + /* XEN_DOMCTL_vmtrace_op: Perform VM tracing operations. */ struct xen_domctl_vmtrace_op { uint32_t cmd; /* IN */ @@ -1368,6 +1378,7 @@ struct xen_domctl { #define XEN_DOMCTL_gsi_permission 88 #define XEN_DOMCTL_set_llc_colors 89 #define XEN_DOMCTL_get_domain_state 90 /* stable interface */ +#define XEN_DOMCTL_arm_cca_op 91 #define XEN_DOMCTL_gdbsx_guestmemio 1000 #define XEN_DOMCTL_gdbsx_pausevcpu 1001 #define XEN_DOMCTL_gdbsx_unpausevcpu 1002 @@ -1429,6 +1440,7 @@ struct xen_domctl { struct xen_domctl_monitor_op monitor_op; struct xen_domctl_psr_alloc psr_alloc; struct xen_domctl_vuart_op vuart_op; + struct xen_domctl_arm_cca_op arm_cca_op; struct xen_domctl_vmtrace_op vmtrace_op; struct xen_domctl_paging_mempool paging_mempool; #if defined(__arm__) || defined(__aarch64__) diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 28522dcbd271..f95552992a26 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -805,6 +805,9 @@ static int cf_check flask_domctl(struct domain *d, unsigned int cmd, case XEN_DOMCTL_vuart_op: return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VUART_OP); + case XEN_DOMCTL_arm_cca_op: + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__ARM_CCA_OP); + case XEN_DOMCTL_get_cpu_policy: return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GET_CPU_POLICY); diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index bbb9c117ec4a..dee895bef673 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -253,6 +253,8 @@ class domain2 set_llc_colors # XEN_DOMCTL_get_domain_state get_domain_state +# XEN_DOMCTL_arm_cca_op + arm_cca_op } # Similar to class domain, but primarily contains domctls related to HVM domains -- 2.51.0
