From: Sriram Nambakam <snambakam@linux.microsoft.com>
To: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: [RFC PATCH v1 32/42] security/vbs: add secure-plane monitor backend
Date: Wed, 5 Aug 2026 04:03:14 -0700 [thread overview]
Message-ID: <20260805110324.25067-33-snambakam@linux.microsoft.com> (raw)
In-Reply-To: <20260805110324.25067-1-snambakam@linux.microsoft.com>
Add the secure-plane counterpart of the normal-plane kvm_planes backend.
The same kernel image boots as both planes; when started as the secure
plane (via the "vbs_secure_plane" command-line option) this monitor
takes over, parks via KVM_HC_VBS_VTL_RETURN, and dispatches the VTL
calls issued by the normal plane from the shared calling area.
Unlike the minimal CONFIG_VBS_PARK stub, this backend is part of the
full VBS stack and is meant to grow real handlers (seal, memory
protection, attestation). Built with CONFIG_VBS_KVM_PLANES.
Signed-off-by: Sriram Nambakam <snambakam@linux.microsoft.com>
---
security/vbs/Makefile | 1 +
security/vbs/secure_monitor.c | 266 ++++++++++++++++++++++++++++++++++
2 files changed, 267 insertions(+)
create mode 100644 security/vbs/secure_monitor.c
diff --git a/security/vbs/Makefile b/security/vbs/Makefile
index 01e831e28ac7..f24f31727a65 100644
--- a/security/vbs/Makefile
+++ b/security/vbs/Makefile
@@ -7,6 +7,7 @@ vbs-y := probe.o core.o
vbs-$(CONFIG_VBS_HEKI) += heki.o
obj-$(CONFIG_VBS_KVM_PLANES) += kvm_planes.o
+obj-$(CONFIG_VBS_KVM_PLANES) += secure_monitor.o
obj-$(CONFIG_VBS_SEV_SNP) += sev_snp.o
obj-$(CONFIG_VBS_TDX) += tdx.o
obj-$(CONFIG_VBS_HV_VSM) += hv_vsm.o
diff --git a/security/vbs/secure_monitor.c b/security/vbs/secure_monitor.c
new file mode 100644
index 000000000000..c1221ad5019b
--- /dev/null
+++ b/security/vbs/secure_monitor.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * VBS secure-plane monitor — in-guest VTL dispatcher
+ *
+ * This is the secure-plane counterpart of the normal-plane kvm_planes
+ * backend. The SAME kernel image boots as both the normal plane and the
+ * secure plane; when booted as the secure plane (selected via the
+ * "vbs_secure_plane" kernel command-line option) this monitor takes over
+ * and services VTL calls issued by the normal plane.
+ *
+ * "Secure plane" is the highest-privilege plane of the VM (conventionally
+ * plane 1 / VTL1 / VMPL0, but a VM may have up to KVM_MAX_PLANES planes and
+ * the index is not hard-coded here). "Normal plane" is the requesting,
+ * lower-privilege plane (conventionally plane 0).
+ *
+ * Control flow (all within the normal plane's single KVM_RUN, see
+ * arch/x86/kvm/x86.c ____kvm_emulate_hypercall):
+ *
+ * normal plane KVM secure plane
+ * ------------ --- ------------
+ * fill calling area
+ * HC_VBS_VTL_CALL(ca_gpa) ─────▶ switch_plane ───────────▶ resume in
+ * (RAX := ca_gpa) secmon_vtl_return()
+ * dispatch(call_id)
+ * write ca->status
+ * resume after VTL_CALL ◀─────── switch_plane ◀─────────── HC_VBS_VTL_RETURN(status)
+ * read ca->status
+ *
+ * Because all planes of a VM share the same memslots (struct kvm_plane has
+ * no memslots of its own; they live in struct kvm), the secure plane sees
+ * the same guest-physical address space as the normal plane and can read
+ * the calling area and the GPAs referenced by each request directly.
+ */
+
+#define pr_fmt(fmt) "vbs-secmon: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/vbs.h>
+#include <linux/kvm_para.h>
+#include <asm/kvm_para.h>
+
+#include "heki.h"
+
+/*
+ * Shared-memory calling area — must match struct vbs_kvm_ca in kvm_planes.c
+ * (this is the normal-plane <-> secure-plane wire ABI).
+ *
+ * [ call_pending | call_id | status | arg_size | resp_size | buffer ]
+ */
+struct vbs_kvm_ca {
+ __u8 call_pending; /* 1 while call is in flight */
+ __u8 rsvd[3];
+ __u32 call_id; /* enum vbs_call_id (set by caller) */
+ __s32 status; /* return code (set by responder) */
+ __u32 arg_size; /* request payload size */
+ __u32 resp_size; /* response payload size */
+ __u8 buffer[]; /* request data in, response data out */
+} __packed;
+
+/* Set from the "vbs_secure_plane" kernel command-line option. */
+static bool secmon_active __ro_after_init;
+
+static int __init secmon_setup(char *str)
+{
+ secmon_active = true;
+ return 1;
+}
+__setup("vbs_secure_plane", secmon_setup);
+
+/*
+ * Park the secure plane and hand control back to the normal plane. On the
+ * next VTL call, KVM resumes us here with the calling-area GPA in the
+ * hypercall return value (RAX). @status is carried for tracing only; the
+ * real result is already in the calling area.
+ */
+static u64 secmon_vtl_return(long status)
+{
+ return kvm_hypercall1(KVM_HC_VBS_VTL_RETURN, (unsigned long)status);
+}
+
+/*
+ * Apply EPT permissions on a normal-plane GPA range from the secure plane.
+ *
+ * The secure plane cannot issue the host KVM_SET_MEMORY_ATTRIBUTES ioctl,
+ * so it asks KVM to do it via the KVM_HC_VBS_SET_MEM_ATTRS hypercall, which
+ * KVM honours only for a higher-privilege plane. @perms carries the access
+ * bits the normal plane should retain (VBS_MEM_*); KVM translates a cleared
+ * write/exec bit into NO_WRITE / NO_EXEC memory attributes.
+ */
+static int secmon_apply_attrs(u64 gpa, u64 size, u32 perms)
+{
+ long ret;
+
+ pr_debug("apply_attrs gpa=0x%llx size=0x%llx perms=%c%c%c\n",
+ gpa, size,
+ (perms & VBS_MEM_READ) ? 'r' : '-',
+ (perms & VBS_MEM_WRITE) ? 'w' : '-',
+ (perms & VBS_MEM_EXEC) ? 'x' : '-');
+
+ ret = kvm_hypercall3(KVM_HC_VBS_SET_MEM_ATTRS, gpa, size, perms);
+ if (ret)
+ return (int)ret;
+
+ return 0;
+}
+
+/* ── per-call handlers ────────────────────────────────────────────────── */
+
+static int secmon_do_protect_memory(const void *arg, u32 arg_size)
+{
+ const struct vbs_protect_memory_req *r = arg;
+
+ if (arg_size < sizeof(*r))
+ return -EINVAL;
+
+ return secmon_apply_attrs(r->gpa, r->size, r->perms);
+}
+
+static int secmon_do_seal_kernel(const void *arg, u32 arg_size)
+{
+ const struct vbs_seal_kernel_req *r = arg;
+ int ret;
+
+ if (arg_size < sizeof(*r))
+ return -EINVAL;
+
+ /* Kernel text: read + execute, no write. */
+ ret = secmon_apply_attrs(r->text_gpa, r->text_size,
+ VBS_MEM_READ | VBS_MEM_EXEC);
+ if (ret)
+ return ret;
+
+ /* Kernel rodata: read only, no write, no execute. */
+ return secmon_apply_attrs(r->rodata_gpa, r->rodata_size,
+ VBS_MEM_READ);
+}
+
+static int secmon_do_set_module_perms(const void *arg, u32 arg_size)
+{
+ const struct vbs_set_module_perms_req *hdr = arg;
+ const struct vbs_module_section *sec;
+ u32 i, n;
+
+ if (arg_size < sizeof(*hdr))
+ return -EINVAL;
+
+ n = hdr->nr_sections;
+ if (arg_size < sizeof(*hdr) + n * sizeof(*sec))
+ return -EINVAL;
+
+ sec = (const struct vbs_module_section *)(hdr + 1);
+ for (i = 0; i < n; i++) {
+ int ret = secmon_apply_attrs(sec[i].gpa, sec[i].size,
+ sec[i].perms);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static long secmon_dispatch(u32 call_id, const void *arg, u32 arg_size,
+ u32 *resp_size)
+{
+ *resp_size = 0;
+
+ switch (call_id) {
+ case VBS_CALL_INIT:
+ case VBS_CALL_SHUTDOWN:
+ return 0;
+
+ case VBS_CALL_PROTECT_MEMORY:
+ return secmon_do_protect_memory(arg, arg_size);
+ case VBS_CALL_SEAL_KERNEL:
+ return secmon_do_seal_kernel(arg, arg_size);
+
+ case VBS_CALL_SET_MODULE_PERMS:
+ return secmon_do_set_module_perms(arg, arg_size);
+
+ /*
+ * Module/kexec validation and key management are acknowledged for
+ * now (mirroring the previous userspace dispatcher); real signature
+ * verification runs here in a later stage.
+ */
+ case VBS_CALL_VALIDATE_MODULE:
+ case VBS_CALL_UNLOAD_MODULE:
+ case VBS_CALL_ADD_KEY:
+ case VBS_CALL_REVOKE_KEY:
+ case VBS_CALL_SEND_CERTS:
+ case VBS_CALL_KEXEC_VALIDATE:
+ case VBS_CALL_KEXEC_INVALIDATE:
+ return 0;
+
+ default:
+ pr_warn_ratelimited("unknown call_id 0x%x\n", call_id);
+ return -ENOSYS;
+ }
+}
+
+/* ── monitor loop ─────────────────────────────────────────────────────── */
+
+static int secmon_monitor_fn(void *unused)
+{
+ long status = 0;
+
+ pr_info("secure monitor started\n");
+
+ for (;;) {
+ struct vbs_kvm_ca *ca;
+ u64 ca_gpa;
+ u32 call_id, arg_size, resp_size = 0;
+
+ /* Park; resume with the next request's calling-area GPA. */
+ ca_gpa = secmon_vtl_return(status);
+ if (!ca_gpa) {
+ status = -EINVAL;
+ continue;
+ }
+
+ ca = memremap(ca_gpa, PAGE_SIZE, MEMREMAP_WB);
+ if (!ca) {
+ pr_err_ratelimited("failed to map calling area 0x%llx\n",
+ ca_gpa);
+ status = -EFAULT;
+ continue;
+ }
+
+ call_id = ca->call_id;
+ arg_size = ca->arg_size;
+ if (arg_size > PAGE_SIZE - sizeof(*ca))
+ arg_size = PAGE_SIZE - sizeof(*ca);
+
+ status = secmon_dispatch(call_id, ca->buffer, arg_size,
+ &resp_size);
+
+ ca->status = (s32)status;
+ ca->resp_size = resp_size;
+
+ memunmap(ca);
+ }
+
+ return 0;
+}
+
+static int __init secmon_init(void)
+{
+ struct task_struct *t;
+
+ if (!secmon_active)
+ return 0;
+
+ t = kthread_run(secmon_monitor_fn, NULL, "vbs-secmon");
+ if (IS_ERR(t)) {
+ pr_err("failed to start secure monitor: %ld\n", PTR_ERR(t));
+ return PTR_ERR(t);
+ }
+
+ return 0;
+}
+late_initcall(secmon_init);
--
2.55.0
next prev parent reply other threads:[~2026-08-05 11:04 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 11:02 [RFC PATCH v1 00/42] VBS/VSM-on-KVM: VBS integration for KVM VM planes Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 01/42] Fix merge issue - Remove duplicate definition for kvm_arch_has_irq_bypass Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 02/42] Fix compilation Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 03/42] Fix compile error Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 04/42] Fix compile errors Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 05/42] Initial support for VM Planes - Add kernel config for CONFIG_VM_PLANES - Parse vm plane config from initrd for plane configuration - Make hypercalls to allocate memory for the vm planes Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 06/42] Use vcpu count from the plane configuration Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 07/42] skip processing plane configuration for plane 0 - plane 0 is the boot plane Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 08/42] Add plane config param to specify kernel image format Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 09/42] Activate the VM Planes through the Hypervisor - Using KVM as the VMM Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 10/42] allow the command line to be specified for kernels in other planes Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 11/42] Various changes to support VM Planes Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 12/42] Add a Virtualization Based Security (VBS) framework. - Add backends for AMD SEV-SNP, Intel TDX, Arm CCA and KVM Planes. - Support VTL on Hyper-V in addition to Planes on KVM Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 13/42] Add a inter-plane communication mechanism through KVM. - model this to use a single page similar to SEV-SNP Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 14/42] KVM: Add per-plane memory attribute support for cross-plane EPT protection Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 15/42] KVM: x86: Add KVM_HC_VBS_VTL_CALL hypercall for VBS inter-plane calls Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 16/42] vbs: Add HEKI kernel sealing and fix KVM plane memory attribute guards Sriram Nambakam
2026-08-05 11:02 ` [RFC PATCH v1 17/42] vbs: Add module authentication via VBS/HEKI Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 18/42] vbs: Add kexec validation and make module auth non-fatal Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 19/42] Merge branch 'master' into vm-planes Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 20/42] kvm: x86: fix merged plane API/stat build regressions Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 21/42] KVM: x86: exit VM planes and VBS hypercalls to userspace Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 22/42] kexec: block legacy kexec_load when VBS is active Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 23/42] kvm: x86: fix merged plane API/stat build regressions Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 24/42] KVM: planes: expose memory-attribute setting to in-kernel callers Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 25/42] vm_planes: drop unused per-plane vcpu_count Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 26/42] drivers/virt: add VBS secure-plane park loop Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 27/42] KVM: planes: add arch-neutral in-kernel plane switch helper Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 28/42] KVM: x86: add VBS VTL call/return and cross-plane set-mem-attrs hypercalls Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 29/42] init/vm_planes: set up planes from rootfs_initcall and load ELF payloads Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 30/42] security/vbs: run backend probe and HEKI seal at rootfs_initcall Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 31/42] security/vbs: pin the VTL call hypercall to CPU0 Sriram Nambakam
2026-08-05 11:03 ` Sriram Nambakam [this message]
2026-08-05 11:03 ` [RFC PATCH v1 33/42] drivers/virt: rename VBS park loop to secure_monitor Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 34/42] x86/realmode: skip the sub-1M trampoline for the VBS secure plane Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 35/42] KVM: x86: deny normal-plane access to secure-plane memory Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 36/42] KVM: plane: handle KVM_CHECK_EXTENSION on the plane fd Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 37/42] KVM: selftests: run plane tests with a split IRQ chip Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 38/42] kvm: x86: drop obsolete kvm_cache_regs.h Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 39/42] kvm: arch: finalize plane hooks and kvm_arch_vcpu_create signature Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 40/42] kvm: x86: use kvm_vcpu scheduling-state accessors and struct stat fields Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 41/42] kvm: x86: finalize per-plane APIC state and CPUID placement Sriram Nambakam
2026-08-05 11:03 ` [RFC PATCH v1 42/42] kvm: planes: reconcile core plane state, UAPI and hypercall exit Sriram Nambakam
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=20260805110324.25067-33-snambakam@linux.microsoft.com \
--to=snambakam@linux.microsoft.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/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