--- /dev/null
+From e844908ea463a7812ff132419734f6319cd7dc0e Mon Sep 17 00:00:00 2001
+From: Juergen Gross <jgross@suse.com>
+Date: Tue, 14 Oct 2025 13:28:15 +0200
+Subject: xen/privcmd: add boot control for restricted usage in domU
+
+From: Juergen Gross <jgross@suse.com>
+
+commit 1613462be621ad5103ec338a7b0ca0746ec4e5f1 upstream.
+
+When running in an unprivileged domU under Xen, the privcmd driver
+is restricted to allow only hypercalls against a target domain, for
+which the current domU is acting as a device model.
+
+Add a boot parameter "unrestricted" to allow all hypercalls (the
+hypervisor will still refuse destructive hypercalls affecting other
+guests).
+
+Make this new parameter effective only in case the domU wasn't started
+using secure boot, as otherwise hypercalls targeting the domU itself
+might result in violating the secure boot functionality.
+
+This is achieved by adding another lockdown reason, which can be
+tested to not being set when applying the "unrestricted" option.
+
+This is part of XSA-482
+
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/privcmd.c | 13 +++++++++++++
+ include/linux/security.h | 1 +
+ security/security.c | 1 +
+ 3 files changed, 15 insertions(+)
+
+--- a/drivers/xen/privcmd.c
++++ b/drivers/xen/privcmd.c
+@@ -26,6 +26,7 @@
+ #include <linux/miscdevice.h>
+ #include <linux/moduleparam.h>
+ #include <linux/notifier.h>
++#include <linux/security.h>
+ #include <linux/wait.h>
+
+ #include <asm/xen/hypervisor.h>
+@@ -59,6 +60,11 @@ module_param_named(dm_op_buf_max_size, p
+ MODULE_PARM_DESC(dm_op_buf_max_size,
+ "Maximum size of a dm_op hypercall buffer");
+
++static bool unrestricted;
++module_param(unrestricted, bool, 0);
++MODULE_PARM_DESC(unrestricted,
++ "Don't restrict hypercalls to target domain if running in a domU");
++
+ struct privcmd_data {
+ domid_t domid;
+ };
+@@ -1023,6 +1029,13 @@ static struct notifier_block xenstore_no
+
+ static void __init restrict_driver(void)
+ {
++ if (unrestricted) {
++ if (security_locked_down(LOCKDOWN_XEN_USER_ACTIONS))
++ pr_warn("Kernel is locked down, parameter \"unrestricted\" ignored\n");
++ else
++ return;
++ }
++
+ restrict_wait = true;
+
+ register_xenstore_notifier(&xenstore_notifier);
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -123,6 +123,7 @@ enum lockdown_reason {
+ LOCKDOWN_XMON_WR,
+ LOCKDOWN_BPF_WRITE_USER,
+ LOCKDOWN_DBG_WRITE_KERNEL,
++ LOCKDOWN_XEN_USER_ACTIONS,
+ LOCKDOWN_INTEGRITY_MAX,
+ LOCKDOWN_KCORE,
+ LOCKDOWN_KPROBES,
+--- a/security/security.c
++++ b/security/security.c
+@@ -60,6 +60,7 @@ const char *const lockdown_reasons[LOCKD
+ [LOCKDOWN_XMON_WR] = "xmon write access",
+ [LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM",
+ [LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM",
++ [LOCKDOWN_XEN_USER_ACTIONS] = "Xen guest user action",
+ [LOCKDOWN_INTEGRITY_MAX] = "integrity",
+ [LOCKDOWN_KCORE] = "/proc/kcore access",
+ [LOCKDOWN_KPROBES] = "use of kprobes",
--- /dev/null
+From 00a5c8fcf7c8c8c4bcdf991d8104139494d23139 Mon Sep 17 00:00:00 2001
+From: Juergen Gross <jgross@suse.com>
+Date: Thu, 9 Oct 2025 16:54:58 +0200
+Subject: xen/privcmd: restrict usage in unprivileged domU
+
+From: Juergen Gross <jgross@suse.com>
+
+commit 453b8fb68f3641fea970db88b7d9a153ed2a37e8 upstream.
+
+The Xen privcmd driver allows to issue arbitrary hypercalls from
+user space processes. This is normally no problem, as access is
+usually limited to root and the hypervisor will deny any hypercalls
+affecting other domains.
+
+In case the guest is booted using secure boot, however, the privcmd
+driver would be enabling a root user process to modify e.g. kernel
+memory contents, thus breaking the secure boot feature.
+
+The only known case where an unprivileged domU is really needing to
+use the privcmd driver is the case when it is acting as the device
+model for another guest. In this case all hypercalls issued via the
+privcmd driver will target that other guest.
+
+Fortunately the privcmd driver can already be locked down to allow
+only hypercalls targeting a specific domain, but this mode can be
+activated from user land only today.
+
+The target domain can be obtained from Xenstore, so when not running
+in dom0 restrict the privcmd driver to that target domain from the
+beginning, resolving the potential problem of breaking secure boot.
+
+This is XSA-482
+
+Reported-by: Teddy Astie <teddy.astie@vates.tech>
+Fixes: 1c5de1939c20 ("xen: add privcmd driver")
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/privcmd.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 57 insertions(+), 3 deletions(-)
+
+--- a/drivers/xen/privcmd.c
++++ b/drivers/xen/privcmd.c
+@@ -10,6 +10,7 @@
+ #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
+ #include <linux/kernel.h>
++#include <linux/kstrtox.h>
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/slab.h>
+@@ -24,6 +25,8 @@
+ #include <linux/seq_file.h>
+ #include <linux/miscdevice.h>
+ #include <linux/moduleparam.h>
++#include <linux/notifier.h>
++#include <linux/wait.h>
+
+ #include <asm/xen/hypervisor.h>
+ #include <asm/xen/hypercall.h>
+@@ -37,6 +40,7 @@
+ #include <xen/page.h>
+ #include <xen/xen-ops.h>
+ #include <xen/balloon.h>
++#include <xen/xenbus.h>
+
+ #include "privcmd.h"
+
+@@ -59,6 +63,11 @@ struct privcmd_data {
+ domid_t domid;
+ };
+
++/* DOMID_INVALID implies no restriction */
++static domid_t target_domain = DOMID_INVALID;
++static bool restrict_wait;
++static DECLARE_WAIT_QUEUE_HEAD(restrict_wait_wq);
++
+ static int privcmd_vma_range_is_mapped(
+ struct vm_area_struct *vma,
+ unsigned long addr,
+@@ -878,13 +887,16 @@ static long privcmd_ioctl(struct file *f
+
+ static int privcmd_open(struct inode *ino, struct file *file)
+ {
+- struct privcmd_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
++ struct privcmd_data *data;
++
++ if (wait_event_interruptible(restrict_wait_wq, !restrict_wait) < 0)
++ return -EINTR;
+
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+- /* DOMID_INVALID implies no restriction */
+- data->domid = DOMID_INVALID;
++ data->domid = target_domain;
+
+ file->private_data = data;
+ return 0;
+@@ -977,6 +989,45 @@ static struct miscdevice privcmd_dev = {
+ .fops = &xen_privcmd_fops,
+ };
+
++static int init_restrict(struct notifier_block *notifier,
++ unsigned long event,
++ void *data)
++{
++ char *target;
++ unsigned int domid;
++
++ /* Default to an guaranteed unused domain-id. */
++ target_domain = DOMID_IDLE;
++
++ target = xenbus_read(XBT_NIL, "target", "", NULL);
++ if (IS_ERR(target) || kstrtouint(target, 10, &domid)) {
++ pr_err("No target domain found, blocking all hypercalls\n");
++ goto out;
++ }
++
++ target_domain = domid;
++
++ out:
++ if (!IS_ERR(target))
++ kfree(target);
++
++ restrict_wait = false;
++ wake_up_all(&restrict_wait_wq);
++
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block xenstore_notifier = {
++ .notifier_call = init_restrict,
++};
++
++static void __init restrict_driver(void)
++{
++ restrict_wait = true;
++
++ register_xenstore_notifier(&xenstore_notifier);
++}
++
+ static int __init privcmd_init(void)
+ {
+ int err;
+@@ -984,6 +1035,9 @@ static int __init privcmd_init(void)
+ if (!xen_domain())
+ return -ENODEV;
+
++ if (!xen_initial_domain())
++ restrict_driver();
++
+ err = misc_register(&privcmd_dev);
+ if (err != 0) {
+ pr_err("Could not register Xen privcmd device\n");