From patchwork Mon Nov 13 02:23:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= X-Patchwork-Id: 164313 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b909:0:b0:403:3b70:6f57 with SMTP id t9csp960729vqg; Sun, 12 Nov 2023 18:25:45 -0800 (PST) X-Google-Smtp-Source: AGHT+IEerj4BiijgPFbniOKdCzqEWSwtZUCgdTrNDy1uPwVR/d3rXeJKufjeqvGi8jkWmTiorRJd X-Received: by 2002:a05:6a20:3caa:b0:161:76a4:4f74 with SMTP id b42-20020a056a203caa00b0016176a44f74mr7745952pzj.1.1699842345533; Sun, 12 Nov 2023 18:25:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1699842345; cv=none; d=google.com; s=arc-20160816; b=SXg9Uw7MLMFg4BzY46POjHxNs8CvehrIjeFP+koGOIrSRyNVv/LcoXERpvPMLZbfV7 dA+LIlhOQD5nAJNErRIbx4+CfPbN/7yt74l1KJkZQCDvGqB3Kt1+dPezkEc87/pnKXFz DqKkRVYXfSxHUFrRXy0PiDWBxpTs/38ojRBJeoN7uxr9H7egjPaxkqAVTjThe7H7pnqu xVHK/ZAgVHo9EeO6zKWbpOBt4Ux0WVQGBXlgS0mw0Au4O3czwX8sEJGST/HIZDw9dMRu M701gMrq31XEzde3aKNEhcWg6tUR0yFfm8iCi2b7y82xD8FZa6hgZH55GtxutxXbgrb4 pb4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=CCFNEM0/8ZlCtoyid+Q+bIz4psUB75E6AfxVUicyRaI=; fh=AZdbNnvkerEwIaxrkEHewrGZFSiDsGxZahLkp7gMUH8=; b=p6Ei5/BxPBIJSlF9G1DFajaDbF1lSmX09wcwnEVXcKckUa8rijeSSMXIa5zq+mT0Sx cnb+OmZ/uYb9DgHGVm14au72rgcvmIZa276Gp/yURlXm7zE4QTSJwH5PETJiPuJbP++w 4wypd5TJF+ECmwfBP5WjW5MpYXMGtpOnh/fJ98obVI71ELPNpMQbmtk28JB2D322WvfL tTiOwglXajNAmZUzwy3gmy8hgb6gA96EyeR6Du7++QeVaQAktqdqOkZ6fyjE0MGuctPq xNeYrpqnidVPrC6O8XK0k4gbkLbcB3nNCyU/j72TrceCujR/2gcDPAK/aZVfc/Zz3o5/ yq/Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@digikod.net header.s=20191114 header.b=oy65yEMw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.37 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from snail.vger.email (snail.vger.email. [23.128.96.37]) by mx.google.com with ESMTPS id l7-20020a170902f68700b001cc283d99a6si5073784plg.474.2023.11.12.18.25.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 12 Nov 2023 18:25:45 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.37 as permitted sender) client-ip=23.128.96.37; Authentication-Results: mx.google.com; dkim=pass header.i=@digikod.net header.s=20191114 header.b=oy65yEMw; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.37 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id A878180A992F; Sun, 12 Nov 2023 18:25:44 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232997AbjKMCZb (ORCPT + 30 others); Sun, 12 Nov 2023 21:25:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44552 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232925AbjKMCZD (ORCPT ); Sun, 12 Nov 2023 21:25:03 -0500 Received: from smtp-190d.mail.infomaniak.ch (smtp-190d.mail.infomaniak.ch [IPv6:2001:1600:3:17::190d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 194F83A85 for ; Sun, 12 Nov 2023 18:24:34 -0800 (PST) Received: from smtp-3-0001.mail.infomaniak.ch (unknown [10.4.36.108]) by smtp-2-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4STCtR28lmzMq1pb; Mon, 13 Nov 2023 02:24:31 +0000 (UTC) Received: from unknown by smtp-3-0001.mail.infomaniak.ch (Postfix) with ESMTPA id 4STCtP6n2FzMpnPd; Mon, 13 Nov 2023 03:24:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=digikod.net; s=20191114; t=1699842271; bh=HO3RcULwQ802eeIPFZkXgFQnmnXm7kA4hgpvD90H0yM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oy65yEMwFBZXkzY8/GbCSCY015c7FsKYAOxiyiLLg876EDse7qPjjQ2TawXHbDdpo RqYXUhhMZo8wrcdUoNJcKni3rzSjF0HzYO1MLe/71b+NvJhrkaU1fgwZGfleYIbVsx 7CZiYxZUd35oWxWwZ9c+J67orF3hA2vwNYlS1LAw= From: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= To: Borislav Petkov , Dave Hansen , "H . Peter Anvin" , Ingo Molnar , Kees Cook , Paolo Bonzini , Sean Christopherson , Thomas Gleixner , Vitaly Kuznetsov , Wanpeng Li Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Alexander Graf , Chao Peng , "Edgecombe, Rick P" , Forrest Yuan Yu , James Gowans , James Morris , John Andersen , "Madhavan T . Venkataraman" , Marian Rotariu , =?utf-8?q?Mihai_Don=C8=9Bu?= , =?utf-8?b?TmljdciZ?= =?utf-8?b?b3IgQ8OuyJt1?= , Thara Gopinath , Trilok Soni , Wei Liu , Will Deacon , Yu Zhang , Zahra Tarkhani , =?utf-8?q?=C8=98tefan_=C8=98icler?= =?utf-8?q?u?= , dev@lists.cloudhypervisor.org, kvm@vger.kernel.org, linux-hardening@vger.kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, qemu-devel@nongnu.org, virtualization@lists.linux-foundation.org, x86@kernel.org, xen-devel@lists.xenproject.org Subject: [RFC PATCH v2 10/19] KVM: x86: Implement per-guest-page permissions Date: Sun, 12 Nov 2023 21:23:17 -0500 Message-ID: <20231113022326.24388-11-mic@digikod.net> In-Reply-To: <20231113022326.24388-1-mic@digikod.net> References: <20231113022326.24388-1-mic@digikod.net> MIME-Version: 1.0 X-Infomaniak-Routing: alpha X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Sun, 12 Nov 2023 18:25:44 -0800 (PST) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1782413887632970304 X-GMAIL-MSGID: 1782413887632970304 Define memory attributes that can be associated with guest physical pages in KVM. To begin with, define permissions as memory attributes (READ, WRITE and EXECUTE), and the IMMUTABLE property. In the future, other attributes could be defined. Use the memory attribute feature to implement the following functions in KVM: - kvm_permissions_set(): Set the permissions for a guest page in the memory attribute XArray. - kvm_permissions_get(): Retrieve the permissions associated with a guest page in same XArray. These functions will be called in a following commit to associate proper permissions with guest pages instead of RWX for all the pages. Add 4 new memory attributes, private to the KVM implementation: - KVM_MEMORY_ATTRIBUTE_HEKI_READ - KVM_MEMORY_ATTRIBUTE_HEKI_WRITE - KVM_MEMORY_ATTRIBUTE_HEKI_EXEC - KVM_MEMORY_ATTRIBUTE_HEKI_IMMUTABLE Cc: Borislav Petkov Cc: Dave Hansen Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Kees Cook Cc: Madhavan T. Venkataraman Cc: Mickaël Salaün Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Thomas Gleixner Cc: Vitaly Kuznetsov Cc: Wanpeng Li Co-developed-by: Madhavan T. Venkataraman Signed-off-by: Madhavan T. Venkataraman Signed-off-by: Mickaël Salaün --- Changes since v1: * New patch replacing the deprecated page tracking mechanism. * Add new files: virt/lib/kvm_permissions.c and include/linux/kvm_mem_attr.h * Add new kvm_permissions_get() and kvm_permissions_set() leveraging the to-be-upstream memory attributes for KVM. * Introduce the KVM_MEMORY_ATTRIBUTE_HEKI_* values. --- arch/x86/kvm/Kconfig | 1 + arch/x86/kvm/Makefile | 4 +- include/linux/kvm_mem_attr.h | 32 +++++++++++ include/uapi/linux/kvm.h | 5 ++ virt/heki/Kconfig | 1 + virt/lib/kvm_permissions.c | 104 +++++++++++++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 include/linux/kvm_mem_attr.h create mode 100644 virt/lib/kvm_permissions.c diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 7a3b52b7e456..ea6d73241632 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -50,6 +50,7 @@ config KVM select HAVE_KVM_PM_NOTIFIER if PM select KVM_GENERIC_HARDWARE_ENABLING select HYPERVISOR_SUPPORTS_HEKI + select SPARSEMEM help Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 80e3fe184d17..aac51a5d2cae 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -9,10 +9,12 @@ endif include $(srctree)/virt/kvm/Makefile.kvm +VIRT_LIB = ../../../virt/lib + kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \ i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \ hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \ - mmu/spte.o + mmu/spte.o $(VIRT_LIB)/kvm_permissions.o ifdef CONFIG_HYPERV kvm-y += kvm_onhyperv.o diff --git a/include/linux/kvm_mem_attr.h b/include/linux/kvm_mem_attr.h new file mode 100644 index 000000000000..0a755025e553 --- /dev/null +++ b/include/linux/kvm_mem_attr.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * KVM guest page permissions - Definitions. + * + * Copyright © 2023 Microsoft Corporation. + */ +#ifndef __KVM_MEM_ATTR_H__ +#define __KVM_MEM_ATTR_H__ + +#include +#include + +/* clang-format off */ + +#define MEM_ATTR_READ BIT(0) +#define MEM_ATTR_WRITE BIT(1) +#define MEM_ATTR_EXEC BIT(2) +#define MEM_ATTR_IMMUTABLE BIT(3) + +#define MEM_ATTR_PROT ( \ + MEM_ATTR_READ | \ + MEM_ATTR_WRITE | \ + MEM_ATTR_EXEC | \ + MEM_ATTR_IMMUTABLE) + +/* clang-format on */ + +int kvm_permissions_set(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end, + unsigned long heki_attr); +unsigned long kvm_permissions_get(struct kvm *kvm, gfn_t gfn); + +#endif /* __KVM_MEM_ATTR_H__ */ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 2477b4a16126..2b5b90216565 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -2319,6 +2319,11 @@ struct kvm_memory_attributes { #define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3) +#define KVM_MEMORY_ATTRIBUTE_HEKI_READ (1ULL << 4) +#define KVM_MEMORY_ATTRIBUTE_HEKI_WRITE (1ULL << 5) +#define KVM_MEMORY_ATTRIBUTE_HEKI_EXEC (1ULL << 6) +#define KVM_MEMORY_ATTRIBUTE_HEKI_IMMUTABLE (1ULL << 7) + #define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd) struct kvm_create_guest_memfd { diff --git a/virt/heki/Kconfig b/virt/heki/Kconfig index 5ea75b595667..75a784653e31 100644 --- a/virt/heki/Kconfig +++ b/virt/heki/Kconfig @@ -5,6 +5,7 @@ config HEKI bool "Hypervisor Enforced Kernel Integrity (Heki)" depends on ARCH_SUPPORTS_HEKI && HYPERVISOR_SUPPORTS_HEKI + select KVM_GENERIC_MEMORY_ATTRIBUTES help This feature enhances guest virtual machine security by taking advantage of security features provided by the hypervisor for guests. diff --git a/virt/lib/kvm_permissions.c b/virt/lib/kvm_permissions.c new file mode 100644 index 000000000000..9f4e8027d21c --- /dev/null +++ b/virt/lib/kvm_permissions.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KVM guest page permissions - functions. + * + * Copyright © 2023 Microsoft Corporation. + */ +#include +#include + +#ifdef pr_fmt +#undef pr_fmt +#endif + +#define pr_fmt(fmt) "kvm: heki: " fmt + +/* clang-format off */ + +static unsigned long kvm_default_permissions = + MEM_ATTR_READ | + MEM_ATTR_WRITE | + MEM_ATTR_EXEC; + +static unsigned long kvm_memory_attributes_heki = + KVM_MEMORY_ATTRIBUTE_HEKI_READ | + KVM_MEMORY_ATTRIBUTE_HEKI_WRITE | + KVM_MEMORY_ATTRIBUTE_HEKI_EXEC | + KVM_MEMORY_ATTRIBUTE_HEKI_IMMUTABLE; + +/* clang-format on */ + +static unsigned long heki_attr_to_kvm_attr(unsigned long heki_attr) +{ + unsigned long kvm_attr = 0; + + if (WARN_ON_ONCE((heki_attr | MEM_ATTR_PROT) != MEM_ATTR_PROT)) + return 0; + + if (heki_attr & MEM_ATTR_READ) + kvm_attr |= KVM_MEMORY_ATTRIBUTE_HEKI_READ; + if (heki_attr & MEM_ATTR_WRITE) + kvm_attr |= KVM_MEMORY_ATTRIBUTE_HEKI_WRITE; + if (heki_attr & MEM_ATTR_EXEC) + kvm_attr |= KVM_MEMORY_ATTRIBUTE_HEKI_EXEC; + if (heki_attr & MEM_ATTR_IMMUTABLE) + kvm_attr |= KVM_MEMORY_ATTRIBUTE_HEKI_IMMUTABLE; + return kvm_attr; +} + +static unsigned long kvm_attr_to_heki_attr(unsigned long kvm_attr) +{ + unsigned long heki_attr = 0; + + if (kvm_attr & KVM_MEMORY_ATTRIBUTE_HEKI_READ) + heki_attr |= MEM_ATTR_READ; + if (kvm_attr & KVM_MEMORY_ATTRIBUTE_HEKI_WRITE) + heki_attr |= MEM_ATTR_WRITE; + if (kvm_attr & KVM_MEMORY_ATTRIBUTE_HEKI_EXEC) + heki_attr |= MEM_ATTR_EXEC; + if (kvm_attr & KVM_MEMORY_ATTRIBUTE_HEKI_IMMUTABLE) + heki_attr |= MEM_ATTR_IMMUTABLE; + return heki_attr; +} + +unsigned long kvm_permissions_get(struct kvm *kvm, gfn_t gfn) +{ + unsigned long kvm_attr = 0; + + /* + * Retrieve the permissions for a guest page. If not present (i.e., no + * attribute), then return default permissions (RWX). This means + * setting permissions to 0 resets them to RWX. We might want to + * revisit that in a future version. + */ + kvm_attr = kvm_get_memory_attributes(kvm, gfn); + if (kvm_attr) + return kvm_attr_to_heki_attr(kvm_attr); + else + return kvm_default_permissions; +} +EXPORT_SYMBOL_GPL(kvm_permissions_get); + +int kvm_permissions_set(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end, + unsigned long heki_attr) +{ + if ((heki_attr | MEM_ATTR_PROT) != MEM_ATTR_PROT) + return -EINVAL; + + if (gfn_end <= gfn_start) + return -EINVAL; + + if (kvm_range_has_memory_attributes(kvm, gfn_start, gfn_end, + KVM_MEMORY_ATTRIBUTE_HEKI_IMMUTABLE, + false)) { + pr_warn_ratelimited( + "Guest tried to change immutable permission for GFNs %llx-%llx\n", + gfn_start, gfn_end); + return -EPERM; + } + + return kvm_vm_set_mem_attributes(kvm, gfn_start, gfn_end, + heki_attr_to_kvm_attr(heki_attr), + kvm_memory_attributes_heki); +} +EXPORT_SYMBOL_GPL(kvm_permissions_set);