Commit cd5a0c2f authored by Sean Christopherson's avatar Sean Christopherson
Browse files

KVM: selftests: Manage CPUID array in Hyper-V CPUID test's core helper



Allocate, get, and free the CPUID array in the Hyper-V CPUID test in the
test's core helper, instead of copy+pasting code at each call site.  In
addition to deduplicating a small amount of code, restricting visibility
of the array to a single invocation of the core test prevents "leaking" an
array across test cases.  Passing in @vcpu to the helper will also allow
pivoting on VM-scoped information without needing to pass more booleans,
e.g. to conditionally assert on features that require an in-kernel APIC.

To avoid use-after-free bugs due to overzealous and careless developers,
opportunstically add a comment to explain that the system-scoped helper
caches the Hyper-V CPUID entries, i.e. that the caller is not responsible
for freeing the memory.

Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Reviewed-by: default avatarVitaly Kuznetsov <vkuznets@redhat.com>
Link: https://lore.kernel.org/r/20250118003454.2619573-4-seanjc@google.com


Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
parent 0b6db0dc
Loading
Loading
Loading
Loading
+17 −13
Original line number Diff line number Diff line
@@ -41,13 +41,18 @@ static bool smt_possible(void)
	return res;
}

static void test_hv_cpuid(const struct kvm_cpuid2 *hv_cpuid_entries,
			  bool evmcs_expected)
static void test_hv_cpuid(struct kvm_vcpu *vcpu, bool evmcs_expected)
{
	const struct kvm_cpuid2 *hv_cpuid_entries;
	int i;
	int nent_expected = 10;
	u32 test_val;

	if (vcpu)
		hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu);
	else
		hv_cpuid_entries = kvm_get_supported_hv_cpuid();

	TEST_ASSERT(hv_cpuid_entries->nent == nent_expected,
		    "KVM_GET_SUPPORTED_HV_CPUID should return %d entries"
		    " (returned %d)",
@@ -109,6 +114,13 @@ static void test_hv_cpuid(const struct kvm_cpuid2 *hv_cpuid_entries,
		 *	entry->edx);
		 */
	}

	/*
	 * Note, the CPUID array returned by the system-scoped helper is a one-
	 * time allocation, i.e. must not be freed.
	 */
	if (vcpu)
		free((void *)hv_cpuid_entries);
}

static void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
@@ -129,7 +141,6 @@ static void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
int main(int argc, char *argv[])
{
	struct kvm_vm *vm;
	const struct kvm_cpuid2 *hv_cpuid_entries;
	struct kvm_vcpu *vcpu;

	TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_CPUID));
@@ -138,10 +149,7 @@ int main(int argc, char *argv[])

	/* Test vCPU ioctl version */
	test_hv_cpuid_e2big(vm, vcpu);

	hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu);
	test_hv_cpuid(hv_cpuid_entries, false);
	free((void *)hv_cpuid_entries);
	test_hv_cpuid(vcpu, false);

	if (!kvm_cpu_has(X86_FEATURE_VMX) ||
	    !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) {
@@ -149,9 +157,7 @@ int main(int argc, char *argv[])
		goto do_sys;
	}
	vcpu_enable_evmcs(vcpu);
	hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu);
	test_hv_cpuid(hv_cpuid_entries, true);
	free((void *)hv_cpuid_entries);
	test_hv_cpuid(vcpu, true);

do_sys:
	/* Test system ioctl version */
@@ -161,9 +167,7 @@ int main(int argc, char *argv[])
	}

	test_hv_cpuid_e2big(vm, NULL);

	hv_cpuid_entries = kvm_get_supported_hv_cpuid();
	test_hv_cpuid(hv_cpuid_entries, kvm_cpu_has(X86_FEATURE_VMX));
	test_hv_cpuid(NULL, kvm_cpu_has(X86_FEATURE_VMX));

out:
	kvm_vm_free(vm);