Skip to content

Commit b39c6bd

Browse files
committed
Merge tag 'kvm-x86-sev-7.2' of https://github.com/kvm-x86/linux into HEAD
KVM SEV changes for 7.2 - Don't advertise support for unusuable VM types, and account for VM types that are disabled by firmware, e.g. to mitigate security vulnerabilities. - Rewrite the SEV {en,de}crypt debug ioctls as they were riddle with bugs and unnecessarily complicated, and add comprehensive tests. - Clean up and deduplicate the SEV page pinning code. - Fix minor goofs related to writing back CPUID information after firmware rejects a CPUID page for an SNP vCPU.
2 parents b02a4f8 + 97cd21d commit b39c6bd

12 files changed

Lines changed: 518 additions & 257 deletions

File tree

arch/x86/kvm/svm/sev.c

Lines changed: 229 additions & 234 deletions
Large diffs are not rendered by default.

arch/x86/kvm/vmx/tdx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3261,7 +3261,7 @@ static int tdx_vcpu_init_mem_region(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *c
32613261
};
32623262
gmem_ret = kvm_gmem_populate(kvm, gpa_to_gfn(region.gpa),
32633263
u64_to_user_ptr(region.source_addr),
3264-
1, tdx_gmem_post_populate, &arg);
3264+
1, false, tdx_gmem_post_populate, &arg);
32653265
if (gmem_ret < 0) {
32663266
ret = gmem_ret;
32673267
break;

drivers/crypto/ccp/sev-dev.c

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,17 +2381,15 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable)
23812381
return ret;
23822382
}
23832383

2384-
static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
2384+
static int __sev_do_snp_platform_status(struct sev_user_data_snp_status *status,
2385+
int *error)
23852386
{
23862387
struct sev_device *sev = psp_master->sev_data;
23872388
struct sev_data_snp_addr buf;
23882389
struct page *status_page;
23892390
void *data;
23902391
int ret;
23912392

2392-
if (!argp->data)
2393-
return -EINVAL;
2394-
23952393
status_page = alloc_page(GFP_KERNEL_ACCOUNT);
23962394
if (!status_page)
23972395
return -ENOMEM;
@@ -2414,7 +2412,7 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
24142412
}
24152413

24162414
buf.address = __psp_pa(data);
2417-
ret = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &argp->error);
2415+
ret = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, error);
24182416

24192417
if (sev->snp_initialized) {
24202418
/*
@@ -2429,15 +2427,32 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
24292427
if (ret)
24302428
goto cleanup;
24312429

2432-
if (copy_to_user((void __user *)argp->data, data,
2433-
sizeof(struct sev_user_data_snp_status)))
2434-
ret = -EFAULT;
2430+
memcpy(status, data, sizeof(*status));
24352431

24362432
cleanup:
24372433
__free_pages(status_page, 0);
24382434
return ret;
24392435
}
24402436

2437+
static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
2438+
{
2439+
struct sev_user_data_snp_status status;
2440+
int ret;
2441+
2442+
if (!argp->data)
2443+
return -EINVAL;
2444+
2445+
ret = __sev_do_snp_platform_status(&status, &argp->error);
2446+
if (ret < 0)
2447+
return ret;
2448+
2449+
if (copy_to_user((void __user *)argp->data, &status,
2450+
sizeof(struct sev_user_data_snp_status)))
2451+
ret = -EFAULT;
2452+
2453+
return ret;
2454+
}
2455+
24412456
static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp)
24422457
{
24432458
struct sev_device *sev = psp_master->sev_data;
@@ -2939,3 +2954,73 @@ void sev_pci_exit(void)
29392954

29402955
sev_firmware_shutdown(sev);
29412956
}
2957+
2958+
static int get_v1_svn(struct sev_device *sev)
2959+
{
2960+
struct sev_snp_tcb_version_genoa_milan *tcb;
2961+
struct sev_user_data_snp_status status;
2962+
int ret, error = 0;
2963+
2964+
mutex_lock(&sev_cmd_mutex);
2965+
ret = __sev_do_snp_platform_status(&status, &error);
2966+
mutex_unlock(&sev_cmd_mutex);
2967+
if (ret < 0)
2968+
return ret;
2969+
2970+
tcb = (struct sev_snp_tcb_version_genoa_milan *)&status
2971+
.current_tcb_version;
2972+
return tcb->snp;
2973+
}
2974+
2975+
static int get_v2_svn(struct sev_device *sev)
2976+
{
2977+
struct sev_user_data_snp_status status;
2978+
struct sev_snp_tcb_version_turin *tcb;
2979+
int ret, error = 0;
2980+
2981+
mutex_lock(&sev_cmd_mutex);
2982+
ret = __sev_do_snp_platform_status(&status, &error);
2983+
mutex_unlock(&sev_cmd_mutex);
2984+
if (ret < 0)
2985+
return ret;
2986+
2987+
tcb = (struct sev_snp_tcb_version_turin *)&status
2988+
.current_tcb_version;
2989+
return tcb->snp;
2990+
}
2991+
2992+
static bool sev_firmware_allows_es(struct sev_device *sev)
2993+
{
2994+
/* Documented in AMD-SB-3023 */
2995+
if (boot_cpu_has(X86_FEATURE_ZEN4) || boot_cpu_has(X86_FEATURE_ZEN3))
2996+
return get_v1_svn(sev) < 0x1b;
2997+
else if (boot_cpu_has(X86_FEATURE_ZEN5))
2998+
return get_v2_svn(sev) < 0x4;
2999+
else
3000+
return true;
3001+
}
3002+
3003+
int sev_firmware_supported_vm_types(void)
3004+
{
3005+
int supported_vm_types = 0;
3006+
struct sev_device *sev;
3007+
3008+
if (!psp_master || !psp_master->sev_data)
3009+
return supported_vm_types;
3010+
sev = psp_master->sev_data;
3011+
3012+
supported_vm_types |= BIT(KVM_X86_SEV_VM);
3013+
supported_vm_types |= BIT(KVM_X86_SEV_ES_VM);
3014+
3015+
if (!sev->snp_initialized)
3016+
return supported_vm_types;
3017+
3018+
supported_vm_types |= BIT(KVM_X86_SNP_VM);
3019+
3020+
if (!sev_firmware_allows_es(sev))
3021+
supported_vm_types &= ~BIT(KVM_X86_SEV_ES_VM);
3022+
3023+
return supported_vm_types;
3024+
3025+
}
3026+
EXPORT_SYMBOL_FOR_MODULES(sev_firmware_supported_vm_types, "kvm-amd");

include/linux/kvm_host.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2596,7 +2596,8 @@ int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_ord
25962596
typedef int (*kvm_gmem_populate_cb)(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
25972597
struct page *page, void *opaque);
25982598

2599-
long kvm_gmem_populate(struct kvm *kvm, gfn_t gfn, void __user *src, long npages,
2599+
long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src,
2600+
long npages, bool may_writeback_src,
26002601
kvm_gmem_populate_cb post_populate, void *opaque);
26012602
#endif
26022603

include/linux/psp-sev.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,42 @@ struct snp_feature_info {
902902
/* Feature bits in EBX */
903903
#define SNP_SEV_TIO_SUPPORTED BIT(1)
904904

905+
/**
906+
* struct sev_snp_tcb_version_genoa_milan
907+
*
908+
* @boot_loader: SVN of PSP bootloader
909+
* @tee: SVN of PSP operating system
910+
* @reserved: reserved
911+
* @snp: SVN of SNP firmware
912+
* @microcode: Lowest current patch level of all cores
913+
*/
914+
struct sev_snp_tcb_version_genoa_milan {
915+
u8 boot_loader;
916+
u8 tee;
917+
u8 reserved[4];
918+
u8 snp;
919+
u8 microcode;
920+
};
921+
922+
/**
923+
* struct sev_snp_tcb_version_turin
924+
*
925+
* @fmc: SVN of FMC firmware
926+
* @boot_loader: SVN of PSP bootloader
927+
* @tee: SVN of PSP operating system
928+
* @snp: SVN of SNP firmware
929+
* @reserved: reserved
930+
* @microcode: Lowest current patch level of all cores
931+
*/
932+
struct sev_snp_tcb_version_turin {
933+
u8 fmc;
934+
u8 boot_loader;
935+
u8 tee;
936+
u8 snp;
937+
u8 reserved[3];
938+
u8 microcode;
939+
};
940+
905941
#ifdef CONFIG_CRYPTO_DEV_SP_PSP
906942

907943
/**
@@ -1048,6 +1084,7 @@ void snp_free_firmware_page(void *addr);
10481084
void sev_platform_shutdown(void);
10491085
bool sev_is_snp_ciphertext_hiding_supported(void);
10501086
u64 sev_get_snp_policy_bits(void);
1087+
int sev_firmware_supported_vm_types(void);
10511088

10521089
#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
10531090

tools/testing/selftests/kvm/Makefile.kvm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ TEST_GEN_PROGS_x86 += x86/tsc_msrs_test
141141
TEST_GEN_PROGS_x86 += x86/vmx_pmu_caps_test
142142
TEST_GEN_PROGS_x86 += x86/xen_shinfo_test
143143
TEST_GEN_PROGS_x86 += x86/xen_vmcall_test
144+
TEST_GEN_PROGS_x86 += x86/sev_dbg_test
144145
TEST_GEN_PROGS_x86 += x86/sev_init2_tests
145146
TEST_GEN_PROGS_x86 += x86/sev_migrate_tests
146147
TEST_GEN_PROGS_x86 += x86/sev_smoke_test

tools/testing/selftests/kvm/include/x86/sev.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,28 @@ static inline void snp_launch_update_data(struct kvm_vm *vm, gpa_t gpa,
144144
vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_UPDATE, &update_data);
145145
}
146146

147+
static inline void sev_dbg_crypt_memory(struct kvm_vm *vm, unsigned int cmd,
148+
void *dst, void *src, unsigned int len)
149+
{
150+
struct kvm_sev_dbg dbg = {
151+
.src_uaddr = (unsigned long)src,
152+
.dst_uaddr = (unsigned long)dst,
153+
.len = len,
154+
};
155+
156+
vm_sev_ioctl(vm, cmd, &dbg);
157+
}
158+
159+
static inline void sev_decrypt_memory(struct kvm_vm *vm, void *dst, void *src,
160+
unsigned int len)
161+
{
162+
sev_dbg_crypt_memory(vm, KVM_SEV_DBG_DECRYPT, dst, src, len);
163+
}
164+
165+
static inline void sev_encrypt_memory(struct kvm_vm *vm, void *dst, void *src,
166+
unsigned int len)
167+
{
168+
sev_dbg_crypt_memory(vm, KVM_SEV_DBG_ENCRYPT, dst, src, len);
169+
}
170+
147171
#endif /* SELFTEST_KVM_SEV_H */
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <fcntl.h>
3+
#include <string.h>
4+
#include <sys/ioctl.h>
5+
6+
#include "test_util.h"
7+
#include "kvm_util.h"
8+
#include "processor.h"
9+
#include "sev.h"
10+
11+
#define BUFFER_SIZE (PAGE_SIZE * 2)
12+
13+
static u8 *data;
14+
static u8 src[BUFFER_SIZE] __aligned(PAGE_SIZE);
15+
static u8 dst[BUFFER_SIZE] __aligned(PAGE_SIZE);
16+
17+
static void validate_dst(int i, int nr_bytes, u8 pattern)
18+
{
19+
for ( ; i < nr_bytes; i++)
20+
TEST_ASSERT(dst[i] == pattern,
21+
"Expected 0x%x at byte %u, got 0x%x",
22+
pattern, i, dst[i]);
23+
}
24+
25+
static void validate_buffers(void)
26+
{
27+
int i;
28+
29+
for (i = 0; i < BUFFER_SIZE; i++)
30+
TEST_ASSERT(src[i] == dst[i],
31+
"Expected src[%u] (0x%x) == dst[%u] (0x%x)",
32+
i, src[i], i, dst[i]);
33+
}
34+
35+
static void ____test_sev_dbg(struct kvm_vm *vm, int i, int j, int nr_bytes)
36+
{
37+
u8 pattern = guest_random_u32(&guest_rng);
38+
39+
if (i + nr_bytes > BUFFER_SIZE || j + nr_bytes > BUFFER_SIZE)
40+
return;
41+
42+
memset(&src[i], pattern, nr_bytes);
43+
sev_encrypt_memory(vm, &data[j], &src[i], nr_bytes);
44+
sev_decrypt_memory(vm, &dst[i], &data[j], nr_bytes);
45+
validate_buffers();
46+
validate_dst(i, nr_bytes, pattern);
47+
}
48+
49+
static void __test_sev_dbg(struct kvm_vm *vm, int nr_bytes)
50+
{
51+
/*
52+
* In a perfect world, all sizes at all combinations within the buffers
53+
* would be tested. In reality, even this much testing is quite slow.
54+
* Target sizes and offsets around the chunk (16 bytes) and page (4096
55+
* bytes) sizes.
56+
*/
57+
int x[] = { 1, 8, 15, 16, 23 };
58+
int p = PAGE_SIZE - 24;
59+
int i, j;
60+
61+
____test_sev_dbg(vm, 0, 0, nr_bytes);
62+
63+
for (i = 0; i < ARRAY_SIZE(x); i++) {
64+
for (j = 0; j < ARRAY_SIZE(x); j++) {
65+
____test_sev_dbg(vm, x[i], x[j], nr_bytes);
66+
____test_sev_dbg(vm, x[i], p + x[j], nr_bytes);
67+
____test_sev_dbg(vm, p + x[i], x[j], nr_bytes);
68+
____test_sev_dbg(vm, p + x[i], p + x[j], nr_bytes);
69+
}
70+
}
71+
}
72+
73+
static void test_sev_dbg(u32 type, u64 policy)
74+
{
75+
int sizes[] = { 1, 8, 15, 16, 17, 32, 33 };
76+
struct kvm_vcpu *vcpu;
77+
struct kvm_vm *vm;
78+
int i;
79+
80+
if (!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(type)))
81+
return;
82+
83+
vm = vm_sev_create_with_one_vcpu(type, NULL, &vcpu);
84+
85+
data = addr_gva2hva(vm, vm_alloc(vm, BUFFER_SIZE, KVM_UTIL_MIN_VADDR));
86+
memset(data, 0xaa, BUFFER_SIZE);
87+
88+
vm_sev_launch(vm, policy, NULL);
89+
90+
sev_decrypt_memory(vm, dst, data, BUFFER_SIZE);
91+
validate_dst(0, BUFFER_SIZE, 0xaa);
92+
93+
memset(src, 0x55, BUFFER_SIZE);
94+
sev_encrypt_memory(vm, data, src, BUFFER_SIZE);
95+
sev_decrypt_memory(vm, dst, data, BUFFER_SIZE);
96+
validate_dst(0, BUFFER_SIZE, 0x55);
97+
98+
__test_sev_dbg(vm, PAGE_SIZE);
99+
100+
for (i = 0; i < ARRAY_SIZE(sizes); i++) {
101+
__test_sev_dbg(vm, sizes[i]);
102+
__test_sev_dbg(vm, PAGE_SIZE - sizes[i]);
103+
__test_sev_dbg(vm, PAGE_SIZE + sizes[i]);
104+
__test_sev_dbg(vm, BUFFER_SIZE - sizes[i]);
105+
}
106+
107+
kvm_vm_free(vm);
108+
}
109+
110+
int main(int argc, char *argv[])
111+
{
112+
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
113+
114+
/* Note, KVM doesn't support {de,en}crypt commands for SNP. */
115+
test_sev_dbg(KVM_X86_SEV_VM, 0);
116+
test_sev_dbg(KVM_X86_SEV_ES_VM, SEV_POLICY_ES);
117+
return 0;
118+
}

tools/testing/selftests/kvm/x86/sev_init2_tests.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,14 @@ int main(int argc, char *argv[])
136136
kvm_check_cap(KVM_CAP_VM_TYPES), 1 << KVM_X86_SEV_VM);
137137

138138
TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_VM));
139-
have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES);
139+
have_sev_es = kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_ES_VM);
140140

141-
TEST_ASSERT(have_sev_es == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_ES_VM)),
142-
"sev-es: KVM_CAP_VM_TYPES (%x) does not match cpuid (checking %x)",
143-
kvm_check_cap(KVM_CAP_VM_TYPES), 1 << KVM_X86_SEV_ES_VM);
141+
TEST_ASSERT(!have_sev_es || kvm_cpu_has(X86_FEATURE_SEV_ES),
142+
"sev-es: SEV_ES_VM supported without SEV_ES in CPUID");
144143

145-
have_snp = kvm_cpu_has(X86_FEATURE_SEV_SNP);
146-
TEST_ASSERT(have_snp == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SNP_VM)),
147-
"sev-snp: KVM_CAP_VM_TYPES (%x) indicates SNP support (bit %d), but CPUID does not",
148-
kvm_check_cap(KVM_CAP_VM_TYPES), KVM_X86_SNP_VM);
144+
have_snp = kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SNP_VM);
145+
TEST_ASSERT(!have_snp || kvm_cpu_has(X86_FEATURE_SEV_SNP),
146+
"sev-snp: SNP_VM supported without SEV_SNP in CPUID");
149147

150148
test_vm_types();
151149

tools/testing/selftests/kvm/x86/sev_migrate_tests.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ int main(int argc, char *argv[])
374374

375375
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
376376

377-
have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES);
377+
have_sev_es = kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_ES_VM);
378378

379379
if (kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) {
380380
test_sev_migrate_from(/* es= */ false);

0 commit comments

Comments
 (0)