diff mbox series

[v4,5/5] selftests: kvm/x86: Test the flags in MSR filtering and MSR exiting

Message ID 20220921151525.904162-6-aaronlewis@google.com (mailing list archive)
State New, archived
Headers show
Series MSR filtering and MSR exiting flag clean up | expand

Commit Message

Aaron Lewis Sept. 21, 2022, 3:15 p.m. UTC
When using the flags in KVM_X86_SET_MSR_FILTER and
KVM_CAP_X86_USER_SPACE_MSR it is expected that an attempt to write to
any of the unused bits will fail.  Add testing to walk over every bit
in each of the flag fields in MSR filtering and MSR exiting to verify
that unused bits return and error and used bits, i.e. valid bits,
succeed.

Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
 .../kvm/x86_64/userspace_msr_exit_test.c      | 85 +++++++++++++++++++
 1 file changed, 85 insertions(+)

Comments

Sean Christopherson Oct. 7, 2022, 10:24 p.m. UTC | #1
On Wed, Sep 21, 2022, Aaron Lewis wrote:
> +#define test_user_exit_msr_ioctl(vm, cmd, arg, flag, valid_mask)	\

There's nothing specific to userspace MSR exiting in this macro.  To keep the
name short, and to potentially allow moving it to common code in the future, how
about test_ioctl_flags()?

> +({									\
> +	int r = __vm_ioctl(vm, cmd, arg);				\
> +									\
> +	if (flag & valid_mask)						\
> +		TEST_ASSERT(!r, __KVM_IOCTL_ERROR(#cmd, r));		\
> +	else								\
> +		TEST_ASSERT(r == -1 && errno == EINVAL,			\
> +			    "Wanted EINVAL for %s with flag = 0x%llx, got  rc: %i errno: %i (%s)", \
> +			    #cmd, flag, r, errno,  strerror(errno));	\
> +})
> +
> +static void run_user_space_msr_flag_test(struct kvm_vm *vm)
> +{
> +	struct kvm_enable_cap cap = { .cap = KVM_CAP_X86_USER_SPACE_MSR };
> +	int nflags = sizeof(cap.args[0]) * BITS_PER_BYTE;
> +	int rc;
> +	int i;

These declarations can go on a single line.

> +
> +	rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR);
> +	TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available");
> +
> +	for (i = 0; i < nflags; i++) {
> +		cap.args[0] = BIT_ULL(i);
> +		test_user_exit_msr_ioctl(vm, KVM_ENABLE_CAP, &cap,
> +			   BIT_ULL(i), KVM_MSR_EXIT_REASON_VALID_MASK);

Align params.  With a shorter macro name, that's easy to do without creating
massively long lines.

And pass in the actual flags, e.g. cap.args[0] here, so that it's slightly more
obvious what is being tested, and to minimize the risk of mixups.

E.g.

		test_ioctl_flags(vm, KVM_ENABLE_CAP, &cap, cap.args[0],
				 KVM_MSR_EXIT_REASON_VALID_MASK);

> +	}
> +}
> +
> +static void run_msr_filter_flag_test(struct kvm_vm *vm)
> +{
> +	u64 deny_bits = 0;
> +	struct kvm_msr_filter filter = {
> +		.flags = KVM_MSR_FILTER_DEFAULT_ALLOW,
> +		.ranges = {
> +			{
> +				.flags = KVM_MSR_FILTER_READ,
> +				.nmsrs = 1,
> +				.base = 0,
> +				.bitmap = (uint8_t *)&deny_bits,
> +			},
> +		},
> +	};
> +	int nflags;
> +	int rc;
> +	int i;

	int nflags, rc, i;

> +
> +	rc = kvm_check_cap(KVM_CAP_X86_MSR_FILTER);
> +	TEST_ASSERT(rc, "KVM_CAP_X86_MSR_FILTER is available");
> +
> +	nflags = sizeof(filter.flags) * BITS_PER_BYTE;
> +	for (i = 0; i < nflags; i++) {
> +		filter.flags = BIT_ULL(i);
> +		test_user_exit_msr_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter,
> +			   BIT_ULL(i), KVM_MSR_FILTER_VALID_MASK);

		test_ioctl_flags(vm, KVM_X86_SET_MSR_FILTER, &filter,
				 filter.flags, KVM_MSR_FILTER_VALID_MASK);

> +	}
> +
> +	filter.flags = KVM_MSR_FILTER_DEFAULT_ALLOW;
> +	nflags = sizeof(filter.ranges[0].flags) * BITS_PER_BYTE;
> +	for (i = 0; i < nflags; i++) {
> +		filter.ranges[0].flags = BIT_ULL(i);
> +		test_user_exit_msr_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter,
> +			   BIT_ULL(i), KVM_MSR_FILTER_RANGE_VALID_MASK);

		test_ioctl_flags(vm, KVM_X86_SET_MSR_FILTER, &filter,
				 filter.ranges[0].flags,
				 KVM_MSR_FILTER_RANGE_VALID_MASK);

> +	}
> +}

Nits aside, nice test!
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c
index a4f06370a245..fae95089e655 100644
--- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c
+++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c
@@ -733,6 +733,89 @@  static void test_msr_permission_bitmap(void)
 	kvm_vm_free(vm);
 }
 
+#define test_user_exit_msr_ioctl(vm, cmd, arg, flag, valid_mask)	\
+({									\
+	int r = __vm_ioctl(vm, cmd, arg);				\
+									\
+	if (flag & valid_mask)						\
+		TEST_ASSERT(!r, __KVM_IOCTL_ERROR(#cmd, r));		\
+	else								\
+		TEST_ASSERT(r == -1 && errno == EINVAL,			\
+			    "Wanted EINVAL for %s with flag = 0x%llx, got  rc: %i errno: %i (%s)", \
+			    #cmd, flag, r, errno,  strerror(errno));	\
+})
+
+static void run_user_space_msr_flag_test(struct kvm_vm *vm)
+{
+	struct kvm_enable_cap cap = { .cap = KVM_CAP_X86_USER_SPACE_MSR };
+	int nflags = sizeof(cap.args[0]) * BITS_PER_BYTE;
+	int rc;
+	int i;
+
+	rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR);
+	TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available");
+
+	for (i = 0; i < nflags; i++) {
+		cap.args[0] = BIT_ULL(i);
+		test_user_exit_msr_ioctl(vm, KVM_ENABLE_CAP, &cap,
+			   BIT_ULL(i), KVM_MSR_EXIT_REASON_VALID_MASK);
+	}
+}
+
+static void run_msr_filter_flag_test(struct kvm_vm *vm)
+{
+	u64 deny_bits = 0;
+	struct kvm_msr_filter filter = {
+		.flags = KVM_MSR_FILTER_DEFAULT_ALLOW,
+		.ranges = {
+			{
+				.flags = KVM_MSR_FILTER_READ,
+				.nmsrs = 1,
+				.base = 0,
+				.bitmap = (uint8_t *)&deny_bits,
+			},
+		},
+	};
+	int nflags;
+	int rc;
+	int i;
+
+	rc = kvm_check_cap(KVM_CAP_X86_MSR_FILTER);
+	TEST_ASSERT(rc, "KVM_CAP_X86_MSR_FILTER is available");
+
+	nflags = sizeof(filter.flags) * BITS_PER_BYTE;
+	for (i = 0; i < nflags; i++) {
+		filter.flags = BIT_ULL(i);
+		test_user_exit_msr_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter,
+			   BIT_ULL(i), KVM_MSR_FILTER_VALID_MASK);
+	}
+
+	filter.flags = KVM_MSR_FILTER_DEFAULT_ALLOW;
+	nflags = sizeof(filter.ranges[0].flags) * BITS_PER_BYTE;
+	for (i = 0; i < nflags; i++) {
+		filter.ranges[0].flags = BIT_ULL(i);
+		test_user_exit_msr_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter,
+			   BIT_ULL(i), KVM_MSR_FILTER_RANGE_VALID_MASK);
+	}
+}
+
+/* Test that attempts to write to the unused bits in a flag fails. */
+static void test_user_exit_msr_flags(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	vm = vm_create_with_one_vcpu(&vcpu, NULL);
+
+	/* Test flags for KVM_CAP_X86_USER_SPACE_MSR. */
+	run_user_space_msr_flag_test(vm);
+
+	/* Test flags and range flags for KVM_X86_SET_MSR_FILTER. */
+	run_msr_filter_flag_test(vm);
+
+	kvm_vm_free(vm);
+}
+
 int main(int argc, char *argv[])
 {
 	/* Tell stdout not to buffer its content */
@@ -744,5 +827,7 @@  int main(int argc, char *argv[])
 
 	test_msr_permission_bitmap();
 
+	test_user_exit_msr_flags();
+
 	return 0;
 }