[PATCH OLK-5.10 1/3] xen/privcmd: restrict usage in unprivileged domU
From: Juergen Gross <jgross@suse.com> mainline inclusion from mainline-v7.0-rc6 commit 453b8fb68f3641fea970db88b7d9a153ed2a37e8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14027 CVE: CVE-2026-31788 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- 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> Conflicts: drivers/xen/privcmd.c [commit bf4afc53b77ae not merged] Signed-off-by: Zhang Yuwei <zhangyuwei20@huawei.com> it push" to publish your local commits) --- drivers/xen/privcmd.c | 62 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 28537a1a0e0b..cb50038c0c9c 100644 --- 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,7 +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,7 +39,7 @@ #include <xen/page.h> #include <xen/xen-ops.h> #include <xen/balloon.h> - +#include <xen/xenbus.h> #include "privcmd.h" MODULE_LICENSE("GPL"); @@ -59,6 +61,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 +885,16 @@ static long privcmd_ioctl(struct file *file, 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 +987,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 +1033,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"); -- 2.22.0
From: GuoHan Zhao <zhaoguohan@kylinos.cn> mainline inclusion from mainline-v7.0-rc6 commit cd7e1fef5a1ca1c4fcd232211962ac2395601636 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14027 CVE: CVE-2026-31788 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Commit 453b8fb68f36 ("xen/privcmd: restrict usage in unprivileged domU") added a xenstore notifier to defer setting the restriction target until Xenstore is ready. XEN_PRIVCMD can be built as a module, but privcmd_exit() leaves that notifier behind. Balance the notifier lifecycle by unregistering it on module exit. This is harmless even if xenstore was already ready at registration time and the notifier was never queued on the chain. Fixes: 453b8fb68f36 ("xen/privcmd: restrict usage in unprivileged domU") Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn> Reviewed-by: Juergen Gross <jgross@suse.com> Signed-off-by: Juergen Gross <jgross@suse.com> Message-ID: <20260325120246.252899-1-zhaoguohan@kylinos.cn> Conflicts: drivers/xen/privcmd.c [commit f0d7db7b33243 not merged] Signed-off-by: Zhang Yuwei <zhangyuwei20@huawei.com> --- drivers/xen/privcmd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index cb50038c0c9c..f082fa8c77f9 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -1054,6 +1054,9 @@ static int __init privcmd_init(void) static void __exit privcmd_exit(void) { + if (!xen_initial_domain()) + unregister_xenstore_notifier(&xenstore_notifier); + misc_deregister(&privcmd_dev); misc_deregister(&xen_privcmdbuf_dev); } -- 2.22.0
From: Juergen Gross <jgross@suse.com> mainline inclusion from mainline-v7.0-rc6 commit 1613462be621ad5103ec338a7b0ca0746ec4e5f1 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14027 CVE: CVE-2026-31788 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- 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> Conflicts: security/security.c include/linux/security.h drivers/xen/privcmd.c [commit b8f3e48834fe8 not merged] Signed-off-by: Zhang Yuwei <zhangyuwei20@huawei.com> --- drivers/xen/privcmd.c | 13 +++++++++++++ include/linux/security.h | 1 + security/security.c | 1 + 3 files changed, 15 insertions(+) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index f082fa8c77f9..3f198ded58b8 100644 --- 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> #include <asm/xen/hypercall.h> @@ -57,6 +58,11 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint, 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; }; @@ -1021,6 +1027,13 @@ static struct notifier_block xenstore_notifier = { 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); diff --git a/include/linux/security.h b/include/linux/security.h index 8ad5958a2570..0d33b61d6f82 100644 --- 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, diff --git a/security/security.c b/security/security.c index a67aa63c8c8b..98b8ce46d113 100644 --- a/security/security.c +++ b/security/security.c @@ -60,6 +60,7 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { [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", -- 2.22.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,转换为PR失败! 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/23K... 失败原因:补丁集缺失封面信息 建议解决方法:请提供补丁集并重新发送您的补丁集到邮件列表 FeedBack: The patch(es) which you have sent to kernel@openeuler.org has been converted to PR failed! Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/23K... Failed Reason: the cover of the patches is missing Suggest Solution: please checkout and apply the patches' cover and send all again
participants (2)
-
patchwork bot -
Zhang Yuwei