From patchwork Tue Jul 9 13:20:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Roy X-Patchwork-Id: 13727949 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 08080C2BD09 for ; Tue, 9 Jul 2024 13:21:03 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8E07A6B00A3; Tue, 9 Jul 2024 09:21:02 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 86A496B00A7; Tue, 9 Jul 2024 09:21:02 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 6E30A6B00A8; Tue, 9 Jul 2024 09:21:02 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 4CF266B00A3 for ; Tue, 9 Jul 2024 09:21:02 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id E4BB81A152B for ; Tue, 9 Jul 2024 13:21:01 +0000 (UTC) X-FDA: 82320274722.18.8F35EE1 Received: from smtp-fw-52004.amazon.com (smtp-fw-52004.amazon.com [52.119.213.154]) by imf21.hostedemail.com (Postfix) with ESMTP id 029A41C001A for ; Tue, 9 Jul 2024 13:20:59 +0000 (UTC) Authentication-Results: imf21.hostedemail.com; dkim=pass header.d=amazon.co.uk header.s=amazon201209 header.b=bEsxCxdN; spf=pass (imf21.hostedemail.com: domain of "prvs=913fd7204=roypat@amazon.co.uk" designates 52.119.213.154 as permitted sender) smtp.mailfrom="prvs=913fd7204=roypat@amazon.co.uk"; dmarc=pass (policy=quarantine) header.from=amazon.co.uk ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1720531245; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=myefINasqoLP8LFmYmmDEFb4CuSNvTYNmrkp8V5RNNQ=; b=kkHuAT8g+HICsBQC7WVtXlmQf7epGgLeHHui/kJ2kw2/8GQDrmclbm0S6mmFDfHiluN/Om ESkKrT6XiMCnB8tzPwpmdfTYfwQUrLhkhIb7/cM+QNRdc6mRbiCDjWeRK7gnharN4zAESk C3TD5qKpzox7DnHPy2Z7sdvtFgj3P7I= ARC-Authentication-Results: i=1; imf21.hostedemail.com; dkim=pass header.d=amazon.co.uk header.s=amazon201209 header.b=bEsxCxdN; spf=pass (imf21.hostedemail.com: domain of "prvs=913fd7204=roypat@amazon.co.uk" designates 52.119.213.154 as permitted sender) smtp.mailfrom="prvs=913fd7204=roypat@amazon.co.uk"; dmarc=pass (policy=quarantine) header.from=amazon.co.uk ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1720531245; a=rsa-sha256; cv=none; b=j/p488vNBEyd9+py7nuj3jVdw2kuobMD7mimdVkxHyRdtVR6gVy0KqvhZbigZxfVnNXz8v Hqu14QD0tooeYteg4C1uOBdCS3gLxMQq6a9WQeD1OYnj342ZQhj/SSS6IoBzcr2hfqXRli +uUuFRyJRYY6Y8heqaU4gGQblPUxMjg= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.co.uk; i=@amazon.co.uk; q=dns/txt; s=amazon201209; t=1720531260; x=1752067260; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=myefINasqoLP8LFmYmmDEFb4CuSNvTYNmrkp8V5RNNQ=; b=bEsxCxdN3ru94aKZb0/1q4Gst3DjyxBRIiFbG8KuVk28wAnM/z/Xpc9s WRlKtr2wazKJVhx5mHreB1pfy2RkrhEmP1VU1iNKLU6wIwVOL5FOontin 1XSKRl2kDsQ+Za/E9B8ZDSBLejoVfWuuusJRbh4twHSnA8Yid6P5Mu4ja 0=; X-IronPort-AV: E=Sophos;i="6.09,195,1716249600"; d="scan'208";a="217222124" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO smtpout.prod.us-east-1.prod.farcaster.email.amazon.dev) ([10.43.8.2]) by smtp-border-fw-52004.iad7.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jul 2024 13:20:58 +0000 Received: from EX19MTAUEB001.ant.amazon.com [10.0.0.204:19435] by smtpin.naws.us-east-1.prod.farcaster.email.amazon.dev [10.0.13.24:2525] with esmtp (Farcaster) id 18a4efc4-1b3b-4e58-98d8-17e4bb420299; Tue, 9 Jul 2024 13:20:57 +0000 (UTC) X-Farcaster-Flow-ID: 18a4efc4-1b3b-4e58-98d8-17e4bb420299 Received: from EX19D008UEA004.ant.amazon.com (10.252.134.191) by EX19MTAUEB001.ant.amazon.com (10.252.135.108) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 9 Jul 2024 13:20:57 +0000 Received: from EX19MTAUEC001.ant.amazon.com (10.252.135.222) by EX19D008UEA004.ant.amazon.com (10.252.134.191) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 9 Jul 2024 13:20:56 +0000 Received: from ua2d7e1a6107c5b.ant.amazon.com (172.19.88.180) by mail-relay.amazon.com (10.252.135.200) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 9 Jul 2024 13:20:54 +0000 From: Patrick Roy To: , , , , , CC: Patrick Roy , , , , , , , , , , , , , , , , , Subject: [RFC PATCH 1/8] kvm: Allow reading/writing gmem using kvm_{read,write}_guest Date: Tue, 9 Jul 2024 14:20:29 +0100 Message-ID: <20240709132041.3625501-2-roypat@amazon.co.uk> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240709132041.3625501-1-roypat@amazon.co.uk> References: <20240709132041.3625501-1-roypat@amazon.co.uk> MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam01 X-Rspamd-Queue-Id: 029A41C001A X-Stat-Signature: zea6isqq8r58ay4cu63oo1h9yx4sxmm3 X-HE-Tag: 1720531259-448239 X-HE-Meta: U2FsdGVkX1/udc607P0FYmyzvL6SMwe2oH7wLDrBEXxxn3tt+7GuGJ/gQDStRiruB+8EN1fmWJCHInrrSbIqvHVQArxM1Yi+XkmgQFSSJr2CrtaedEEna4np2ubeh+9XAY2vo/Ecj+xRfrYW+7g38hh00y1nyD1KRlQ6kR2HhyQ4mBoWW5ME75xUFt0SWuIOfwq/7sqjXpM57qPXlbSKmN6tbn+S+J5SJL/2zmkKFM1Ehv1DvCV81ww/DgLJGcLgj4mNIj6bFM8eH/fedB9i2JM8xpMPJVJcjzB/1m1HuWWLEnPROL2+XWl7qjLlKkUSx1cHE4V6A7fH3EGDc8gdnsMBCDXAYC9VpHeDy6DBIQXi0eOp9Vyck5TSWn1Qn88KnO7GhsVy15iUwAlBFdCTZ4SR1MGU5QlUTuWlFp5RL4vSPkrbtfUpJkbafJ3N5xx/BN0yKBCetGNigUgr/aZS8FY5B86vhU2NrCkvTbNRmeDHHpFkDiFx1WRtvWV6Tfn2M3YmIKhwbB8f78QWryysh3S6GbCGH5pXL+mKapuXLMvlUYDrAb1CYDmkjTWRMEdM95LBt17Ymnfj7nfxE/zJqmWPF9N6BF/rjjjpIB1aN4DLj19bvNGssWp5unKfbTJeDh0f3jAqPcai9ur2y09A3Ynhrq0CxzirFCVoEjTMAipx5TfQchTU7XCWEW5l/GNWWC3P+6Dm6HMgytz5NEAcdGt/l8UzacsBfOLW3xaudGRXxcsfMxhTR6OVtnRA0avue1tF+INpJ60gDW3PmLnznv1kgT/n6Dj5rqLvFINO19JzyPF7v3rGRoMKUMCVK87Gv8zFY5JkcqaRhdqDP+ppnnsqv/TyklIuaP21OR437jpuTRhxZLwa7pc3hpLYfTFewRPpBKHA4C6bohsJLkcQCB3dtvQHvMdPyou9e12Olb0fin9gqyZhtwQrMi8iW55EDRAWvhzEQWE4yFMPHlB y+lV7bCE Nc3BWtrbFygRi8Bp8mrfaLQFZD7oxMtsGZYjo5/PrbDZUNsvWCnXtaGjS6Sk7QVpR+pS6Q0fp0VvJA/rS4wgZvpSMVTaBqeZyrt4wozXLO6lTRYGV+vHycaUU1SjziXBesSDA9Ky0xAuV1me3OvlUEPn+3ILRXXsMBR/mtn6Mv0Tcl7K0wz3tndJAAB0Dtfg0JY5pksRjy5wItrib1YxaLJ16LFRuEO4Rb0mGhhK1bVCJe+h+U3Dij1CxUWVFyoh/snpqPaFLDNk0Zo74G3bdcfN+OsTbZe0NjJ1gTfhVSUy7KK9VfC6mIdrxBYfGRX/EQGjtMHRGgX8Df7eirLm5N7n8zgH321WQwhe/2fRslTTAVyVzSrmc4ln/iJ+aBQjsX2t+VtvfAnGuya2sHhXtxvsIGunGShDqZjp9 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: If KVM can access guest-private memory without causing a host-kernel panic (e.g. currently only if the vm type is KVM_SW_PROTECTED_VM), allow `kvm_{read,write}_guest` to access gfns that are set to "private". If KVM cannot access guest-private memory (say, because it is running a TDX VM), prepare a KVM_EXIT_MEMORY_FAULT (if possible) and return -EFAULT. KVM can only prepare the memory fault exit inside the `kvm_vcpu_{read,write}_guest` variant, as it needs a vcpu reference to assign the exit reason to. KVM accesses guest-private memory via kernel virtual addresses/the direct map. In the special case of guest_memfd, it does not have to worry about gfn->pfn mappings being invalidated, since guest_memfd pages are immovable. Signed-off-by: Patrick Roy --- include/linux/kvm_host.h | 5 +++ virt/kvm/kvm_main.c | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) base-commit: 771df9ffadb8204e61d3e98f36c5067102aab78f diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 2a6679b46427..8f980aafd5ca 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -2407,6 +2407,11 @@ static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, vcpu->run->memory_fault.flags |= KVM_MEMORY_EXIT_FLAG_PRIVATE; } +static inline bool kvm_can_access_gmem(struct kvm *kvm) +{ + return kvm->arch.vm_type == KVM_X86_SW_PROTECTED_VM; +} + #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES static inline unsigned long kvm_get_memory_attributes(struct kvm *kvm, gfn_t gfn) { diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8c7cbc9ec9ee..b3b3de70a4df 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3286,11 +3286,51 @@ static int __kvm_read_guest_page(struct kvm_memory_slot *slot, gfn_t gfn, return 0; } +static int __kvm_read_guest_private_page(struct kvm *kvm, + struct kvm_memory_slot *memslot, gfn_t gfn, + void *data, int offset, int len) +{ + kvm_pfn_t pfn; + int r; + struct page *page; + void *kaddr; + + if (!kvm_can_access_gmem(kvm)) + return -EFAULT; + + r = kvm_gmem_get_pfn(kvm, memslot, gfn, &pfn, NULL); + + if (r < 0) + return -EFAULT; + + page = pfn_to_page(pfn); + lock_page(page); + kaddr = page_address(page) + offset; + memcpy(data, kaddr, len); + unlock_page(page); + put_page(page); + return 0; +} + +static int __kvm_vcpu_read_guest_private_page(struct kvm_vcpu *vcpu, + struct kvm_memory_slot *memslot, gfn_t gfn, + void *data, int offset, int len) +{ + if (!kvm_can_access_gmem(vcpu->kvm)) { + kvm_prepare_memory_fault_exit(vcpu, gfn + offset, len, false, + false, true); + return -EFAULT; + } + return __kvm_read_guest_private_page(vcpu->kvm, memslot, gfn, data, offset, len); +} + int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, int len) { struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); + if (kvm_mem_is_private(kvm, gfn)) + return __kvm_read_guest_private_page(kvm, slot, gfn, data, offset, len); return __kvm_read_guest_page(slot, gfn, data, offset, len); } EXPORT_SYMBOL_GPL(kvm_read_guest_page); @@ -3300,6 +3340,8 @@ int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, { struct kvm_memory_slot *slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); + if (kvm_mem_is_private(vcpu->kvm, gfn)) + return __kvm_vcpu_read_guest_private_page(vcpu, slot, gfn, data, offset, len); return __kvm_read_guest_page(slot, gfn, data, offset, len); } EXPORT_SYMBOL_GPL(kvm_vcpu_read_guest_page); @@ -3390,11 +3432,52 @@ static int __kvm_write_guest_page(struct kvm *kvm, return 0; } +static int __kvm_write_guest_private_page(struct kvm *kvm, + struct kvm_memory_slot *memslot, gfn_t gfn, + const void *data, int offset, int len) +{ + kvm_pfn_t pfn; + int r; + struct page *page; + void *kaddr; + + if (!kvm_can_access_gmem(kvm)) + return -EFAULT; + + r = kvm_gmem_get_pfn(kvm, memslot, gfn, &pfn, NULL); + + if (r < 0) + return -EFAULT; + + page = pfn_to_page(pfn); + lock_page(page); + kaddr = page_address(page) + offset; + memcpy(kaddr, data, len); + unlock_page(page); + put_page(page); + + return 0; +} + +static int __kvm_vcpu_write_guest_private_page(struct kvm_vcpu *vcpu, + struct kvm_memory_slot *memslot, gfn_t gfn, + const void *data, int offset, int len) +{ + if (!kvm_can_access_gmem(vcpu->kvm)) { + kvm_prepare_memory_fault_exit(vcpu, gfn + offset, len, true, + false, true); + return -EFAULT; + } + return __kvm_write_guest_private_page(vcpu->kvm, memslot, gfn, data, offset, len); +} + int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data, int offset, int len) { struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); + if (kvm_mem_is_private(kvm, gfn)) + return __kvm_write_guest_private_page(kvm, slot, gfn, data, offset, len); return __kvm_write_guest_page(kvm, slot, gfn, data, offset, len); } EXPORT_SYMBOL_GPL(kvm_write_guest_page); @@ -3404,6 +3487,8 @@ int kvm_vcpu_write_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, { struct kvm_memory_slot *slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); + if (kvm_mem_is_private(vcpu->kvm, gfn)) + return __kvm_vcpu_write_guest_private_page(vcpu, slot, gfn, data, offset, len); return __kvm_write_guest_page(vcpu->kvm, slot, gfn, data, offset, len); } EXPORT_SYMBOL_GPL(kvm_vcpu_write_guest_page);