Skip to content

Commit 5dfe7a7

Browse files
committed
Merge tag 'x86_tdx_for_6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 tdx updates from Dave Hansen: - Fix a race window where load_unaligned_zeropad() could cause a fatal shutdown during TDX private<=>shared conversion The race has never been observed in practice but might allow load_unaligned_zeropad() to catch a TDX page in the middle of its conversion process which would lead to a fatal and unrecoverable guest shutdown. - Annotate sites where VM "exit reasons" are reused as hypercall numbers. * tag 'x86_tdx_for_6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/mm: Fix enc_status_change_finish_noop() x86/tdx: Fix race between set_memory_encrypted() and load_unaligned_zeropad() x86/mm: Allow guest.enc_status_change_prepare() to fail x86/tdx: Wrap exit reason with hcall_func()
2 parents 36db314 + 94142c9 commit 5dfe7a7

File tree

7 files changed

+69
-21
lines changed

7 files changed

+69
-21
lines changed

arch/x86/boot/compressed/tdx.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static inline unsigned int tdx_io_in(int size, u16 port)
2020
{
2121
struct tdx_hypercall_args args = {
2222
.r10 = TDX_HYPERCALL_STANDARD,
23-
.r11 = EXIT_REASON_IO_INSTRUCTION,
23+
.r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION),
2424
.r12 = size,
2525
.r13 = 0,
2626
.r14 = port,
@@ -36,7 +36,7 @@ static inline void tdx_io_out(int size, u16 port, u32 value)
3636
{
3737
struct tdx_hypercall_args args = {
3838
.r10 = TDX_HYPERCALL_STANDARD,
39-
.r11 = EXIT_REASON_IO_INSTRUCTION,
39+
.r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION),
4040
.r12 = size,
4141
.r13 = 1,
4242
.r14 = port,

arch/x86/coco/tdx/tdx.c

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,6 @@ noinstr void __tdx_hypercall_failed(void)
4444
panic("TDVMCALL failed. TDX module bug?");
4545
}
4646

47-
/*
48-
* The TDG.VP.VMCALL-Instruction-execution sub-functions are defined
49-
* independently from but are currently matched 1:1 with VMX EXIT_REASONs.
50-
* Reusing the KVM EXIT_REASON macros makes it easier to connect the host and
51-
* guest sides of these calls.
52-
*/
53-
static __always_inline u64 hcall_func(u64 exit_reason)
54-
{
55-
return exit_reason;
56-
}
57-
5847
#ifdef CONFIG_KVM_GUEST
5948
long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, unsigned long p2,
6049
unsigned long p3, unsigned long p4)
@@ -744,6 +733,30 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc)
744733
return true;
745734
}
746735

736+
static bool tdx_enc_status_change_prepare(unsigned long vaddr, int numpages,
737+
bool enc)
738+
{
739+
/*
740+
* Only handle shared->private conversion here.
741+
* See the comment in tdx_early_init().
742+
*/
743+
if (enc)
744+
return tdx_enc_status_changed(vaddr, numpages, enc);
745+
return true;
746+
}
747+
748+
static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages,
749+
bool enc)
750+
{
751+
/*
752+
* Only handle private->shared conversion here.
753+
* See the comment in tdx_early_init().
754+
*/
755+
if (!enc)
756+
return tdx_enc_status_changed(vaddr, numpages, enc);
757+
return true;
758+
}
759+
747760
void __init tdx_early_init(void)
748761
{
749762
u64 cc_mask;
@@ -771,9 +784,30 @@ void __init tdx_early_init(void)
771784
*/
772785
physical_mask &= cc_mask - 1;
773786

774-
x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required;
775-
x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required;
776-
x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed;
787+
/*
788+
* The kernel mapping should match the TDX metadata for the page.
789+
* load_unaligned_zeropad() can touch memory *adjacent* to that which is
790+
* owned by the caller and can catch even _momentary_ mismatches. Bad
791+
* things happen on mismatch:
792+
*
793+
* - Private mapping => Shared Page == Guest shutdown
794+
* - Shared mapping => Private Page == Recoverable #VE
795+
*
796+
* guest.enc_status_change_prepare() converts the page from
797+
* shared=>private before the mapping becomes private.
798+
*
799+
* guest.enc_status_change_finish() converts the page from
800+
* private=>shared after the mapping becomes private.
801+
*
802+
* In both cases there is a temporary shared mapping to a private page,
803+
* which can result in a #VE. But, there is never a private mapping to
804+
* a shared page.
805+
*/
806+
x86_platform.guest.enc_status_change_prepare = tdx_enc_status_change_prepare;
807+
x86_platform.guest.enc_status_change_finish = tdx_enc_status_change_finish;
808+
809+
x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required;
810+
x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required;
777811

778812
/*
779813
* TDX intercepts the RDMSR to read the X2APIC ID in the parallel

arch/x86/include/asm/shared/tdx.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,16 @@ u64 __tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9,
9393

9494
bool tdx_accept_memory(phys_addr_t start, phys_addr_t end);
9595

96+
/*
97+
* The TDG.VP.VMCALL-Instruction-execution sub-functions are defined
98+
* independently from but are currently matched 1:1 with VMX EXIT_REASONs.
99+
* Reusing the KVM EXIT_REASON macros makes it easier to connect the host and
100+
* guest sides of these calls.
101+
*/
102+
static __always_inline u64 hcall_func(u64 exit_reason)
103+
{
104+
return exit_reason;
105+
}
106+
96107
#endif /* !__ASSEMBLY__ */
97108
#endif /* _ASM_X86_SHARED_TDX_H */

arch/x86/include/asm/x86_init.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ struct x86_init_acpi {
150150
* @enc_cache_flush_required Returns true if a cache flush is needed before changing page encryption status
151151
*/
152152
struct x86_guest {
153-
void (*enc_status_change_prepare)(unsigned long vaddr, int npages, bool enc);
153+
bool (*enc_status_change_prepare)(unsigned long vaddr, int npages, bool enc);
154154
bool (*enc_status_change_finish)(unsigned long vaddr, int npages, bool enc);
155155
bool (*enc_tlb_flush_required)(bool enc);
156156
bool (*enc_cache_flush_required)(void);

arch/x86/kernel/x86_init.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ struct x86_cpuinit_ops x86_cpuinit = {
131131

132132
static void default_nmi_init(void) { };
133133

134-
static void enc_status_change_prepare_noop(unsigned long vaddr, int npages, bool enc) { }
135-
static bool enc_status_change_finish_noop(unsigned long vaddr, int npages, bool enc) { return false; }
134+
static bool enc_status_change_prepare_noop(unsigned long vaddr, int npages, bool enc) { return true; }
135+
static bool enc_status_change_finish_noop(unsigned long vaddr, int npages, bool enc) { return true; }
136136
static bool enc_tlb_flush_required_noop(bool enc) { return false; }
137137
static bool enc_cache_flush_required_noop(void) { return false; }
138138
static bool is_private_mmio_noop(u64 addr) {return false; }

arch/x86/mm/mem_encrypt_amd.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,16 @@ static void enc_dec_hypercall(unsigned long vaddr, int npages, bool enc)
319319
#endif
320320
}
321321

322-
static void amd_enc_status_change_prepare(unsigned long vaddr, int npages, bool enc)
322+
static bool amd_enc_status_change_prepare(unsigned long vaddr, int npages, bool enc)
323323
{
324324
/*
325325
* To maintain the security guarantees of SEV-SNP guests, make sure
326326
* to invalidate the memory before encryption attribute is cleared.
327327
*/
328328
if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP) && !enc)
329329
snp_set_memory_shared(vaddr, npages);
330+
331+
return true;
330332
}
331333

332334
/* Return true unconditionally: return value doesn't matter for the SEV side */

arch/x86/mm/pat/set_memory.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2152,7 +2152,8 @@ static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc)
21522152
cpa_flush(&cpa, x86_platform.guest.enc_cache_flush_required());
21532153

21542154
/* Notify hypervisor that we are about to set/clr encryption attribute. */
2155-
x86_platform.guest.enc_status_change_prepare(addr, numpages, enc);
2155+
if (!x86_platform.guest.enc_status_change_prepare(addr, numpages, enc))
2156+
return -EIO;
21562157

21572158
ret = __change_page_attr_set_clr(&cpa, 1);
21582159

0 commit comments

Comments
 (0)