Skip to content

Commit e423e0f

Browse files
committed
Merge: SEV: Guest bug fixes
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/4476 JIRA: https://issues.redhat.com/browse/RHEL-39439 Depends: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/4224 v3: Added a stackleak plugin fix for bug introduced due to 0f7f7b6 v2: Patch 1/5 fixes a crash with cpu hotplug. 2/5 and 3/5 and 4/5 do not introduce any functional changes - 3/5 and 4/5 are for SME and SEV respectively but are tied up since they use common machinery for running kernels with C-bit-encrypted. They help apply the following patch cleanly. 5/5 fixes a bug with SEV guests' behavior with accessing ROM regions. Although, it's unlikely we will hit it on top of KVM/QEMU, it is a bug fix and prevents a crash on top of non-efi hypervisors. v1: Patch 1/4 fixes a crash with cpu hotplug. 2/4 and 3/4 do not introduce any functional changes but 3/4 helps applying 4/4 cleanly. 4/4 fixes a bug with SEV guests' behavior with accessing ROM regions. Although, it's unlikely we will hit it on top of KVM/QEMU, it is a bug fix and prevents a crash on top of non-efi hypervisors. Signed-off-by: Bandan Das <bsd@redhat.com> Approved-by: Waiman Long <longman@redhat.com> Approved-by: Donald Dutile <ddutile@redhat.com> Approved-by: David Arcari <darcari@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Approved-by: Vitaly Kuznetsov <vkuznets@redhat.com> Merged-by: Scott Weaver <scweaver@redhat.com>
2 parents 1a8fed7 + c2fc69a commit e423e0f

File tree

14 files changed

+118
-97
lines changed

14 files changed

+118
-97
lines changed

arch/x86/boot/compressed/sev.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ static bool fault_in_kernel_space(unsigned long address)
116116
#undef __init
117117
#define __init
118118

119+
#undef __head
120+
#define __head
121+
119122
#define __BOOT_COMPRESSED
120123

121124
/* Basic instruction decoding support needed */

arch/x86/include/asm/mem_encrypt.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ void __init sme_unmap_bootdata(char *real_mode_data);
4747

4848
void __init sme_early_init(void);
4949

50-
void __init sme_encrypt_kernel(struct boot_params *bp);
51-
void __init sme_enable(struct boot_params *bp);
50+
void sme_encrypt_kernel(struct boot_params *bp);
51+
void sme_enable(struct boot_params *bp);
5252

5353
int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
5454
int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
@@ -81,8 +81,8 @@ static inline void __init sme_unmap_bootdata(char *real_mode_data) { }
8181

8282
static inline void __init sme_early_init(void) { }
8383

84-
static inline void __init sme_encrypt_kernel(struct boot_params *bp) { }
85-
static inline void __init sme_enable(struct boot_params *bp) { }
84+
static inline void sme_encrypt_kernel(struct boot_params *bp) { }
85+
static inline void sme_enable(struct boot_params *bp) { }
8686

8787
static inline void sev_es_init_vc_handling(void) { }
8888

arch/x86/include/asm/sev.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,16 +216,16 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
216216
struct snp_guest_request_ioctl;
217217

218218
void setup_ghcb(void);
219-
void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
220-
unsigned long npages);
221-
void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
222-
unsigned long npages);
223-
void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op);
219+
void early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
220+
unsigned long npages);
221+
void early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
222+
unsigned long npages);
224223
void snp_set_memory_shared(unsigned long vaddr, unsigned long npages);
225224
void snp_set_memory_private(unsigned long vaddr, unsigned long npages);
226225
void snp_set_wakeup_secondary_cpu(void);
227226
bool snp_init(struct boot_params *bp);
228-
void __init __noreturn snp_abort(void);
227+
void __noreturn snp_abort(void);
228+
void snp_dmi_setup(void);
229229
int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio);
230230
void snp_accept_memory(phys_addr_t start, phys_addr_t end);
231231
u64 snp_get_unsupported_features(u64 status);
@@ -245,12 +245,12 @@ static inline void __init
245245
early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, unsigned long npages) { }
246246
static inline void __init
247247
early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, unsigned long npages) { }
248-
static inline void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op) { }
249248
static inline void snp_set_memory_shared(unsigned long vaddr, unsigned long npages) { }
250249
static inline void snp_set_memory_private(unsigned long vaddr, unsigned long npages) { }
251250
static inline void snp_set_wakeup_secondary_cpu(void) { }
252251
static inline bool snp_init(struct boot_params *bp) { return false; }
253252
static inline void snp_abort(void) { }
253+
static inline void snp_dmi_setup(void) { }
254254
static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio)
255255
{
256256
return -ENOTTY;

arch/x86/include/asm/x86_init.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ struct x86_init_mpparse {
3030
* @reserve_resources: reserve the standard resources for the
3131
* platform
3232
* @memory_setup: platform specific memory setup
33-
*
33+
* @dmi_setup: platform specific DMI setup
3434
*/
3535
struct x86_init_resources {
3636
void (*probe_roms)(void);
3737
void (*reserve_resources)(void);
3838
char *(*memory_setup)(void);
39+
void (*dmi_setup)(void);
3940
};
4041

4142
/**

arch/x86/kernel/eisa.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/*
33
* EISA specific code
44
*/
5+
#include <linux/cc_platform.h>
56
#include <linux/ioport.h>
67
#include <linux/eisa.h>
78
#include <linux/io.h>
@@ -12,7 +13,7 @@ static __init int eisa_bus_probe(void)
1213
{
1314
void __iomem *p;
1415

15-
if (xen_pv_domain() && !xen_initial_domain())
16+
if ((xen_pv_domain() && !xen_initial_domain()) || cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
1617
return 0;
1718

1819
p = ioremap(0x0FFFD9, 4);

arch/x86/kernel/head_64.S

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,28 @@ SYM_CODE_START_NOALIGN(startup_64)
115115

116116
/* Form the CR3 value being sure to include the CR3 modifier */
117117
addq $(early_top_pgt - __START_KERNEL_map), %rax
118+
119+
#ifdef CONFIG_AMD_MEM_ENCRYPT
120+
mov %rax, %rdi
121+
mov %rax, %r14
122+
123+
addq phys_base(%rip), %rdi
124+
125+
/*
126+
* For SEV guests: Verify that the C-bit is correct. A malicious
127+
* hypervisor could lie about the C-bit position to perform a ROP
128+
* attack on the guest by writing to the unencrypted stack and wait for
129+
* the next RET instruction.
130+
*/
131+
call sev_verify_cbit
132+
133+
/*
134+
* Restore CR3 value without the phys_base which will be added
135+
* below, before writing %cr3.
136+
*/
137+
mov %r14, %rax
138+
#endif
139+
118140
jmp 1f
119141
SYM_CODE_END(startup_64)
120142

@@ -193,15 +215,6 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
193215
/* Setup early boot stage 4-/5-level pagetables. */
194216
addq phys_base(%rip), %rax
195217

196-
/*
197-
* For SEV guests: Verify that the C-bit is correct. A malicious
198-
* hypervisor could lie about the C-bit position to perform a ROP
199-
* attack on the guest by writing to the unencrypted stack and wait for
200-
* the next RET instruction.
201-
*/
202-
movq %rax, %rdi
203-
call sev_verify_cbit
204-
205218
/*
206219
* Switch to new page-table
207220
*

arch/x86/kernel/probe_roms.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,6 @@ void __init probe_roms(void)
203203
unsigned char c;
204204
int i;
205205

206-
/*
207-
* The ROM memory range is not part of the e820 table and is therefore not
208-
* pre-validated by BIOS. The kernel page table maps the ROM region as encrypted
209-
* memory, and SNP requires encrypted memory to be validated before access.
210-
* Do that here.
211-
*/
212-
snp_prep_memory(video_rom_resource.start,
213-
((system_rom_resource.end + 1) - video_rom_resource.start),
214-
SNP_PAGE_STATE_PRIVATE);
215-
216206
/* video rom */
217207
upper = adapter_rom_resources[0].start;
218208
for (start = video_rom_resource.start; start < upper; start += 2048) {

arch/x86/kernel/setup.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <linux/console.h>
1010
#include <linux/crash_dump.h>
1111
#include <linux/dma-map-ops.h>
12-
#include <linux/dmi.h>
1312
#include <linux/efi.h>
1413
#include <linux/ima.h>
1514
#include <linux/init_ohci1394_dma.h>
@@ -1112,7 +1111,7 @@ void __init setup_arch(char **cmdline_p)
11121111
#endif
11131112

11141113
reserve_ibft_region();
1115-
dmi_setup();
1114+
x86_init.resources.dmi_setup();
11161115

11171116
/*
11181117
* VMware detection requires dmi to be available, so this

arch/x86/kernel/sev-shared.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ static bool __init sev_es_check_cpu_features(void)
9393
return true;
9494
}
9595

96-
static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason)
96+
static void __head __noreturn
97+
sev_es_terminate(unsigned int set, unsigned int reason)
9798
{
9899
u64 val = GHCB_MSR_TERM_REQ;
99100

@@ -330,13 +331,7 @@ static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid
330331
*/
331332
static const struct snp_cpuid_table *snp_cpuid_get_table(void)
332333
{
333-
void *ptr;
334-
335-
asm ("lea cpuid_table_copy(%%rip), %0"
336-
: "=r" (ptr)
337-
: "p" (&cpuid_table_copy));
338-
339-
return ptr;
334+
return &RIP_REL_REF(cpuid_table_copy);
340335
}
341336

342337
/*
@@ -395,7 +390,7 @@ static u32 snp_cpuid_calc_xsave_size(u64 xfeatures_en, bool compacted)
395390
return xsave_size;
396391
}
397392

398-
static bool
393+
static bool __head
399394
snp_cpuid_get_validated_func(struct cpuid_leaf *leaf)
400395
{
401396
const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
@@ -532,7 +527,8 @@ static int snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
532527
* Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value
533528
* should be treated as fatal by caller.
534529
*/
535-
static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
530+
static int __head
531+
snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
536532
{
537533
const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
538534

@@ -574,7 +570,7 @@ static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_le
574570
* page yet, so it only supports the MSR based communication with the
575571
* hypervisor and only the CPUID exit-code.
576572
*/
577-
void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
573+
void __head do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
578574
{
579575
unsigned int subfn = lower_bits(regs->cx, 32);
580576
unsigned int fn = lower_bits(regs->ax, 32);
@@ -1025,7 +1021,8 @@ struct cc_setup_data {
10251021
* Search for a Confidential Computing blob passed in as a setup_data entry
10261022
* via the Linux Boot Protocol.
10271023
*/
1028-
static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
1024+
static __head
1025+
struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
10291026
{
10301027
struct cc_setup_data *sd = NULL;
10311028
struct setup_data *hdr;
@@ -1052,7 +1049,7 @@ static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
10521049
* mapping needs to be updated in sync with all the changes to virtual memory
10531050
* layout and related mapping facilities throughout the boot process.
10541051
*/
1055-
static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
1052+
static void __head setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
10561053
{
10571054
const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table;
10581055
int i;

arch/x86/kernel/sev.c

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
#include <linux/platform_device.h>
2424
#include <linux/io.h>
2525
#include <linux/psp-sev.h>
26+
#include <linux/dmi.h>
2627
#include <uapi/linux/sev-guest.h>
2728

29+
#include <asm/init.h>
2830
#include <asm/cpu_entry_area.h>
2931
#include <asm/stacktrace.h>
3032
#include <asm/sev.h>
@@ -701,8 +703,9 @@ static u64 __init get_jump_table_addr(void)
701703
return ret;
702704
}
703705

704-
static void early_set_pages_state(unsigned long vaddr, unsigned long paddr,
705-
unsigned long npages, enum psc_op op)
706+
static void __head
707+
early_set_pages_state(unsigned long vaddr, unsigned long paddr,
708+
unsigned long npages, enum psc_op op)
706709
{
707710
unsigned long paddr_end;
708711
u64 val;
@@ -758,7 +761,7 @@ static void early_set_pages_state(unsigned long vaddr, unsigned long paddr,
758761
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
759762
}
760763

761-
void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
764+
void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
762765
unsigned long npages)
763766
{
764767
/*
@@ -793,21 +796,6 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr
793796
early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_SHARED);
794797
}
795798

796-
void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op)
797-
{
798-
unsigned long vaddr, npages;
799-
800-
vaddr = (unsigned long)__va(paddr);
801-
npages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
802-
803-
if (op == SNP_PAGE_STATE_PRIVATE)
804-
early_snp_set_memory_private(vaddr, paddr, npages);
805-
else if (op == SNP_PAGE_STATE_SHARED)
806-
early_snp_set_memory_shared(vaddr, paddr, npages);
807-
else
808-
WARN(1, "invalid memory op %d\n", op);
809-
}
810-
811799
static unsigned long __set_pages_state(struct snp_psc_desc *data, unsigned long vaddr,
812800
unsigned long vaddr_end, int op)
813801
{
@@ -1253,10 +1241,6 @@ void setup_ghcb(void)
12531241
if (!cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT))
12541242
return;
12551243

1256-
/* First make sure the hypervisor talks a supported protocol. */
1257-
if (!sev_es_negotiate_protocol())
1258-
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
1259-
12601244
/*
12611245
* Check whether the runtime #VC exception handler is active. It uses
12621246
* the per-CPU GHCB page which is set up by sev_es_init_vc_handling().
@@ -1273,6 +1257,13 @@ void setup_ghcb(void)
12731257
return;
12741258
}
12751259

1260+
/*
1261+
* Make sure the hypervisor talks a supported protocol.
1262+
* This gets called only in the BSP boot phase.
1263+
*/
1264+
if (!sev_es_negotiate_protocol())
1265+
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
1266+
12761267
/*
12771268
* Clear the boot_ghcb. The first exception comes in before the bss
12781269
* section is cleared.
@@ -2078,7 +2069,7 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)
20782069
*
20792070
* Scan for the blob in that order.
20802071
*/
2081-
static __init struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
2072+
static __head struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
20822073
{
20832074
struct cc_blob_sev_info *cc_info;
20842075

@@ -2104,7 +2095,7 @@ static __init struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
21042095
return cc_info;
21052096
}
21062097

2107-
bool __init snp_init(struct boot_params *bp)
2098+
bool __head snp_init(struct boot_params *bp)
21082099
{
21092100
struct cc_blob_sev_info *cc_info;
21102101

@@ -2126,11 +2117,22 @@ bool __init snp_init(struct boot_params *bp)
21262117
return true;
21272118
}
21282119

2129-
void __init __noreturn snp_abort(void)
2120+
void __head __noreturn snp_abort(void)
21302121
{
21312122
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
21322123
}
21332124

2125+
/*
2126+
* SEV-SNP guests should only execute dmi_setup() if EFI_CONFIG_TABLES are
2127+
* enabled, as the alternative (fallback) logic for DMI probing in the legacy
2128+
* ROM region can cause a crash since this region is not pre-validated.
2129+
*/
2130+
void __init snp_dmi_setup(void)
2131+
{
2132+
if (efi_enabled(EFI_CONFIG_TABLES))
2133+
dmi_setup();
2134+
}
2135+
21342136
static void dump_cpuid_table(void)
21352137
{
21362138
const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();

0 commit comments

Comments
 (0)