Skip to content

Commit 2c96136

Browse files
committed
Merge tag 'x86_cc_for_v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 confidential computing update from Borislav Petkov: - Add support for unaccepted memory as specified in the UEFI spec v2.9. The gist of it all is that Intel TDX and AMD SEV-SNP confidential computing guests define the notion of accepting memory before using it and thus preventing a whole set of attacks against such guests like memory replay and the like. There are a couple of strategies of how memory should be accepted - the current implementation does an on-demand way of accepting. * tag 'x86_cc_for_v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: virt: sevguest: Add CONFIG_CRYPTO dependency x86/efi: Safely enable unaccepted memory in UEFI x86/sev: Add SNP-specific unaccepted memory support x86/sev: Use large PSC requests if applicable x86/sev: Allow for use of the early boot GHCB for PSC requests x86/sev: Put PSC struct on the stack in prep for unaccepted memory support x86/sev: Fix calculation of end address based on number of pages x86/tdx: Add unaccepted memory support x86/tdx: Refactor try_accept_one() x86/tdx: Make _tdx_hypercall() and __tdx_module_call() available in boot stub efi/unaccepted: Avoid load_unaligned_zeropad() stepping into unaccepted memory efi: Add unaccepted memory support x86/boot/compressed: Handle unaccepted memory efi/libstub: Implement support for unaccepted memory efi/x86: Get full memory map in allocate_e820() mm: Add support for unaccepted memory
2 parents 3e5822e + 84b9b44 commit 2c96136

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1448
-307
lines changed

arch/x86/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,9 +887,11 @@ config INTEL_TDX_GUEST
887887
bool "Intel TDX (Trust Domain Extensions) - Guest Support"
888888
depends on X86_64 && CPU_SUP_INTEL
889889
depends on X86_X2APIC
890+
depends on EFI_STUB
890891
select ARCH_HAS_CC_PLATFORM
891892
select X86_MEM_ENCRYPT
892893
select X86_MCE
894+
select UNACCEPTED_MEMORY
893895
help
894896
Support running as a guest under Intel TDX. Without this support,
895897
the guest kernel can not boot or run under TDX.
@@ -1544,11 +1546,13 @@ config X86_MEM_ENCRYPT
15441546
config AMD_MEM_ENCRYPT
15451547
bool "AMD Secure Memory Encryption (SME) support"
15461548
depends on X86_64 && CPU_SUP_AMD
1549+
depends on EFI_STUB
15471550
select DMA_COHERENT_POOL
15481551
select ARCH_USE_MEMREMAP_PROT
15491552
select INSTRUCTION_DECODER
15501553
select ARCH_HAS_CC_PLATFORM
15511554
select X86_MEM_ENCRYPT
1555+
select UNACCEPTED_MEMORY
15521556
help
15531557
Say yes to enable support for the encryption of system memory.
15541558
This requires an AMD processor that supports Secure Memory

arch/x86/boot/compressed/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ ifdef CONFIG_X86_64
106106
endif
107107

108108
vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
109-
vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o
109+
vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o $(obj)/tdx-shared.o
110+
vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o
110111

111112
vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
112113
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o

arch/x86/boot/compressed/efi.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ typedef guid_t efi_guid_t __aligned(__alignof__(u32));
1616
#define ACPI_TABLE_GUID EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
1717
#define ACPI_20_TABLE_GUID EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81)
1818
#define EFI_CC_BLOB_GUID EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42)
19+
#define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9, 0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31)
1920

2021
#define EFI32_LOADER_SIGNATURE "EL32"
2122
#define EFI64_LOADER_SIGNATURE "EL64"
@@ -32,6 +33,7 @@ typedef struct {
3233
} efi_table_hdr_t;
3334

3435
#define EFI_CONVENTIONAL_MEMORY 7
36+
#define EFI_UNACCEPTED_MEMORY 15
3537

3638
#define EFI_MEMORY_MORE_RELIABLE \
3739
((u64)0x0000000000010000ULL) /* higher reliability */
@@ -104,6 +106,14 @@ struct efi_setup_data {
104106
u64 reserved[8];
105107
};
106108

109+
struct efi_unaccepted_memory {
110+
u32 version;
111+
u32 unit_size;
112+
u64 phys_base;
113+
u64 size;
114+
unsigned long bitmap[];
115+
};
116+
107117
static inline int efi_guidcmp (efi_guid_t left, efi_guid_t right)
108118
{
109119
return memcmp(&left, &right, sizeof (efi_guid_t));

arch/x86/boot/compressed/error.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,22 @@ void error(char *m)
2222
while (1)
2323
asm("hlt");
2424
}
25+
26+
/* EFI libstub provides vsnprintf() */
27+
#ifdef CONFIG_EFI_STUB
28+
void panic(const char *fmt, ...)
29+
{
30+
static char buf[1024];
31+
va_list args;
32+
int len;
33+
34+
va_start(args, fmt);
35+
len = vsnprintf(buf, sizeof(buf), fmt, args);
36+
va_end(args);
37+
38+
if (len && buf[len - 1] == '\n')
39+
buf[len - 1] = '\0';
40+
41+
error(buf);
42+
}
43+
#endif

arch/x86/boot/compressed/error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66

77
void warn(char *m);
88
void error(char *m) __noreturn;
9+
void panic(const char *fmt, ...) __noreturn __cold;
910

1011
#endif /* BOOT_COMPRESSED_ERROR_H */

arch/x86/boot/compressed/kaslr.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,33 @@ static bool process_mem_region(struct mem_vector *region,
672672
}
673673

674674
#ifdef CONFIG_EFI
675+
676+
/*
677+
* Only EFI_CONVENTIONAL_MEMORY and EFI_UNACCEPTED_MEMORY (if supported) are
678+
* guaranteed to be free.
679+
*
680+
* Pick free memory more conservatively than the EFI spec allows: according to
681+
* the spec, EFI_BOOT_SERVICES_{CODE|DATA} are also free memory and thus
682+
* available to place the kernel image into, but in practice there's firmware
683+
* where using that memory leads to crashes. Buggy vendor EFI code registers
684+
* for an event that triggers on SetVirtualAddressMap(). The handler assumes
685+
* that EFI_BOOT_SERVICES_DATA memory has not been touched by loader yet, which
686+
* is probably true for Windows.
687+
*
688+
* Preserve EFI_BOOT_SERVICES_* regions until after SetVirtualAddressMap().
689+
*/
690+
static inline bool memory_type_is_free(efi_memory_desc_t *md)
691+
{
692+
if (md->type == EFI_CONVENTIONAL_MEMORY)
693+
return true;
694+
695+
if (IS_ENABLED(CONFIG_UNACCEPTED_MEMORY) &&
696+
md->type == EFI_UNACCEPTED_MEMORY)
697+
return true;
698+
699+
return false;
700+
}
701+
675702
/*
676703
* Returns true if we processed the EFI memmap, which we prefer over the E820
677704
* table if it is available.
@@ -716,18 +743,7 @@ process_efi_entries(unsigned long minimum, unsigned long image_size)
716743
for (i = 0; i < nr_desc; i++) {
717744
md = efi_early_memdesc_ptr(pmap, e->efi_memdesc_size, i);
718745

719-
/*
720-
* Here we are more conservative in picking free memory than
721-
* the EFI spec allows:
722-
*
723-
* According to the spec, EFI_BOOT_SERVICES_{CODE|DATA} are also
724-
* free memory and thus available to place the kernel image into,
725-
* but in practice there's firmware where using that memory leads
726-
* to crashes.
727-
*
728-
* Only EFI_CONVENTIONAL_MEMORY is guaranteed to be free.
729-
*/
730-
if (md->type != EFI_CONVENTIONAL_MEMORY)
746+
if (!memory_type_is_free(md))
731747
continue;
732748

733749
if (efi_soft_reserve_enabled() &&

arch/x86/boot/compressed/mem.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include "error.h"
4+
#include "misc.h"
5+
#include "tdx.h"
6+
#include "sev.h"
7+
#include <asm/shared/tdx.h>
8+
9+
/*
10+
* accept_memory() and process_unaccepted_memory() called from EFI stub which
11+
* runs before decompresser and its early_tdx_detect().
12+
*
13+
* Enumerate TDX directly from the early users.
14+
*/
15+
static bool early_is_tdx_guest(void)
16+
{
17+
static bool once;
18+
static bool is_tdx;
19+
20+
if (!IS_ENABLED(CONFIG_INTEL_TDX_GUEST))
21+
return false;
22+
23+
if (!once) {
24+
u32 eax, sig[3];
25+
26+
cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax,
27+
&sig[0], &sig[2], &sig[1]);
28+
is_tdx = !memcmp(TDX_IDENT, sig, sizeof(sig));
29+
once = true;
30+
}
31+
32+
return is_tdx;
33+
}
34+
35+
void arch_accept_memory(phys_addr_t start, phys_addr_t end)
36+
{
37+
/* Platform-specific memory-acceptance call goes here */
38+
if (early_is_tdx_guest()) {
39+
if (!tdx_accept_memory(start, end))
40+
panic("TDX: Failed to accept memory\n");
41+
} else if (sev_snp_enabled()) {
42+
snp_accept_memory(start, end);
43+
} else {
44+
error("Cannot accept memory: unknown platform\n");
45+
}
46+
}
47+
48+
bool init_unaccepted_memory(void)
49+
{
50+
guid_t guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID;
51+
struct efi_unaccepted_memory *table;
52+
unsigned long cfg_table_pa;
53+
unsigned int cfg_table_len;
54+
enum efi_type et;
55+
int ret;
56+
57+
et = efi_get_type(boot_params);
58+
if (et == EFI_TYPE_NONE)
59+
return false;
60+
61+
ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len);
62+
if (ret) {
63+
warn("EFI config table not found.");
64+
return false;
65+
}
66+
67+
table = (void *)efi_find_vendor_table(boot_params, cfg_table_pa,
68+
cfg_table_len, guid);
69+
if (!table)
70+
return false;
71+
72+
if (table->version != 1)
73+
error("Unknown version of unaccepted memory table\n");
74+
75+
/*
76+
* In many cases unaccepted_table is already set by EFI stub, but it
77+
* has to be initialized again to cover cases when the table is not
78+
* allocated by EFI stub or EFI stub copied the kernel image with
79+
* efi_relocate_kernel() before the variable is set.
80+
*
81+
* It must be initialized before the first usage of accept_memory().
82+
*/
83+
unaccepted_table = table;
84+
85+
return true;
86+
}

arch/x86/boot/compressed/misc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,12 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
455455
#endif
456456

457457
debug_putstr("\nDecompressing Linux... ");
458+
459+
if (init_unaccepted_memory()) {
460+
debug_putstr("Accepting memory... ");
461+
accept_memory(__pa(output), __pa(output) + needed_size);
462+
}
463+
458464
__decompress(input_data, input_len, NULL, NULL, output, output_len,
459465
NULL, error);
460466
entry_offset = parse_elf(output);

arch/x86/boot/compressed/misc.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,14 @@ static inline unsigned long efi_find_vendor_table(struct boot_params *bp,
247247
}
248248
#endif /* CONFIG_EFI */
249249

250+
#ifdef CONFIG_UNACCEPTED_MEMORY
251+
bool init_unaccepted_memory(void);
252+
#else
253+
static inline bool init_unaccepted_memory(void) { return false; }
254+
#endif
255+
256+
/* Defined in EFI stub */
257+
extern struct efi_unaccepted_memory *unaccepted_table;
258+
void accept_memory(phys_addr_t start, phys_addr_t end);
259+
250260
#endif /* BOOT_COMPRESSED_MISC_H */

arch/x86/boot/compressed/sev.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
115115
/* Include code for early handlers */
116116
#include "../../kernel/sev-shared.c"
117117

118-
static inline bool sev_snp_enabled(void)
118+
bool sev_snp_enabled(void)
119119
{
120120
return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
121121
}
@@ -181,6 +181,58 @@ static bool early_setup_ghcb(void)
181181
return true;
182182
}
183183

184+
static phys_addr_t __snp_accept_memory(struct snp_psc_desc *desc,
185+
phys_addr_t pa, phys_addr_t pa_end)
186+
{
187+
struct psc_hdr *hdr;
188+
struct psc_entry *e;
189+
unsigned int i;
190+
191+
hdr = &desc->hdr;
192+
memset(hdr, 0, sizeof(*hdr));
193+
194+
e = desc->entries;
195+
196+
i = 0;
197+
while (pa < pa_end && i < VMGEXIT_PSC_MAX_ENTRY) {
198+
hdr->end_entry = i;
199+
200+
e->gfn = pa >> PAGE_SHIFT;
201+
e->operation = SNP_PAGE_STATE_PRIVATE;
202+
if (IS_ALIGNED(pa, PMD_SIZE) && (pa_end - pa) >= PMD_SIZE) {
203+
e->pagesize = RMP_PG_SIZE_2M;
204+
pa += PMD_SIZE;
205+
} else {
206+
e->pagesize = RMP_PG_SIZE_4K;
207+
pa += PAGE_SIZE;
208+
}
209+
210+
e++;
211+
i++;
212+
}
213+
214+
if (vmgexit_psc(boot_ghcb, desc))
215+
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
216+
217+
pvalidate_pages(desc);
218+
219+
return pa;
220+
}
221+
222+
void snp_accept_memory(phys_addr_t start, phys_addr_t end)
223+
{
224+
struct snp_psc_desc desc = {};
225+
unsigned int i;
226+
phys_addr_t pa;
227+
228+
if (!boot_ghcb && !early_setup_ghcb())
229+
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
230+
231+
pa = start;
232+
while (pa < end)
233+
pa = __snp_accept_memory(&desc, pa, end);
234+
}
235+
184236
void sev_es_shutdown_ghcb(void)
185237
{
186238
if (!boot_ghcb)

0 commit comments

Comments
 (0)