From patchwork Fri Jul 8 21:21:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Collingbourne X-Patchwork-Id: 12911899 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2715BCCA47B for ; Fri, 8 Jul 2022 21:21:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240461AbiGHVVT (ORCPT ); Fri, 8 Jul 2022 17:21:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39690 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238467AbiGHVVS (ORCPT ); Fri, 8 Jul 2022 17:21:18 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 75F682BB09 for ; Fri, 8 Jul 2022 14:21:17 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-31cdce3ed04so180287b3.13 for ; Fri, 08 Jul 2022 14:21:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=twUVJxIVhhRUka3ujAGpgx5jyolc6+CWViYPAjBE+SE=; b=gGW7BYWFyEalfApr15oYFvpIMQcxD7X1mQiNqiPuiVHYYUJgo4j9T8+HQrwKcnXi4E uEYEIa6xfRlrn0clPA2WDvMuAzqAf91T7W2xQHSARkmZ8P1Lz2oyGz5DLXF4tH9Ry9TJ NSulr8r64BRrltG4I9PBO5kezDuJpeqU5FtSpSKwFcouadKfcfrj2G0ftpInI2imZOKz SM+n0KcxkrqAmu334mXP1Menw+lX76bcByeebg6rmKPRCwX4ejI7DrvTf6emYPf0kcHg /DgDGUJ4pRWEXgIDl2tKPrWdfeRCoIuV6Znk/PyHVb51PY7O7o//T5G4QkZZXL6unvXn Qp2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=twUVJxIVhhRUka3ujAGpgx5jyolc6+CWViYPAjBE+SE=; b=4PEktQNAiw8u9kvOtProaJFy4gJltiVHLK07HxJKu4/qDlYJx9Z/2bSPI7ncy9Rq/t kqqKCuMLbMy2mRMIR8KWtuNPX/7YNEWhuMMcBqBo1VTm+QuWjmImtiqs92oNsmPcW87o kMb4c/N17HstpTqxnvk9yelBfy5f8gfv9oAJxZum0jaRZ5xBLGUTlnPXTDxl4lIYGi/H RKh2+7U31QeagRRcH0YPxfAbQMwTvPTfzKcotbO3XMo8k6aSslVbo9ni7YWHuxmh82Nr Uivi36Khxo2lqEbeX7i2uEtIMSDeGU4galQ0KRmzZSldW6tUeIdJ7nkRp5PX2k+6T/Kk LB6w== X-Gm-Message-State: AJIora8t9aZSx9TU3Zlg8m14nRXAejrDFf+I+t7ZVBemRwvpumT3t6dv 7dUQGT08B8wdmxuCiRekzRaVfgo= X-Google-Smtp-Source: AGRyM1sGe6ArR8ij03wbQdy/kCKJfdsfrfRo/UOh8N3xvvxXsh3eCjHm+5S8mVUGa8PtuJjzKsK3bH4= X-Received: from pcc-desktop.svl.corp.google.com ([2620:15c:2ce:200:ff27:d65:6bb8:b084]) (user=pcc job=sendgmr) by 2002:a81:4eca:0:b0:31c:7a6a:f6d3 with SMTP id c193-20020a814eca000000b0031c7a6af6d3mr6573793ywb.82.1657315276782; Fri, 08 Jul 2022 14:21:16 -0700 (PDT) Date: Fri, 8 Jul 2022 14:21:04 -0700 In-Reply-To: <20220708212106.325260-1-pcc@google.com> Message-Id: <20220708212106.325260-2-pcc@google.com> Mime-Version: 1.0 References: <20220708212106.325260-1-pcc@google.com> X-Mailer: git-send-email 2.37.0.144.g8ac04bfd2-goog Subject: [PATCH v2 1/3] KVM: arm64: add a hypercall for disowning pages From: Peter Collingbourne To: kvmarm@lists.cs.columbia.edu Cc: Peter Collingbourne , Marc Zyngier , kvm@vger.kernel.org, Andy Lutomirski , linux-arm-kernel@lists.infradead.org, Michael Roth , Catalin Marinas , Chao Peng , Will Deacon , Evgenii Stepanov Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Currently we only deny the host access to hyp and guest pages. However, there may be other pages that could potentially be used to indirectly compromise the hypervisor or the other guests. Therefore introduce a __pkvm_disown_pages hypercall that the host kernel may use to deny its future self access to those pages before deprivileging itself. Signed-off-by: Peter Collingbourne --- v2: - refcount the PTEs owned by NOBODY arch/arm64/include/asm/kvm_asm.h | 1 + arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 1 + arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 1 + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 9 +++++++++ arch/arm64/kvm/hyp/nvhe/mem_protect.c | 11 +++++++++++ 5 files changed, 23 insertions(+) diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 411cfbe3ebbd..1a177d9ed517 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -63,6 +63,7 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa, __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid, __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context, + __KVM_HOST_SMCCC_FUNC___pkvm_disown_pages, __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize, /* Hypercalls available after pKVM finalisation */ diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index e0bbb1726fa3..e88a9dab9cd5 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -58,6 +58,7 @@ enum pkvm_component_id { PKVM_ID_HOST, PKVM_ID_HYP, PKVM_ID_GUEST, + PKVM_ID_NOBODY, }; extern unsigned long hyp_nr_cpus; diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h index c1987115b217..fbd991a46ab3 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h @@ -98,6 +98,7 @@ int __pkvm_init_shadow(struct kvm *kvm, unsigned long pgd_hva, unsigned long last_ran_hva, size_t last_ran_size); int __pkvm_teardown_shadow(unsigned int shadow_handle); +int __pkvm_disown_pages(phys_addr_t phys, size_t size); struct kvm_shadow_vcpu_state * pkvm_load_shadow_vcpu_state(unsigned int shadow_handle, unsigned int vcpu_idx); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index e575224244e6..0dab343734e8 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -1031,6 +1031,14 @@ static void handle___pkvm_teardown_shadow(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __pkvm_teardown_shadow(shadow_handle); } +static void handle___pkvm_disown_pages(struct kvm_cpu_context *host_ctxt) +{ + DECLARE_REG(phys_addr_t, phys, host_ctxt, 1); + DECLARE_REG(size_t, size, host_ctxt, 2); + + cpu_reg(host_ctxt, 1) = __pkvm_disown_pages(phys, size); +} + typedef void (*hcall_t)(struct kvm_cpu_context *); #define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x @@ -1048,6 +1056,7 @@ static const hcall_t host_hcall[] = { HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa), HANDLE_FUNC(__kvm_tlb_flush_vmid), HANDLE_FUNC(__kvm_flush_cpu_context), + HANDLE_FUNC(__pkvm_disown_pages), HANDLE_FUNC(__pkvm_prot_finalize), HANDLE_FUNC(__pkvm_host_share_hyp), diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index d839bb573b49..b3a2ad8454cc 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -1756,3 +1756,14 @@ int __pkvm_host_reclaim_page(u64 pfn) return ret; } + +int __pkvm_disown_pages(phys_addr_t phys, size_t size) +{ + int ret; + + host_lock_component(); + ret = host_stage2_set_owner_locked(phys, size, PKVM_ID_NOBODY); + host_unlock_component(); + + return ret; +} From patchwork Fri Jul 8 21:21:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Collingbourne X-Patchwork-Id: 12911900 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7981BC43334 for ; Fri, 8 Jul 2022 21:21:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240465AbiGHVVW (ORCPT ); Fri, 8 Jul 2022 17:21:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238467AbiGHVVU (ORCPT ); Fri, 8 Jul 2022 17:21:20 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A3E173121F for ; Fri, 8 Jul 2022 14:21:19 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-2dc7bdd666fso336367b3.7 for ; Fri, 08 Jul 2022 14:21:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=d06KtJGM9Urh+hEma1oe+1DCWv79kZEo+4GAAOkgM9k=; b=oQDT6Wq7kEbhP3BM0f12sQqelVDyuIBAdNcbuWk1GGVjjUSN1gd5aAKSBazbYqFS4K +arOzs7jC2zDxprNY10dM8KLjkEYfomASm4epKLHtGTSor91ZAwLYfV5t0WmZjdt/Z4O vACDN7b5l6kICT11HPPKfdfBk2O8d9ITJsAyLdFuTFiEQLLoDPCM58N3u6CiOZzQvKSH s3gAaUaVxHr/Co94+2LthvqvFUXhIY9DH6eoOuoA2qViPNkh72I32WcBfGyOYgoqiBMM 80/uUyzDRSTU4pwtkVhUeJAn3GLyj0tD++8Zd2IcqMvG6kcz0FDO8avyiv4s16nl/HHr wu9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=d06KtJGM9Urh+hEma1oe+1DCWv79kZEo+4GAAOkgM9k=; b=YTSFxV0Vsh0zPkRLlINFD/Z9flcrr4LuISXKu0Lf5EnaO01Mh8o3G1SUbaIN92tnQU 5NqIBUmQ/NxjZkmPAcgzXbgiKwDGpSOWDYj1I3PupCR3O5gYVnzTAFLuf3+0U3THqZTH j1q8Bw7If/XbzZeIlpujt8/uZNSqI48+aJ7icqYJwWC3g3OINZnBVs9m+9ghk6ufqfbu C7G6VNDHokbO1VHTbJYya6X/icUvGp+WXVXuOH5Dj9g2Vp0EXUWach34YLWUpu0U0gLh MUTsRkB6AZipHx4S6yDyowrOkxzzb5ZTR3u0HKVJjjx9itNRjpQDGwFbBqO3tAl4TENw H2mQ== X-Gm-Message-State: AJIora8MyERgTiKhVld1YKMD5HG2VCEVHty5rACc0oRwAaZZrhxfS+Rw lT/PYR1u39pT0GlHwrBDWf05hCU= X-Google-Smtp-Source: AGRyM1vfmvu7rG+koN3KOKJWw2zBTYS3L0eEAox4rXFwqECYm1TTG82R1SDiGf/lpsF8NErbOex4Qe4= X-Received: from pcc-desktop.svl.corp.google.com ([2620:15c:2ce:200:ff27:d65:6bb8:b084]) (user=pcc job=sendgmr) by 2002:a25:6b0b:0:b0:66e:445a:17bb with SMTP id g11-20020a256b0b000000b0066e445a17bbmr5638981ybc.147.1657315278964; Fri, 08 Jul 2022 14:21:18 -0700 (PDT) Date: Fri, 8 Jul 2022 14:21:05 -0700 In-Reply-To: <20220708212106.325260-1-pcc@google.com> Message-Id: <20220708212106.325260-3-pcc@google.com> Mime-Version: 1.0 References: <20220708212106.325260-1-pcc@google.com> X-Mailer: git-send-email 2.37.0.144.g8ac04bfd2-goog Subject: [PATCH v2 2/3] KVM: arm64: disown unused reserved-memory regions From: Peter Collingbourne To: kvmarm@lists.cs.columbia.edu Cc: Peter Collingbourne , Marc Zyngier , kvm@vger.kernel.org, Andy Lutomirski , linux-arm-kernel@lists.infradead.org, Michael Roth , Catalin Marinas , Chao Peng , Will Deacon , Evgenii Stepanov Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The meaning of no-map on a reserved-memory node is as follows: Indicates the operating system must not create a virtual mapping of the region as part of its standard mapping of system memory, nor permit speculative access to it under any circumstances other than under the control of the device driver using the region. If there is no compatible property, there is no device driver, so the host kernel has no business accessing the reserved-memory region. Since these regions may represent a route through which the host kernel can gain additional privileges, disown any such memory regions before deprivileging ourselves. Signed-off-by: Peter Collingbourne --- arch/arm64/kvm/arm.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index c1fc4ef82f93..91ca128e7daa 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -4,6 +4,7 @@ * Author: Christoffer Dall */ +#include #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1913,6 +1915,48 @@ static bool init_psci_relay(void) return true; } +static void disown_reserved_memory(struct device_node *node) +{ + int addr_cells = of_n_addr_cells(node); + int size_cells = of_n_size_cells(node); + const __be32 *reg, *end; + int len; + + reg = of_get_property(node, "reg", &len); + if (len % (4 * (addr_cells + size_cells))) + return; + + end = reg + (len / 4); + while (reg != end) { + u64 addr, size; + + addr = of_read_number(reg, addr_cells); + reg += addr_cells; + size = of_read_number(reg, size_cells); + reg += size_cells; + + kvm_call_hyp_nvhe(__pkvm_disown_pages, addr, size); + } +} + +static void kvm_reserved_memory_init(void) +{ + struct device_node *parent, *node; + + if (!acpi_disabled || !is_protected_kvm_enabled()) + return; + + parent = of_find_node_by_path("/reserved-memory"); + if (!parent) + return; + + for_each_child_of_node(parent, node) { + if (!of_get_property(node, "compatible", NULL) && + of_get_property(node, "no-map", NULL)) + disown_reserved_memory(node); + } +} + static int init_subsystems(void) { int err = 0; @@ -1953,6 +1997,8 @@ static int init_subsystems(void) kvm_register_perf_callbacks(NULL); + kvm_reserved_memory_init(); + out: if (err || !is_protected_kvm_enabled()) on_each_cpu(_kvm_arch_hardware_disable, NULL, 1); From patchwork Fri Jul 8 21:21:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Collingbourne X-Patchwork-Id: 12911901 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B124C433EF for ; Fri, 8 Jul 2022 21:21:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239786AbiGHVVX (ORCPT ); Fri, 8 Jul 2022 17:21:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39720 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240466AbiGHVVW (ORCPT ); Fri, 8 Jul 2022 17:21:22 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB7A83121F for ; Fri, 8 Jul 2022 14:21:21 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31c8a5d51adso151847b3.14 for ; Fri, 08 Jul 2022 14:21:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=BncZ+nQY2fXKcGj97BWocHuOMgLnRAIrtoobxQvs+yg=; b=CWeilK91Y66KvfDXv80VI1osstHUx7mu0s9JCS9R8rcDcQWS2d6uBrXLe9YHxAl7Cq o9TM7VGgNMHiTQYhpsQEJwhCeyD8AefacE6+tKMSRWdTPA/SFuS6WV3nfkecQddJ3UWq SsYFRGnUllJcqhTN2lIRFTRHcxOOarrveOZ7476oJF9BPyipsNJNzfVDF6oetllNluez Ax00g1m4aTcv7m7elKPKEcLm6y66I0W/gsdePiYiOstKmoatljFIZoDT/OTPwDdmWlT/ JqsxIsUFCetoSRsIYXdjGDEpKDlrJrZiqAuN9CqPSo5kJw/C/winwNHczgt1dvr9ub3S NZow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=BncZ+nQY2fXKcGj97BWocHuOMgLnRAIrtoobxQvs+yg=; b=sm1hgvJEyruyz2gAxB0ykf0QOxAgjd1QHuFob7mU/RqKjSNwP/ZvgoYWZIrBLgSAJn 0eRqeQmSjbyywZgFx2dJ+oQBMxk3iQQzLd+mx1VxI4VdGj9sSlDmM4fBK05JGHAqvzbx xe2UjEWUSVjPQ+tPqALmHFduv5CvI5ClIK+A7Nbyeo2iymcDWApEMvEjTKpG7uMaWdP7 BtnCH9h00HnUeHk3Ul4wTSk/BlRUd3zRizI18+FewKryCQ8YUF3iyZE+nNwpKD0DCE/q P+V9D5J9EkGwXmvWRTyoy8+56z47XD1fGvI2kRa2v5zhoclATdjA0MHkup77pbCJAHju fFZg== X-Gm-Message-State: AJIora+2GPE/75KFrcxPfuXqaAgAYezV+D61QLlGqjVlP1c6b87KQ9HW u5g0g9BEYiCeFxnnHGGIzby/3jE= X-Google-Smtp-Source: AGRyM1vx7nO49BRSoJ6ckQ8LmFvqQhFRH6xNwGFXgnVWrZVBFW74MN7oiNIzcxG/XrQ842Yj8o1bmgs= X-Received: from pcc-desktop.svl.corp.google.com ([2620:15c:2ce:200:ff27:d65:6bb8:b084]) (user=pcc job=sendgmr) by 2002:a25:ccca:0:b0:66e:c109:a884 with SMTP id l193-20020a25ccca000000b0066ec109a884mr6026929ybf.161.1657315281268; Fri, 08 Jul 2022 14:21:21 -0700 (PDT) Date: Fri, 8 Jul 2022 14:21:06 -0700 In-Reply-To: <20220708212106.325260-1-pcc@google.com> Message-Id: <20220708212106.325260-4-pcc@google.com> Mime-Version: 1.0 References: <20220708212106.325260-1-pcc@google.com> X-Mailer: git-send-email 2.37.0.144.g8ac04bfd2-goog Subject: [PATCH v2 3/3] KVM: arm64: allow MTE in protected VMs if the tag storage is known From: Peter Collingbourne To: kvmarm@lists.cs.columbia.edu Cc: Peter Collingbourne , Marc Zyngier , kvm@vger.kernel.org, Andy Lutomirski , linux-arm-kernel@lists.infradead.org, Michael Roth , Catalin Marinas , Chao Peng , Will Deacon , Evgenii Stepanov Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Because the host may corrupt a protected guest's tag storage unless protected by stage 2 page tables, we can't expose MTE to protected guests if the location of the tag storage is not known. Therefore, only allow protected VM guests to use MTE if the location of the tag storage is described in the device tree, and only after disowning any physical memory accessible tag storage regions. To avoid exposing MTE tags from the host to protected VMs, sanitize tags before donating pages. Signed-off-by: Peter Collingbourne --- arch/arm64/include/asm/kvm_host.h | 6 +++++ arch/arm64/include/asm/kvm_pkvm.h | 4 +++- arch/arm64/kernel/image-vars.h | 3 +++ arch/arm64/kvm/arm.c | 37 ++++++++++++++++++++++++++++--- arch/arm64/kvm/hyp/nvhe/pkvm.c | 8 ++++--- arch/arm64/kvm/mmu.c | 4 +++- 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e54e76afccc0..35cba0408eca 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1037,6 +1037,12 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); #define kvm_arm_vcpu_sve_finalized(vcpu) vcpu_get_flag(vcpu, VCPU_SVE_FINALIZED) +DECLARE_STATIC_KEY_FALSE(pkvm_mte_supported); + +#define kvm_supports_mte(kvm) \ + (system_supports_mte() && \ + (!kvm_vm_is_protected(kvm) || \ + static_branch_unlikely(&pkvm_mte_supported))) #define kvm_has_mte(kvm) \ (system_supports_mte() && \ test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &(kvm)->arch.flags)) diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index cd56438a34be..ef5d4870c043 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -73,10 +73,12 @@ void kvm_shadow_destroy(struct kvm *kvm); * Allow for protected VMs: * - Branch Target Identification * - Speculative Store Bypassing + * - Memory Tagging Extension */ #define PVM_ID_AA64PFR1_ALLOW (\ ARM64_FEATURE_MASK(ID_AA64PFR1_BT) | \ - ARM64_FEATURE_MASK(ID_AA64PFR1_SSBS) \ + ARM64_FEATURE_MASK(ID_AA64PFR1_SSBS) | \ + ARM64_FEATURE_MASK(ID_AA64PFR1_MTE) \ ) /* diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 2d4d6836ff47..26a9b31478aa 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -84,6 +84,9 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors); KVM_NVHE_ALIAS(arm64_const_caps_ready); KVM_NVHE_ALIAS(cpu_hwcap_keys); +/* Kernel symbol needed for kvm_supports_mte() check. */ +KVM_NVHE_ALIAS(pkvm_mte_supported); + /* Static keys which are set if a vGIC trap should be handled in hyp. */ KVM_NVHE_ALIAS(vgic_v2_cpuif_trap); KVM_NVHE_ALIAS(vgic_v3_cpuif_trap); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 91ca128e7daa..7c79a1be1e39 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -60,6 +60,7 @@ static bool vgic_present; static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled); DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use); +DEFINE_STATIC_KEY_FALSE(pkvm_mte_supported); int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) { @@ -96,9 +97,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, break; case KVM_CAP_ARM_MTE: mutex_lock(&kvm->lock); - if (!system_supports_mte() || - kvm_vm_is_protected(kvm) || - kvm->created_vcpus) { + if (!kvm_supports_mte(kvm) || kvm->created_vcpus) { r = -EINVAL; } else { r = 0; @@ -334,6 +333,9 @@ static int pkvm_check_extension(struct kvm *kvm, long ext, int kvm_cap) case KVM_CAP_ARM_VM_IPA_SIZE: r = kvm_cap; break; + case KVM_CAP_ARM_MTE: + r = kvm_cap && static_branch_unlikely(&pkvm_mte_supported); + break; case KVM_CAP_GUEST_DEBUG_HW_BPS: r = min(kvm_cap, pkvm_get_max_brps()); break; @@ -1954,9 +1956,36 @@ static void kvm_reserved_memory_init(void) if (!of_get_property(node, "compatible", NULL) && of_get_property(node, "no-map", NULL)) disown_reserved_memory(node); + + if (of_device_is_compatible(node, "arm,mte-tag-storage")) + disown_reserved_memory(node); } } +static void kvm_mte_init(void) +{ + struct device_node *memory; + + if (!system_supports_mte() || !acpi_disabled || + !is_protected_kvm_enabled()) + return; + + /* + * It is only safe to turn on MTE for protected VMs if we can protect + * the guests from host accesses to their tag storage. If every memory + * region has an arm,mte-alloc property we know that all tag storage + * regions exposed to physical memory, if any, are described by a + * reserved-memory compatible with arm,mte-tag-storage. We can use these + * descriptions to unmap these regions from the host's stage 2 page + * tables (see kvm_reserved_memory_init). + */ + for_each_node_by_type(memory, "memory") + if (!of_get_property(memory, "arm,mte-alloc", NULL)) + return; + + static_branch_enable(&pkvm_mte_supported); +} + static int init_subsystems(void) { int err = 0; @@ -1999,6 +2028,8 @@ static int init_subsystems(void) kvm_reserved_memory_init(); + kvm_mte_init(); + out: if (err || !is_protected_kvm_enabled()) on_each_cpu(_kvm_arch_hardware_disable, NULL, 1); diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 80260e8e97f2..96538c984858 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -88,7 +88,7 @@ static void pvm_init_traps_aa64pfr1(struct kvm_vcpu *vcpu) /* Memory Tagging: Trap and Treat as Untagged if not supported. */ if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_MTE), feature_ids)) { hcr_set |= HCR_TID5; - hcr_clear |= HCR_DCT | HCR_ATA; + hcr_clear |= HCR_ATA; } vcpu->arch.hcr_el2 |= hcr_set; @@ -179,8 +179,8 @@ static void pvm_init_trap_regs(struct kvm_vcpu *vcpu) * - Feature id registers: to control features exposed to guests * - Implementation-defined features */ - vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS | - HCR_TID3 | HCR_TACR | HCR_TIDCP | HCR_TID1; + vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS | HCR_TID3 | HCR_TACR | HCR_TIDCP | + HCR_TID1 | HCR_ATA; if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) { /* route synchronous external abort exceptions to EL2 */ @@ -473,6 +473,8 @@ static int init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, vm->host_kvm = kvm; vm->kvm.created_vcpus = nr_vcpus; vm->kvm.arch.vtcr = host_kvm.arch.vtcr; + if (kvm_supports_mte(kvm) && test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags)) + set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &vm->kvm.arch.flags); vm->kvm.arch.pkvm.enabled = READ_ONCE(kvm->arch.pkvm.enabled); vm->kvm.arch.mmu.last_vcpu_ran = last_ran; vm->last_ran_size = last_ran_size; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index bca90b7354b9..5e079daf2d8e 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1228,8 +1228,10 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, goto dec_account; } - write_lock(&kvm->mmu_lock); pfn = page_to_pfn(page); + sanitise_mte_tags(kvm, pfn, PAGE_SIZE); + + write_lock(&kvm->mmu_lock); ret = pkvm_host_map_guest(pfn, fault_ipa >> PAGE_SHIFT); if (ret) { if (ret == -EAGAIN)