From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id B6B9F44E043; Wed, 5 Aug 2026 11:04:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927847; cv=none; b=JIwnGm5UaFiJO7Gh0sO7nkF/apIL1ETVaRNh/Xvjui0+lGGq/Fr702T0N0LDCoV7CO/McrQUAj/ZONdwwUOp1HNRdHajCCiZSssrjxVd8ekEJQNTMEv0S84UYZZ58Dz6hdRtWOOpgnM2difeyK7AUob9gYUHExcd1/esWjrBoi4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927847; c=relaxed/simple; bh=4dPfLjvwm2dCi1BpCMDr3OP9+uCo2/wqxW9zUls3bwQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WybgL+mf6uQx3Xbx5IOIPFHZvyy6b/od/lg3W2zomQVuLy5CwdxUNL6VdnAb17FsYbrbjCkPL+FK1PzBlzYlVAtINhIRQdcYlHLT9gBzAUwV8U96rcR13b653CExyPq3yRDreuF4T7sgySGCu8u3RFCeVbU2YZgSy9lG3WmiJnk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=McK/7jlH; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="McK/7jlH" Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id B1C0820B7169; Wed, 5 Aug 2026 04:03:44 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com B1C0820B7169 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927824; bh=YC/fxgTEyFQzMd6QeSrs/+l70c1o6pfZQI4vPOn5O4s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=McK/7jlH+ZQ6BTAv7M9GKKYFCIpIGiF7OBWPc4hD5x/M/GkXhkX4mmnYkqfjFWx4s CU5Zz/4yLZKczsVWIQ3eyLVvMklhUE0QeKrbDt6xHRb8CImgbVJl7gs+fzafVaPZEv 7eWY0gzTQ4PGWTjAkGYE+XzZi/7wWTKrodZLGi3w= From: Sriram Nambakam To: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Subject: [RFC PATCH v1 26/42] drivers/virt: add VBS secure-plane park loop Date: Wed, 5 Aug 2026 04:03:08 -0700 Message-ID: <20260805110324.25067-27-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110324.25067-1-snambakam@linux.microsoft.com> References: <20260805110324.25067-1-snambakam@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a minimal, self-contained driver that lets an otherwise ordinary kernel act as the secure plane (plane >0) of a KVM VM-planes guest. When the "vbs_park" command-line option is present, a kernel thread hands control back to the normal plane via KVM_HC_VBS_VTL_RETURN and then services VTL calls from a shared calling area, acknowledging each as a no-op. This is deliberately independent of the full VBS/HEKI stack (CONFIG_VBS): it implements only the park/dispatch handshake so that any secure kernel (or a future SVSM) can act as plane 1. Gated behind CONFIG_VBS_PARK. Signed-off-by: Sriram Nambakam --- drivers/virt/Kconfig | 15 +++++ drivers/virt/Makefile | 1 + drivers/virt/vbs_park.c | 136 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 drivers/virt/vbs_park.c diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig index 52eb7e4ba71f..88e40eaba1c2 100644 --- a/drivers/virt/Kconfig +++ b/drivers/virt/Kconfig @@ -13,6 +13,21 @@ menuconfig VIRT_DRIVERS if VIRT_DRIVERS +config VBS_PARK + bool "KVM VM-planes secure-plane park loop" + depends on X86 && KVM_GUEST + help + Minimal in-kernel handler for the secure plane (plane >0) of a KVM + VM-planes guest. When enabled and the "vbs_park" kernel command-line + option is present, a kernel thread hands control back to the normal + plane via the KVM_HC_VBS_VTL_RETURN hypercall and then services VTL + calls from a shared calling area. + + This is independent of the full VBS/HEKI stack (CONFIG_VBS): it + implements only the park/dispatch handshake so that any secure kernel + can act as plane 1. Calls are acknowledged as no-ops. Say N unless + this kernel is used as a VM-planes secure plane. + config VMGENID tristate "Virtual Machine Generation ID driver" default y diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile index f29901bd7820..fa91899a356d 100644 --- a/drivers/virt/Makefile +++ b/drivers/virt/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_FSL_HV_MANAGER) += fsl_hypervisor.o obj-$(CONFIG_VMGENID) += vmgenid.o +obj-$(CONFIG_VBS_PARK) += vbs_park.o obj-y += vboxguest/ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/ diff --git a/drivers/virt/vbs_park.c b/drivers/virt/vbs_park.c new file mode 100644 index 000000000000..fabb6beeea7b --- /dev/null +++ b/drivers/virt/vbs_park.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vbs_park - minimal KVM VM-planes secure-plane park loop + * + * This provides only the secure-plane (plane >0) side of the VM-planes + * park/dispatch handshake so that an otherwise ordinary kernel can act as + * plane 1. It is deliberately independent of the full VBS/HEKI stack + * (CONFIG_VBS): it implements no security policy. Its single job is to hand + * control back to the normal plane (plane 0) via the KVM_HC_VBS_VTL_RETURN + * hypercall and then service VTL calls from the shared calling area. + * + * Control flow (all within plane 0's single KVM_RUN; see + * arch/x86/kvm/x86.c __kvm_emulate_hypercall): + * + * plane 0 KVM plane 1 (here) + * ------- --- -------------- + * fill calling area + * HC_VBS_VTL_CALL(ca_gpa) ─────▶ switch_plane ───────────▶ resume in + * (RAX := ca_gpa) vtl_return() + * handle call_id + * write ca->status + * resume after VTL_CALL ◀─────── switch_plane ◀─────────── HC_VBS_VTL_RETURN + * + * Activated by the "vbs_park" kernel command-line option; without it this + * kernel boots normally and never parks. + */ + +#define pr_fmt(fmt) "vbs-park: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Shared-memory calling area. MUST match struct vbs_kvm_ca in + * security/vbs/kvm_planes.c (the normal-plane <-> secure-plane wire ABI): + * + * [ call_pending | call_id | status | arg_size | resp_size | buffer ] + */ +struct vtl_ca { + __u8 call_pending; /* 1 while call is in flight */ + __u8 rsvd[3]; + __u32 call_id; /* request 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_park" kernel command-line option. */ +static bool vbs_park_active __ro_after_init; + +static int __init vbs_park_setup(char *str) +{ + vbs_park_active = true; + return 1; +} +__setup("vbs_park", vbs_park_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 vtl_return(long status) +{ + return kvm_hypercall1(KVM_HC_VBS_VTL_RETURN, (unsigned long)status); +} + +static int vbs_park_fn(void *unused) +{ + long status = 0; + + pr_info("secure-plane park loop started\n"); + + for (;;) { + struct vtl_ca *ca; + u64 ca_gpa; + + /* Park; resume with the next request's calling-area GPA. */ + ca_gpa = 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; + } + + /* + * No security policy lives here: acknowledge the call as a + * no-op so the normal plane can make progress. Replace this + * with real handlers (or move plane 1 to a dedicated SVSM) to + * enforce actual VBS semantics. + */ + pr_info_ratelimited("VTL call id=0x%x arg_size=%u (no-op)\n", + ca->call_id, ca->arg_size); + ca->status = 0; + ca->resp_size = 0; + status = 0; + + memunmap(ca); + } + + return 0; +} + +static int __init vbs_park_init(void) +{ + struct task_struct *t; + + if (!vbs_park_active) + return 0; + + t = kthread_run(vbs_park_fn, NULL, "vbs-park"); + if (IS_ERR(t)) { + pr_err("failed to start park loop: %ld\n", PTR_ERR(t)); + return PTR_ERR(t); + } + + return 0; +} +late_initcall(vbs_park_init); -- 2.55.0