xen/privcmd: add boot control for restricted usage in domU

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>
---
V2:
- new patch
This commit is contained in:
Juergen Gross 2025-10-14 13:28:15 +02:00
parent 453b8fb68f
commit 1613462be6
3 changed files with 15 additions and 0 deletions

View File

@ -32,6 +32,7 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/security.h>
#include <linux/virtio_mmio.h> #include <linux/virtio_mmio.h>
#include <linux/wait.h> #include <linux/wait.h>
@ -72,6 +73,11 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
MODULE_PARM_DESC(dm_op_buf_max_size, MODULE_PARM_DESC(dm_op_buf_max_size,
"Maximum size of a dm_op hypercall buffer"); "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 { struct privcmd_data {
domid_t domid; domid_t domid;
}; };
@ -1708,6 +1714,13 @@ static struct notifier_block xenstore_notifier = {
static void __init restrict_driver(void) 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; restrict_wait = true;
register_xenstore_notifier(&xenstore_notifier); register_xenstore_notifier(&xenstore_notifier);

View File

@ -145,6 +145,7 @@ enum lockdown_reason {
LOCKDOWN_BPF_WRITE_USER, LOCKDOWN_BPF_WRITE_USER,
LOCKDOWN_DBG_WRITE_KERNEL, LOCKDOWN_DBG_WRITE_KERNEL,
LOCKDOWN_RTAS_ERROR_INJECTION, LOCKDOWN_RTAS_ERROR_INJECTION,
LOCKDOWN_XEN_USER_ACTIONS,
LOCKDOWN_INTEGRITY_MAX, LOCKDOWN_INTEGRITY_MAX,
LOCKDOWN_KCORE, LOCKDOWN_KCORE,
LOCKDOWN_KPROBES, LOCKDOWN_KPROBES,

View File

@ -61,6 +61,7 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM", [LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM",
[LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM", [LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM",
[LOCKDOWN_RTAS_ERROR_INJECTION] = "RTAS error injection", [LOCKDOWN_RTAS_ERROR_INJECTION] = "RTAS error injection",
[LOCKDOWN_XEN_USER_ACTIONS] = "Xen guest user action",
[LOCKDOWN_INTEGRITY_MAX] = "integrity", [LOCKDOWN_INTEGRITY_MAX] = "integrity",
[LOCKDOWN_KCORE] = "/proc/kcore access", [LOCKDOWN_KCORE] = "/proc/kcore access",
[LOCKDOWN_KPROBES] = "use of kprobes", [LOCKDOWN_KPROBES] = "use of kprobes",