From nobody Wed Dec 31 02:48:49 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1699842437; cv=none; d=zohomail.com; s=zohoarc; b=b7Q+KmMk6ZUEVzYbxJDYgt66oJsaIeEM5e8tebsAdeUKK+7mfID0vIafhgVbe3JEJq5JWO+iQt241N8DQ8qEhIF67HcwTpLcPZGivFeBpkAXsPc646/a+6Y9OfE+oKSGVxYVm+0HnKWLOeq/CHmkAE/tcpY7/RMafNJ0jzFev8M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1699842437; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=8WJz1bKKdUs9xcU2dFmXJLCmSFo9jSqkndsw0dI+Hss=; b=dl/g7VlJH+f8zevO+PhJccCmSruEuS2P/1qsDhY40HPyUcLRBuMQpE7tJeotTcVmsoZdCesOXggo7peay+GvgidB4qkEg03v8qRlw1QOkKFZpaN13b6vinhV8l/nxyMqPnchNmF91ZEKQR4qYsjGXFORbRyPr5IVzE8JzoO4yLo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1699842437112254.67611595340816; Sun, 12 Nov 2023 18:27:17 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r2Md5-0006XL-B1; Sun, 12 Nov 2023 21:24:47 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r2Md4-0006XD-8M for qemu-devel@nongnu.org; Sun, 12 Nov 2023 21:24:46 -0500 Received: from smtp-1908.mail.infomaniak.ch ([185.125.25.8]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r2Md2-0008A3-Cl for qemu-devel@nongnu.org; Sun, 12 Nov 2023 21:24:46 -0500 Received: from smtp-3-0001.mail.infomaniak.ch (unknown [10.4.36.108]) by smtp-3-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4STCtf4t44zMpvd2; Mon, 13 Nov 2023 02:24:42 +0000 (UTC) Received: from unknown by smtp-3-0001.mail.infomaniak.ch (Postfix) with ESMTPA id 4STCtd2zG3zMpnPr; Mon, 13 Nov 2023 03:24:41 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=digikod.net; s=20191114; t=1699842282; bh=hEzwbKiCPTVRprt7TA2n5SNi5zwGnb2iVWTsgeipVHE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K6v5KJH9jR6IiLGfGMDtfMvhMpsRKAlNdnYP3VLP1tQYDJsD9yOa1l7BiqESRCqDJ cmZYiFVvTDYPtiXd2tBOhB0CrMCZj3y2+qczeM+o9M04Idv7FHkodSM7IbhjzC/hXd PiK+ofD1UU5HDgZ8vthIvlYSVcyE4os40daGAPbA= From: =?UTF-8?q?Micka=C3=ABl=20Sala=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=20Sala=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=20Don=C8=9Bu?= , =?UTF-8?q?Nicu=C8=99or=20C=C3=AE=C8=9Bu?= , Thara Gopinath , Trilok Soni , Wei Liu , Will Deacon , Yu Zhang , Zahra Tarkhani , =?UTF-8?q?=C8=98tefan=20=C8=98icleru?= , 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 13/19] heki: Implement a kernel page table walker Date: Sun, 12 Nov 2023 21:23:20 -0500 Message-ID: <20231113022326.24388-14-mic@digikod.net> In-Reply-To: <20231113022326.24388-1-mic@digikod.net> References: <20231113022326.24388-1-mic@digikod.net> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Infomaniak-Routing: alpha Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=185.125.25.8; envelope-from=mic@digikod.net; helo=smtp-1908.mail.infomaniak.ch X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @digikod.net) X-ZM-MESSAGEID: 1699842439213100003 From: Madhavan T. Venkataraman The Heki feature needs to do the following: - Find kernel mappings. - Determine the permissions associated with each mapping. - Determine the collective permissions for a guest physical page across all of its mappings. This way, a guest physical page can reflect only the required permissions in the EPT thanks to the KVM_HC_PROTECT_MEMORY hypercall.. Implement a kernel page table walker that walks all of the kernel mappings and calls a callback function for each mapping. Cc: Borislav Petkov Cc: Dave Hansen Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Kees Cook Cc: Madhavan T. Venkataraman Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Thomas Gleixner Cc: Vitaly Kuznetsov Cc: Wanpeng Li Co-developed-by: Micka=C3=ABl Sala=C3=BCn Signed-off-by: Micka=C3=ABl Sala=C3=BCn Signed-off-by: Madhavan T. Venkataraman --- Change since v1: * New patch and new file: virt/heki/walk.c --- include/linux/heki.h | 16 +++++ virt/heki/Makefile | 1 + virt/heki/walk.c | 140 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 virt/heki/walk.c diff --git a/include/linux/heki.h b/include/linux/heki.h index 9b0c966c50d1..a7ae0b387dfe 100644 --- a/include/linux/heki.h +++ b/include/linux/heki.h @@ -61,6 +61,22 @@ struct heki { struct heki_hypervisor *hypervisor; }; =20 +/* + * The kernel page table is walked to locate kernel mappings. For each + * mapping, a callback function is called. The table walker passes informa= tion + * about the mapping to the callback using this structure. + */ +struct heki_args { + /* Information passed by the table walker to the callback. */ + unsigned long va; + phys_addr_t pa; + size_t size; + unsigned long flags; +}; + +/* Callback function called by the table walker. */ +typedef void (*heki_func_t)(struct heki_args *args); + extern struct heki heki; extern bool heki_enabled; =20 diff --git a/virt/heki/Makefile b/virt/heki/Makefile index 354e567df71c..a5daa4ff7a4f 100644 --- a/virt/heki/Makefile +++ b/virt/heki/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only =20 obj-y +=3D main.o +obj-y +=3D walk.o diff --git a/virt/heki/walk.c b/virt/heki/walk.c new file mode 100644 index 000000000000..e10b54226fcc --- /dev/null +++ b/virt/heki/walk.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Hypervisor Enforced Kernel Integrity (Heki) - Kernel page table walker. + * + * Copyright =C2=A9 2023 Microsoft Corporation + * + * Cf. arch/x86/mm/init_64.c + */ + +#include +#include + +static void heki_walk_pte(pmd_t *pmd, unsigned long va, unsigned long va_e= nd, + heki_func_t func, struct heki_args *args) +{ + pte_t *pte; + unsigned long next_va; + + for (pte =3D pte_offset_kernel(pmd, va); va < va_end; + va =3D next_va, pte++) { + next_va =3D (va + PAGE_SIZE) & PAGE_MASK; + + if (next_va > va_end) + next_va =3D va_end; + + if (!pte_present(*pte)) + continue; + + args->va =3D va; + args->pa =3D pte_pfn(*pte) << PAGE_SHIFT; + args->size =3D PAGE_SIZE; + args->flags =3D pte_flags(*pte); + + func(args); + } +} + +static void heki_walk_pmd(pud_t *pud, unsigned long va, unsigned long va_e= nd, + heki_func_t func, struct heki_args *args) +{ + pmd_t *pmd; + unsigned long next_va; + + for (pmd =3D pmd_offset(pud, va); va < va_end; va =3D next_va, pmd++) { + next_va =3D pmd_addr_end(va, va_end); + + if (!pmd_present(*pmd)) + continue; + + if (pmd_large(*pmd)) { + args->va =3D va; + args->pa =3D pmd_pfn(*pmd) << PAGE_SHIFT; + args->pa +=3D va & (PMD_SIZE - 1); + args->size =3D next_va - va; + args->flags =3D pmd_flags(*pmd); + + func(args); + } else { + heki_walk_pte(pmd, va, next_va, func, args); + } + } +} + +static void heki_walk_pud(p4d_t *p4d, unsigned long va, unsigned long va_e= nd, + heki_func_t func, struct heki_args *args) +{ + pud_t *pud; + unsigned long next_va; + + for (pud =3D pud_offset(p4d, va); va < va_end; va =3D next_va, pud++) { + next_va =3D pud_addr_end(va, va_end); + + if (!pud_present(*pud)) + continue; + + if (pud_large(*pud)) { + args->va =3D va; + args->pa =3D pud_pfn(*pud) << PAGE_SHIFT; + args->pa +=3D va & (PUD_SIZE - 1); + args->size =3D next_va - va; + args->flags =3D pud_flags(*pud); + + func(args); + } else { + heki_walk_pmd(pud, va, next_va, func, args); + } + } +} + +static void heki_walk_p4d(pgd_t *pgd, unsigned long va, unsigned long va_e= nd, + heki_func_t func, struct heki_args *args) +{ + p4d_t *p4d; + unsigned long next_va; + + for (p4d =3D p4d_offset(pgd, va); va < va_end; va =3D next_va, p4d++) { + next_va =3D p4d_addr_end(va, va_end); + + if (!p4d_present(*p4d)) + continue; + + if (p4d_large(*p4d)) { + args->va =3D va; + args->pa =3D p4d_pfn(*p4d) << PAGE_SHIFT; + args->pa +=3D va & (P4D_SIZE - 1); + args->size =3D next_va - va; + args->flags =3D p4d_flags(*p4d); + + func(args); + } else { + heki_walk_pud(p4d, va, next_va, func, args); + } + } +} + +void heki_walk(unsigned long va, unsigned long va_end, heki_func_t func, + struct heki_args *args) +{ + pgd_t *pgd; + unsigned long next_va; + + for (pgd =3D pgd_offset_k(va); va < va_end; va =3D next_va, pgd++) { + next_va =3D pgd_addr_end(va, va_end); + + if (!pgd_present(*pgd)) + continue; + + if (pgd_large(*pgd)) { + args->va =3D va; + args->pa =3D pgd_pfn(*pgd) << PAGE_SHIFT; + args->pa +=3D va & (PGDIR_SIZE - 1); + args->size =3D next_va - va; + args->flags =3D pgd_flags(*pgd); + + func(args); + } else { + heki_walk_p4d(pgd, va, next_va, func, args); + } + } +} --=20 2.42.1