Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: selftests: Compare insn opcodes directly in fix_hypercall_test

Directly compare the expected versus observed hypercall instructions when
verifying that KVM patched in the native hypercall (FIX_HYPERCALL_INSN
quirk enabled). gcc rightly complains that doing a 4-byte memcpy() with
an "unsigned char" as the source generates an out-of-bounds accesses.

Alternatively, "exp" and "obs" could be declared as 3-byte arrays, but
there's no known reason to copy locally instead of comparing directly.

In function ‘assert_hypercall_insn’,
inlined from ‘guest_main’ at x86_64/fix_hypercall_test.c:91:2:
x86_64/fix_hypercall_test.c:63:9: error: array subscript ‘unsigned int[0]’
is partly outside array bounds of ‘unsigned char[1]’ [-Werror=array-bounds]
63 | memcpy(&exp, exp_insn, sizeof(exp));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
x86_64/fix_hypercall_test.c: In function ‘guest_main’:
x86_64/fix_hypercall_test.c:42:22: note: object ‘vmx_hypercall_insn’ of size 1
42 | extern unsigned char vmx_hypercall_insn;
| ^~~~~~~~~~~~~~~~~~
x86_64/fix_hypercall_test.c:25:22: note: object ‘svm_hypercall_insn’ of size 1
25 | extern unsigned char svm_hypercall_insn;
| ^~~~~~~~~~~~~~~~~~
In function ‘assert_hypercall_insn’,
inlined from ‘guest_main’ at x86_64/fix_hypercall_test.c:91:2:
x86_64/fix_hypercall_test.c:64:9: error: array subscript ‘unsigned int[0]’
is partly outside array bounds of ‘unsigned char[1]’ [-Werror=array-bounds]
64 | memcpy(&obs, obs_insn, sizeof(obs));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
x86_64/fix_hypercall_test.c: In function ‘guest_main’:
x86_64/fix_hypercall_test.c:25:22: note: object ‘svm_hypercall_insn’ of size 1
25 | extern unsigned char svm_hypercall_insn;
| ^~~~~~~~~~~~~~~~~~
x86_64/fix_hypercall_test.c:42:22: note: object ‘vmx_hypercall_insn’ of size 1
42 | extern unsigned char vmx_hypercall_insn;
| ^~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [../lib.mk:135: tools/testing/selftests/kvm/x86_64/fix_hypercall_test] Error 1

Fixes: 6c2fa8b20d0c ("selftests: KVM: Test KVM_X86_QUIRK_FIX_HYPERCALL_INSN")
Cc: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Message-Id: <20220928233652.783504-3-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Sean Christopherson and committed by
Paolo Bonzini
39426507 6b6f7148

+16 -18
+16 -18
tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c
··· 14 14 #include "kvm_util.h" 15 15 #include "processor.h" 16 16 17 + /* VMCALL and VMMCALL are both 3-byte opcodes. */ 18 + #define HYPERCALL_INSN_SIZE 3 19 + 17 20 static bool ud_expected; 18 21 19 22 static void guest_ud_handler(struct ex_regs *regs) ··· 25 22 GUEST_DONE(); 26 23 } 27 24 28 - extern unsigned char svm_hypercall_insn; 25 + extern uint8_t svm_hypercall_insn[HYPERCALL_INSN_SIZE]; 29 26 static uint64_t svm_do_sched_yield(uint8_t apic_id) 30 27 { 31 28 uint64_t ret; ··· 42 39 return ret; 43 40 } 44 41 45 - extern unsigned char vmx_hypercall_insn; 42 + extern uint8_t vmx_hypercall_insn[HYPERCALL_INSN_SIZE]; 46 43 static uint64_t vmx_do_sched_yield(uint8_t apic_id) 47 44 { 48 45 uint64_t ret; ··· 59 56 return ret; 60 57 } 61 58 62 - static void assert_hypercall_insn(unsigned char *exp_insn, unsigned char *obs_insn) 63 - { 64 - uint32_t exp = 0, obs = 0; 65 - 66 - memcpy(&exp, exp_insn, sizeof(exp)); 67 - memcpy(&obs, obs_insn, sizeof(obs)); 68 - 69 - GUEST_ASSERT_EQ(exp, obs); 70 - } 71 - 72 59 static void guest_main(void) 73 60 { 74 - unsigned char *native_hypercall_insn, *hypercall_insn; 61 + uint8_t *native_hypercall_insn, *hypercall_insn; 75 62 uint8_t apic_id; 76 63 77 64 apic_id = GET_APIC_ID_FIELD(xapic_read_reg(APIC_ID)); 78 65 79 66 if (is_intel_cpu()) { 80 - native_hypercall_insn = &vmx_hypercall_insn; 81 - hypercall_insn = &svm_hypercall_insn; 67 + native_hypercall_insn = vmx_hypercall_insn; 68 + hypercall_insn = svm_hypercall_insn; 82 69 svm_do_sched_yield(apic_id); 83 70 } else if (is_amd_cpu()) { 84 - native_hypercall_insn = &svm_hypercall_insn; 85 - hypercall_insn = &vmx_hypercall_insn; 71 + native_hypercall_insn = svm_hypercall_insn; 72 + hypercall_insn = vmx_hypercall_insn; 86 73 vmx_do_sched_yield(apic_id); 87 74 } else { 88 75 GUEST_ASSERT(0); ··· 80 87 return; 81 88 } 82 89 90 + /* 91 + * The hypercall didn't #UD (guest_ud_handler() signals "done" if a #UD 92 + * occurs). Verify that a #UD is NOT expected and that KVM patched in 93 + * the native hypercall. 94 + */ 83 95 GUEST_ASSERT(!ud_expected); 84 - assert_hypercall_insn(native_hypercall_insn, hypercall_insn); 96 + GUEST_ASSERT(!memcmp(native_hypercall_insn, hypercall_insn, HYPERCALL_INSN_SIZE)); 85 97 GUEST_DONE(); 86 98 } 87 99