Skip to content

Commit 9591fdb

Browse files
committed
Merge tag 'x86_core_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull more x86 updates from Borislav Petkov: - Remove a bunch of asm implementing condition flags testing in KVM's emulator in favor of int3_emulate_jcc() which is written in C - Replace KVM fastops with C-based stubs which avoids problems with the fastop infra related to latter not adhering to the C ABI due to their special calling convention and, more importantly, bypassing compiler control-flow integrity checking because they're written in asm - Remove wrongly used static branches and other ugliness accumulated over time in hyperv's hypercall implementation with a proper static function call to the correct hypervisor call variant - Add some fixes and modifications to allow running FRED-enabled kernels in KVM even on non-FRED hardware - Add kCFI improvements like validating indirect calls and prepare for enabling kCFI with GCC. Add cmdline params documentation and other code cleanups - Use the single-byte 0xd6 insn as the official #UD single-byte undefined opcode instruction as agreed upon by both x86 vendors - Other smaller cleanups and touchups all over the place * tag 'x86_core_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits) x86,retpoline: Optimize patch_retpoline() x86,ibt: Use UDB instead of 0xEA x86/cfi: Remove __noinitretpoline and __noretpoline x86/cfi: Add "debug" option to "cfi=" bootparam x86/cfi: Standardize on common "CFI:" prefix for CFI reports x86/cfi: Document the "cfi=" bootparam options x86/traps: Clarify KCFI instruction layout compiler_types.h: Move __nocfi out of compiler-specific header objtool: Validate kCFI calls x86/fred: KVM: VMX: Always use FRED for IRQs when CONFIG_X86_FRED=y x86/fred: Play nice with invoking asm_fred_entry_from_kvm() on non-FRED hardware x86/fred: Install system vector handlers even if FRED isn't fully enabled x86/hyperv: Use direct call to hypercall-page x86/hyperv: Clean up hv_do_hypercall() KVM: x86: Remove fastops KVM: x86: Convert em_salc() to C KVM: x86: Introduce EM_ASM_3WCL KVM: x86: Introduce EM_ASM_1SRC2 KVM: x86: Introduce EM_ASM_2CL KVM: x86: Introduce EM_ASM_2W ...
2 parents 2f0a750 + 4a1e02b commit 9591fdb

File tree

36 files changed

+728
-665
lines changed

36 files changed

+728
-665
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,24 @@
608608
ccw_timeout_log [S390]
609609
See Documentation/arch/s390/common_io.rst for details.
610610

611+
cfi= [X86-64] Set Control Flow Integrity checking features
612+
when CONFIG_FINEIBT is enabled.
613+
Format: feature[,feature...]
614+
Default: auto
615+
616+
auto: Use FineIBT if IBT available, otherwise kCFI.
617+
Under FineIBT, enable "paranoid" mode when
618+
FRED is not available.
619+
off: Turn off CFI checking.
620+
kcfi: Use kCFI (disable FineIBT).
621+
fineibt: Use FineIBT (even if IBT not available).
622+
norand: Do not re-randomize CFI hashes.
623+
paranoid: Add caller hash checking under FineIBT.
624+
bhi: Enable register poisoning to stop speculation
625+
across FineIBT. (Disabled by default.)
626+
warn: Do not enforce CFI checking: warn only.
627+
debug: Report CFI initialization details.
628+
611629
cgroup_disable= [KNL] Disable a particular controller or optional feature
612630
Format: {name of the controller(s) or feature(s) to disable}
613631
The effects of cgroup_disable=foo are:

arch/x86/entry/calling.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ For 32-bit we have the following conventions - kernel is built with
9999
.endif
100100
.endm
101101

102-
.macro CLEAR_REGS clear_bp=1
102+
.macro CLEAR_REGS clear_callee=1
103103
/*
104104
* Sanitize registers of values that a speculation attack might
105105
* otherwise want to exploit. The lower registers are likely clobbered
@@ -113,20 +113,19 @@ For 32-bit we have the following conventions - kernel is built with
113113
xorl %r9d, %r9d /* nospec r9 */
114114
xorl %r10d, %r10d /* nospec r10 */
115115
xorl %r11d, %r11d /* nospec r11 */
116+
.if \clear_callee
116117
xorl %ebx, %ebx /* nospec rbx */
117-
.if \clear_bp
118118
xorl %ebp, %ebp /* nospec rbp */
119-
.endif
120119
xorl %r12d, %r12d /* nospec r12 */
121120
xorl %r13d, %r13d /* nospec r13 */
122121
xorl %r14d, %r14d /* nospec r14 */
123122
xorl %r15d, %r15d /* nospec r15 */
124-
123+
.endif
125124
.endm
126125

127-
.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_bp=1 unwind_hint=1
126+
.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_callee=1 unwind_hint=1
128127
PUSH_REGS rdx=\rdx, rcx=\rcx, rax=\rax, save_ret=\save_ret unwind_hint=\unwind_hint
129-
CLEAR_REGS clear_bp=\clear_bp
128+
CLEAR_REGS clear_callee=\clear_callee
130129
.endm
131130

132131
.macro POP_REGS pop_rdi=1

arch/x86/entry/entry_64_fred.S

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,37 @@ SYM_FUNC_START(asm_fred_entry_from_kvm)
111111
push %rax /* Return RIP */
112112
push $0 /* Error code, 0 for IRQ/NMI */
113113

114-
PUSH_AND_CLEAR_REGS clear_bp=0 unwind_hint=0
114+
PUSH_AND_CLEAR_REGS clear_callee=0 unwind_hint=0
115+
115116
movq %rsp, %rdi /* %rdi -> pt_regs */
117+
/*
118+
* At this point: {rdi, rsi, rdx, rcx, r8, r9}, {r10, r11}, {rax, rdx}
119+
* are clobbered, which corresponds to: arguments, extra caller-saved
120+
* and return. All registers a C function is allowed to clobber.
121+
*
122+
* Notably, the callee-saved registers: {rbx, r12, r13, r14, r15}
123+
* are untouched, with the exception of rbp, which carries the stack
124+
* frame and will be restored before exit.
125+
*
126+
* Further calling another C function will not alter this state.
127+
*/
116128
call __fred_entry_from_kvm /* Call the C entry point */
117-
POP_REGS
118-
ERETS
119-
1:
129+
120130
/*
121-
* Objtool doesn't understand what ERETS does, this hint tells it that
122-
* yes, we'll reach here and with what stack state. A save/restore pair
123-
* isn't strictly needed, but it's the simplest form.
131+
* When FRED, use ERETS to potentially clear NMIs, otherwise simply
132+
* restore the stack pointer.
133+
*/
134+
ALTERNATIVE "nop; nop; mov %rbp, %rsp", \
135+
__stringify(add $C_PTREGS_SIZE, %rsp; ERETS), \
136+
X86_FEATURE_FRED
137+
138+
1: /*
139+
* Objtool doesn't understand ERETS, and the cfi register state is
140+
* different from initial_func_cfi due to PUSH_REGS. Tell it the state
141+
* is similar to where UNWIND_HINT_SAVE is.
124142
*/
125143
UNWIND_HINT_RESTORE
144+
126145
pop %rbp
127146
RET
128147

arch/x86/hyperv/hv_init.c

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <asm/desc.h>
1818
#include <asm/e820/api.h>
1919
#include <asm/sev.h>
20-
#include <asm/ibt.h>
2120
#include <asm/hypervisor.h>
2221
#include <hyperv/hvhdk.h>
2322
#include <asm/mshyperv.h>
@@ -37,7 +36,45 @@
3736
#include <linux/export.h>
3837

3938
void *hv_hypercall_pg;
39+
40+
#ifdef CONFIG_X86_64
41+
static u64 __hv_hyperfail(u64 control, u64 param1, u64 param2)
42+
{
43+
return U64_MAX;
44+
}
45+
46+
DEFINE_STATIC_CALL(__hv_hypercall, __hv_hyperfail);
47+
48+
u64 hv_std_hypercall(u64 control, u64 param1, u64 param2)
49+
{
50+
u64 hv_status;
51+
52+
register u64 __r8 asm("r8") = param2;
53+
asm volatile ("call " STATIC_CALL_TRAMP_STR(__hv_hypercall)
54+
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
55+
"+c" (control), "+d" (param1), "+r" (__r8)
56+
: : "cc", "memory", "r9", "r10", "r11");
57+
58+
return hv_status;
59+
}
60+
61+
typedef u64 (*hv_hypercall_f)(u64 control, u64 param1, u64 param2);
62+
63+
static inline void hv_set_hypercall_pg(void *ptr)
64+
{
65+
hv_hypercall_pg = ptr;
66+
67+
if (!ptr)
68+
ptr = &__hv_hyperfail;
69+
static_call_update(__hv_hypercall, (hv_hypercall_f)ptr);
70+
}
71+
#else
72+
static inline void hv_set_hypercall_pg(void *ptr)
73+
{
74+
hv_hypercall_pg = ptr;
75+
}
4076
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
77+
#endif
4178

4279
union hv_ghcb * __percpu *hv_ghcb_pg;
4380

@@ -330,7 +367,7 @@ static int hv_suspend(void)
330367
* pointer is restored on resume.
331368
*/
332369
hv_hypercall_pg_saved = hv_hypercall_pg;
333-
hv_hypercall_pg = NULL;
370+
hv_set_hypercall_pg(NULL);
334371

335372
/* Disable the hypercall page in the hypervisor */
336373
rdmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
@@ -356,7 +393,7 @@ static void hv_resume(void)
356393
vmalloc_to_pfn(hv_hypercall_pg_saved);
357394
wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
358395

359-
hv_hypercall_pg = hv_hypercall_pg_saved;
396+
hv_set_hypercall_pg(hv_hypercall_pg_saved);
360397
hv_hypercall_pg_saved = NULL;
361398

362399
/*
@@ -476,8 +513,8 @@ void __init hyperv_init(void)
476513
if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present)
477514
goto skip_hypercall_pg_init;
478515

479-
hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START,
480-
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX,
516+
hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, MODULES_VADDR,
517+
MODULES_END, GFP_KERNEL, PAGE_KERNEL_ROX,
481518
VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
482519
__builtin_return_address(0));
483520
if (hv_hypercall_pg == NULL)
@@ -515,27 +552,9 @@ void __init hyperv_init(void)
515552
wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
516553
}
517554

518-
skip_hypercall_pg_init:
519-
/*
520-
* Some versions of Hyper-V that provide IBT in guest VMs have a bug
521-
* in that there's no ENDBR64 instruction at the entry to the
522-
* hypercall page. Because hypercalls are invoked via an indirect call
523-
* to the hypercall page, all hypercall attempts fail when IBT is
524-
* enabled, and Linux panics. For such buggy versions, disable IBT.
525-
*
526-
* Fixed versions of Hyper-V always provide ENDBR64 on the hypercall
527-
* page, so if future Linux kernel versions enable IBT for 32-bit
528-
* builds, additional hypercall page hackery will be required here
529-
* to provide an ENDBR32.
530-
*/
531-
#ifdef CONFIG_X86_KERNEL_IBT
532-
if (cpu_feature_enabled(X86_FEATURE_IBT) &&
533-
*(u32 *)hv_hypercall_pg != gen_endbr()) {
534-
setup_clear_cpu_cap(X86_FEATURE_IBT);
535-
pr_warn("Disabling IBT because of Hyper-V bug\n");
536-
}
537-
#endif
555+
hv_set_hypercall_pg(hv_hypercall_pg);
538556

557+
skip_hypercall_pg_init:
539558
/*
540559
* hyperv_init() is called before LAPIC is initialized: see
541560
* apic_intr_mode_init() -> x86_platform.apic_post_init() and

arch/x86/hyperv/ivm.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,23 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
385385
return ret;
386386
}
387387

388+
u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2)
389+
{
390+
u64 hv_status;
391+
392+
register u64 __r8 asm("r8") = param2;
393+
asm volatile("vmmcall"
394+
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
395+
"+c" (control), "+d" (param1), "+r" (__r8)
396+
: : "cc", "memory", "r9", "r10", "r11");
397+
398+
return hv_status;
399+
}
400+
388401
#else
389402
static inline void hv_ghcb_msr_write(u64 msr, u64 value) {}
390403
static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {}
404+
u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2) { return U64_MAX; }
391405
#endif /* CONFIG_AMD_MEM_ENCRYPT */
392406

393407
#ifdef CONFIG_INTEL_TDX_GUEST
@@ -437,6 +451,7 @@ u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2)
437451
#else
438452
static inline void hv_tdx_msr_write(u64 msr, u64 value) {}
439453
static inline void hv_tdx_msr_read(u64 msr, u64 *value) {}
454+
u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2) { return U64_MAX; }
440455
#endif /* CONFIG_INTEL_TDX_GUEST */
441456

442457
#if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)

arch/x86/include/asm/bug.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@
55
#include <linux/stringify.h>
66
#include <linux/instrumentation.h>
77
#include <linux/objtool.h>
8+
#include <asm/asm.h>
89

910
/*
1011
* Despite that some emulators terminate on UD2, we use it for WARN().
1112
*/
12-
#define ASM_UD2 ".byte 0x0f, 0x0b"
13+
#define ASM_UD2 _ASM_BYTES(0x0f, 0x0b)
1314
#define INSN_UD2 0x0b0f
1415
#define LEN_UD2 2
1516

17+
#define ASM_UDB _ASM_BYTES(0xd6)
18+
#define INSN_UDB 0xd6
19+
#define LEN_UDB 1
20+
1621
/*
1722
* In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
1823
*/
@@ -26,7 +31,7 @@
2631
#define BUG_UD2 0xfffe
2732
#define BUG_UD1 0xfffd
2833
#define BUG_UD1_UBSAN 0xfffc
29-
#define BUG_EA 0xffea
34+
#define BUG_UDB 0xffd6
3035
#define BUG_LOCK 0xfff0
3136

3237
#ifdef CONFIG_GENERIC_BUG

arch/x86/include/asm/cfi.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,10 @@
7171
*
7272
* __cfi_foo:
7373
* endbr64
74-
* subl 0x12345678, %r10d
75-
* jz foo
76-
* ud2
77-
* nop
74+
* subl 0x12345678, %eax
75+
* jne.32,pn foo+3
7876
* foo:
79-
* osp nop3 # was endbr64
77+
* nopl -42(%rax) # was endbr64
8078
* ... code here ...
8179
* ret
8280
*
@@ -86,9 +84,9 @@
8684
* indirect caller:
8785
* lea foo(%rip), %r11
8886
* ...
89-
* movl $0x12345678, %r10d
90-
* subl $16, %r11
91-
* nop4
87+
* movl $0x12345678, %eax
88+
* lea -0x10(%r11), %r11
89+
* nop5
9290
* call *%r11
9391
*
9492
*/

arch/x86/include/asm/ibt.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,17 @@ static __always_inline __attribute_const__ u32 gen_endbr(void)
5959
static __always_inline __attribute_const__ u32 gen_endbr_poison(void)
6060
{
6161
/*
62-
* 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it
63-
* will be unique to (former) ENDBR sites.
62+
* 4 byte NOP that isn't NOP4, such that it will be unique to (former)
63+
* ENDBR sites. Additionally it carries UDB as immediate.
6464
*/
65-
return 0x001f0f66; /* osp nopl (%rax) */
65+
return 0xd6401f0f; /* nopl -42(%rax) */
6666
}
6767

6868
static inline bool __is_endbr(u32 val)
6969
{
7070
if (val == gen_endbr_poison())
7171
return true;
7272

73-
/* See cfi_fineibt_bhi_preamble() */
74-
if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5)
75-
return true;
76-
7773
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
7874
return val == gen_endbr();
7975
}

arch/x86/include/asm/idtentry.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -460,17 +460,12 @@ __visible noinstr void func(struct pt_regs *regs, \
460460
#endif
461461

462462
void idt_install_sysvec(unsigned int n, const void *function);
463-
464-
#ifdef CONFIG_X86_FRED
465463
void fred_install_sysvec(unsigned int vector, const idtentry_t function);
466-
#else
467-
static inline void fred_install_sysvec(unsigned int vector, const idtentry_t function) { }
468-
#endif
469464

470465
#define sysvec_install(vector, function) { \
471-
if (cpu_feature_enabled(X86_FEATURE_FRED)) \
466+
if (IS_ENABLED(CONFIG_X86_FRED)) \
472467
fred_install_sysvec(vector, function); \
473-
else \
468+
if (!cpu_feature_enabled(X86_FEATURE_FRED)) \
474469
idt_install_sysvec(vector, asm_##function); \
475470
}
476471

0 commit comments

Comments
 (0)