Skip to content

Commit c20d403

Browse files
sean-jcbonzini
authored andcommitted
KVM: VMX: Make VMREAD error path play nice with noinstr
Mark vmread_error_trampoline() as noinstr, and add a second trampoline for the CONFIG_CC_HAS_ASM_GOTO_OUTPUT=n case to enable instrumentation when handling VM-Fail on VMREAD. VMREAD is used in various noinstr flows, e.g. immediately after VM-Exit, and objtool rightly complains that the call to the error trampoline leaves a no-instrumentation section without annotating that it's safe to do so. vmlinux.o: warning: objtool: vmx_vcpu_enter_exit+0xc9: call to vmread_error_trampoline() leaves .noinstr.text section Note, strictly speaking, enabling instrumentation in the VM-Fail path isn't exactly safe, but if VMREAD fails the kernel/system is likely hosed anyways, and logging that there is a fatal error is more important than *maybe* encountering slightly unsafe instrumentation. Reported-by: Su Hui <suhui@nfschina.com> Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20230721235637.2345403-2-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 5e1fe4a commit c20d403

3 files changed

Lines changed: 26 additions & 9 deletions

File tree

arch/x86/kvm/vmx/vmenter.S

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,8 @@ SYM_FUNC_START(vmx_do_nmi_irqoff)
303303
VMX_DO_EVENT_IRQOFF call asm_exc_nmi_kvm_vmx
304304
SYM_FUNC_END(vmx_do_nmi_irqoff)
305305

306-
307-
.section .text, "ax"
308-
309306
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
307+
310308
/**
311309
* vmread_error_trampoline - Trampoline from inline asm to vmread_error()
312310
* @field: VMCS field encoding that failed
@@ -335,7 +333,7 @@ SYM_FUNC_START(vmread_error_trampoline)
335333
mov 3*WORD_SIZE(%_ASM_BP), %_ASM_ARG2
336334
mov 2*WORD_SIZE(%_ASM_BP), %_ASM_ARG1
337335

338-
call vmread_error
336+
call vmread_error_trampoline2
339337

340338
/* Zero out @fault, which will be popped into the result register. */
341339
_ASM_MOV $0, 3*WORD_SIZE(%_ASM_BP)
@@ -357,6 +355,8 @@ SYM_FUNC_START(vmread_error_trampoline)
357355
SYM_FUNC_END(vmread_error_trampoline)
358356
#endif
359357

358+
.section .text, "ax"
359+
360360
SYM_FUNC_START(vmx_do_interrupt_irqoff)
361361
VMX_DO_EVENT_IRQOFF CALL_NOSPEC _ASM_ARG1
362362
SYM_FUNC_END(vmx_do_interrupt_irqoff)

arch/x86/kvm/vmx/vmx.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,23 @@ do { \
441441
pr_warn_ratelimited(fmt); \
442442
} while (0)
443443

444-
void vmread_error(unsigned long field, bool fault)
444+
noinline void vmread_error(unsigned long field)
445445
{
446-
if (fault)
446+
vmx_insn_failed("vmread failed: field=%lx\n", field);
447+
}
448+
449+
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
450+
noinstr void vmread_error_trampoline2(unsigned long field, bool fault)
451+
{
452+
if (fault) {
447453
kvm_spurious_fault();
448-
else
449-
vmx_insn_failed("vmread failed: field=%lx\n", field);
454+
} else {
455+
instrumentation_begin();
456+
vmread_error(field);
457+
instrumentation_end();
458+
}
450459
}
460+
#endif
451461

452462
noinline void vmwrite_error(unsigned long field, unsigned long value)
453463
{

arch/x86/kvm/vmx/vmx_ops.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "vmcs.h"
1111
#include "../x86.h"
1212

13-
void vmread_error(unsigned long field, bool fault);
13+
void vmread_error(unsigned long field);
1414
void vmwrite_error(unsigned long field, unsigned long value);
1515
void vmclear_error(struct vmcs *vmcs, u64 phys_addr);
1616
void vmptrld_error(struct vmcs *vmcs, u64 phys_addr);
@@ -31,6 +31,13 @@ void invept_error(unsigned long ext, u64 eptp, gpa_t gpa);
3131
* void vmread_error_trampoline(unsigned long field, bool fault);
3232
*/
3333
extern unsigned long vmread_error_trampoline;
34+
35+
/*
36+
* The second VMREAD error trampoline, called from the assembly trampoline,
37+
* exists primarily to enable instrumentation for the VM-Fail path.
38+
*/
39+
void vmread_error_trampoline2(unsigned long field, bool fault);
40+
3441
#endif
3542

3643
static __always_inline void vmcs_check16(unsigned long field)

0 commit comments

Comments
 (0)