The Linux Kernel Mailing List
 help / color / mirror / Atom feed
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


  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