]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ptp: kvm: Use decrypted memory in confidential guest on x86
authorJeremi Piotrowski <jpiotrowski@linux.microsoft.com>
Wed, 8 Mar 2023 15:05:31 +0000 (15:05 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Dec 2024 17:08:53 +0000 (18:08 +0100)
[ Upstream commit 6365ba64b4dbe8b59ddaeaa724b281f3787715d5 ]

KVM_HC_CLOCK_PAIRING currently fails inside SEV-SNP guests because the
guest passes an address to static data to the host. In confidential
computing the host can't access arbitrary guest memory so handling the
hypercall runs into an "rmpfault". To make the hypercall work, the guest
needs to explicitly mark the memory as decrypted. Do that in
kvm_arch_ptp_init(), but retain the previous behavior for
non-confidential guests to save us from having to allocate memory.

Add a new arch-specific function (kvm_arch_ptp_exit()) to free the
allocation and mark the memory as encrypted again.

Signed-off-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com>
Link: https://lore.kernel.org/r/20230308150531.477741-1-jpiotrowski@linux.microsoft.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5e7aa97c7acf ("ptp: kvm: x86: Return EOPNOTSUPP instead of ENODEV from kvm_arch_ptp_init()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/ptp/ptp_kvm_arm.c
drivers/ptp/ptp_kvm_common.c
drivers/ptp/ptp_kvm_x86.c
include/linux/ptp_kvm.h

index b7d28c8dfb84e37df45f2dc4def7c2c11e1efa08..e68e6943167beb448b0aca75665236ff8314773e 100644 (file)
@@ -22,6 +22,10 @@ int kvm_arch_ptp_init(void)
        return 0;
 }
 
+void kvm_arch_ptp_exit(void)
+{
+}
+
 int kvm_arch_ptp_get_clock(struct timespec64 *ts)
 {
        return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL);
index fcae32f56f25a2d23807a5d1fdd643e1804fbbf4..051114a592865dfdd73b21a781969135b1306347 100644 (file)
@@ -130,6 +130,7 @@ static struct kvm_ptp_clock kvm_ptp_clock;
 static void __exit ptp_kvm_exit(void)
 {
        ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
+       kvm_arch_ptp_exit();
 }
 
 static int __init ptp_kvm_init(void)
index 4991054a213506601a24a515418223ee278dd448..902844cc1a17d5bd46461702ea149c852454db46 100644 (file)
 #include <uapi/linux/kvm_para.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/ptp_kvm.h>
+#include <linux/set_memory.h>
 
 static phys_addr_t clock_pair_gpa;
-static struct kvm_clock_pairing clock_pair;
+static struct kvm_clock_pairing clock_pair_glbl;
+static struct kvm_clock_pairing *clock_pair;
 
 int kvm_arch_ptp_init(void)
 {
+       struct page *p;
        long ret;
 
        if (!kvm_para_available())
                return -ENODEV;
 
-       clock_pair_gpa = slow_virt_to_phys(&clock_pair);
-       if (!pvclock_get_pvti_cpu0_va())
-               return -ENODEV;
+       if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+               p = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               if (!p)
+                       return -ENOMEM;
+
+               clock_pair = page_address(p);
+               ret = set_memory_decrypted((unsigned long)clock_pair, 1);
+               if (ret) {
+                       __free_page(p);
+                       clock_pair = NULL;
+                       goto nofree;
+               }
+       } else {
+               clock_pair = &clock_pair_glbl;
+       }
+
+       clock_pair_gpa = slow_virt_to_phys(clock_pair);
+       if (!pvclock_get_pvti_cpu0_va()) {
+               ret = -ENODEV;
+               goto err;
+       }
 
        ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
                             KVM_CLOCK_PAIRING_WALLCLOCK);
-       if (ret == -KVM_ENOSYS)
-               return -ENODEV;
+       if (ret == -KVM_ENOSYS) {
+               ret = -ENODEV;
+               goto err;
+       }
 
        return ret;
+
+err:
+       kvm_arch_ptp_exit();
+nofree:
+       return ret;
+}
+
+void kvm_arch_ptp_exit(void)
+{
+       if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+               WARN_ON(set_memory_encrypted((unsigned long)clock_pair, 1));
+               free_page((unsigned long)clock_pair);
+               clock_pair = NULL;
+       }
 }
 
 int kvm_arch_ptp_get_clock(struct timespec64 *ts)
@@ -49,8 +86,8 @@ int kvm_arch_ptp_get_clock(struct timespec64 *ts)
                return -EOPNOTSUPP;
        }
 
-       ts->tv_sec = clock_pair.sec;
-       ts->tv_nsec = clock_pair.nsec;
+       ts->tv_sec = clock_pair->sec;
+       ts->tv_nsec = clock_pair->nsec;
 
        return 0;
 }
@@ -81,9 +118,9 @@ int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,
                        pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
                        return -EOPNOTSUPP;
                }
-               tspec->tv_sec = clock_pair.sec;
-               tspec->tv_nsec = clock_pair.nsec;
-               *cycle = __pvclock_read_cycles(src, clock_pair.tsc);
+               tspec->tv_sec = clock_pair->sec;
+               tspec->tv_nsec = clock_pair->nsec;
+               *cycle = __pvclock_read_cycles(src, clock_pair->tsc);
        } while (pvclock_read_retry(src, version));
 
        *cs = &kvm_clock;
index c2e28deef33a8d09d4b7014731e2660016ffa8ba..746fd67c34806b0c19959b182a4088f5c560ceb8 100644 (file)
@@ -14,6 +14,7 @@ struct timespec64;
 struct clocksource;
 
 int kvm_arch_ptp_init(void);
+void kvm_arch_ptp_exit(void);
 int kvm_arch_ptp_get_clock(struct timespec64 *ts);
 int kvm_arch_ptp_get_crosststamp(u64 *cycle,
                struct timespec64 *tspec, struct clocksource **cs);