Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: "Iván Ezequiel Rodriguez" <ivanrwcm25@gmail.com>
To: pbonzini@redhat.com, seanjc@google.com
Cc: kvm@vger.kernel.org, linux-kselftest@lists.kernel.org,
	"Iván Ezequiel Rodriguez" <ivanrwcm25@gmail.com>
Subject: [PATCH 1/1] kvm: reject unknown flags in device and dirty-log ioctls
Date: Wed,  1 Jul 2026 16:49:46 -0300	[thread overview]
Message-ID: <20260701194946.768731-2-ivanrwcm25@gmail.com> (raw)
In-Reply-To: <20260701194946.768731-1-ivanrwcm25@gmail.com>

KVM_CREATE_DEVICE only defines KVM_CREATE_DEVICE_TEST, but unknown
flag bits were silently ignored. kvm_device_attr.flags is documented
as unused yet was never checked centrally. KVM_ENABLE_CAP for
KVM_CAP_DIRTY_LOG_RING and KVM_CAP_DIRTY_LOG_RING_ACQ_REL requires
cap->flags to be zero per api.rst, but the generic handler did not
enforce it.

Reject unknown or non-zero flags with -EINVAL, consistent with other
KVM ioctls and dma-heap flag validation. Add a selftest covering all
three paths.

Signed-off-by: Iván Ezequiel Rodriguez <ivanrwcm25@gmail.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../kvm/ioctl_flag_validation_test.c          | 104 ++++++++++++++++++
 virt/kvm/kvm_main.c                           |   9 ++
 3 files changed, 114 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/ioctl_flag_validation_test.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index d28a057fa6c2..38c78838318c 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -59,6 +59,7 @@ TEST_PROGS_x86 += x86/nx_huge_pages_test.sh
 TEST_GEN_PROGS_COMMON = demand_paging_test
 TEST_GEN_PROGS_COMMON += dirty_log_test
 TEST_GEN_PROGS_COMMON += guest_print_test
+TEST_GEN_PROGS_COMMON += ioctl_flag_validation_test
 TEST_GEN_PROGS_COMMON += irqfd_test
 TEST_GEN_PROGS_COMMON += kvm_binary_stats_test
 TEST_GEN_PROGS_COMMON += kvm_create_max_vcpus
diff --git a/tools/testing/selftests/kvm/ioctl_flag_validation_test.c b/tools/testing/selftests/kvm/ioctl_flag_validation_test.c
new file mode 100644
index 000000000000..30c22435bb14
--- /dev/null
+++ b/tools/testing/selftests/kvm/ioctl_flag_validation_test.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test that selected KVM ioctls reject unknown flag bits with -EINVAL.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+
+static void test_create_device_unknown_flags(struct kvm_vm *vm)
+{
+	struct kvm_create_device cd = {
+		.type = KVM_DEV_TYPE_VFIO,
+		.flags = 0x2,
+	};
+	int r;
+
+	TEST_REQUIRE(kvm_check_cap(KVM_CAP_DEVICE_CTRL));
+
+	r = __vm_ioctl(vm, KVM_CREATE_DEVICE, &cd);
+	TEST_ASSERT(r == -1 && errno == EINVAL,
+		    "KVM_CREATE_DEVICE with unknown flags");
+
+	cd.flags = KVM_CREATE_DEVICE_TEST | 0x2;
+	r = __vm_ioctl(vm, KVM_CREATE_DEVICE, &cd);
+	TEST_ASSERT(r == -1 && errno == EINVAL,
+		    "KVM_CREATE_DEVICE TEST with unknown flags");
+}
+
+static void test_device_attr_flags(struct kvm_vm *vm)
+{
+	struct kvm_device_attr attr = {
+		.flags = 1,
+		.group = KVM_DEV_VFIO_FILE,
+		.attr = KVM_DEV_VFIO_FILE_ADD,
+		.addr = 0,
+	};
+	int dev_fd, r;
+
+	TEST_REQUIRE(kvm_check_cap(KVM_CAP_DEVICE_CTRL));
+
+	dev_fd = __kvm_create_device(vm, KVM_DEV_TYPE_VFIO);
+	if (dev_fd < 0) {
+		pr_info("Skipping device_attr test, KVM_DEV_TYPE_VFIO unavailable\n");
+		return;
+	}
+
+	r = __kvm_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attr);
+	TEST_ASSERT(r == -1 && errno == EINVAL,
+		    "KVM_HAS_DEVICE_ATTR with unknown flags");
+
+	close(dev_fd);
+}
+
+static void test_dirty_log_ring_cap_flags(struct kvm_vm *vm)
+{
+	struct kvm_enable_cap cap = {
+		.flags = 1,
+		.args = { 4096 },
+	};
+	int r;
+
+	if (!kvm_has_cap(KVM_CAP_DIRTY_LOG_RING) &&
+	    !kvm_has_cap(KVM_CAP_DIRTY_LOG_RING_ACQ_REL)) {
+		pr_info("Skipping dirty log ring cap flag test, cap unavailable\n");
+		return;
+	}
+
+	if (kvm_has_cap(KVM_CAP_DIRTY_LOG_RING)) {
+		cap.cap = KVM_CAP_DIRTY_LOG_RING;
+		cap.flags = 1;
+		r = __vm_ioctl(vm, KVM_ENABLE_CAP, &cap);
+		TEST_ASSERT(r == -1 && errno == EINVAL,
+			    "KVM_ENABLE_CAP DIRTY_LOG_RING with unknown flags");
+	}
+
+	if (kvm_has_cap(KVM_CAP_DIRTY_LOG_RING_ACQ_REL)) {
+		cap.cap = KVM_CAP_DIRTY_LOG_RING_ACQ_REL;
+		cap.flags = 1;
+		r = __vm_ioctl(vm, KVM_ENABLE_CAP, &cap);
+		TEST_ASSERT(r == -1 && errno == EINVAL,
+			    "KVM_ENABLE_CAP DIRTY_LOG_RING_ACQ_REL with unknown flags");
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct kvm_vm *vm;
+
+	vm = vm_create_barebones();
+
+	test_create_device_unknown_flags(vm);
+	test_device_attr_flags(vm);
+	test_dirty_log_ring_cap_flags(vm);
+
+	kvm_vm_free(vm);
+	return 0;
+}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index e44c20c04961..a2aecc06ab67 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4719,6 +4719,9 @@ static int kvm_device_ioctl_attr(struct kvm_device *dev,
 	if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
 		return -EFAULT;
 
+	if (attr.flags)
+		return -EINVAL;
+
 	return accessor(dev, &attr);
 }
 
@@ -4811,6 +4814,9 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
 	int type;
 	int ret;
 
+	if (cd->flags & ~KVM_CREATE_DEVICE_TEST)
+		return -EINVAL;
+
 	if (cd->type >= ARRAY_SIZE(kvm_device_ops_table))
 		return -ENODEV;
 
@@ -5061,6 +5067,9 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
 		if (!kvm_vm_ioctl_check_extension_generic(kvm, cap->cap))
 			return -EINVAL;
 
+		if (cap->flags)
+			return -EINVAL;
+
 		return kvm_vm_ioctl_enable_dirty_log_ring(kvm, cap->args[0]);
 	case KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP: {
 		int r = -EINVAL;
-- 
2.43.0


  reply	other threads:[~2026-07-01 19:50 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-01 19:49 [PATCH 0/1] kvm: reject unknown flags in device and dirty-log ioctls Iván Ezequiel Rodriguez
2026-07-01 19:49 ` Iván Ezequiel Rodriguez [this message]
2026-07-01 20:09   ` [PATCH 1/1] " sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260701194946.768731-2-ivanrwcm25@gmail.com \
    --to=ivanrwcm25@gmail.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kselftest@lists.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox