From a54439cc72f1434e97eb4242873d7540ef5c4b6a Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 13 Dec 2022 20:46:36 +0000 Subject: [PATCH 01/99] update to xen-4.17.0 rebase xen.fedora.systemd.patch and xen.canonicalize.patch remove or adjust patches now included or superceded upstream /var/lib/xenstored has moved to /run/xenstored --- .gitignore | 2 +- sources | 2 +- xen.canonicalize.patch | 4 +- xen.efi.build.patch | 19 +- xen.fedora.systemd.patch | 35 +- xen.gcc10.fixes.patch | 10 - xen.spec | 139 +-- xsa326-4.16-oxenstored-01.patch | 55 -- xsa326-4.16-oxenstored-02.patch | 94 -- xsa326-4.16-oxenstored-03.patch | 119 --- xsa326-4.16-oxenstored-04.patch | 85 -- xsa326-4.16-oxenstored-05.patch | 214 ----- xsa326-4.16-oxenstored-06.patch | 127 --- xsa326-4.16-oxenstored-07.patch | 872 ------------------ xsa326-4.16-oxenstored-08.patch | 49 - xsa326-4.16-xenstored-01.patch | 205 ---- xsa326-4.16-xenstored-02.patch | 108 --- xsa326-4.16-xenstored-03.patch | 192 ---- xsa326-4.16-xenstored-04.patch | 302 ------ xsa326-4.16-xenstored-05.patch | 443 --------- xsa326-4.16-xenstored-06.patch | 85 -- xsa326-4.16-xenstored-07.patch | 53 -- xsa326-4.16-xenstored-08.patch | 326 ------- xsa326-4.16-xenstored-09.patch | 244 ----- xsa326-4.16-xenstored-10.patch | 88 -- xsa326-4.16-xenstored-11.patch | 280 ------ xsa326-4.16-xenstored-12.patch | 76 -- xsa326-4.16-xenstored-13.patch | 89 -- xsa326-4.16-xenstored-14.patch | 334 ------- xsa326-4.16-xenstored-15.patch | 54 -- xsa326-4.16-xenstored-16.patch | 238 ----- xsa376.patch | 145 --- ...-arch-specific-default-paging-memory.patch | 147 --- ...struct-the-P2M-pages-pool-for-guests.patch | 187 ---- ...plement-XEN_DOMCTL_shadow_op-for-Arm.patch | 106 --- ...-and-free-P2M-pages-from-the-P2M-poo.patch | 287 ------ xsa410-4.16-01.patch | 59 -- xsa410-4.16-02.patch | 165 ---- xsa410-4.16-03.patch | 113 --- xsa410-4.16-04.patch | 62 -- xsa410-4.16-05.patch | 60 -- xsa410-4.16-06.patch | 255 ----- xsa410-4.16-07.patch | 82 -- xsa410-4.16-08.patch | 96 -- xsa410-4.16-09.patch | 159 ---- xsa410-4.16-10.patch | 171 ---- xsa411.patch | 55 -- xsa412-4.16.patch | 245 ----- xsa414.patch | 112 --- xsa415.patch | 134 --- xsa416-4.16.patch | 704 -------------- xsa417.patch | 135 --- xsa418-4.16-01.patch | 119 --- xsa418-4.16-02.patch | 103 --- xsa418-4.16-03.patch | 243 ----- xsa418-4.16-04.patch | 108 --- xsa418-4.16-05.patch | 164 ---- xsa418-4.16-06.patch | 174 ---- xsa418-4.16-07.patch | 163 ---- xsa419-oxenstored.patch | 85 -- xsa419-xenstored-01.patch | 289 ------ xsa419-xenstored-02.patch | 93 -- xsa419-xenstored-03.patch | 44 - xsa420.patch | 68 -- xsa421-01.patch | 40 - xsa421-02.patch | 401 -------- xsa422-4.16-1.patch | 70 -- xsa422-4.16-2.patch | 100 -- 68 files changed, 35 insertions(+), 10651 deletions(-) delete mode 100644 xen.gcc10.fixes.patch delete mode 100644 xsa326-4.16-oxenstored-01.patch delete mode 100644 xsa326-4.16-oxenstored-02.patch delete mode 100644 xsa326-4.16-oxenstored-03.patch delete mode 100644 xsa326-4.16-oxenstored-04.patch delete mode 100644 xsa326-4.16-oxenstored-05.patch delete mode 100644 xsa326-4.16-oxenstored-06.patch delete mode 100644 xsa326-4.16-oxenstored-07.patch delete mode 100644 xsa326-4.16-oxenstored-08.patch delete mode 100644 xsa326-4.16-xenstored-01.patch delete mode 100644 xsa326-4.16-xenstored-02.patch delete mode 100644 xsa326-4.16-xenstored-03.patch delete mode 100644 xsa326-4.16-xenstored-04.patch delete mode 100644 xsa326-4.16-xenstored-05.patch delete mode 100644 xsa326-4.16-xenstored-06.patch delete mode 100644 xsa326-4.16-xenstored-07.patch delete mode 100644 xsa326-4.16-xenstored-08.patch delete mode 100644 xsa326-4.16-xenstored-09.patch delete mode 100644 xsa326-4.16-xenstored-10.patch delete mode 100644 xsa326-4.16-xenstored-11.patch delete mode 100644 xsa326-4.16-xenstored-12.patch delete mode 100644 xsa326-4.16-xenstored-13.patch delete mode 100644 xsa326-4.16-xenstored-14.patch delete mode 100644 xsa326-4.16-xenstored-15.patch delete mode 100644 xsa326-4.16-xenstored-16.patch delete mode 100644 xsa376.patch delete mode 100644 xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch delete mode 100644 xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch delete mode 100644 xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch delete mode 100644 xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch delete mode 100644 xsa410-4.16-01.patch delete mode 100644 xsa410-4.16-02.patch delete mode 100644 xsa410-4.16-03.patch delete mode 100644 xsa410-4.16-04.patch delete mode 100644 xsa410-4.16-05.patch delete mode 100644 xsa410-4.16-06.patch delete mode 100644 xsa410-4.16-07.patch delete mode 100644 xsa410-4.16-08.patch delete mode 100644 xsa410-4.16-09.patch delete mode 100644 xsa410-4.16-10.patch delete mode 100644 xsa411.patch delete mode 100644 xsa412-4.16.patch delete mode 100644 xsa414.patch delete mode 100644 xsa415.patch delete mode 100644 xsa416-4.16.patch delete mode 100644 xsa417.patch delete mode 100644 xsa418-4.16-01.patch delete mode 100644 xsa418-4.16-02.patch delete mode 100644 xsa418-4.16-03.patch delete mode 100644 xsa418-4.16-04.patch delete mode 100644 xsa418-4.16-05.patch delete mode 100644 xsa418-4.16-06.patch delete mode 100644 xsa418-4.16-07.patch delete mode 100644 xsa419-oxenstored.patch delete mode 100644 xsa419-xenstored-01.patch delete mode 100644 xsa419-xenstored-02.patch delete mode 100644 xsa419-xenstored-03.patch delete mode 100644 xsa420.patch delete mode 100644 xsa421-01.patch delete mode 100644 xsa421-02.patch delete mode 100644 xsa422-4.16-1.patch delete mode 100644 xsa422-4.16-2.patch diff --git a/.gitignore b/.gitignore index f41c7f1..139f059 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.16.2.tar.gz +/xen-4.17.0.tar.gz diff --git a/sources b/sources index f6803eb..435fdc0 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.16.2.tar.gz) = b6cd036c1073798dffa167ca14c954fbdfb4c0ef99662f7c435e7e5de687d1bde8856ff6bd030d0d2e661bd17ab631551f01b2cc728cad7e70b59aaa6e692783 +SHA512 (xen-4.17.0.tar.gz) = 8aa7c3025c81127a4f653411bc1cbe8fc27b767a2f96a2a454329a6773cb74d714ecc1ff011a8e7169c6b83b2cc5cb39c39798bd6b1178df75ce9ff00f5a1011 diff --git a/xen.canonicalize.patch b/xen.canonicalize.patch index e339530..f3ae37d 100644 --- a/xen.canonicalize.patch +++ b/xen.canonicalize.patch @@ -13,8 +13,8 @@ if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) return EINVAL; -- node = canonicalize(conn, in, vec[0]); -+ node = xenstore_canonicalize(conn, in, vec[0]); +- node = canonicalize(conn, ctx, vec[0]); ++ node = xenstore_canonicalize(conn, ctx, vec[0]); if (!node) return ENOMEM; list_for_each_entry(watch, &conn->watches, list) { diff --git a/xen.efi.build.patch b/xen.efi.build.patch index d0c160b..06ee249 100644 --- a/xen.efi.build.patch +++ b/xen.efi.build.patch @@ -1,12 +1,13 @@ ---- xen-4.16.0/xen/arch/x86/Makefile.orig 2021-11-30 11:42:42.000000000 +0000 -+++ xen-4.16.0/xen/arch/x86/Makefile 2022-03-17 22:43:21.077990559 +0000 -@@ -127,7 +127,8 @@ - CFLAGS-$(XEN_BUILD_EFI) += -DXEN_BUILD_EFI +--- xen-4.17.0/xen/arch/x86/arch.mk.orig 2022-12-08 18:03:08.000000000 +0000 ++++ xen-4.17.0/xen/arch/x86/arch.mk 2022-12-10 12:13:11.043182208 +0000 +@@ -94,7 +94,9 @@ + XEN_BUILD_EFI := $(call if-success,$(CC) $(CFLAGS) -c $(srctree)/$(efi-check).c -o $(efi-check).o,y) # Check if the linker supports PE. --EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(XEN_LDFLAGS)) --subsystem=10 -+#EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(XEN_LDFLAGS)) --subsystem=10 +-EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 ++#EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 ++# use a reduced set of options from LDFLAGS +EFI_LDFLAGS = --as-needed --build-id=sha1 -mi386pep --subsystem=10 - XEN_BUILD_PE := $(if $(XEN_BUILD_EFI),$(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o efi/check.efi efi/check.o)) - # If the above failed, it may be merely because of the linker not dealing well - # with debug info. Try again with stripping it. + LD_PE_check_cmd = $(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o $(efi-check).efi $(efi-check).o) + XEN_BUILD_PE := $(LD_PE_check_cmd) + diff --git a/xen.fedora.systemd.patch b/xen.fedora.systemd.patch index 3b75ed0..ac56245 100644 --- a/xen.fedora.systemd.patch +++ b/xen.fedora.systemd.patch @@ -1,7 +1,6 @@ -diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/Makefile xen-4.5.0/tools/hotplug/Linux/systemd/Makefile ---- xen-4.5.0/tools/hotplug/Linux/systemd.orig/Makefile 2015-01-12 16:53:24.000000000 +0000 -+++ xen-4.5.0/tools/hotplug/Linux/systemd/Makefile 2015-01-25 22:23:26.000000000 +0000 -@@ -14,7 +14,8 @@ +--- xen-4.17.0/tools/hotplug/Linux/systemd/Makefile.orig 2022-12-08 18:03:08.000000000 +0000 ++++ xen-4.17.0/tools/hotplug/Linux/systemd/Makefile 2022-12-09 19:47:53.227189371 +0000 +@@ -10,7 +10,8 @@ XEN_SYSTEMD_SERVICE += xen-qemu-dom0-disk-backend.service XEN_SYSTEMD_SERVICE += xendomains.service XEN_SYSTEMD_SERVICE += xen-watchdog.service @@ -10,16 +9,7 @@ diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/Makefile xen-4.5.0/tools/hot +XEN_SYSTEMD_SERVICE += oxenstored.service XEN_SYSTEMD_SERVICE += xendriverdomain.service - ALL_XEN_SYSTEMD = $(XEN_SYSTEMD_MODULES) \ -diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/var-lib-xenstored.mount.in xen-4.5.0/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in ---- xen-4.5.0/tools/hotplug/Linux/systemd.orig/var-lib-xenstored.mount.in 2015-01-12 16:53:24.000000000 +0000 -+++ xen-4.5.0/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in 2015-01-25 22:28:59.000000000 +0000 -@@ -9,4 +9,4 @@ - What=xenstore - Where=@XEN_LIB_STORED@ - Type=tmpfs --Options=mode=755 -+Options=mode=755,context="system_u:object_r:xenstored_var_lib_t:s0" + ALL_XEN_SYSTEMD := $(XEN_SYSTEMD_MODULES) \ diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/xenconsoled.service.in xen-4.5.0/tools/hotplug/Linux/systemd/xenconsoled.service.in --- xen-4.5.0/tools/hotplug/Linux/systemd.orig/xenconsoled.service.in 2015-01-12 16:53:24.000000000 +0000 +++ xen-4.5.0/tools/hotplug/Linux/systemd/xenconsoled.service.in 2015-01-25 22:30:26.000000000 +0000 @@ -59,27 +49,26 @@ diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/xen-qemu-dom0-disk-backend.s Before=xendomains.service libvirtd.service libvirt-guests.service RefuseManualStop=true ConditionPathExists=/proc/xen/capabilities ---- xen-4.6.0/tools/configure.ac.orig 2015-02-15 16:47:22.000000000 +0000 -+++ xen-4.6.0/tools/configure.ac 2015-03-01 16:18:30.493647587 +0000 -@@ -382,9 +382,9 @@ +--- xen-4.17.0/tools/configure.ac.orig 2022-12-08 18:03:08.000000000 +0000 ++++ xen-4.17.0/tools/configure.ac 2022-12-09 19:50:24.773193862 +0000 +@@ -481,8 +481,8 @@ AS_IF([test "x$systemd" = "xy"], [ AC_CONFIG_FILES([ + hotplug/Linux/systemd/oxenstored.service hotplug/Linux/systemd/proc-xen.mount - hotplug/Linux/systemd/var-lib-xenstored.mount - hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service ---- xen-4.6.0/tools/configure.orig 2015-02-15 16:47:22.000000000 +0000 -+++ xen-4.6.0/tools/configure 2015-03-01 16:20:10.648285840 +0000 -@@ -8995,7 +8995,7 @@ +--- xen-4.17.0/tools/configure.orig 2022-12-08 18:03:08.000000000 +0000 ++++ xen-4.17.0/tools/configure 2022-12-09 19:51:43.278708226 +0000 +@@ -10081,7 +10081,7 @@ if test "x$systemd" = "xy"; then : -- ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/var-lib-xenstored.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service" -+ ac_config_files="$ac_config_files hotplug/Linux/systemd/oxenstored.service hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/var-lib-xenstored.mount hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service" +- ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service" ++ ac_config_files="$ac_config_files hotplug/Linux/systemd/oxenstored.service hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service" fi diff --git a/xen.gcc10.fixes.patch b/xen.gcc10.fixes.patch deleted file mode 100644 index 657989b..0000000 --- a/xen.gcc10.fixes.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- xen-4.13.0/tools/xenpmd/Makefile.orig 2019-12-17 14:23:09.000000000 +0000 -+++ xen-4.13.0/tools/xenpmd/Makefile 2020-01-22 22:13:16.564873608 +0000 -@@ -3,6 +3,7 @@ - - CFLAGS += -Werror - CFLAGS += $(CFLAGS_libxenstore) -+CFLAGS += -Wno-error=format-truncation - - LDLIBS += $(LDLIBS_libxenstore) - diff --git a/xen.spec b/xen.spec index 27ed461..989eaba 100644 --- a/xen.spec +++ b/xen.spec @@ -50,12 +50,12 @@ %endif # Hypervisor ABI -%define hv_abi 4.16 +%define hv_abi 4.17 Summary: Xen is a virtual machine monitor Name: xen -Version: 4.16.2 -Release: 4%{?dist} +Version: 4.17.0 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -106,71 +106,9 @@ Patch38: qemu.trad.CVE-2017-8309.patch Patch39: qemu.trad.CVE-2017-9330.patch Patch40: xen.drop.brctl.patch Patch41: xen.gcc9.fixes.patch -Patch42: xen.gcc10.fixes.patch Patch43: xen.gcc11.fixes.patch -Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch -Patch47: xsa410-4.16-01.patch -Patch48: xsa410-4.16-02.patch -Patch49: xsa410-4.16-03.patch -Patch50: xsa410-4.16-04.patch -Patch51: xsa410-4.16-05.patch -Patch52: xsa410-4.16-06.patch -Patch53: xsa410-4.16-07.patch -Patch54: xsa410-4.16-08.patch -Patch55: xsa410-4.16-09.patch -Patch56: xsa410-4.16-10.patch -Patch57: xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch -Patch58: xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch -Patch59: xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch -Patch60: xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch -Patch61: xsa411.patch -Patch62: xsa412-4.16.patch -Patch63: xsa414.patch -Patch64: xsa415.patch -Patch65: xsa326-4.16-oxenstored-01.patch -Patch66: xsa326-4.16-oxenstored-02.patch -Patch67: xsa326-4.16-oxenstored-03.patch -Patch68: xsa326-4.16-oxenstored-04.patch -Patch69: xsa326-4.16-oxenstored-05.patch -Patch70: xsa326-4.16-oxenstored-06.patch -Patch71: xsa326-4.16-oxenstored-07.patch -Patch72: xsa326-4.16-oxenstored-08.patch -Patch73: xsa326-4.16-xenstored-01.patch -Patch74: xsa326-4.16-xenstored-02.patch -Patch75: xsa326-4.16-xenstored-03.patch -Patch76: xsa326-4.16-xenstored-04.patch -Patch77: xsa326-4.16-xenstored-05.patch -Patch78: xsa326-4.16-xenstored-06.patch -Patch79: xsa326-4.16-xenstored-07.patch -Patch80: xsa326-4.16-xenstored-08.patch -Patch81: xsa326-4.16-xenstored-09.patch -Patch82: xsa326-4.16-xenstored-10.patch -Patch83: xsa326-4.16-xenstored-11.patch -Patch84: xsa326-4.16-xenstored-12.patch -Patch85: xsa326-4.16-xenstored-13.patch -Patch86: xsa326-4.16-xenstored-14.patch -Patch87: xsa326-4.16-xenstored-15.patch -Patch88: xsa326-4.16-xenstored-16.patch -Patch89: xsa416-4.16.patch -Patch90: xsa417.patch -Patch91: xsa418-4.16-01.patch -Patch92: xsa418-4.16-02.patch -Patch93: xsa418-4.16-03.patch -Patch94: xsa418-4.16-04.patch -Patch95: xsa418-4.16-05.patch -Patch96: xsa418-4.16-06.patch -Patch97: xsa418-4.16-07.patch -Patch98: xsa419-oxenstored.patch -Patch99: xsa419-xenstored-01.patch -Patch100: xsa419-xenstored-02.patch -Patch101: xsa419-xenstored-03.patch -Patch102: xsa420.patch -Patch103: xsa421-01.patch -Patch104: xsa421-02.patch -Patch105: xsa422-4.16-1.patch -Patch106: xsa422-4.16-2.patch %if %build_qemutrad @@ -378,71 +316,9 @@ manage Xen virtual machines. %patch37 -p1 %patch40 -p1 %patch41 -p1 -%patch42 -p1 %patch43 -p1 -%patch44 -p1 %patch45 -p1 %patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 -%patch54 -p1 -%patch55 -p1 -%patch56 -p1 -%patch57 -p1 -%patch58 -p1 -%patch59 -p1 -%patch60 -p1 -%patch61 -p1 -%patch62 -p1 -%patch63 -p1 -%patch64 -p1 -%patch65 -p1 -%patch66 -p1 -%patch67 -p1 -%patch68 -p1 -%patch69 -p1 -%patch70 -p1 -%patch71 -p1 -%patch72 -p1 -%patch73 -p1 -%patch74 -p1 -%patch75 -p1 -%patch76 -p1 -%patch77 -p1 -%patch78 -p1 -%patch79 -p1 -%patch80 -p1 -%patch81 -p1 -%patch82 -p1 -%patch83 -p1 -%patch84 -p1 -%patch85 -p1 -%patch86 -p1 -%patch87 -p1 -%patch88 -p1 -%patch89 -p1 -%patch90 -p1 -%patch91 -p1 -%patch92 -p1 -%patch93 -p1 -%patch94 -p1 -%patch95 -p1 -%patch96 -p1 -%patch97 -p1 -%patch98 -p1 -%patch99 -p1 -%patch100 -p1 -%patch101 -p1 -%patch102 -p1 -%patch103 -p1 -%patch104 -p1 -%patch105 -p1 -%patch106 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -846,7 +722,6 @@ fi %{_sysconfdir}/bash_completion.d/xl %{_unitdir}/proc-xen.mount -%{_unitdir}/var-lib-xenstored.mount %{_unitdir}/xenstored.service %{_unitdir}/xenconsoled.service %{_unitdir}/xen-watchdog.service @@ -929,8 +804,6 @@ fi %dir %{_localstatedir}/lib/%{name} %dir %{_localstatedir}/lib/%{name}/dump %dir %{_localstatedir}/lib/%{name}/images -# Xenstore persistent state -%dir %{_localstatedir}/lib/xenstored # Xenstore runtime state %ghost %{_localstatedir}/run/xenstored @@ -1058,6 +931,12 @@ fi %endif %changelog +* Tue Dec 13 2022 Michael Young - 4.17.0-1 +- update to xen-4.17.0 + rebase xen.fedora.systemd.patch and xen.canonicalize.patch + remove or adjust patches now included or superceded upstream + /var/lib/xenstored has moved to /run/xenstored + * Tue Nov 08 2022 Michael Young - 4.16.2-4 - x86: Multiple speculative security issues [XSA-422, CVE-2022-23824] diff --git a/xsa326-4.16-oxenstored-01.patch b/xsa326-4.16-oxenstored-01.patch deleted file mode 100644 index 848a5d0..0000000 --- a/xsa326-4.16-oxenstored-01.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 8d6bb4ac40619877130533b11655829101b31d04 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:01 +0100 -Subject: tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We currently have 2 different set of defaults in upstream Xen git tree: -* defined in the source code, only used if there is no config file -* defined in the oxenstored.conf.in upstream Xen - -An oxenstored.conf file is not mandatory, and if missing, maxrequests in -particular has an unsafe default. - -Resync the defaults from oxenstored.conf.in into the source code. - -This is part of XSA-326 / CVE-2022-42316. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml -index ebe18b8e312c..6b06f808595b 100644 ---- a/tools/ocaml/xenstored/define.ml -+++ b/tools/ocaml/xenstored/define.ml -@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket" - - let default_config_dir = Paths.xen_config_dir - --let maxwatch = ref (50) --let maxtransaction = ref (20) --let maxrequests = ref (-1) (* maximum requests per transaction *) -+let maxwatch = ref (100) -+let maxtransaction = ref (10) -+let maxrequests = ref (1024) (* maximum requests per transaction *) - - let conflict_burst_limit = ref 5.0 - let conflict_max_history_seconds = ref 0.05 -diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml -index abcac912805a..6e3d6401ae89 100644 ---- a/tools/ocaml/xenstored/quota.ml -+++ b/tools/ocaml/xenstored/quota.ml -@@ -20,8 +20,8 @@ exception Transaction_opened - - let warn fmt = Logging.warn "quota" fmt - let activate = ref true --let maxent = ref (10000) --let maxsize = ref (4096) -+let maxent = ref (1000) -+let maxsize = ref (2048) - - type t = { - maxent: int; (* max entities per domU *) diff --git a/xsa326-4.16-oxenstored-02.patch b/xsa326-4.16-oxenstored-02.patch deleted file mode 100644 index 7680efb..0000000 --- a/xsa326-4.16-oxenstored-02.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 78d5af44ab13bb18c87b6ad75e505bd374379cb3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Thu, 28 Jul 2022 17:08:15 +0100 -Subject: tools/ocaml/xenstored: Check for maxrequests before performing - operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Previously we'd perform the operation, record the updated tree in the -transaction record, then try to insert a watchop path and the reply packet. - -If we exceeded max requests we would've returned EQUOTA, but still: -* have performed the operation on the transaction's tree -* have recorded the watchop, making this queue effectively unbounded - -It is better if we check whether we'd have room to store the operation before -performing the transaction, and raise EQUOTA there. Then the transaction -record won't grow. - -This is part of XSA-326 / CVE-2022-42317. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 27790d4a5c41..dd58e6979cf9 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -389,6 +389,7 @@ let input_handle_error ~cons ~doms ~fct ~con ~t ~req = - let reply_error e = - Packet.Error e in - try -+ Transaction.check_quota_exn ~perm:(Connection.get_perm con) t; - fct con t doms cons req.Packet.data - with - | Define.Invalid_path -> reply_error "EINVAL" -@@ -681,9 +682,10 @@ let process_packet ~store ~cons ~doms ~con ~req = - in - - let response = try -+ Transaction.check_quota_exn ~perm:(Connection.get_perm con) t; - if tid <> Transaction.none then - (* Remember the request and response for this operation in case we need to replay the transaction *) -- Transaction.add_operation ~perm:(Connection.get_perm con) t req response; -+ Transaction.add_operation t req response; - response - with Quota.Limit_reached -> - Packet.Error "EQUOTA" -diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml -index 17b1bdf2eaf9..294143e2335b 100644 ---- a/tools/ocaml/xenstored/transaction.ml -+++ b/tools/ocaml/xenstored/transaction.ml -@@ -85,6 +85,7 @@ type t = { - oldroot: Store.Node.t; - mutable paths: (Xenbus.Xb.Op.operation * Store.Path.t) list; - mutable operations: (Packet.request * Packet.response) list; -+ mutable quota_reached: bool; - mutable read_lowpath: Store.Path.t option; - mutable write_lowpath: Store.Path.t option; - } -@@ -127,6 +128,7 @@ let make ?(internal=false) id store = - oldroot = Store.get_root store; - paths = []; - operations = []; -+ quota_reached = false; - read_lowpath = None; - write_lowpath = None; - } in -@@ -143,13 +145,19 @@ let get_root t = Store.get_root t.store - - let is_read_only t = t.paths = [] - let add_wop t ty path = t.paths <- (ty, path) :: t.paths --let add_operation ~perm t request response = -+let get_operations t = List.rev t.operations -+ -+let check_quota_exn ~perm t = - if !Define.maxrequests >= 0 - && not (Perms.Connection.is_dom0 perm) -- && List.length t.operations >= !Define.maxrequests -- then raise Quota.Limit_reached; -+ && (t.quota_reached || List.length t.operations >= !Define.maxrequests) -+ then begin -+ t.quota_reached <- true; -+ raise Quota.Limit_reached; -+ end -+ -+let add_operation t request response = - t.operations <- (request, response) :: t.operations --let get_operations t = List.rev t.operations - let set_read_lowpath t path = t.read_lowpath <- get_lowest path t.read_lowpath - let set_write_lowpath t path = t.write_lowpath <- get_lowest path t.write_lowpath - diff --git a/xsa326-4.16-oxenstored-03.patch b/xsa326-4.16-oxenstored-03.patch deleted file mode 100644 index 0b42411..0000000 --- a/xsa326-4.16-oxenstored-03.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 600c45e49c2060e077c06ab19078da89aa8e2e08 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:07 +0100 -Subject: tools/ocaml: GC parameter tuning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -By default the OCaml garbage collector would return memory to the OS only -after unused memory is 5x live memory. Tweak this to 120% instead, which -would match the major GC speed. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml -index 6b06f808595b..ba63a8147e09 100644 ---- a/tools/ocaml/xenstored/define.ml -+++ b/tools/ocaml/xenstored/define.ml -@@ -25,6 +25,7 @@ let maxwatch = ref (100) - let maxtransaction = ref (10) - let maxrequests = ref (1024) (* maximum requests per transaction *) - -+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *) - let conflict_burst_limit = ref 5.0 - let conflict_max_history_seconds = ref 0.05 - let conflict_rate_limit_is_aggregate = ref true -diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml -index d44ae673c42a..3b57ad016dfb 100644 ---- a/tools/ocaml/xenstored/xenstored.ml -+++ b/tools/ocaml/xenstored/xenstored.ml -@@ -104,6 +104,7 @@ let parse_config filename = - ("quota-maxsize", Config.Set_int Quota.maxsize); - ("quota-maxrequests", Config.Set_int Define.maxrequests); - ("quota-path-max", Config.Set_int Define.path_max); -+ ("gc-max-overhead", Config.Set_int Define.gc_max_overhead); - ("test-eagain", Config.Set_bool Transaction.test_eagain); - ("persistent", Config.Set_bool Disk.enable); - ("xenstored-log-file", Config.String Logging.set_xenstored_log_destination); -@@ -265,6 +266,67 @@ let to_file store cons fds file = - (fun () -> close_out channel) - end - -+(* -+ By default OCaml's GC only returns memory to the OS when it exceeds a -+ configurable 'max overhead' setting. -+ The default is 500%, that is 5/6th of the OCaml heap needs to be free -+ and only 1/6th live for a compaction to be triggerred that would -+ release memory back to the OS. -+ If the limit is not hit then the OCaml process can reuse that memory -+ for its own purposes, but other processes won't be able to use it. -+ -+ There is also a 'space overhead' setting that controls how much work -+ each major GC slice does, and by default aims at having no more than -+ 80% or 120% (depending on version) garbage values compared to live -+ values. -+ This doesn't have as much relevance to memory returned to the OS as -+ long as space_overhead <= max_overhead, because compaction is only -+ triggerred at the end of major GC cycles. -+ -+ The defaults are too large once the program starts using ~100MiB of -+ memory, at which point ~500MiB would be unavailable to other processes -+ (which would be fine if this was the main process in this VM, but it is -+ not). -+ -+ Max overhead can also be set to 0, however this is for testing purposes -+ only (setting it lower than 'space overhead' wouldn't help because the -+ major GC wouldn't run fast enough, and compaction does have a -+ performance cost: we can only compact contiguous regions, so memory has -+ to be moved around). -+ -+ Max overhead controls how often the heap is compacted, which is useful -+ if there are burst of activity followed by long periods of idle state, -+ or if a domain quits, etc. Compaction returns memory to the OS. -+ -+ wasted = live * space_overhead / 100 -+ -+ For globally overriding the GC settings one can use OCAMLRUNPARAM, -+ however we provide a config file override to be consistent with other -+ oxenstored settings. -+ -+ One might want to dynamically adjust the overhead setting based on used -+ memory, i.e. to use a fixed upper bound in bytes, not percentage. However -+ measurements show that such adjustments increase GC overhead massively, -+ while still not guaranteeing that memory is returned any more quickly -+ than with a percentage based setting. -+ -+ The allocation policy could also be tweaked, e.g. first fit would reduce -+ fragmentation and thus memory usage, but the documentation warns that it -+ can be sensibly slower, and indeed one of our own testcases can trigger -+ such a corner case where it is multiple times slower, so it is best to keep -+ the default allocation policy (next-fit/best-fit depending on version). -+ -+ There are other tweaks that can be attempted in the future, e.g. setting -+ 'ulimit -v' to 75% of RAM, however getting the kernel to actually return -+ NULL from allocations is difficult even with that setting, and without a -+ NULL the emergency GC won't be triggerred. -+ Perhaps cgroup limits could help, but for now tweak the safest only. -+*) -+ -+let tweak_gc () = -+ Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead } -+ -+ - let _ = - let cf = do_argv in - let pidfile = -@@ -274,6 +336,8 @@ let _ = - default_pidfile - in - -+ tweak_gc (); -+ - (try - Unixext.mkdir_rec (Filename.dirname pidfile) 0o755 - with _ -> diff --git a/xsa326-4.16-oxenstored-04.patch b/xsa326-4.16-oxenstored-04.patch deleted file mode 100644 index 0f2534b..0000000 --- a/xsa326-4.16-oxenstored-04.patch +++ /dev/null @@ -1,85 +0,0 @@ -From fd6d9cd3d20e496bdbf3e0a07354f65de0bcf4ae Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Fri, 29 Jul 2022 18:53:29 +0100 -Subject: tools/ocaml/libs/xb: hide type of Xb.t -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Hiding the type will make it easier to change the implementation -in the future without breaking code that relies on it. - -No functional change. - -Signed-off-by: Edwin Török -Acked-by: Christian Lindig -(cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba) - -Reported-by: Julien Grall -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 104d319d7747..8404ddd8a682 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out - let input_len con = Queue.length con.pkt_in - let has_in_packet con = Queue.length con.pkt_in > 0 - let get_in_packet con = Queue.pop con.pkt_in -+let has_partial_input con = match con.partial_in with -+ | HaveHdr _ -> true -+ | NoHdr (n, _) -> n < Partial.header_size () - let has_more_input con = - match con.backend with - | Fd _ -> false -diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli -index 3a00da6cddc1..794e35bb343e 100644 ---- a/tools/ocaml/libs/xb/xb.mli -+++ b/tools/ocaml/libs/xb/xb.mli -@@ -66,13 +66,7 @@ type backend_mmap = { - type backend_fd = { fd : Unix.file_descr; } - type backend = Fd of backend_fd | Xenmmap of backend_mmap - type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes --type t = { -- backend : backend; -- pkt_in : Packet.t Queue.t; -- pkt_out : Packet.t Queue.t; -- mutable partial_in : partial_buf; -- mutable partial_out : string; --} -+type t - val init_partial_in : unit -> partial_buf - val reconnect : t -> unit - val queue : t -> Packet.t -> unit -@@ -97,6 +91,7 @@ val has_output : t -> bool - val peek_output : t -> Packet.t - val input_len : t -> int - val has_in_packet : t -> bool -+val has_partial_input : t -> bool - val get_in_packet : t -> Packet.t - val has_more_input : t -> bool - val is_selectable : t -> bool -diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml -index 65f99ea6f28a..38b47363a173 100644 ---- a/tools/ocaml/xenstored/connection.ml -+++ b/tools/ocaml/xenstored/connection.ml -@@ -125,9 +125,7 @@ let get_perm con = - let set_target con target_domid = - con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid - --let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with -- | Xenbus.Xb.Xenmmap _ -> true -- | _ -> false -+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb - - let send_reply con tid rid ty data = - if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then -@@ -280,9 +278,7 @@ let get_transaction con tid = - - let do_input con = Xenbus.Xb.input con.xb - let has_input con = Xenbus.Xb.has_in_packet con.xb --let has_partial_input con = match con.xb.Xenbus.Xb.partial_in with -- | HaveHdr _ -> true -- | NoHdr (n, _) -> n < Xenbus.Partial.header_size () -+let has_partial_input con = Xenbus.Xb.has_partial_input con.xb - let pop_in con = Xenbus.Xb.get_in_packet con.xb - let has_more_input con = Xenbus.Xb.has_more_input con.xb - diff --git a/xsa326-4.16-oxenstored-05.patch b/xsa326-4.16-oxenstored-05.patch deleted file mode 100644 index 8b253a9..0000000 --- a/xsa326-4.16-oxenstored-05.patch +++ /dev/null @@ -1,214 +0,0 @@ -From f13fe5903361953e4ccf8602b9c8df7e64568d55 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:02 +0100 -Subject: tools/ocaml: Change Xb.input to return Packet.t option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The queue here would only ever hold at most one element. This will simplify -follow-up patches. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 8404ddd8a682..165fd4a1edf4 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes - type t = - { - backend: backend; -- pkt_in: Packet.t Queue.t; - pkt_out: Packet.t Queue.t; - mutable partial_in: partial_buf; - mutable partial_out: string; -@@ -62,7 +61,6 @@ let reconnect t = match t.backend with - Xs_ring.close backend.mmap; - backend.eventchn_notify (); - (* Clear our old connection state *) -- Queue.clear t.pkt_in; - Queue.clear t.pkt_out; - t.partial_in <- init_partial_in (); - t.partial_out <- "" -@@ -124,7 +122,6 @@ let output con = - - (* NB: can throw Reconnect *) - let input con = -- let newpacket = ref false in - let to_read = - match con.partial_in with - | HaveHdr partial_pkt -> Partial.to_complete partial_pkt -@@ -143,21 +140,19 @@ let input con = - if Partial.to_complete partial_pkt = 0 then ( - let pkt = Packet.of_partialpkt partial_pkt in - con.partial_in <- init_partial_in (); -- Queue.push pkt con.pkt_in; -- newpacket := true -- ) -+ Some pkt -+ ) else None - | NoHdr (i, buf) -> - (* we complete the partial header *) - if sz > 0 then - Bytes.blit b 0 buf (Partial.header_size () - i) sz; - con.partial_in <- if sz = i then -- HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf) -- ); -- !newpacket -+ HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf); -+ None -+ ) - - let newcon backend = { - backend = backend; -- pkt_in = Queue.create (); - pkt_out = Queue.create (); - partial_in = init_partial_in (); - partial_out = ""; -@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con - - let peek_output con = Queue.peek con.pkt_out - --let input_len con = Queue.length con.pkt_in --let has_in_packet con = Queue.length con.pkt_in > 0 --let get_in_packet con = Queue.pop con.pkt_in - let has_partial_input con = match con.partial_in with - | HaveHdr _ -> true - | NoHdr (n, _) -> n < Partial.header_size () -diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli -index 794e35bb343e..91c682162cea 100644 ---- a/tools/ocaml/libs/xb/xb.mli -+++ b/tools/ocaml/libs/xb/xb.mli -@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int - val write_mmap : backend_mmap -> 'a -> string -> int -> int - val write : t -> string -> int -> int - val output : t -> bool --val input : t -> bool -+val input : t -> Packet.t option - val newcon : backend -> t - val open_fd : Unix.file_descr -> t - val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t -@@ -89,10 +89,7 @@ val has_new_output : t -> bool - val has_old_output : t -> bool - val has_output : t -> bool - val peek_output : t -> Packet.t --val input_len : t -> int --val has_in_packet : t -> bool - val has_partial_input : t -> bool --val get_in_packet : t -> Packet.t - val has_more_input : t -> bool - val is_selectable : t -> bool - val get_fd : t -> Unix.file_descr -diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml -index d982fb24dbb1..451f8b38dbcc 100644 ---- a/tools/ocaml/libs/xs/xsraw.ml -+++ b/tools/ocaml/libs/xs/xsraw.ml -@@ -94,26 +94,18 @@ let pkt_send con = - done - - (* receive one packet - can sleep *) --let pkt_recv con = -- let workdone = ref false in -- while not !workdone -- do -- workdone := Xb.input con.xb -- done; -- Xb.get_in_packet con.xb -+let rec pkt_recv con = -+ match Xb.input con.xb with -+ | Some packet -> packet -+ | None -> pkt_recv con - - let pkt_recv_timeout con timeout = - let fd = Xb.get_fd con.xb in - let r, _, _ = Unix.select [ fd ] [] [] timeout in - if r = [] then - true, None -- else ( -- let workdone = Xb.input con.xb in -- if workdone then -- false, (Some (Xb.get_in_packet con.xb)) -- else -- false, None -- ) -+ else -+ false, Xb.input con.xb - - let queue_watchevent con data = - let ls = split_string ~limit:2 '\000' data in -diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml -index 38b47363a173..cc20e047d2b9 100644 ---- a/tools/ocaml/xenstored/connection.ml -+++ b/tools/ocaml/xenstored/connection.ml -@@ -277,9 +277,7 @@ let get_transaction con tid = - Hashtbl.find con.transactions tid - - let do_input con = Xenbus.Xb.input con.xb --let has_input con = Xenbus.Xb.has_in_packet con.xb - let has_partial_input con = Xenbus.Xb.has_partial_input con.xb --let pop_in con = Xenbus.Xb.get_in_packet con.xb - let has_more_input con = Xenbus.Xb.has_more_input con.xb - - let has_output con = Xenbus.Xb.has_output con.xb -@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do - Restrictions below can be relaxed once xenstored learns to dump more - of its live state in a safe way *) - let has_extra_connection_data con = -- let has_in = has_input con || has_partial_input con in -+ let has_in = has_partial_input con in - let has_out = has_output con in - let has_socket = con.dom = None in - let has_nondefault_perms = make_perm con.dom <> con.perm in -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 6a3435c265d3..2d67456a2aa0 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -195,10 +195,9 @@ let parse_live_update args = - | _ when Unix.gettimeofday () < t.deadline -> false - | l -> - warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l); -- let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s" -+ let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s" - (Connection.get_domstr con) - (Connection.number_of_transactions con) -- (Connection.has_input con) - (Connection.has_output con) - (Connection.get_perm con |> Perms.Connection.to_string) - ) l in -@@ -705,16 +704,17 @@ let do_input store cons doms con = - info "%s requests a reconnect" (Connection.get_domstr con); - History.reconnect con; - info "%s reconnection complete" (Connection.get_domstr con); -- false -+ None - | Failure exp -> - error "caught exception %s" exp; - error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con)); - Connection.mark_as_bad con; -- false -+ None - in - -- if newpacket then ( -- let packet = Connection.pop_in con in -+ match newpacket with -+ | None -> () -+ | Some packet -> - let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in - let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in - -@@ -724,8 +724,7 @@ let do_input store cons doms con = - (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *) - process_packet ~store ~cons ~doms ~con ~req; - write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data; -- Connection.incr_ops con; -- ) -+ Connection.incr_ops con - - let do_output _store _cons _doms con = - if Connection.has_output con then ( diff --git a/xsa326-4.16-oxenstored-06.patch b/xsa326-4.16-oxenstored-06.patch deleted file mode 100644 index c8ebc34..0000000 --- a/xsa326-4.16-oxenstored-06.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 2440a8b69a118fe14e73eb6cab4a050922866f1a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:03 +0100 -Subject: tools/ocaml/xb: Add BoundedQueue -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Ensures we cannot store more than [capacity] elements in a [Queue]. Replacing -all Queue with this module will then ensure at compile time that all Queues -are correctly bound checked. - -Each element in the queue has a class with its own limits. This, in a -subsequent change, will ensure that command responses can proceed during a -flood of watch events. - -No functional change. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 165fd4a1edf4..4197a3888a68 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -17,6 +17,98 @@ - module Op = struct include Op end - module Packet = struct include Packet end - -+module BoundedQueue : sig -+ type ('a, 'b) t -+ -+ (** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements. -+ This is burst capacity, each element is further classified according to [classify], -+ and each class can have its own [limit]. -+ [capacity] is enforced as an overall limit. -+ The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class, -+ in which case those elements are considered to use "burst capacity". -+ *) -+ val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t -+ -+ (** [clear q] discards all elements from [q] *) -+ val clear: ('a, 'b) t -> unit -+ -+ (** [can_push q] when [length q < capacity]. *) -+ val can_push: ('a, 'b) t -> 'b -> bool -+ -+ (** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *) -+ val push: 'a -> ('a, 'b) t -> unit option -+ -+ (** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *) -+ val pop: ('a, 'b) t -> 'a -+ -+ (** [peek q] returns the first element in [q], or raises [Queue.Empty]. *) -+ val peek : ('a, 'b) t -> 'a -+ -+ (** [length q] returns the current number of elements in [q] *) -+ val length: ('a, 'b) t -> int -+ -+ (** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *) -+ val debug: ('b -> string) -> (_, 'b) t -> string -+end = struct -+ type ('a, 'b) t = -+ { q: 'a Queue.t -+ ; capacity: int -+ ; classify: 'a -> 'b -+ ; limit: 'b -> int -+ ; class_count: ('b, int) Hashtbl.t -+ } -+ -+ let create ~capacity ~classify ~limit = -+ { capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 } -+ -+ let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0 -+ -+ let can_push_internal t classification class_count = -+ Queue.length t.q < t.capacity && class_count < t.limit classification -+ -+ let ok = Some () -+ -+ let push e t = -+ let classification = t.classify e in -+ let class_count = get_count t classification in -+ if can_push_internal t classification class_count then begin -+ Queue.push e t.q; -+ Hashtbl.replace t.class_count classification (class_count + 1); -+ ok -+ end -+ else -+ None -+ -+ let can_push t classification = -+ can_push_internal t classification @@ get_count t classification -+ -+ let clear t = -+ Queue.clear t.q; -+ Hashtbl.reset t.class_count -+ -+ let pop t = -+ let e = Queue.pop t.q in -+ let classification = t.classify e in -+ let () = match get_count t classification - 1 with -+ | 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *) -+ | n -> Hashtbl.replace t.class_count classification n -+ in -+ e -+ -+ let peek t = Queue.peek t.q -+ let length t = Queue.length t.q -+ -+ let debug string_of_class t = -+ let b = Buffer.create 128 in -+ Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity; -+ Hashtbl.iter (fun packet_class count -> -+ Printf.bprintf b " %s: %d" (string_of_class packet_class) count -+ ) t.class_count; -+ Printf.bprintf b "}"; -+ Buffer.contents b -+end -+ -+ - exception End_of_file - exception Eagain - exception Noent diff --git a/xsa326-4.16-oxenstored-07.patch b/xsa326-4.16-oxenstored-07.patch deleted file mode 100644 index ef02467..0000000 --- a/xsa326-4.16-oxenstored-07.patch +++ /dev/null @@ -1,872 +0,0 @@ -From bc0f05e6f3a3c93c853ceffd1f6d2022dc30fb77 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:04 +0100 -Subject: tools/ocaml: Limit maximum in-flight requests / outstanding replies -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Introduce a limit on the number of outstanding reply packets in the xenbus -queue. This limits the number of in-flight requests: when the output queue is -full we'll stop processing inputs until the output queue has room again. - -To avoid a busy loop on the Unix socket we only add it to the watched input -file descriptor set if we'd be able to call `input` on it. Even though Dom0 -is trusted and exempt from quotas a flood of events might cause a backlog -where events are produced faster than daemons in Dom0 can consume them, which -could lead to an unbounded queue size and OOM. - -Therefore the xenbus queue limit must apply to all connections, Dom0 is not -exempt from it, although if everything works correctly it will eventually -catch up. - -This prevents a malicious guest from sending more commands while it has -outstanding watch events or command replies in its input ring. However if it -can cause the generation of watch events by other means (e.g. by Dom0, or -another cooperative guest) and stop reading its own ring then watch events -would've queued up without limit. - -The xenstore protocol doesn't have a back-pressure mechanism, and doesn't -allow dropping watch events. In fact, dropping watch events is known to break -some pieces of normal functionality. This leaves little choice to safely -implement the xenstore protocol without exposing the xenstore daemon to -out-of-memory attacks. - -Implement the fix as pipes with bounded buffers: -* Use a bounded buffer for watch events -* The watch structure will have a bounded receiving pipe of watch events -* The source will have an "overflow" pipe of pending watch events it couldn't - deliver - -Items are queued up on one end and are sent as far along the pipe as possible: - - source domain -> watch -> xenbus of target -> xenstore ring/socket of target - -If the pipe is "full" at any point then back-pressure is applied and we prevent -more items from being queued up. For the source domain this means that we'll -stop accepting new commands as long as its pipe buffer is not empty. - -Before we try to enqueue an item we first check whether it is possible to send -it further down the pipe, by attempting to recursively flush the pipes. This -ensures that we retain the order of events as much as possible. - -We might break causality of watch events if the target domain's queue is full -and we need to start using the watch's queue. This is a breaking change in -the xenstore protocol, but only for domains which are not processing their -incoming ring as expected. - -When a watch is deleted its entire pending queue is dropped (no code is needed -for that, because it is part of the 'watch' type). - -There is a cache of watches that have pending events that we attempt to flush -at every cycle if possible. - -Introduce 3 limits here: -* quota-maxwatchevents on watch event destination: when this is hit the - source will not be allowed to queue up more watch events. -* quota-maxoustanding which is the number of responses not read from the ring: - once exceeded, no more inputs are processed until all outstanding replies - are consumed by the client. -* overflow queue on the watch event source: all watches that cannot be stored - on destination are queued up here, a single command can trigger multiple - watches (e.g. due to recursion). - -The overflow queue currently doesn't have an upper bound, it is difficult to -accurately calculate one as it depends on whether you are Dom0 and how many -watches each path has registered and how many watch events you can trigger -with a single command (e.g. a commit). However these events were already -using memory, this just moves them elsewhere, and as long as we correctly -block a domain it shouldn't result in unbounded memory usage. - -Note that Dom0 is not excluded from these checks, it is important that Dom0 is -especially not excluded when it is the source, since there are many ways in -which a guest could trigger Dom0 to send it watch events. - -This should protect against malicious frontends as long as the backend follows -the PV xenstore protocol and only exposes paths needed by the frontend, and -changes those paths at most once as a reaction to guest events, or protocol -state. - -The queue limits are per watch, and per domain-pair, so even if one -communication channel would be "blocked", others would keep working, and the -domain itself won't get blocked as long as it doesn't overflow the queue of -watch events. - -Similarly a malicious backend could cause the frontend to get blocked, but -this watch queue protects the frontend as well as long as it follows the PV -protocol. (Although note that protection against malicious backends is only a -best effort at the moment) - -This is part of XSA-326 / CVE-2022-42318. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 4197a3888a68..b292ed7a874d 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap - - type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes - -+(* -+ separate capacity reservation for replies and watch events: -+ this allows a domain to keep working even when under a constant flood of -+ watch events -+*) -+type capacity = { maxoutstanding: int; maxwatchevents: int } -+ -+module Queue = BoundedQueue -+ -+type packet_class = -+ | CommandReply -+ | Watchevent -+ -+let string_of_packet_class = function -+ | CommandReply -> "command_reply" -+ | Watchevent -> "watch_event" -+ - type t = - { - backend: backend; -- pkt_out: Packet.t Queue.t; -+ pkt_out: (Packet.t, packet_class) Queue.t; - mutable partial_in: partial_buf; - mutable partial_out: string; -+ capacity: capacity - } - -+let to_read con = -+ match con.partial_in with -+ | HaveHdr partial_pkt -> Partial.to_complete partial_pkt -+ | NoHdr (i, _) -> i -+ -+let debug t = -+ Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s" -+ (to_read t) -+ (String.length t.partial_out) -+ (Queue.length t.pkt_out) -+ (BoundedQueue.debug string_of_packet_class t.pkt_out) -+ - let init_partial_in () = NoHdr - (Partial.header_size (), Bytes.make (Partial.header_size()) '\000') - -@@ -199,7 +229,8 @@ let output con = - let s = if String.length con.partial_out > 0 then - con.partial_out - else if Queue.length con.pkt_out > 0 then -- Packet.to_string (Queue.pop con.pkt_out) -+ let pkt = Queue.pop con.pkt_out in -+ Packet.to_string pkt - else - "" in - (* send data from s, and save the unsent data to partial_out *) -@@ -212,12 +243,15 @@ let output con = - (* after sending one packet, partial is empty *) - con.partial_out = "" - -+(* we can only process an input packet if we're guaranteed to have room -+ to store the response packet *) -+let can_input con = Queue.can_push con.pkt_out CommandReply -+ - (* NB: can throw Reconnect *) - let input con = -- let to_read = -- match con.partial_in with -- | HaveHdr partial_pkt -> Partial.to_complete partial_pkt -- | NoHdr (i, _) -> i in -+ if not (can_input con) then None -+ else -+ let to_read = to_read con in - - (* try to get more data from input stream *) - let b = Bytes.make to_read '\000' in -@@ -243,11 +277,22 @@ let input con = - None - ) - --let newcon backend = { -+let classify t = -+ match t.Packet.ty with -+ | Op.Watchevent -> Watchevent -+ | _ -> CommandReply -+ -+let newcon ~capacity backend = -+ let limit = function -+ | CommandReply -> capacity.maxoutstanding -+ | Watchevent -> capacity.maxwatchevents -+ in -+ { - backend = backend; -- pkt_out = Queue.create (); -+ pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit; - partial_in = init_partial_in (); - partial_out = ""; -+ capacity = capacity; - } - - let open_fd fd = newcon (Fd { fd = fd; }) -diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli -index 91c682162cea..71b2754ca788 100644 ---- a/tools/ocaml/libs/xb/xb.mli -+++ b/tools/ocaml/libs/xb/xb.mli -@@ -66,10 +66,11 @@ type backend_mmap = { - type backend_fd = { fd : Unix.file_descr; } - type backend = Fd of backend_fd | Xenmmap of backend_mmap - type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes -+type capacity = { maxoutstanding: int; maxwatchevents: int } - type t - val init_partial_in : unit -> partial_buf - val reconnect : t -> unit --val queue : t -> Packet.t -> unit -+val queue : t -> Packet.t -> unit option - val read_fd : backend_fd -> 'a -> bytes -> int -> int - val read_mmap : backend_mmap -> 'a -> bytes -> int -> int - val read : t -> bytes -> int -> int -@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int - val write : t -> string -> int -> int - val output : t -> bool - val input : t -> Packet.t option --val newcon : backend -> t --val open_fd : Unix.file_descr -> t --val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t -+val newcon : capacity:capacity -> backend -> t -+val open_fd : Unix.file_descr -> capacity:capacity -> t -+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t - val close : t -> unit - val is_fd : t -> bool - val is_mmap : t -> bool - val output_len : t -> int -+val can_input: t -> bool - val has_new_output : t -> bool - val has_old_output : t -> bool - val has_output : t -> bool -@@ -93,3 +95,4 @@ val has_partial_input : t -> bool - val has_more_input : t -> bool - val is_selectable : t -> bool - val get_fd : t -> Unix.file_descr -+val debug: t -> string -diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml -index 9ff5bbd529ce..4e532cdaeacb 100644 ---- a/tools/ocaml/libs/xs/queueop.ml -+++ b/tools/ocaml/libs/xs/queueop.ml -@@ -16,9 +16,10 @@ - open Xenbus - - let data_concat ls = (String.concat "\000" ls) ^ "\000" -+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None) - let queue_path ty (tid: int) (path: string) con = - let data = data_concat [ path; ] in -- Xb.queue con (Xb.Packet.create tid 0 ty data) -+ queue con (Xb.Packet.create tid 0 ty data) - - (* operations *) - let directory tid path con = queue_path Xb.Op.Directory tid path con -@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con - let getperms tid path con = queue_path Xb.Op.Getperms tid path con - - let debug commands con = -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands)) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands)) - - let watch path data con = - let data = data_concat [ path; data; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Watch data) - - let unwatch path data con = - let data = data_concat [ path; data; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data) - - let transaction_start con = -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat [])) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat [])) - - let transaction_end tid commit con = - let data = data_concat [ (if commit then "T" else "F"); ] in -- Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data) -+ queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data) - - let introduce domid mfn port con = - let data = data_concat [ Printf.sprintf "%u" domid; - Printf.sprintf "%nu" mfn; - string_of_int port; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data) - - let release domid con = - let data = data_concat [ Printf.sprintf "%u" domid; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Release data) - - let resume domid con = - let data = data_concat [ Printf.sprintf "%u" domid; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Resume data) - - let getdomainpath domid con = - let data = data_concat [ Printf.sprintf "%u" domid; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data) - - let write tid path value con = - let data = path ^ "\000" ^ value (* no NULL at the end *) in -- Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data) -+ queue con (Xb.Packet.create tid 0 Xb.Op.Write data) - - let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con - let rm tid path con = queue_path Xb.Op.Rm tid path con - - let setperms tid path perms con = - let data = data_concat [ path; perms ] in -- Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data) -+ queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data) -diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml -index 451f8b38dbcc..cbd17280600c 100644 ---- a/tools/ocaml/libs/xs/xsraw.ml -+++ b/tools/ocaml/libs/xs/xsraw.ml -@@ -36,8 +36,10 @@ type con = { - let close con = - Xb.close con.xb - -+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; } -+ - let open_fd fd = { -- xb = Xb.open_fd fd; -+ xb = Xb.open_fd ~capacity fd; - watchevents = Queue.create (); - } - -diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml -index cc20e047d2b9..9624a5f9da2c 100644 ---- a/tools/ocaml/xenstored/connection.ml -+++ b/tools/ocaml/xenstored/connection.ml -@@ -20,12 +20,84 @@ open Stdext - - let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *) - -+type 'a bounded_sender = 'a -> unit option -+(** a bounded sender accepts an ['a] item and returns: -+ None - if there is no room to accept the item -+ Some () - if it has successfully accepted/sent the item -+ *) -+ -+module BoundedPipe : sig -+ type 'a t -+ -+ (** [create ~capacity ~destination] creates a bounded pipe with a -+ local buffer holding at most [capacity] items. Once the buffer is -+ full it will not accept further items. items from the pipe are -+ flushed into [destination] as long as it accepts items. The -+ destination could be another pipe. -+ *) -+ val create: capacity:int -> destination:'a bounded_sender -> 'a t -+ -+ (** [is_empty t] returns whether the local buffer of [t] is empty. *) -+ val is_empty : _ t -> bool -+ -+ (** [length t] the number of items in the internal buffer *) -+ val length: _ t -> int -+ -+ (** [flush_pipe t] sends as many items from the local buffer as possible, -+ which could be none. *) -+ val flush_pipe: _ t -> unit -+ -+ (** [push t item] tries to [flush_pipe] and then push [item] -+ into the pipe if its [capacity] allows. -+ Returns [None] if there is no more room -+ *) -+ val push : 'a t -> 'a bounded_sender -+end = struct -+ (* items are enqueued in [q], and then flushed to [connect_to] *) -+ type 'a t = -+ { q: 'a Queue.t -+ ; destination: 'a bounded_sender -+ ; capacity: int -+ } -+ -+ let create ~capacity ~destination = -+ { q = Queue.create (); capacity; destination } -+ -+ let rec flush_pipe t = -+ if not Queue.(is_empty t.q) then -+ let item = Queue.peek t.q in -+ match t.destination item with -+ | None -> () (* no room *) -+ | Some () -> -+ (* successfully sent item to next stage *) -+ let _ = Queue.pop t.q in -+ (* continue trying to send more items *) -+ flush_pipe t -+ -+ let push t item = -+ (* first try to flush as many items from this pipe as possible to make room, -+ it is important to do this first to preserve the order of the items -+ *) -+ flush_pipe t; -+ if Queue.length t.q < t.capacity then begin -+ (* enqueue, instead of sending directly. -+ this ensures that [out] sees the items in the same order as we receive them -+ *) -+ Queue.push item t.q; -+ Some (flush_pipe t) -+ end else None -+ -+ let is_empty t = Queue.is_empty t.q -+ let length t = Queue.length t.q -+end -+ - type watch = { - con: t; - token: string; - path: string; - base: string; - is_relative: bool; -+ pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t; - } - - and t = { -@@ -38,8 +110,36 @@ and t = { - anonid: int; - mutable stat_nb_ops: int; - mutable perm: Perms.Connection.t; -+ pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t - } - -+module Watch = struct -+ module T = struct -+ type t = watch -+ -+ let compare w1 w2 = -+ (* cannot compare watches from different connections *) -+ assert (w1.con == w2.con); -+ match String.compare w1.token w2.token with -+ | 0 -> String.compare w1.path w2.path -+ | n -> n -+ end -+ module Set = Set.Make(T) -+ -+ let flush_events t = -+ BoundedPipe.flush_pipe t.pending_watchevents; -+ not (BoundedPipe.is_empty t.pending_watchevents) -+ -+ let pending_watchevents t = -+ BoundedPipe.length t.pending_watchevents -+end -+ -+let source_flush_watchevents t = -+ BoundedPipe.flush_pipe t.pending_source_watchevents -+ -+let source_pending_watchevents t = -+ BoundedPipe.length t.pending_source_watchevents -+ - let mark_as_bad con = - match con.dom with - |None -> () -@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = { - token = token; - path = path; - base = get_path con; -- is_relative = path.[0] <> '/' && path.[0] <> '@' -+ is_relative = path.[0] <> '/' && path.[0] <> '@'; -+ pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb) - } - - let get_con w = w.con -@@ -93,6 +194,9 @@ let make_perm dom = - Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid - - let create xbcon dom = -+ let destination (watch, pkt) = -+ BoundedPipe.push watch.pending_watchevents pkt -+ in - let id = - match dom with - | None -> let old = !anon_id_next in incr anon_id_next; old -@@ -109,6 +213,16 @@ let create xbcon dom = - anonid = id; - stat_nb_ops = 0; - perm = make_perm dom; -+ -+ (* the actual capacity will be lower, this is used as an overflow -+ buffer: anything that doesn't fit elsewhere gets put here, only -+ limited by the amount of watches that you can generate with a -+ single xenstore command (which is finite, although possibly very -+ large in theory for Dom0). Once the pipe here has any contents the -+ domain is blocked from sending more commands until it is empty -+ again though. -+ *) -+ pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination - } - in - Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con); -@@ -127,11 +241,17 @@ let set_target con target_domid = - - let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb - --let send_reply con tid rid ty data = -+let packet_of con tid rid ty data = - if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then -- Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000") -+ Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000" - else -- Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data) -+ Xenbus.Xb.Packet.create tid rid ty data -+ -+let send_reply con tid rid ty data = -+ let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in -+ (* should never happen: we only process an input packet when there is room for an output packet *) -+ (* and the limit for replies is different from the limit for watch events *) -+ assert (result <> None) - - let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000") - let send_ack con tid rid ty = send_reply con tid rid ty "OK\000" -@@ -181,11 +301,11 @@ let del_watch con path token = - apath, w - - let del_watches con = -- Hashtbl.clear con.watches; -+ Hashtbl.reset con.watches; - con.nb_watches <- 0 - - let del_transactions con = -- Hashtbl.clear con.transactions -+ Hashtbl.reset con.transactions - - let list_watches con = - let ll = Hashtbl.fold -@@ -208,21 +328,29 @@ let lookup_watch_perm path = function - let lookup_watch_perms oldroot root path = - lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root) - --let fire_single_watch_unchecked watch = -+let fire_single_watch_unchecked source watch = - let data = Utils.join_by_null [watch.path; watch.token; ""] in -- send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data -+ let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in -+ -+ match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with -+ | Some () -> () (* packet queued *) -+ | None -> -+ (* a well behaved Dom0 shouldn't be able to trigger this, -+ if it happens it is likely a Dom0 bug causing runaway memory usage -+ *) -+ failwith "watch event overflow, cannot happen" - --let fire_single_watch (oldroot, root) watch = -+let fire_single_watch source (oldroot, root) watch = - let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in - let perms = lookup_watch_perms oldroot root abspath in - if Perms.can_fire_watch watch.con.perm perms then -- fire_single_watch_unchecked watch -+ fire_single_watch_unchecked source watch - else - let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in - let con = get_domstr watch.con in - Logging.watch_not_fired ~con perms (Store.Path.to_string abspath) - --let fire_watch roots watch path = -+let fire_watch source roots watch path = - let new_path = - if watch.is_relative && path.[0] = '/' - then begin -@@ -232,7 +360,7 @@ let fire_watch roots watch path = - end else - path - in -- fire_single_watch roots { watch with path = new_path } -+ fire_single_watch source roots { watch with path = new_path } - - (* Search for a valid unused transaction id. *) - let rec valid_transaction_id con proposed_id = -@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb - let has_partial_input con = Xenbus.Xb.has_partial_input con.xb - let has_more_input con = Xenbus.Xb.has_more_input con.xb - -+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents - let has_output con = Xenbus.Xb.has_output con.xb - let has_old_output con = Xenbus.Xb.has_old_output con.xb - let has_new_output con = Xenbus.Xb.has_new_output con.xb -@@ -323,7 +452,7 @@ let prevents_live_update con = not (is_bad con) - && (has_extra_connection_data con || has_transaction_data con) - - let has_more_work con = -- has_more_input con || not (has_old_output con) && has_new_output con -+ (has_more_input con && can_input con) || not (has_old_output con) && has_new_output con - - let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1 - -diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml -index 3c7429fe7f61..7d68c583b43a 100644 ---- a/tools/ocaml/xenstored/connections.ml -+++ b/tools/ocaml/xenstored/connections.ml -@@ -22,22 +22,30 @@ type t = { - domains: (int, Connection.t) Hashtbl.t; - ports: (Xeneventchn.t, Connection.t) Hashtbl.t; - mutable watches: Connection.watch list Trie.t; -+ mutable has_pending_watchevents: Connection.Watch.Set.t - } - - let create () = { - anonymous = Hashtbl.create 37; - domains = Hashtbl.create 37; - ports = Hashtbl.create 37; -- watches = Trie.create () -+ watches = Trie.create (); -+ has_pending_watchevents = Connection.Watch.Set.empty; - } - -+let get_capacity () = -+ (* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *) -+ { Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents } -+ - let add_anonymous cons fd = -- let xbcon = Xenbus.Xb.open_fd fd in -+ let capacity = get_capacity () in -+ let xbcon = Xenbus.Xb.open_fd fd ~capacity in - let con = Connection.create xbcon None in - Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con - - let add_domain cons dom = -- let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in -+ let capacity = get_capacity () in -+ let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in - let con = Connection.create xbcon (Some dom) in - Hashtbl.add cons.domains (Domain.get_id dom) con; - match Domain.get_port dom with -@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons = - Hashtbl.fold (fun _ con (ins, outs) -> - if (only_if con) then ( - let fd = Connection.get_fd con in -- (fd :: ins, if Connection.has_output con then fd :: outs else outs) -+ let in_fds = if Connection.can_input con then fd :: ins else ins in -+ let out_fds = if Connection.has_output con then fd :: outs else outs in -+ in_fds, out_fds - ) else (ins, outs) - ) - cons.anonymous ([], []) -@@ -67,10 +77,17 @@ let del_watches_of_con con watches = - | [] -> None - | ws -> Some ws - -+let del_watches cons con = -+ Connection.del_watches con; -+ cons.watches <- Trie.map (del_watches_of_con con) cons.watches; -+ cons.has_pending_watchevents <- -+ cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w -> -+ Connection.get_con w != con -+ - let del_anonymous cons con = - try - Hashtbl.remove cons.anonymous (Connection.get_fd con); -- cons.watches <- Trie.map (del_watches_of_con con) cons.watches; -+ del_watches cons con; - Connection.close con - with exn -> - debug "del anonymous %s" (Printexc.to_string exn) -@@ -85,7 +102,7 @@ let del_domain cons id = - | Some p -> Hashtbl.remove cons.ports p - | None -> ()) - | None -> ()); -- cons.watches <- Trie.map (del_watches_of_con con) cons.watches; -+ del_watches cons con; - Connection.close con - with exn -> - debug "del domain %u: %s" id (Printexc.to_string exn) -@@ -136,31 +153,33 @@ let del_watch cons con path token = - cons.watches <- Trie.set cons.watches key watches; - watch - --let del_watches cons con = -- Connection.del_watches con; -- cons.watches <- Trie.map (del_watches_of_con con) cons.watches -- - (* path is absolute *) --let fire_watches ?oldroot root cons path recurse = -+let fire_watches ?oldroot source root cons path recurse = - let key = key_of_path path in - let path = Store.Path.to_string path in - let roots = oldroot, root in - let fire_watch _ = function - | None -> () -- | Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches -+ | Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches - in - let fire_rec _x = function - | None -> () - | Some watches -> -- List.iter (Connection.fire_single_watch roots) watches -+ List.iter (Connection.fire_single_watch source roots) watches - in - Trie.iter_path fire_watch cons.watches key; - if recurse then - Trie.iter fire_rec (Trie.sub cons.watches key) - -+let send_watchevents cons con = -+ cons.has_pending_watchevents <- -+ cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events; -+ Connection.source_flush_watchevents con -+ - let fire_spec_watches root cons specpath = -+ let source = find_domain cons 0 in - iter cons (fun con -> -- List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath)) -+ List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath)) - - let set_target cons domain target_domain = - let con = find_domain cons domain in -@@ -197,6 +216,16 @@ let debug cons = - let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in - String.concat "" (domains @ anonymous) - -+let debug_watchevents cons con = -+ (* == (physical equality) -+ has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular -+ comparison to fail due to having a 'functional value' which cannot be compared. -+ *) -+ let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in -+ let pending = s |> Connection.Watch.Set.elements -+ |> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in -+ Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending -+ - let filter ~f cons = - let fold _ v acc = if f v then v :: acc else acc in - [] -diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml -index ba63a8147e09..327b6d795ec7 100644 ---- a/tools/ocaml/xenstored/define.ml -+++ b/tools/ocaml/xenstored/define.ml -@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir - let maxwatch = ref (100) - let maxtransaction = ref (10) - let maxrequests = ref (1024) (* maximum requests per transaction *) -+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *) -+let maxwatchevents = ref (1024) -+(* -+ maximum outstanding watch events per watch, -+ recommended >= maxoutstanding to avoid blocking backend transactions due to -+ malicious frontends -+ *) - - let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *) - let conflict_burst_limit = ref 5.0 -diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in -index 4ae48e42d47d..9d034e744b4b 100644 ---- a/tools/ocaml/xenstored/oxenstored.conf.in -+++ b/tools/ocaml/xenstored/oxenstored.conf.in -@@ -62,6 +62,8 @@ quota-maxwatch = 100 - quota-transaction = 10 - quota-maxrequests = 1024 - quota-path-max = 1024 -+quota-maxoutstanding = 1024 -+quota-maxwatchevents = 1024 - - # Activate filed base backend - persistent = false -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 2d67456a2aa0..6dcedfda86e4 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -57,7 +57,7 @@ let split_one_path data con = - | path :: "" :: [] -> Store.Path.create path (Connection.get_path con) - | _ -> raise Invalid_Cmd_Args - --let process_watch t cons = -+let process_watch source t cons = - let oldroot = t.Transaction.oldroot in - let newroot = Store.get_root t.store in - let ops = Transaction.get_paths t |> List.rev in -@@ -67,8 +67,9 @@ let process_watch t cons = - | Xenbus.Xb.Op.Rm -> true, None, oldroot - | Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot - | _ -> raise (Failure "huh ?") in -- Connections.fire_watches ?oldroot root cons (snd op) recurse in -- List.iter (fun op -> do_op_watch op cons) ops -+ Connections.fire_watches ?oldroot source root cons (snd op) recurse in -+ List.iter (fun op -> do_op_watch op cons) ops; -+ Connections.send_watchevents cons source - - let create_implicit_path t perm path = - let dirname = Store.Path.get_parent path in -@@ -234,6 +235,20 @@ let do_debug con t _domains cons data = - | "watches" :: _ -> - let watches = Connections.debug cons in - Some (watches ^ "\000") -+ | "xenbus" :: domid :: _ -> -+ let domid = int_of_string domid in -+ let con = Connections.find_domain cons domid in -+ let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s" -+ (Xenbus.Xb.debug con.xb) -+ (Connection.source_pending_watchevents con) -+ (Connection.can_input con) -+ (Connection.has_more_input con) -+ (Connection.has_old_output con) -+ (Connection.has_new_output con) -+ (Connection.has_more_work con) -+ (Connections.debug_watchevents cons con) -+ in -+ Some s - | "mfn" :: domid :: _ -> - let domid = int_of_string domid in - let con = Connections.find_domain cons domid in -@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data = - fct con t doms cons data; - Packet.Ack (fun () -> - if Transaction.get_id t = Transaction.none then -- process_watch t cons -+ process_watch con t cons - ) - - let reply_data fct con t doms cons data = -@@ -501,7 +516,7 @@ let do_watch con t _domains cons data = - Packet.Ack (fun () -> - (* xenstore.txt says this watch is fired immediately, - implying even if path doesn't exist or is unreadable *) -- Connection.fire_single_watch_unchecked watch) -+ Connection.fire_single_watch_unchecked con watch) - - let do_unwatch con _t _domains cons data = - let (node, token) = -@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data = - if not success then - raise Transaction_again; - if commit then begin -- process_watch t cons; -+ process_watch con t cons; - match t.Transaction.ty with - | Transaction.No -> - () (* no need to record anything *) -@@ -699,7 +714,8 @@ let process_packet ~store ~cons ~doms ~con ~req = - let do_input store cons doms con = - let newpacket = - try -- Connection.do_input con -+ if Connection.can_input con then Connection.do_input con -+ else None - with Xenbus.Xb.Reconnect -> - info "%s requests a reconnect" (Connection.get_domstr con); - History.reconnect con; -@@ -727,6 +743,7 @@ let do_input store cons doms con = - Connection.incr_ops con - - let do_output _store _cons _doms con = -+ Connection.source_flush_watchevents con; - if Connection.has_output con then ( - if Connection.has_new_output con then ( - let packet = Connection.peek_output con in -diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml -index 3b57ad016dfb..c799e20f1145 100644 ---- a/tools/ocaml/xenstored/xenstored.ml -+++ b/tools/ocaml/xenstored/xenstored.ml -@@ -103,6 +103,8 @@ let parse_config filename = - ("quota-maxentity", Config.Set_int Quota.maxent); - ("quota-maxsize", Config.Set_int Quota.maxsize); - ("quota-maxrequests", Config.Set_int Define.maxrequests); -+ ("quota-maxoutstanding", Config.Set_int Define.maxoutstanding); -+ ("quota-maxwatchevents", Config.Set_int Define.maxwatchevents); - ("quota-path-max", Config.Set_int Define.path_max); - ("gc-max-overhead", Config.Set_int Define.gc_max_overhead); - ("test-eagain", Config.Set_bool Transaction.test_eagain); diff --git a/xsa326-4.16-oxenstored-08.patch b/xsa326-4.16-oxenstored-08.patch deleted file mode 100644 index 8a47200..0000000 --- a/xsa326-4.16-oxenstored-08.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 09aa10649f75a262028e9a9b7d859ef7efb23d54 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Thu, 29 Sep 2022 13:07:35 +0200 -Subject: SUPPORT.md: clarify support of untrusted driver domains with - oxenstored - -Add a support statement for the scope of support regarding different -Xenstore variants. Especially oxenstored does not (yet) have security -support of untrusted driver domains, as those might drive oxenstored -out of memory by creating lots of watch events for the guests they are -servicing. - -Add a statement regarding Live Update support of oxenstored. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: George Dunlap -Acked-by: Julien Grall -Reviewed-by: Christian Lindig - -diff --git a/SUPPORT.md b/SUPPORT.md -index 85726102eab8..7d0cb34c8f6f 100644 ---- a/SUPPORT.md -+++ b/SUPPORT.md -@@ -179,13 +179,18 @@ Support for running qemu-xen device model in a linux stubdomain. - - Status: Tech Preview - --## Liveupdate of C xenstored daemon -+## Xenstore - -- Status: Tech Preview -+### C xenstored daemon - --## Liveupdate of OCaml xenstored daemon -+ Status: Supported -+ Status, Liveupdate: Tech Preview - -- Status: Tech Preview -+### OCaml xenstored daemon -+ -+ Status: Supported -+ Status, untrusted driver domains: Supported, not security supported -+ Status, Liveupdate: Not functional - - ## Toolstack/3rd party - diff --git a/xsa326-4.16-xenstored-01.patch b/xsa326-4.16-xenstored-01.patch deleted file mode 100644 index b4a4b0e..0000000 --- a/xsa326-4.16-xenstored-01.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 5192f13a41661b1c1b9e0889d57c0f5b41925c39 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: split up send_reply() - -Today send_reply() is used for both, normal request replies and watch -events. - -Split it up into send_reply() and send_event(). This will be used to -add some event specific handling. - -add_event() can be merged into send_event(), removing the need for an -intermediate memory allocation. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index e9c9695fd16e..249ad5ec6fb1 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -767,49 +767,32 @@ static void send_error(struct connection *conn, int error) - void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - const void *data, unsigned int len) - { -- struct buffered_data *bdata; -+ struct buffered_data *bdata = conn->in; -+ -+ assert(type != XS_WATCH_EVENT); - - if ( len > XENSTORE_PAYLOAD_MAX ) { - send_error(conn, E2BIG); - return; - } - -- /* Replies reuse the request buffer, events need a new one. */ -- if (type != XS_WATCH_EVENT) { -- bdata = conn->in; -- /* Drop asynchronous responses, e.g. errors for watch events. */ -- if (!bdata) -- return; -- bdata->inhdr = true; -- bdata->used = 0; -- conn->in = NULL; -- } else { -- /* Message is a child of the connection for auto-cleanup. */ -- bdata = new_buffer(conn); -+ if (!bdata) -+ return; -+ bdata->inhdr = true; -+ bdata->used = 0; - -- /* -- * Allocation failure here is unfortunate: we have no way to -- * tell anybody about it. -- */ -- if (!bdata) -- return; -- } - if (len <= DEFAULT_BUFFER_SIZE) - bdata->buffer = bdata->default_buffer; -- else -+ else { - bdata->buffer = talloc_array(bdata, char, len); -- if (!bdata->buffer) { -- if (type == XS_WATCH_EVENT) { -- /* Same as above: no way to tell someone. */ -- talloc_free(bdata); -+ if (!bdata->buffer) { -+ send_error(conn, ENOMEM); - return; - } -- /* re-establish request buffer for sending ENOMEM. */ -- conn->in = bdata; -- send_error(conn, ENOMEM); -- return; - } - -+ conn->in = NULL; -+ - /* Update relevant header fields and fill in the message body. */ - bdata->hdr.msg.type = type; - bdata->hdr.msg.len = len; -@@ -817,8 +800,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+} - -- return; -+/* -+ * Send a watch event. -+ * As this is not directly related to the current command, errors can't be -+ * reported. -+ */ -+void send_event(struct connection *conn, const char *path, const char *token) -+{ -+ struct buffered_data *bdata; -+ unsigned int len; -+ -+ len = strlen(path) + 1 + strlen(token) + 1; -+ /* Don't try to send over-long events. */ -+ if (len > XENSTORE_PAYLOAD_MAX) -+ return; -+ -+ bdata = new_buffer(conn); -+ if (!bdata) -+ return; -+ -+ bdata->buffer = talloc_array(bdata, char, len); -+ if (!bdata->buffer) { -+ talloc_free(bdata); -+ return; -+ } -+ strcpy(bdata->buffer, path); -+ strcpy(bdata->buffer + strlen(path) + 1, token); -+ bdata->hdr.msg.type = XS_WATCH_EVENT; -+ bdata->hdr.msg.len = len; -+ -+ /* Queue for later transmission. */ -+ list_add_tail(&bdata->list, &conn->out_list); - } - - /* Some routines (write, mkdir, etc) just need a non-error return */ -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 0004fa848c83..9af9af4390bd 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -187,6 +187,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset); - - void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - const void *data, unsigned int len); -+void send_event(struct connection *conn, const char *path, const char *token); - - /* Some routines (write, mkdir, etc) just need a non-error return */ - void send_ack(struct connection *conn, enum xsd_sockmsg_type type); -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index aca0a71bada1..99a2c266b28a 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -86,35 +86,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name) - } - - /* -- * Send a watch event. -- * Temporary memory allocations are done with ctx. -- */ --static void add_event(struct connection *conn, -- const void *ctx, -- struct watch *watch, -- const char *name) --{ -- /* Data to send (node\0token\0). */ -- unsigned int len; -- char *data; -- -- name = get_watch_path(watch, name); -- -- len = strlen(name) + 1 + strlen(watch->token) + 1; -- /* Don't try to send over-long events. */ -- if (len > XENSTORE_PAYLOAD_MAX) -- return; -- -- data = talloc_array(ctx, char, len); -- if (!data) -- return; -- strcpy(data, name); -- strcpy(data + strlen(name) + 1, watch->token); -- send_reply(conn, XS_WATCH_EVENT, data, len); -- talloc_free(data); --} -- --/* - * Check permissions of a specific watch to fire: - * Either the node itself or its parent have to be readable by the connection - * the watch has been setup for. In case a watch event is created due to -@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - list_for_each_entry(watch, &i->watches, list) { - if (exact) { - if (streq(name, watch->node)) -- add_event(i, ctx, watch, name); -+ send_event(i, -+ get_watch_path(watch, name), -+ watch->token); - } else { - if (is_child(name, watch->node)) -- add_event(i, ctx, watch, name); -+ send_event(i, -+ get_watch_path(watch, name), -+ watch->token); - } - } - } -@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in) - send_ack(conn, XS_WATCH); - - /* We fire once up front: simplifies clients and restart. */ -- add_event(conn, in, watch, watch->node); -+ send_event(conn, get_watch_path(watch, watch->node), watch->token); - - return 0; - } diff --git a/xsa326-4.16-xenstored-02.patch b/xsa326-4.16-xenstored-02.patch deleted file mode 100644 index 540ab03..0000000 --- a/xsa326-4.16-xenstored-02.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0a4c86f8a8febd85610496470123adfc4fbc1c5d Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: add helpers to free struct buffered_data - -Add two helpers for freeing struct buffered_data: free_buffered_data() -for freeing one instance and conn_free_buffered_data() for freeing all -instances for a connection. - -This is avoiding duplicated code and will help later when more actions -are needed when freeing a struct buffered_data. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 249ad5ec6fb1..527a1ebdeded 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -211,6 +211,21 @@ void reopen_log(void) - } - } - -+static void free_buffered_data(struct buffered_data *out, -+ struct connection *conn) -+{ -+ list_del(&out->list); -+ talloc_free(out); -+} -+ -+void conn_free_buffered_data(struct connection *conn) -+{ -+ struct buffered_data *out; -+ -+ while ((out = list_top(&conn->out_list, struct buffered_data, list))) -+ free_buffered_data(out, conn); -+} -+ - static bool write_messages(struct connection *conn) - { - int ret; -@@ -254,8 +269,7 @@ static bool write_messages(struct connection *conn) - - trace_io(conn, out, 1); - -- list_del(&out->list); -- talloc_free(out); -+ free_buffered_data(out, conn); - - return true; - } -@@ -1506,18 +1520,12 @@ static struct { - */ - void ignore_connection(struct connection *conn) - { -- struct buffered_data *out, *tmp; -- - trace("CONN %p ignored\n", conn); - - conn->is_ignored = true; - conn_delete_all_watches(conn); - conn_delete_all_transactions(conn); -- -- list_for_each_entry_safe(out, tmp, &conn->out_list, list) { -- list_del(&out->list); -- talloc_free(out); -- } -+ conn_free_buffered_data(conn); - - talloc_free(conn->in); - conn->in = NULL; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 9af9af4390bd..e7ee87825c3b 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -276,6 +276,8 @@ int remember_string(struct hashtable *hash, const char *str); - - void set_tdb_key(const char *name, TDB_DATA *key); - -+void conn_free_buffered_data(struct connection *conn); -+ - const char *dump_state_global(FILE *fp); - const char *dump_state_buffered_data(FILE *fp, const struct connection *c, - struct xs_state_connection *sc); -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index d03c7d93a9e7..93c4c1edcdd1 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -411,15 +411,10 @@ static struct domain *find_domain_by_domid(unsigned int domid) - static void domain_conn_reset(struct domain *domain) - { - struct connection *conn = domain->conn; -- struct buffered_data *out; - - conn_delete_all_watches(conn); - conn_delete_all_transactions(conn); -- -- while ((out = list_top(&conn->out_list, struct buffered_data, list))) { -- list_del(&out->list); -- talloc_free(out); -- } -+ conn_free_buffered_data(conn); - - talloc_free(conn->in); - diff --git a/xsa326-4.16-xenstored-03.patch b/xsa326-4.16-xenstored-03.patch deleted file mode 100644 index a3a0d81..0000000 --- a/xsa326-4.16-xenstored-03.patch +++ /dev/null @@ -1,192 +0,0 @@ -From a6c4198242bf69bea1825492b7665b559023390c Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: reduce number of watch events - -When removing a watched node outside of a transaction, two watch events -are being produced instead of just a single one. - -When finalizing a transaction watch events can be generated for each -node which is being modified, even if outside a transaction such -modifications might not have resulted in a watch event. - -This happens e.g.: - -- for nodes which are only modified due to added/removed child entries -- for nodes being removed or created implicitly (e.g. creation of a/b/c - is implicitly creating a/b, resulting in watch events for a, a/b and - a/b/c instead of a/b/c only) - -Avoid these additional watch events, in order to reduce the needed -memory inside Xenstore for queueing them. - -This is being achieved by adding event flags to struct accessed_node -specifying whether an event should be triggered, and whether it should -be an exact match of the modified path. Both flags can be set from -fire_watches() instead of implying them only. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 527a1ebdeded..bf2243873901 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1295,7 +1295,7 @@ static void delete_child(struct connection *conn, - } - - static int delete_node(struct connection *conn, const void *ctx, -- struct node *parent, struct node *node) -+ struct node *parent, struct node *node, bool watch_exact) - { - char *name; - -@@ -1307,7 +1307,7 @@ static int delete_node(struct connection *conn, const void *ctx, - node->children); - child = name ? read_node(conn, node, name) : NULL; - if (child) { -- if (delete_node(conn, ctx, node, child)) -+ if (delete_node(conn, ctx, node, child, true)) - return errno; - } else { - trace("delete_node: Error deleting child '%s/%s'!\n", -@@ -1319,7 +1319,12 @@ static int delete_node(struct connection *conn, const void *ctx, - talloc_free(name); - } - -- fire_watches(conn, ctx, node->name, node, true, NULL); -+ /* -+ * Fire the watches now, when we can still see the node permissions. -+ * This fine as we are single threaded and the next possible read will -+ * be handled only after the node has been really removed. -+ */ -+ fire_watches(conn, ctx, node->name, node, watch_exact, NULL); - delete_node_single(conn, node); - delete_child(conn, parent, basename(node->name)); - talloc_free(node); -@@ -1345,13 +1350,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - return (errno == ENOMEM) ? ENOMEM : EINVAL; - node->parent = parent; - -- /* -- * Fire the watches now, when we can still see the node permissions. -- * This fine as we are single threaded and the next possible read will -- * be handled only after the node has been really removed. -- */ -- fire_watches(conn, ctx, name, node, false, NULL); -- return delete_node(conn, ctx, parent, node); -+ return delete_node(conn, ctx, parent, node, false); - } - - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index faf6c930e42a..54432907fc76 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -130,6 +130,10 @@ struct accessed_node - - /* Transaction node in data base? */ - bool ta_node; -+ -+ /* Watch event flags. */ -+ bool fire_watch; -+ bool watch_exact; - }; - - struct changed_domain -@@ -324,6 +328,29 @@ int access_node(struct connection *conn, struct node *node, - } - - /* -+ * A watch event should be fired for a node modified inside a transaction. -+ * Set the corresponding information. A non-exact event is replacing an exact -+ * one, but not the other way round. -+ */ -+void queue_watches(struct connection *conn, const char *name, bool watch_exact) -+{ -+ struct accessed_node *i; -+ -+ i = find_accessed_node(conn->transaction, name); -+ if (!i) { -+ conn->transaction->fail = true; -+ return; -+ } -+ -+ if (!i->fire_watch) { -+ i->fire_watch = true; -+ i->watch_exact = watch_exact; -+ } else if (!watch_exact) { -+ i->watch_exact = false; -+ } -+} -+ -+/* - * Finalize transaction: - * Walk through accessed nodes and check generation against global data. - * If all entries match, read the transaction entries and write them without -@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn, - ret = tdb_store(tdb_ctx, key, data, - TDB_REPLACE); - talloc_free(data.dptr); -- if (ret) -- goto err; -- fire_watches(conn, trans, i->node, NULL, false, -- i->perms.p ? &i->perms : NULL); - } else { -- fire_watches(conn, trans, i->node, NULL, false, -+ ret = tdb_delete(tdb_ctx, key); -+ } -+ if (ret) -+ goto err; -+ if (i->fire_watch) { -+ fire_watches(conn, trans, i->node, NULL, -+ i->watch_exact, - i->perms.p ? &i->perms : NULL); -- if (tdb_delete(tdb_ctx, key)) -- goto err; - } - } - -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 14062730e3c9..0093cac807e3 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid); - int access_node(struct connection *conn, struct node *node, - enum node_access_type type, TDB_DATA *key); - -+/* Queue watches for a modified node. */ -+void queue_watches(struct connection *conn, const char *name, bool watch_exact); -+ - /* Prepend the transaction to name if appropriate. */ - int transaction_prepend(struct connection *conn, const char *name, - TDB_DATA *key); -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 99a2c266b28a..205d9d8ea116 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -29,6 +29,7 @@ - #include "xenstore_lib.h" - #include "utils.h" - #include "xenstored_domain.h" -+#include "xenstored_transaction.h" - - extern int quota_nb_watch_per_domain; - -@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - struct connection *i; - struct watch *watch; - -- /* During transactions, don't fire watches. */ -- if (conn && conn->transaction) -+ /* During transactions, don't fire watches, but queue them. */ -+ if (conn && conn->transaction) { -+ queue_watches(conn, name, exact); - return; -+ } - - /* Create an event for each watch. */ - list_for_each_entry(i, &connections, list) { diff --git a/xsa326-4.16-xenstored-04.patch b/xsa326-4.16-xenstored-04.patch deleted file mode 100644 index facbba4..0000000 --- a/xsa326-4.16-xenstored-04.patch +++ /dev/null @@ -1,302 +0,0 @@ -From 2feed737530592688382c655680982e10951c1ec Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: let unread watch events time out - -A future modification will limit the number of outstanding requests -for a domain, where "outstanding" means that the response of the -request or any resulting watch event hasn't been consumed yet. - -In order to avoid a malicious guest being capable to block other guests -by not reading watch events, add a timeout for watch events. In case a -watch event hasn't been consumed after this timeout, it is being -deleted. Set the default timeout to 20 seconds (a random value being -not too high). - -In order to support to specify other timeout values in future, use a -generic command line option for that purpose: - ---timeout|-w watch-event= - -This is part of XSA-326 / CVE-2022-42311. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index bf2243873901..45244c021cd3 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -108,6 +108,8 @@ int quota_max_transaction = 10; - int quota_nb_perms_per_node = 5; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; - -+unsigned int timeout_watch_event_msec = 20000; -+ - void trace(const char *fmt, ...) - { - va_list arglist; -@@ -211,19 +213,92 @@ void reopen_log(void) - } - } - -+static uint64_t get_now_msec(void) -+{ -+ struct timespec now_ts; -+ -+ if (clock_gettime(CLOCK_MONOTONIC, &now_ts)) -+ barf_perror("Could not find time (clock_gettime failed)"); -+ -+ return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; -+} -+ - static void free_buffered_data(struct buffered_data *out, - struct connection *conn) - { -+ struct buffered_data *req; -+ - list_del(&out->list); -+ -+ /* -+ * Update conn->timeout_msec with the next found timeout value in the -+ * queued pending requests. -+ */ -+ if (out->timeout_msec) { -+ conn->timeout_msec = 0; -+ list_for_each_entry(req, &conn->out_list, list) { -+ if (req->timeout_msec) { -+ conn->timeout_msec = req->timeout_msec; -+ break; -+ } -+ } -+ } -+ - talloc_free(out); - } - -+static void check_event_timeout(struct connection *conn, uint64_t msecs, -+ int *ptimeout) -+{ -+ uint64_t delta; -+ struct buffered_data *out, *tmp; -+ -+ if (!conn->timeout_msec) -+ return; -+ -+ delta = conn->timeout_msec - msecs; -+ if (conn->timeout_msec <= msecs) { -+ delta = 0; -+ list_for_each_entry_safe(out, tmp, &conn->out_list, list) { -+ /* -+ * Only look at buffers with timeout and no data -+ * already written to the ring. -+ */ -+ if (out->timeout_msec && out->inhdr && !out->used) { -+ if (out->timeout_msec > msecs) { -+ conn->timeout_msec = out->timeout_msec; -+ delta = conn->timeout_msec - msecs; -+ break; -+ } -+ -+ /* -+ * Free out without updating conn->timeout_msec, -+ * as the update is done in this loop already. -+ */ -+ out->timeout_msec = 0; -+ trace("watch event path %s for domain %u timed out\n", -+ out->buffer, conn->id); -+ free_buffered_data(out, conn); -+ } -+ } -+ if (!delta) { -+ conn->timeout_msec = 0; -+ return; -+ } -+ } -+ -+ if (*ptimeout == -1 || *ptimeout > delta) -+ *ptimeout = delta; -+} -+ - void conn_free_buffered_data(struct connection *conn) - { - struct buffered_data *out; - - while ((out = list_top(&conn->out_list, struct buffered_data, list))) - free_buffered_data(out, conn); -+ -+ conn->timeout_msec = 0; - } - - static bool write_messages(struct connection *conn) -@@ -411,6 +486,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout) - { - struct connection *conn; - struct wrl_timestampt now; -+ uint64_t msecs; - - if (fds) - memset(fds, 0, sizeof(struct pollfd) * current_array_size); -@@ -431,10 +507,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout) - - wrl_gettime_now(&now); - wrl_log_periodic(now); -+ msecs = get_now_msec(); - - list_for_each_entry(conn, &connections, list) { - if (conn->domain) { - wrl_check_timeout(conn->domain, now, ptimeout); -+ check_event_timeout(conn, msecs, ptimeout); - if (conn_can_read(conn) || - (conn_can_write(conn) && - !list_empty(&conn->out_list))) -@@ -794,6 +872,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - return; - bdata->inhdr = true; - bdata->used = 0; -+ bdata->timeout_msec = 0; - - if (len <= DEFAULT_BUFFER_SIZE) - bdata->buffer = bdata->default_buffer; -@@ -845,6 +924,12 @@ void send_event(struct connection *conn, const char *path, const char *token) - bdata->hdr.msg.type = XS_WATCH_EVENT; - bdata->hdr.msg.len = len; - -+ if (timeout_watch_event_msec && domain_is_unprivileged(conn)) { -+ bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; -+ if (!conn->timeout_msec) -+ conn->timeout_msec = bdata->timeout_msec; -+ } -+ - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); - } -@@ -2201,6 +2286,9 @@ static void usage(void) - " -t, --transaction limit the number of transaction allowed per domain,\n" - " -A, --perm-nb limit the number of permissions per node,\n" - " -M, --path-max limit the allowed Xenstore node path length,\n" -+" -w, --timeout = set the timeout in seconds for ,\n" -+" allowed timeout candidates are:\n" -+" watch-event: time a watch-event is kept pending\n" - " -R, --no-recovery to request that no recovery should be attempted when\n" - " the store is corrupted (debug only),\n" - " -I, --internal-db store database in memory, not on disk\n" -@@ -2223,6 +2311,7 @@ static struct option options[] = { - { "transaction", 1, NULL, 't' }, - { "perm-nb", 1, NULL, 'A' }, - { "path-max", 1, NULL, 'M' }, -+ { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, - { "verbose", 0, NULL, 'V' }, -@@ -2236,6 +2325,39 @@ int dom0_domid = 0; - int dom0_event = 0; - int priv_domid = 0; - -+static int get_optval_int(const char *arg) -+{ -+ char *end; -+ long val; -+ -+ val = strtol(arg, &end, 10); -+ if (!*arg || *end || val < 0 || val > INT_MAX) -+ barf("invalid parameter value \"%s\"\n", arg); -+ -+ return val; -+} -+ -+static bool what_matches(const char *arg, const char *what) -+{ -+ unsigned int what_len = strlen(what); -+ -+ return !strncmp(arg, what, what_len) && arg[what_len] == '='; -+} -+ -+static void set_timeout(const char *arg) -+{ -+ const char *eq = strchr(arg, '='); -+ int val; -+ -+ if (!eq) -+ barf("quotas must be specified via =\n"); -+ val = get_optval_int(eq + 1); -+ if (what_matches(arg, "watch-event")) -+ timeout_watch_event_msec = val * 1000; -+ else -+ barf("unknown timeout \"%s\"\n", arg); -+} -+ - int main(int argc, char *argv[]) - { - int opt; -@@ -2250,7 +2372,7 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options, -+ while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options, - NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2300,6 +2422,9 @@ int main(int argc, char *argv[]) - quota_max_path_len = min(XENSTORE_REL_PATH_MAX, - quota_max_path_len); - break; -+ case 'w': -+ set_timeout(optarg); -+ break; - case 'e': - dom0_event = strtol(optarg, NULL, 10); - break; -@@ -2741,6 +2866,12 @@ static void add_buffered_data(struct buffered_data *bdata, - barf("error restoring buffered data"); - - memcpy(bdata->buffer, data, len); -+ if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec && -+ domain_is_unprivileged(conn)) { -+ bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; -+ if (!conn->timeout_msec) -+ conn->timeout_msec = bdata->timeout_msec; -+ } - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index e7ee87825c3b..8a81fc693f01 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - - #include "xenstore_lib.h" -@@ -67,6 +68,8 @@ struct buffered_data - char raw[sizeof(struct xsd_sockmsg)]; - } hdr; - -+ uint64_t timeout_msec; -+ - /* The actual data. */ - char *buffer; - char default_buffer[DEFAULT_BUFFER_SIZE]; -@@ -118,6 +121,7 @@ struct connection - - /* Buffered output data */ - struct list_head out_list; -+ uint64_t timeout_msec; - - /* Transaction context for current request (NULL if none). */ - struct transaction *transaction; -@@ -244,6 +248,8 @@ extern int dom0_event; - extern int priv_domid; - extern int quota_nb_entry_per_domain; - -+extern unsigned int timeout_watch_event_msec; -+ - /* Map the kernel's xenstore page. */ - void *xenbus_map(void); - void unmap_xenbus(void *interface); diff --git a/xsa326-4.16-xenstored-05.patch b/xsa326-4.16-xenstored-05.patch deleted file mode 100644 index 77f9c25..0000000 --- a/xsa326-4.16-xenstored-05.patch +++ /dev/null @@ -1,443 +0,0 @@ -From 2eee122a45eb4a218596b103ce7f0759a824cf2e Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: limit outstanding requests - -Add another quota for limiting the number of outstanding requests of a -guest. As the way to specify quotas on the command line is becoming -rather nasty, switch to a new scheme using [--quota|-Q] = -allowing to add more quotas in future easily. - -Set the default value to 20 (basically a random value not seeming to -be too high or too low). - -A request is said to be outstanding if any message generated by this -request (the direct response plus potential watch events) is not yet -completely stored into a ring buffer. The initial watch event sent as -a result of registering a watch is an exception. - -Note that across a live update the relation to buffered watch events -for other domains is lost. - -Use talloc_zero() for allocating the domain structure in order to have -all per-domain quota zeroed initially. - -This is part of XSA-326 / CVE-2022-42312. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 45244c021cd3..488d540f3a32 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */ - int quota_max_transaction = 10; - int quota_nb_perms_per_node = 5; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; -+int quota_req_outstanding = 20; - - unsigned int timeout_watch_event_msec = 20000; - -@@ -223,12 +224,24 @@ static uint64_t get_now_msec(void) - return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; - } - -+/* -+ * Remove a struct buffered_data from the list of outgoing data. -+ * A struct buffered_data related to a request having caused watch events to be -+ * sent is kept until all those events have been written out. -+ * Each watch event is referencing the related request via pend.req, while the -+ * number of watch events caused by a request is kept in pend.ref.event_cnt -+ * (those two cases are mutually exclusive, so the two fields can share memory -+ * via a union). -+ * The struct buffered_data is freed only if no related watch event is -+ * referencing it. The related return data can be freed right away. -+ */ - static void free_buffered_data(struct buffered_data *out, - struct connection *conn) - { - struct buffered_data *req; - - list_del(&out->list); -+ out->on_out_list = false; - - /* - * Update conn->timeout_msec with the next found timeout value in the -@@ -244,6 +257,30 @@ static void free_buffered_data(struct buffered_data *out, - } - } - -+ if (out->hdr.msg.type == XS_WATCH_EVENT) { -+ req = out->pend.req; -+ if (req) { -+ req->pend.ref.event_cnt--; -+ if (!req->pend.ref.event_cnt && !req->on_out_list) { -+ if (req->on_ref_list) { -+ domain_outstanding_domid_dec( -+ req->pend.ref.domid); -+ list_del(&req->list); -+ } -+ talloc_free(req); -+ } -+ } -+ } else if (out->pend.ref.event_cnt) { -+ /* Hang out off from conn. */ -+ talloc_steal(NULL, out); -+ if (out->buffer != out->default_buffer) -+ talloc_free(out->buffer); -+ list_add(&out->list, &conn->ref_list); -+ out->on_ref_list = true; -+ return; -+ } else -+ domain_outstanding_dec(conn); -+ - talloc_free(out); - } - -@@ -405,6 +442,7 @@ int delay_request(struct connection *conn, struct buffered_data *in, - static int destroy_conn(void *_conn) - { - struct connection *conn = _conn; -+ struct buffered_data *req; - - /* Flush outgoing if possible, but don't block. */ - if (!conn->domain) { -@@ -418,6 +456,11 @@ static int destroy_conn(void *_conn) - break; - close(conn->fd); - } -+ -+ conn_free_buffered_data(conn); -+ list_for_each_entry(req, &conn->ref_list, list) -+ req->on_ref_list = false; -+ - if (conn->target) - talloc_unlink(conn, conn->target); - list_del(&conn->list); -@@ -893,6 +936,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+ bdata->on_out_list = true; -+ domain_outstanding_inc(conn); - } - - /* -@@ -900,7 +945,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - * As this is not directly related to the current command, errors can't be - * reported. - */ --void send_event(struct connection *conn, const char *path, const char *token) -+void send_event(struct buffered_data *req, struct connection *conn, -+ const char *path, const char *token) - { - struct buffered_data *bdata; - unsigned int len; -@@ -930,8 +976,13 @@ void send_event(struct connection *conn, const char *path, const char *token) - conn->timeout_msec = bdata->timeout_msec; - } - -+ bdata->pend.req = req; -+ if (req) -+ req->pend.ref.event_cnt++; -+ - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+ bdata->on_out_list = true; - } - - /* Some routines (write, mkdir, etc) just need a non-error return */ -@@ -1740,6 +1791,7 @@ static void handle_input(struct connection *conn) - return; - } - in = conn->in; -+ in->pend.ref.domid = conn->id; - - /* Not finished header yet? */ - if (in->inhdr) { -@@ -1808,6 +1860,7 @@ struct connection *new_connection(const struct interface_funcs *funcs) - new->is_stalled = false; - new->transaction_started = 0; - INIT_LIST_HEAD(&new->out_list); -+ INIT_LIST_HEAD(&new->ref_list); - INIT_LIST_HEAD(&new->watches); - INIT_LIST_HEAD(&new->transaction_list); - INIT_LIST_HEAD(&new->delayed); -@@ -2286,6 +2339,9 @@ static void usage(void) - " -t, --transaction limit the number of transaction allowed per domain,\n" - " -A, --perm-nb limit the number of permissions per node,\n" - " -M, --path-max limit the allowed Xenstore node path length,\n" -+" -Q, --quota = set the quota to the value , allowed\n" -+" quotas are:\n" -+" outstanding: number of outstanding requests\n" - " -w, --timeout = set the timeout in seconds for ,\n" - " allowed timeout candidates are:\n" - " watch-event: time a watch-event is kept pending\n" -@@ -2311,6 +2367,7 @@ static struct option options[] = { - { "transaction", 1, NULL, 't' }, - { "perm-nb", 1, NULL, 'A' }, - { "path-max", 1, NULL, 'M' }, -+ { "quota", 1, NULL, 'Q' }, - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, -@@ -2358,6 +2415,20 @@ static void set_timeout(const char *arg) - barf("unknown timeout \"%s\"\n", arg); - } - -+static void set_quota(const char *arg) -+{ -+ const char *eq = strchr(arg, '='); -+ int val; -+ -+ if (!eq) -+ barf("quotas must be specified via =\n"); -+ val = get_optval_int(eq + 1); -+ if (what_matches(arg, "outstanding")) -+ quota_req_outstanding = val; -+ else -+ barf("unknown quota \"%s\"\n", arg); -+} -+ - int main(int argc, char *argv[]) - { - int opt; -@@ -2372,8 +2443,8 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options, -- NULL)) != -1) { -+ while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U", -+ options, NULL)) != -1) { - switch (opt) { - case 'D': - no_domain_init = true; -@@ -2422,6 +2493,9 @@ int main(int argc, char *argv[]) - quota_max_path_len = min(XENSTORE_REL_PATH_MAX, - quota_max_path_len); - break; -+ case 'Q': -+ set_quota(optarg); -+ break; - case 'w': - set_timeout(optarg); - break; -@@ -2875,6 +2949,14 @@ static void add_buffered_data(struct buffered_data *bdata, - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+ bdata->on_out_list = true; -+ /* -+ * Watch events are never "outstanding", but the request causing them -+ * are instead kept "outstanding" until all watch events caused by that -+ * request have been delivered. -+ */ -+ if (bdata->hdr.msg.type != XS_WATCH_EVENT) -+ domain_outstanding_inc(conn); - } - - void read_state_buffered_data(const void *ctx, struct connection *conn, -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 8a81fc693f01..db09f463a657 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -56,6 +56,8 @@ struct xs_state_connection; - struct buffered_data - { - struct list_head list; -+ bool on_out_list; -+ bool on_ref_list; - - /* Are we still doing the header? */ - bool inhdr; -@@ -63,6 +65,17 @@ struct buffered_data - /* How far are we? */ - unsigned int used; - -+ /* Outstanding request accounting. */ -+ union { -+ /* ref is being used for requests. */ -+ struct { -+ unsigned int event_cnt; /* # of outstanding events. */ -+ unsigned int domid; /* domid of request. */ -+ } ref; -+ /* req is being used for watch events. */ -+ struct buffered_data *req; /* request causing event. */ -+ } pend; -+ - union { - struct xsd_sockmsg msg; - char raw[sizeof(struct xsd_sockmsg)]; -@@ -123,6 +136,9 @@ struct connection - struct list_head out_list; - uint64_t timeout_msec; - -+ /* Referenced requests no longer pending. */ -+ struct list_head ref_list; -+ - /* Transaction context for current request (NULL if none). */ - struct transaction *transaction; - -@@ -191,7 +207,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset); - - void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - const void *data, unsigned int len); --void send_event(struct connection *conn, const char *path, const char *token); -+void send_event(struct buffered_data *req, struct connection *conn, -+ const char *path, const char *token); - - /* Some routines (write, mkdir, etc) just need a non-error return */ - void send_ack(struct connection *conn, enum xsd_sockmsg_type type); -@@ -247,6 +264,7 @@ extern int dom0_domid; - extern int dom0_event; - extern int priv_domid; - extern int quota_nb_entry_per_domain; -+extern int quota_req_outstanding; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 93c4c1edcdd1..850085a92c76 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -78,6 +78,9 @@ struct domain - /* number of watch for this domain */ - int nbwatch; - -+ /* Number of outstanding requests. */ -+ int nboutstanding; -+ - /* write rate limit */ - wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */ - struct wrl_timestampt wrl_timestamp; -@@ -183,8 +186,12 @@ static bool domain_can_read(struct connection *conn) - { - struct xenstore_domain_interface *intf = conn->domain->interface; - -- if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0) -- return false; -+ if (domain_is_unprivileged(conn)) { -+ if (conn->domain->wrl_credit < 0) -+ return false; -+ if (conn->domain->nboutstanding >= quota_req_outstanding) -+ return false; -+ } - - return (intf->req_cons != intf->req_prod); - } -@@ -331,7 +338,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid) - { - struct domain *domain; - -- domain = talloc(context, struct domain); -+ domain = talloc_zero(context, struct domain); - if (!domain) { - errno = ENOMEM; - return NULL; -@@ -392,9 +399,6 @@ static int new_domain(struct domain *domain, int port, bool restore) - domain->conn->domain = domain; - domain->conn->id = domain->domid; - -- domain->nbentry = 0; -- domain->nbwatch = 0; -- - return 0; - } - -@@ -938,6 +942,28 @@ int domain_watch(struct connection *conn) - : 0; - } - -+void domain_outstanding_inc(struct connection *conn) -+{ -+ if (!conn || !conn->domain) -+ return; -+ conn->domain->nboutstanding++; -+} -+ -+void domain_outstanding_dec(struct connection *conn) -+{ -+ if (!conn || !conn->domain) -+ return; -+ conn->domain->nboutstanding--; -+} -+ -+void domain_outstanding_domid_dec(unsigned int domid) -+{ -+ struct domain *d = find_domain_by_domid(domid); -+ -+ if (d) -+ d->nboutstanding--; -+} -+ - static wrl_creditt wrl_config_writecost = WRL_FACTOR; - static wrl_creditt wrl_config_rate = WRL_RATE * WRL_FACTOR; - static wrl_creditt wrl_config_dburst = WRL_DBURST * WRL_FACTOR; -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 1e929b8f8c6f..4f51b005291a 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -64,6 +64,9 @@ int domain_entry(struct connection *conn); - void domain_watch_inc(struct connection *conn); - void domain_watch_dec(struct connection *conn); - int domain_watch(struct connection *conn); -+void domain_outstanding_inc(struct connection *conn); -+void domain_outstanding_dec(struct connection *conn); -+void domain_outstanding_domid_dec(unsigned int domid); - - /* Special node permission handling. */ - int set_perms_special(struct connection *conn, const char *name, -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 205d9d8ea116..0755ffa375ba 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - struct node *node, bool exact, struct node_perms *perms) - { - struct connection *i; -+ struct buffered_data *req; - struct watch *watch; - - /* During transactions, don't fire watches, but queue them. */ -@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - return; - } - -+ req = domain_is_unprivileged(conn) ? conn->in : NULL; -+ - /* Create an event for each watch. */ - list_for_each_entry(i, &connections, list) { - /* introduce/release domain watches */ -@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - list_for_each_entry(watch, &i->watches, list) { - if (exact) { - if (streq(name, watch->node)) -- send_event(i, -+ send_event(req, i, - get_watch_path(watch, name), - watch->token); - } else { - if (is_child(name, watch->node)) -- send_event(i, -+ send_event(req, i, - get_watch_path(watch, name), - watch->token); - } -@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in) - trace_create(watch, "watch"); - send_ack(conn, XS_WATCH); - -- /* We fire once up front: simplifies clients and restart. */ -- send_event(conn, get_watch_path(watch, watch->node), watch->token); -+ /* -+ * We fire once up front: simplifies clients and restart. -+ * This event will not be linked to the XS_WATCH request. -+ */ -+ send_event(NULL, conn, get_watch_path(watch, watch->node), -+ watch->token); - - return 0; - } diff --git a/xsa326-4.16-xenstored-06.patch b/xsa326-4.16-xenstored-06.patch deleted file mode 100644 index b2be7ce..0000000 --- a/xsa326-4.16-xenstored-06.patch +++ /dev/null @@ -1,85 +0,0 @@ -From c8057cb483abf2cd4060b39616423e19283fbd0a Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: don't buffer multiple identical watch events - -A guest not reading its Xenstore response buffer fast enough might -pile up lots of Xenstore watch events buffered. Reduce the generated -load by dropping new events which already have an identical copy -pending. - -The special events "@..." are excluded from that handling as there are -known use cases where the handler is relying on each event to be sent -individually. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 488d540f3a32..f1fa97b8cf50 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -916,6 +916,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - bdata->inhdr = true; - bdata->used = 0; - bdata->timeout_msec = 0; -+ bdata->watch_event = false; - - if (len <= DEFAULT_BUFFER_SIZE) - bdata->buffer = bdata->default_buffer; -@@ -948,7 +949,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - void send_event(struct buffered_data *req, struct connection *conn, - const char *path, const char *token) - { -- struct buffered_data *bdata; -+ struct buffered_data *bdata, *bd; - unsigned int len; - - len = strlen(path) + 1 + strlen(token) + 1; -@@ -970,12 +971,29 @@ void send_event(struct buffered_data *req, struct connection *conn, - bdata->hdr.msg.type = XS_WATCH_EVENT; - bdata->hdr.msg.len = len; - -+ /* -+ * Check whether an identical event is pending already. -+ * Special events are excluded from that check. -+ */ -+ if (path[0] != '@') { -+ list_for_each_entry(bd, &conn->out_list, list) { -+ if (bd->watch_event && bd->hdr.msg.len == len && -+ !memcmp(bdata->buffer, bd->buffer, len)) { -+ trace("dropping duplicate watch %s %s for domain %u\n", -+ path, token, conn->id); -+ talloc_free(bdata); -+ return; -+ } -+ } -+ } -+ - if (timeout_watch_event_msec && domain_is_unprivileged(conn)) { - bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; - if (!conn->timeout_msec) - conn->timeout_msec = bdata->timeout_msec; - } - -+ bdata->watch_event = true; - bdata->pend.req = req; - if (req) - req->pend.ref.event_cnt++; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index db09f463a657..b9b50e81c7b4 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -62,6 +62,9 @@ struct buffered_data - /* Are we still doing the header? */ - bool inhdr; - -+ /* Is this a watch event? */ -+ bool watch_event; -+ - /* How far are we? */ - unsigned int used; - diff --git a/xsa326-4.16-xenstored-07.patch b/xsa326-4.16-xenstored-07.patch deleted file mode 100644 index dfcdc14..0000000 --- a/xsa326-4.16-xenstored-07.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 5eac692b841633be3e85f0125c59fa02af103989 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: fix connection->id usage - -Don't use conn->id for privilege checks, but domain_is_unprivileged(). - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c -index 7b4300ef7777..adb8d51b043b 100644 ---- a/tools/xenstore/xenstored_control.c -+++ b/tools/xenstore/xenstored_control.c -@@ -891,7 +891,7 @@ int do_control(struct connection *conn, struct buffered_data *in) - unsigned int cmd, num, off; - char **vec = NULL; - -- if (conn->id != 0) -+ if (domain_is_unprivileged(conn)) - return EACCES; - - off = get_string(in, 0); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index b9b50e81c7b4..b1a70488b989 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -123,7 +123,7 @@ struct connection - /* The index of pollfd in global pollfd array */ - int pollfd_idx; - -- /* Who am I? 0 for socket connections. */ -+ /* Who am I? Domid of connection. */ - unsigned int id; - - /* Is this connection ignored? */ -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 54432907fc76..ee1b09031a3b 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in) - if (conn->transaction) - return EBUSY; - -- if (conn->id && conn->transaction_started > quota_max_transaction) -+ if (domain_is_unprivileged(conn) && -+ conn->transaction_started > quota_max_transaction) - return ENOSPC; - - /* Attach transaction to input for autofree until it's complete */ diff --git a/xsa326-4.16-xenstored-08.patch b/xsa326-4.16-xenstored-08.patch deleted file mode 100644 index 5aa12c8..0000000 --- a/xsa326-4.16-xenstored-08.patch +++ /dev/null @@ -1,326 +0,0 @@ -From f9f3171441b5fcb3339cf612400794fc26cd2ec2 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: simplify and fix per domain node accounting - -The accounting of nodes can be simplified now that each connection -holds the associated domid. - -Fix the node accounting to cover nodes created for a domain before it -has been introduced. This requires to react properly to an allocation -failure inside domain_entry_inc() by returning an error code. - -Especially in error paths the node accounting has to be fixed in some -cases. - -This is part of XSA-326 / CVE-2022-42313. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index f1fa97b8cf50..692d863fce35 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -638,7 +638,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - - /* Permissions are struct xs_permissions. */ - node->perms.p = hdr->perms; -- if (domain_adjust_node_perms(node)) { -+ if (domain_adjust_node_perms(conn, node)) { - talloc_free(node); - return NULL; - } -@@ -660,7 +660,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - void *p; - struct xs_tdb_record_hdr *hdr; - -- if (domain_adjust_node_perms(node)) -+ if (domain_adjust_node_perms(conn, node)) - return errno; - - data.dsize = sizeof(*hdr) -@@ -1272,13 +1272,17 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - return NULL; - } - --static int destroy_node(struct connection *conn, struct node *node) -+static void destroy_node_rm(struct node *node) - { - if (streq(node->name, "/")) - corrupt(NULL, "Destroying root node!"); - - tdb_delete(tdb_ctx, node->key); -+} - -+static int destroy_node(struct connection *conn, struct node *node) -+{ -+ destroy_node_rm(node); - domain_entry_dec(conn, node); - - /* -@@ -1328,8 +1332,12 @@ static struct node *create_node(struct connection *conn, const void *ctx, - goto err; - - /* Account for new node */ -- if (i->parent) -- domain_entry_inc(conn, i); -+ if (i->parent) { -+ if (domain_entry_inc(conn, i)) { -+ destroy_node_rm(i); -+ return NULL; -+ } -+ } - } - - return node; -@@ -1614,10 +1622,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - old_perms = node->perms; - domain_entry_dec(conn, node); - node->perms = perms; -- domain_entry_inc(conn, node); -+ if (domain_entry_inc(conn, node)) { -+ node->perms = old_perms; -+ /* -+ * This should never fail because we had a reference on the -+ * domain before and Xenstored is single-threaded. -+ */ -+ domain_entry_inc(conn, node); -+ return ENOMEM; -+ } -+ -+ if (write_node(conn, node, false)) { -+ int saved_errno = errno; - -- if (write_node(conn, node, false)) -+ domain_entry_dec(conn, node); -+ node->perms = old_perms; -+ /* No failure possible as above. */ -+ domain_entry_inc(conn, node); -+ -+ errno = saved_errno; - return errno; -+ } - - fire_watches(conn, in, name, node, false, &old_perms); - send_ack(conn, XS_SET_PERMS); -@@ -3122,7 +3147,9 @@ void read_state_node(const void *ctx, const void *state) - set_tdb_key(name, &key); - if (write_node_raw(NULL, &key, node, true)) - barf("write node error restoring node"); -- domain_entry_inc(&conn, node); -+ -+ if (domain_entry_inc(&conn, node)) -+ barf("node accounting error restoring node"); - - talloc_free(node); - } -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 850085a92c76..260952e09096 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -16,6 +16,7 @@ - along with this program; If not, see . - */ - -+#include - #include - #include - #include -@@ -363,6 +364,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid) - return domain ? : alloc_domain(ctx, domid); - } - -+static struct domain *find_or_alloc_existing_domain(unsigned int domid) -+{ -+ struct domain *domain; -+ xc_dominfo_t dominfo; -+ -+ domain = find_domain_struct(domid); -+ if (!domain && get_domain_info(domid, &dominfo)) -+ domain = alloc_domain(NULL, domid); -+ -+ return domain; -+} -+ - static int new_domain(struct domain *domain, int port, bool restore) - { - int rc; -@@ -782,30 +795,28 @@ void domain_deinit(void) - xenevtchn_unbind(xce_handle, virq_port); - } - --void domain_entry_inc(struct connection *conn, struct node *node) -+int domain_entry_inc(struct connection *conn, struct node *node) - { - struct domain *d; -+ unsigned int domid; - - if (!conn) -- return; -+ return 0; - -- if (node->perms.p && node->perms.p[0].id != conn->id) { -- if (conn->transaction) { -- transaction_entry_inc(conn->transaction, -- node->perms.p[0].id); -- } else { -- d = find_domain_by_domid(node->perms.p[0].id); -- if (d) -- d->nbentry++; -- } -- } else if (conn->domain) { -- if (conn->transaction) { -- transaction_entry_inc(conn->transaction, -- conn->domain->domid); -- } else { -- conn->domain->nbentry++; -- } -+ domid = node->perms.p ? node->perms.p[0].id : conn->id; -+ -+ if (conn->transaction) { -+ transaction_entry_inc(conn->transaction, domid); -+ } else { -+ d = (domid == conn->id && conn->domain) ? conn->domain -+ : find_or_alloc_existing_domain(domid); -+ if (d) -+ d->nbentry++; -+ else -+ return ENOMEM; - } -+ -+ return 0; - } - - /* -@@ -841,7 +852,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen) - * Remove permissions for no longer existing domains in order to avoid a new - * domain with the same domid inheriting the permissions. - */ --int domain_adjust_node_perms(struct node *node) -+int domain_adjust_node_perms(struct connection *conn, struct node *node) - { - unsigned int i; - int ret; -@@ -851,8 +862,14 @@ int domain_adjust_node_perms(struct node *node) - return errno; - - /* If the owner doesn't exist any longer give it to priv domain. */ -- if (!ret) -+ if (!ret) { -+ /* -+ * In theory we'd need to update the number of dom0 nodes here, -+ * but we could be called for a read of the node. So better -+ * avoid the risk to overflow the node count of dom0. -+ */ - node->perms.p[0].id = priv_domid; -+ } - - for (i = 1; i < node->perms.num; i++) { - if (node->perms.p[i].perms & XS_PERM_IGNORE) -@@ -871,25 +888,25 @@ int domain_adjust_node_perms(struct node *node) - void domain_entry_dec(struct connection *conn, struct node *node) - { - struct domain *d; -+ unsigned int domid; - - if (!conn) - return; - -- if (node->perms.p && node->perms.p[0].id != conn->id) { -- if (conn->transaction) { -- transaction_entry_dec(conn->transaction, -- node->perms.p[0].id); -- } else { -- d = find_domain_by_domid(node->perms.p[0].id); -- if (d && d->nbentry) -- d->nbentry--; -- } -- } else if (conn->domain && conn->domain->nbentry) { -- if (conn->transaction) { -- transaction_entry_dec(conn->transaction, -- conn->domain->domid); -+ domid = node->perms.p ? node->perms.p[0].id : conn->id; -+ -+ if (conn->transaction) { -+ transaction_entry_dec(conn->transaction, domid); -+ } else { -+ d = (domid == conn->id && conn->domain) ? conn->domain -+ : find_domain_struct(domid); -+ if (d) { -+ d->nbentry--; - } else { -- conn->domain->nbentry--; -+ errno = ENOENT; -+ corrupt(conn, -+ "Node \"%s\" owned by non-existing domain %u\n", -+ node->name, domid); - } - } - } -@@ -899,13 +916,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update) - struct domain *d; - int cnt; - -- d = find_domain_by_domid(domid); -- if (!d) -- return 0; -+ if (update) { -+ d = find_domain_struct(domid); -+ assert(d); -+ } else { -+ /* -+ * We are called first with update == false in order to catch -+ * any error. So do a possible allocation and check for error -+ * only in this case, as in the case of update == true nothing -+ * can go wrong anymore as the allocation already happened. -+ */ -+ d = find_or_alloc_existing_domain(domid); -+ if (!d) -+ return -1; -+ } - - cnt = d->nbentry + num; -- if (cnt < 0) -- cnt = 0; -+ assert(cnt >= 0); - - if (update) - d->nbentry = cnt; -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 4f51b005291a..d6519904d831 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -54,10 +54,10 @@ const char *get_implicit_path(const struct connection *conn); - bool domain_is_unprivileged(struct connection *conn); - - /* Remove node permissions for no longer existing domains. */ --int domain_adjust_node_perms(struct node *node); -+int domain_adjust_node_perms(struct connection *conn, struct node *node); - - /* Quota manipulation */ --void domain_entry_inc(struct connection *conn, struct node *); -+int domain_entry_inc(struct connection *conn, struct node *); - void domain_entry_dec(struct connection *conn, struct node *); - int domain_entry_fix(unsigned int domid, int num, bool update); - int domain_entry(struct connection *conn); -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index ee1b09031a3b..86caf6c398be 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update) - - list_for_each_entry(d, &trans->changed_domains, list) { - cnt = domain_entry_fix(d->domid, d->nbentry, update); -- if (!update && cnt >= quota_nb_entry_per_domain) -- return ENOSPC; -+ if (!update) { -+ if (cnt >= quota_nb_entry_per_domain) -+ return ENOSPC; -+ if (cnt < 0) -+ return ENOMEM; -+ } - } - - return 0; diff --git a/xsa326-4.16-xenstored-09.patch b/xsa326-4.16-xenstored-09.patch deleted file mode 100644 index e2c163c..0000000 --- a/xsa326-4.16-xenstored-09.patch +++ /dev/null @@ -1,244 +0,0 @@ -From 71aac6f7e89d5c101adb9e82eea7031e16d34e46 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: limit max number of nodes accessed in a transaction - -Today a guest is free to access as many nodes in a single transaction -as it wants. This can lead to unbounded memory consumption in Xenstore -as there is the need to keep track of all nodes having been accessed -during a transaction. - -In oxenstored the number of requests in a transaction is being limited -via a quota maxrequests (default is 1024). As multiple accesses of a -node are not problematic in C Xenstore, limit the number of accessed -nodes. - -In order to let read_node() detect a quota error in case too many nodes -are being accessed, check the return value of access_node() and return -NULL in case an error has been seen. Introduce __must_check and add it -to the access_node() prototype. - -This is part of XSA-326 / CVE-2022-42314. - -Reported-by: Julien Grall -Suggested-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h -index a16e0c380709..bafc90e2f603 100644 ---- a/tools/include/xen-tools/libs.h -+++ b/tools/include/xen-tools/libs.h -@@ -63,4 +63,8 @@ - #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) - #endif - -+#ifndef __must_check -+#define __must_check __attribute__((__warn_unused_result__)) -+#endif -+ - #endif /* __XEN_TOOLS_LIBS__ */ -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 692d863fce35..f835aa1b2f1f 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128; - int quota_max_entry_size = 2048; /* 2K */ - int quota_max_transaction = 10; - int quota_nb_perms_per_node = 5; -+int quota_trans_nodes = 1024; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; - int quota_req_outstanding = 20; - -@@ -595,6 +596,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - TDB_DATA key, data; - struct xs_tdb_record_hdr *hdr; - struct node *node; -+ int err; - - node = talloc(ctx, struct node); - if (!node) { -@@ -616,14 +618,13 @@ struct node *read_node(struct connection *conn, const void *ctx, - if (data.dptr == NULL) { - if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) { - node->generation = NO_GENERATION; -- access_node(conn, node, NODE_ACCESS_READ, NULL); -- errno = ENOENT; -+ err = access_node(conn, node, NODE_ACCESS_READ, NULL); -+ errno = err ? : ENOENT; - } else { - log("TDB error on read: %s", tdb_errorstr(tdb_ctx)); - errno = EIO; - } -- talloc_free(node); -- return NULL; -+ goto error; - } - - node->parent = NULL; -@@ -638,19 +639,36 @@ struct node *read_node(struct connection *conn, const void *ctx, - - /* Permissions are struct xs_permissions. */ - node->perms.p = hdr->perms; -- if (domain_adjust_node_perms(conn, node)) { -- talloc_free(node); -- return NULL; -- } -+ if (domain_adjust_node_perms(conn, node)) -+ goto error; - - /* Data is binary blob (usually ascii, no nul). */ - node->data = node->perms.p + hdr->num_perms; - /* Children is strings, nul separated. */ - node->children = node->data + node->datalen; - -- access_node(conn, node, NODE_ACCESS_READ, NULL); -+ if (access_node(conn, node, NODE_ACCESS_READ, NULL)) -+ goto error; - - return node; -+ -+ error: -+ err = errno; -+ talloc_free(node); -+ errno = err; -+ return NULL; -+} -+ -+static bool read_node_can_propagate_errno(void) -+{ -+ /* -+ * 2 error cases for read_node() can always be propagated up: -+ * ENOMEM, because this has nothing to do with the node being in the -+ * data base or not, but is caused by a general lack of memory. -+ * ENOSPC, because this is related to hitting quota limits which need -+ * to be respected. -+ */ -+ return errno == ENOMEM || errno == ENOSPC; - } - - int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, -@@ -767,7 +785,7 @@ static int ask_parents(struct connection *conn, const void *ctx, - node = read_node(conn, ctx, name); - if (node) - break; -- if (errno == ENOMEM) -+ if (read_node_can_propagate_errno()) - return errno; - } while (!streq(name, "/")); - -@@ -829,7 +847,7 @@ static struct node *get_node(struct connection *conn, - } - } - /* Clean up errno if they weren't supposed to know. */ -- if (!node && errno != ENOMEM) -+ if (!node && !read_node_can_propagate_errno()) - errno = errno_from_parents(conn, ctx, name, errno, perm); - return node; - } -@@ -1235,7 +1253,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - - /* If parent doesn't exist, create it. */ - parent = read_node(conn, parentname, parentname); -- if (!parent) -+ if (!parent && errno == ENOENT) - parent = construct_node(conn, ctx, parentname); - if (!parent) - return NULL; -@@ -1509,7 +1527,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - - parent = read_node(conn, ctx, parentname); - if (!parent) -- return (errno == ENOMEM) ? ENOMEM : EINVAL; -+ return read_node_can_propagate_errno() ? errno : EINVAL; - node->parent = parent; - - return delete_node(conn, ctx, parent, node, false); -@@ -1539,7 +1557,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in) - return 0; - } - /* Restore errno, just in case. */ -- if (errno != ENOMEM) -+ if (!read_node_can_propagate_errno()) - errno = ENOENT; - } - return errno; -@@ -2384,6 +2402,8 @@ static void usage(void) - " -M, --path-max limit the allowed Xenstore node path length,\n" - " -Q, --quota = set the quota to the value , allowed\n" - " quotas are:\n" -+" transaction-nodes: number of accessed node per\n" -+" transaction\n" - " outstanding: number of outstanding requests\n" - " -w, --timeout = set the timeout in seconds for ,\n" - " allowed timeout candidates are:\n" -@@ -2468,6 +2488,8 @@ static void set_quota(const char *arg) - val = get_optval_int(eq + 1); - if (what_matches(arg, "outstanding")) - quota_req_outstanding = val; -+ else if (what_matches(arg, "transaction-nodes")) -+ quota_trans_nodes = val; - else - barf("unknown quota \"%s\"\n", arg); - } -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index b1a70488b989..245f9258235f 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -268,6 +268,7 @@ extern int dom0_event; - extern int priv_domid; - extern int quota_nb_entry_per_domain; - extern int quota_req_outstanding; -+extern int quota_trans_nodes; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 86caf6c398be..7bd41eb475e3 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -156,6 +156,9 @@ struct transaction - /* Connection-local identifier for this transaction. */ - uint32_t id; - -+ /* Node counter. */ -+ unsigned int nodes; -+ - /* Generation when transaction started. */ - uint64_t generation; - -@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node, - - i = find_accessed_node(trans, node->name); - if (!i) { -+ if (trans->nodes >= quota_trans_nodes && -+ domain_is_unprivileged(conn)) { -+ ret = ENOSPC; -+ goto err; -+ } - i = talloc_zero(trans, struct accessed_node); - if (!i) - goto nomem; -@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node, - i->ta_node = true; - } - } -+ trans->nodes++; - list_add_tail(&i->list, &trans->accessed); - } - -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 0093cac807e3..e3cbd6b23095 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid); - void transaction_entry_dec(struct transaction *trans, unsigned int domid); - - /* This node was accessed. */ --int access_node(struct connection *conn, struct node *node, -- enum node_access_type type, TDB_DATA *key); -+int __must_check access_node(struct connection *conn, struct node *node, -+ enum node_access_type type, TDB_DATA *key); - - /* Queue watches for a modified node. */ - void queue_watches(struct connection *conn, const char *name, bool watch_exact); diff --git a/xsa326-4.16-xenstored-10.patch b/xsa326-4.16-xenstored-10.patch deleted file mode 100644 index 30e6b50..0000000 --- a/xsa326-4.16-xenstored-10.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 90013d6a735491a7b93a6832eb2a51e5633254f5 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: move the call of setup_structure() to dom0 - introduction - -Setting up the basic structure when introducing dom0 has the advantage -to be able to add proper node memory accounting for the added nodes -later. - -This makes it possible to do proper node accounting, too. - -An additional requirement to make that work fine is to correct the -owner of the created nodes to be dom0_domid instead of domid 0. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index f835aa1b2f1f..5171d34c947e 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2039,7 +2039,8 @@ static int tdb_flags; - static void manual_node(const char *name, const char *child) - { - struct node *node; -- struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE }; -+ struct xs_permissions perms = { .id = dom0_domid, -+ .perms = XS_PERM_NONE }; - - node = talloc_zero(NULL, struct node); - if (!node) -@@ -2078,7 +2079,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...) - } - } - --static void setup_structure(bool live_update) -+void setup_structure(bool live_update) - { - char *tdbname; - -@@ -2101,6 +2102,7 @@ static void setup_structure(bool live_update) - manual_node("/", "tool"); - manual_node("/tool", "xenstored"); - manual_node("/tool/xenstored", NULL); -+ domain_entry_fix(dom0_domid, 3, true); - } - - check_store(); -@@ -2614,9 +2616,6 @@ int main(int argc, char *argv[]) - - init_pipe(reopen_log_pipe); - -- /* Setup the database */ -- setup_structure(live_update); -- - /* Listen to hypervisor. */ - if (!no_domain_init && !live_update) { - domain_init(-1); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 245f9258235f..2c77ec7ee0f4 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -231,6 +231,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - struct node *read_node(struct connection *conn, const void *ctx, - const char *name); - -+void setup_structure(bool live_update); - struct connection *new_connection(const struct interface_funcs *funcs); - struct connection *get_connection_by_id(unsigned int conn_id); - void ignore_connection(struct connection *conn); -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 260952e09096..f04b7aae8a32 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -470,6 +470,9 @@ static struct domain *introduce_domain(const void *ctx, - } - domain->interface = interface; - -+ if (is_master_domain) -+ setup_structure(restore); -+ - /* Now domain belongs to its connection. */ - talloc_steal(domain->conn, domain); - diff --git a/xsa326-4.16-xenstored-11.patch b/xsa326-4.16-xenstored-11.patch deleted file mode 100644 index 49f1497..0000000 --- a/xsa326-4.16-xenstored-11.patch +++ /dev/null @@ -1,280 +0,0 @@ -From 6af17b8bf52b9dfdc6a5ecd3efbcea9fddd57d91 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: add infrastructure to keep track of per domain memory - usage - -The amount of memory a domain can consume in Xenstore is limited by -various quota today, but even with sane quota a domain can still -consume rather large memory quantities. - -Add the infrastructure for keeping track of the amount of memory a -domain is consuming in Xenstore. Note that this is only the memory a -domain has direct control over, so any internal administration data -needed by Xenstore only is not being accounted for. - -There are two quotas defined: a soft quota which will result in a -warning issued via syslog() when it is exceeded, and a hard quota -resulting in a stop of accepting further requests or watch events as -long as the hard quota would be violated by accepting those. - -Setting any of those quotas to 0 will disable it. - -As default values use 2MB per domain for the soft limit (this basically -covers the allowed case to create 1000 nodes needing 2kB each), and -2.5MB for the hard limit. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 5171d34c947e..b2bf6740d430 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5; - int quota_trans_nodes = 1024; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; - int quota_req_outstanding = 20; -+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */ -+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */ - - unsigned int timeout_watch_event_msec = 20000; - -@@ -2406,7 +2408,14 @@ static void usage(void) - " quotas are:\n" - " transaction-nodes: number of accessed node per\n" - " transaction\n" -+" memory: total used memory per domain for nodes,\n" -+" transactions, watches and requests, above\n" -+" which Xenstore will stop talking to domain\n" - " outstanding: number of outstanding requests\n" -+" -q, --quota-soft = set a soft quota to the value ,\n" -+" causing a warning to be issued via syslog() if the\n" -+" limit is violated, allowed quotas are:\n" -+" memory: see above\n" - " -w, --timeout = set the timeout in seconds for ,\n" - " allowed timeout candidates are:\n" - " watch-event: time a watch-event is kept pending\n" -@@ -2433,6 +2442,7 @@ static struct option options[] = { - { "perm-nb", 1, NULL, 'A' }, - { "path-max", 1, NULL, 'M' }, - { "quota", 1, NULL, 'Q' }, -+ { "quota-soft", 1, NULL, 'q' }, - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, -@@ -2480,7 +2490,7 @@ static void set_timeout(const char *arg) - barf("unknown timeout \"%s\"\n", arg); - } - --static void set_quota(const char *arg) -+static void set_quota(const char *arg, bool soft) - { - const char *eq = strchr(arg, '='); - int val; -@@ -2488,11 +2498,16 @@ static void set_quota(const char *arg) - if (!eq) - barf("quotas must be specified via =\n"); - val = get_optval_int(eq + 1); -- if (what_matches(arg, "outstanding")) -+ if (what_matches(arg, "outstanding") && !soft) - quota_req_outstanding = val; -- else if (what_matches(arg, "transaction-nodes")) -+ else if (what_matches(arg, "transaction-nodes") && !soft) - quota_trans_nodes = val; -- else -+ else if (what_matches(arg, "memory")) { -+ if (soft) -+ quota_memory_per_domain_soft = val; -+ else -+ quota_memory_per_domain_hard = val; -+ } else - barf("unknown quota \"%s\"\n", arg); - } - -@@ -2510,7 +2525,7 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U", -+ while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U", - options, NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2561,7 +2576,10 @@ int main(int argc, char *argv[]) - quota_max_path_len); - break; - case 'Q': -- set_quota(optarg); -+ set_quota(optarg, false); -+ break; -+ case 'q': -+ set_quota(optarg, true); - break; - case 'w': - set_timeout(optarg); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 2c77ec7ee0f4..373af18297bf 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -270,6 +270,8 @@ extern int priv_domid; - extern int quota_nb_entry_per_domain; - extern int quota_req_outstanding; - extern int quota_trans_nodes; -+extern int quota_memory_per_domain_soft; -+extern int quota_memory_per_domain_hard; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index f04b7aae8a32..94fd561e9de4 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -76,6 +76,13 @@ struct domain - /* number of entry from this domain in the store */ - int nbentry; - -+ /* Amount of memory allocated for this domain. */ -+ int memory; -+ bool soft_quota_reported; -+ bool hard_quota_reported; -+ time_t mem_last_msg; -+#define MEM_WARN_MINTIME_SEC 10 -+ - /* number of watch for this domain */ - int nbwatch; - -@@ -192,6 +199,9 @@ static bool domain_can_read(struct connection *conn) - return false; - if (conn->domain->nboutstanding >= quota_req_outstanding) - return false; -+ if (conn->domain->memory >= quota_memory_per_domain_hard && -+ quota_memory_per_domain_hard) -+ return false; - } - - return (intf->req_cons != intf->req_prod); -@@ -950,6 +960,89 @@ int domain_entry(struct connection *conn) - : 0; - } - -+static bool domain_chk_quota(struct domain *domain, int mem) -+{ -+ time_t now; -+ -+ if (!domain || !domid_is_unprivileged(domain->domid) || -+ (domain->conn && domain->conn->is_ignored)) -+ return false; -+ -+ now = time(NULL); -+ -+ if (mem >= quota_memory_per_domain_hard && -+ quota_memory_per_domain_hard) { -+ if (domain->hard_quota_reported) -+ return true; -+ syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n", -+ domain->domid); -+ domain->mem_last_msg = now; -+ domain->hard_quota_reported = true; -+ return true; -+ } -+ -+ if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) { -+ if (domain->hard_quota_reported) { -+ domain->mem_last_msg = now; -+ domain->hard_quota_reported = false; -+ syslog(LOG_INFO, "Domain %u below hard memory quota again\n", -+ domain->domid); -+ } -+ if (mem >= quota_memory_per_domain_soft && -+ quota_memory_per_domain_soft && -+ !domain->soft_quota_reported) { -+ domain->mem_last_msg = now; -+ domain->soft_quota_reported = true; -+ syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n", -+ domain->domid); -+ } -+ if (mem < quota_memory_per_domain_soft && -+ domain->soft_quota_reported) { -+ domain->mem_last_msg = now; -+ domain->soft_quota_reported = false; -+ syslog(LOG_INFO, "Domain %u below soft memory quota again\n", -+ domain->domid); -+ } -+ -+ } -+ -+ return false; -+} -+ -+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check) -+{ -+ struct domain *domain; -+ -+ domain = find_domain_struct(domid); -+ if (domain) { -+ /* -+ * domain_chk_quota() will print warning and also store whether -+ * the soft/hard quota has been hit. So check no_quota_check -+ * *after*. -+ */ -+ if (domain_chk_quota(domain, domain->memory + mem) && -+ !no_quota_check) -+ return ENOMEM; -+ domain->memory += mem; -+ } else { -+ /* -+ * The domain the memory is to be accounted for should always -+ * exist, as accounting is done either for a domain related to -+ * the current connection, or for the domain owning a node -+ * (which is always existing, as the owner of the node is -+ * tested to exist and replaced by domid 0 if not). -+ * So not finding the related domain MUST be an error in the -+ * data base. -+ */ -+ errno = ENOENT; -+ corrupt(NULL, "Accounting called for non-existing domain %u\n", -+ domid); -+ return ENOENT; -+ } -+ -+ return 0; -+} -+ - void domain_watch_inc(struct connection *conn) - { - if (!conn || !conn->domain) -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index d6519904d831..633c9a0a0a1f 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -61,6 +61,26 @@ int domain_entry_inc(struct connection *conn, struct node *); - void domain_entry_dec(struct connection *conn, struct node *); - int domain_entry_fix(unsigned int domid, int num, bool update); - int domain_entry(struct connection *conn); -+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check); -+ -+/* -+ * domain_memory_add_chk(): to be used when memory quota should be checked. -+ * Not to be used when specifying a negative mem value, as lowering the used -+ * memory should always be allowed. -+ */ -+static inline int domain_memory_add_chk(unsigned int domid, int mem) -+{ -+ return domain_memory_add(domid, mem, false); -+} -+/* -+ * domain_memory_add_nochk(): to be used when memory quota should not be -+ * checked, e.g. when lowering memory usage, or in an error case for undoing -+ * a previous memory adjustment. -+ */ -+static inline void domain_memory_add_nochk(unsigned int domid, int mem) -+{ -+ domain_memory_add(domid, mem, true); -+} - void domain_watch_inc(struct connection *conn); - void domain_watch_dec(struct connection *conn); - int domain_watch(struct connection *conn); diff --git a/xsa326-4.16-xenstored-12.patch b/xsa326-4.16-xenstored-12.patch deleted file mode 100644 index 517f2a0..0000000 --- a/xsa326-4.16-xenstored-12.patch +++ /dev/null @@ -1,76 +0,0 @@ -From ae7042f024af7584251f776a12d9bb24d13fecaf Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: add memory accounting for responses - -Add the memory accounting for queued responses. - -In case adding a watch event for a guest is causing the hard memory -quota of that guest to be violated, the event is dropped. This will -ensure that it is impossible to drive another guest past its memory -quota by generating insane amounts of events for that guest. This is -especially important for protecting driver domains from that attack -vector. - -This is part of XSA-326 / CVE-2022-42315. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index b2bf6740d430..ecab6cfbbe15 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -260,6 +260,8 @@ static void free_buffered_data(struct buffered_data *out, - } - } - -+ domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr)); -+ - if (out->hdr.msg.type == XS_WATCH_EVENT) { - req = out->pend.req; - if (req) { -@@ -938,11 +940,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - bdata->timeout_msec = 0; - bdata->watch_event = false; - -- if (len <= DEFAULT_BUFFER_SIZE) -+ if (len <= DEFAULT_BUFFER_SIZE) { - bdata->buffer = bdata->default_buffer; -- else { -+ /* Don't check quota, path might be used for returning error. */ -+ domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr)); -+ } else { - bdata->buffer = talloc_array(bdata, char, len); -- if (!bdata->buffer) { -+ if (!bdata->buffer || -+ domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) { - send_error(conn, ENOMEM); - return; - } -@@ -1007,6 +1012,11 @@ void send_event(struct buffered_data *req, struct connection *conn, - } - } - -+ if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) { -+ talloc_free(bdata); -+ return; -+ } -+ - if (timeout_watch_event_msec && domain_is_unprivileged(conn)) { - bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; - if (!conn->timeout_msec) -@@ -3039,6 +3049,12 @@ static void add_buffered_data(struct buffered_data *bdata, - */ - if (bdata->hdr.msg.type != XS_WATCH_EVENT) - domain_outstanding_inc(conn); -+ /* -+ * We are restoring the state after Live-Update and the new quota may -+ * be smaller. So ignore it. The limit will be applied for any resource -+ * after the state has been fully restored. -+ */ -+ domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr)); - } - - void read_state_buffered_data(const void *ctx, struct connection *conn, diff --git a/xsa326-4.16-xenstored-13.patch b/xsa326-4.16-xenstored-13.patch deleted file mode 100644 index c37dd1e..0000000 --- a/xsa326-4.16-xenstored-13.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 4628ae0a56b037dcdc8a3e42c543c5b9fd9990cf Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add memory accounting for watches - -Add the memory accounting for registered watches. - -When a socket connection is destroyed, the associated watches are -removed, too. In order to keep memory accounting correct the watches -must be removed explicitly via a call of conn_delete_all_watches() from -destroy_conn(). - -This is part of XSA-326 / CVE-2022-42315. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index ecab6cfbbe15..d86942f5aa77 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -463,6 +463,7 @@ static int destroy_conn(void *_conn) - } - - conn_free_buffered_data(conn); -+ conn_delete_all_watches(conn); - list_for_each_entry(req, &conn->ref_list, list) - req->on_ref_list = false; - -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 0755ffa375ba..fdf9b2d653a0 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx, - } - - static struct watch *add_watch(struct connection *conn, char *path, char *token, -- bool relative) -+ bool relative, bool no_quota_check) - { - struct watch *watch; - -@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token, - watch->token = talloc_strdup(watch, token); - if (!watch->node || !watch->token) - goto nomem; -+ if (domain_memory_add(conn->id, strlen(path) + strlen(token), -+ no_quota_check)) -+ goto nomem; - - if (relative) - watch->relative_path = get_implicit_path(conn); -@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in) - if (domain_watch(conn) > quota_nb_watch_per_domain) - return E2BIG; - -- watch = add_watch(conn, vec[0], vec[1], relative); -+ watch = add_watch(conn, vec[0], vec[1], relative, false); - if (!watch) - return errno; - -@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in) - list_for_each_entry(watch, &conn->watches, list) { - if (streq(watch->node, node) && streq(watch->token, vec[1])) { - list_del(&watch->list); -+ domain_memory_add_nochk(conn->id, -strlen(watch->node) - -+ strlen(watch->token)); - talloc_free(watch); - domain_watch_dec(conn); - send_ack(conn, XS_UNWATCH); -@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn) - - while ((watch = list_top(&conn->watches, struct watch, list))) { - list_del(&watch->list); -+ domain_memory_add_nochk(conn->id, -strlen(watch->node) - -+ strlen(watch->token)); - talloc_free(watch); - domain_watch_dec(conn); - } -@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state) - if (!path) - barf("allocation error for read watch"); - -- if (!add_watch(conn, path, token, relative)) -+ if (!add_watch(conn, path, token, relative, true)) - barf("error adding watch"); - } - diff --git a/xsa326-4.16-xenstored-14.patch b/xsa326-4.16-xenstored-14.patch deleted file mode 100644 index df898c4..0000000 --- a/xsa326-4.16-xenstored-14.patch +++ /dev/null @@ -1,334 +0,0 @@ -From b8bd74e5e962955211ab0c5c1924ebf2bb526799 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add memory accounting for nodes - -Add the memory accounting for Xenstore nodes. In order to make this -not too complicated allow for some sloppiness when writing nodes. Any -hard quota violation will result in no further requests to be accepted. - -This is part of XSA-326 / CVE-2022-42315. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index d86942f5aa77..16504de42017 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -591,6 +591,117 @@ void set_tdb_key(const char *name, TDB_DATA *key) - key->dsize = strlen(name); - } - -+static void get_acc_data(TDB_DATA *key, struct node_account_data *acc) -+{ -+ TDB_DATA old_data; -+ struct xs_tdb_record_hdr *hdr; -+ -+ if (acc->memory < 0) { -+ old_data = tdb_fetch(tdb_ctx, *key); -+ /* No check for error, as the node might not exist. */ -+ if (old_data.dptr == NULL) { -+ acc->memory = 0; -+ } else { -+ hdr = (void *)old_data.dptr; -+ acc->memory = old_data.dsize; -+ acc->domid = hdr->perms[0].id; -+ } -+ talloc_free(old_data.dptr); -+ } -+} -+ -+/* -+ * Per-transaction nodes need to be accounted for the transaction owner. -+ * Those nodes are stored in the data base with the transaction generation -+ * count prepended (e.g. 123/local/domain/...). So testing for the node's -+ * key not to start with "/" is sufficient. -+ */ -+static unsigned int get_acc_domid(struct connection *conn, TDB_DATA *key, -+ unsigned int domid) -+{ -+ return (!conn || key->dptr[0] == '/') ? domid : conn->id; -+} -+ -+int do_tdb_write(struct connection *conn, TDB_DATA *key, TDB_DATA *data, -+ struct node_account_data *acc, bool no_quota_check) -+{ -+ struct xs_tdb_record_hdr *hdr = (void *)data->dptr; -+ struct node_account_data old_acc = {}; -+ unsigned int old_domid, new_domid; -+ int ret; -+ -+ if (!acc) -+ old_acc.memory = -1; -+ else -+ old_acc = *acc; -+ -+ get_acc_data(key, &old_acc); -+ old_domid = get_acc_domid(conn, key, old_acc.domid); -+ new_domid = get_acc_domid(conn, key, hdr->perms[0].id); -+ -+ /* -+ * Don't check for ENOENT, as we want to be able to switch orphaned -+ * nodes to new owners. -+ */ -+ if (old_acc.memory) -+ domain_memory_add_nochk(old_domid, -+ -old_acc.memory - key->dsize); -+ ret = domain_memory_add(new_domid, data->dsize + key->dsize, -+ no_quota_check); -+ if (ret) { -+ /* Error path, so no quota check. */ -+ if (old_acc.memory) -+ domain_memory_add_nochk(old_domid, -+ old_acc.memory + key->dsize); -+ return ret; -+ } -+ -+ /* TDB should set errno, but doesn't even set ecode AFAICT. */ -+ if (tdb_store(tdb_ctx, *key, *data, TDB_REPLACE) != 0) { -+ domain_memory_add_nochk(new_domid, -data->dsize - key->dsize); -+ /* Error path, so no quota check. */ -+ if (old_acc.memory) -+ domain_memory_add_nochk(old_domid, -+ old_acc.memory + key->dsize); -+ errno = EIO; -+ return errno; -+ } -+ -+ if (acc) { -+ /* Don't use new_domid, as it might be a transaction node. */ -+ acc->domid = hdr->perms[0].id; -+ acc->memory = data->dsize; -+ } -+ -+ return 0; -+} -+ -+int do_tdb_delete(struct connection *conn, TDB_DATA *key, -+ struct node_account_data *acc) -+{ -+ struct node_account_data tmp_acc; -+ unsigned int domid; -+ -+ if (!acc) { -+ acc = &tmp_acc; -+ acc->memory = -1; -+ } -+ -+ get_acc_data(key, acc); -+ -+ if (tdb_delete(tdb_ctx, *key)) { -+ errno = EIO; -+ return errno; -+ } -+ -+ if (acc->memory) { -+ domid = get_acc_domid(conn, key, acc->domid); -+ domain_memory_add_nochk(domid, -acc->memory - key->dsize); -+ } -+ -+ return 0; -+} -+ - /* - * If it fails, returns NULL and sets errno. - * Temporary memory allocations will be done with ctx. -@@ -644,9 +755,15 @@ struct node *read_node(struct connection *conn, const void *ctx, - - /* Permissions are struct xs_permissions. */ - node->perms.p = hdr->perms; -+ node->acc.domid = node->perms.p[0].id; -+ node->acc.memory = data.dsize; - if (domain_adjust_node_perms(conn, node)) - goto error; - -+ /* If owner is gone reset currently accounted memory size. */ -+ if (node->acc.domid != node->perms.p[0].id) -+ node->acc.memory = 0; -+ - /* Data is binary blob (usually ascii, no nul). */ - node->data = node->perms.p + hdr->num_perms; - /* Children is strings, nul separated. */ -@@ -715,12 +832,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - p += node->datalen; - memcpy(p, node->children, node->childlen); - -- /* TDB should set errno, but doesn't even set ecode AFAICT. */ -- if (tdb_store(tdb_ctx, *key, data, TDB_REPLACE) != 0) { -- corrupt(conn, "Write of %s failed", key->dptr); -- errno = EIO; -- return errno; -- } -+ if (do_tdb_write(conn, key, &data, &node->acc, no_quota_check)) -+ return EIO; -+ - return 0; - } - -@@ -1222,7 +1336,7 @@ static void delete_node_single(struct connection *conn, struct node *node) - if (access_node(conn, node, NODE_ACCESS_DELETE, &key)) - return; - -- if (tdb_delete(tdb_ctx, key) != 0) { -+ if (do_tdb_delete(conn, &key, &node->acc) != 0) { - corrupt(conn, "Could not delete '%s'", node->name); - return; - } -@@ -1295,6 +1409,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - /* No children, no data */ - node->children = node->data = NULL; - node->childlen = node->datalen = 0; -+ node->acc.memory = 0; - node->parent = parent; - return node; - -@@ -1303,17 +1418,17 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - return NULL; - } - --static void destroy_node_rm(struct node *node) -+static void destroy_node_rm(struct connection *conn, struct node *node) - { - if (streq(node->name, "/")) - corrupt(NULL, "Destroying root node!"); - -- tdb_delete(tdb_ctx, node->key); -+ do_tdb_delete(conn, &node->key, &node->acc); - } - - static int destroy_node(struct connection *conn, struct node *node) - { -- destroy_node_rm(node); -+ destroy_node_rm(conn, node); - domain_entry_dec(conn, node); - - /* -@@ -1365,7 +1480,7 @@ static struct node *create_node(struct connection *conn, const void *ctx, - /* Account for new node */ - if (i->parent) { - if (domain_entry_inc(conn, i)) { -- destroy_node_rm(i); -+ destroy_node_rm(conn, i); - return NULL; - } - } -@@ -2291,7 +2406,7 @@ static int clean_store_(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA val, - if (!hashtable_search(reachable, name)) { - log("clean_store: '%s' is orphaned!", name); - if (recovery) { -- tdb_delete(tdb, key); -+ do_tdb_delete(NULL, &key, NULL); - } - } - -@@ -3149,6 +3264,7 @@ void read_state_node(const void *ctx, const void *state) - if (!node) - barf("allocation error restoring node"); - -+ node->acc.memory = 0; - node->name = name; - node->generation = ++generation; - node->datalen = sn->data_len; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 373af18297bf..da9ecce67f31 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -176,6 +176,11 @@ struct node_perms { - struct xs_permissions *p; - }; - -+struct node_account_data { -+ unsigned int domid; -+ int memory; /* -1 if unknown */ -+}; -+ - struct node { - const char *name; - /* Key used to update TDB */ -@@ -198,6 +203,9 @@ struct node { - /* Children, each nul-terminated. */ - unsigned int childlen; - char *children; -+ -+ /* Allocation information for node currently in store. */ -+ struct node_account_data acc; - }; - - /* Return the only argument in the input. */ -@@ -306,6 +314,10 @@ extern xengnttab_handle **xgt_handle; - int remember_string(struct hashtable *hash, const char *str); - - void set_tdb_key(const char *name, TDB_DATA *key); -+int do_tdb_write(struct connection *conn, TDB_DATA *key, TDB_DATA *data, -+ struct node_account_data *acc, bool no_quota_check); -+int do_tdb_delete(struct connection *conn, TDB_DATA *key, -+ struct node_account_data *acc); - - void conn_free_buffered_data(struct connection *conn); - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 7bd41eb475e3..ace9a11d77bb 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -153,6 +153,9 @@ struct transaction - /* List of all transactions active on this connection. */ - struct list_head list; - -+ /* Connection this transaction is associated with. */ -+ struct connection *conn; -+ - /* Connection-local identifier for this transaction. */ - uint32_t id; - -@@ -286,6 +289,8 @@ int access_node(struct connection *conn, struct node *node, - - introduce = true; - i->ta_node = false; -+ /* acc.memory < 0 means "unknown, get size from TDB". */ -+ node->acc.memory = -1; - - /* - * Additional transaction-specific node for read type. We only -@@ -410,11 +415,11 @@ static int finalize_transaction(struct connection *conn, - goto err; - hdr = (void *)data.dptr; - hdr->generation = ++generation; -- ret = tdb_store(tdb_ctx, key, data, -- TDB_REPLACE); -+ ret = do_tdb_write(conn, &key, &data, NULL, -+ true); - talloc_free(data.dptr); - } else { -- ret = tdb_delete(tdb_ctx, key); -+ ret = do_tdb_delete(conn, &key, NULL); - } - if (ret) - goto err; -@@ -425,7 +430,7 @@ static int finalize_transaction(struct connection *conn, - } - } - -- if (i->ta_node && tdb_delete(tdb_ctx, ta_key)) -+ if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL)) - goto err; - list_del(&i->list); - talloc_free(i); -@@ -453,7 +458,7 @@ static int destroy_transaction(void *_transaction) - i->node); - if (trans_name) { - set_tdb_key(trans_name, &key); -- tdb_delete(tdb_ctx, key); -+ do_tdb_delete(trans->conn, &key, NULL); - } - } - list_del(&i->list); -@@ -497,6 +502,7 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in) - - INIT_LIST_HEAD(&trans->accessed); - INIT_LIST_HEAD(&trans->changed_domains); -+ trans->conn = conn; - trans->fail = false; - trans->generation = ++generation; - diff --git a/xsa326-4.16-xenstored-15.patch b/xsa326-4.16-xenstored-15.patch deleted file mode 100644 index 8a42a36..0000000 --- a/xsa326-4.16-xenstored-15.patch +++ /dev/null @@ -1,54 +0,0 @@ -From c55a1ea0a5ea7f6a3dc850cb015a49ba9ec571ab Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add exports for quota variables - -Some quota variables are not exported via header files. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index da9ecce67f31..bfd3fc1e9df3 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -275,6 +275,11 @@ extern TDB_CONTEXT *tdb_ctx; - extern int dom0_domid; - extern int dom0_event; - extern int priv_domid; -+extern int quota_nb_watch_per_domain; -+extern int quota_max_transaction; -+extern int quota_max_entry_size; -+extern int quota_nb_perms_per_node; -+extern int quota_max_path_len; - extern int quota_nb_entry_per_domain; - extern int quota_req_outstanding; - extern int quota_trans_nodes; -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index ace9a11d77bb..28774813de83 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -175,7 +175,6 @@ struct transaction - bool fail; - }; - --extern int quota_max_transaction; - uint64_t generation; - - static struct accessed_node *find_accessed_node(struct transaction *trans, -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index fdf9b2d653a0..85362bcce314 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -31,8 +31,6 @@ - #include "xenstored_domain.h" - #include "xenstored_transaction.h" - --extern int quota_nb_watch_per_domain; -- - struct watch - { - /* Watches on this connection */ diff --git a/xsa326-4.16-xenstored-16.patch b/xsa326-4.16-xenstored-16.patch deleted file mode 100644 index c2a8953..0000000 --- a/xsa326-4.16-xenstored-16.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 05cc2af50ba43431d6d50aff758e968833aab9c6 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add control command for setting and showing quota - -Add a xenstore-control command "quota" to: -- show current quota settings -- change quota settings -- show current quota related values of a domain - -Note that in the case the new quota is lower than existing one, -Xenstored may continue to handle requests from a domain exceeding the -new limit (depends on which one has been broken) and the amount of -resource used will not change. However the domain will not be able to -create more resource (associated to the quota) until it is back to below -the limit. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt -index 334dc8b6fdf5..a7d006519ae8 100644 ---- a/docs/misc/xenstore.txt -+++ b/docs/misc/xenstore.txt -@@ -366,6 +366,17 @@ CONTROL |[|] - print| - print to syslog (xenstore runs as daemon) or - to console (xenstore runs as stubdom) -+ quota|[set |] -+ without parameters: print the current quota settings -+ with "set ": set the quota to new value -+ (The admin should make sure all the domain usage is -+ below the quota. If it is not, then Xenstored may continue to -+ handle requests from the domain as long as the resource -+ violating the new quota setting isn't increased further) -+ with "": print quota related accounting data for -+ the domain -+ quota-soft|[set ] -+ like the "quota" command, but for soft-quota. - help - return list of supported commands for CONTROL - -diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c -index adb8d51b043b..1031a81c3874 100644 ---- a/tools/xenstore/xenstored_control.c -+++ b/tools/xenstore/xenstored_control.c -@@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn, - return 0; - } - -+struct quota { -+ const char *name; -+ int *quota; -+ const char *descr; -+}; -+ -+static const struct quota hard_quotas[] = { -+ { "nodes", "a_nb_entry_per_domain, "Nodes per domain" }, -+ { "watches", "a_nb_watch_per_domain, "Watches per domain" }, -+ { "transactions", "a_max_transaction, "Transactions per domain" }, -+ { "outstanding", "a_req_outstanding, -+ "Outstanding requests per domain" }, -+ { "transaction-nodes", "a_trans_nodes, -+ "Max. number of accessed nodes per transaction" }, -+ { "memory", "a_memory_per_domain_hard, -+ "Total Xenstore memory per domain (error level)" }, -+ { "node-size", "a_max_entry_size, "Max. size of a node" }, -+ { "path-max", "a_max_path_len, "Max. length of a node path" }, -+ { "permissions", "a_nb_perms_per_node, -+ "Max. number of permissions per node" }, -+ { NULL, NULL, NULL } -+}; -+ -+static const struct quota soft_quotas[] = { -+ { "memory", "a_memory_per_domain_soft, -+ "Total Xenstore memory per domain (warning level)" }, -+ { NULL, NULL, NULL } -+}; -+ -+static int quota_show_current(const void *ctx, struct connection *conn, -+ const struct quota *quotas) -+{ -+ char *resp; -+ unsigned int i; -+ -+ resp = talloc_strdup(ctx, "Quota settings:\n"); -+ if (!resp) -+ return ENOMEM; -+ -+ for (i = 0; quotas[i].quota; i++) { -+ resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n", -+ quotas[i].name, *quotas[i].quota, -+ quotas[i].descr); -+ if (!resp) -+ return ENOMEM; -+ } -+ -+ send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1); -+ -+ return 0; -+} -+ -+static int quota_set(const void *ctx, struct connection *conn, -+ char **vec, int num, const struct quota *quotas) -+{ -+ unsigned int i; -+ int val; -+ -+ if (num != 2) -+ return EINVAL; -+ -+ val = atoi(vec[1]); -+ if (val < 1) -+ return EINVAL; -+ -+ for (i = 0; quotas[i].quota; i++) { -+ if (!strcmp(vec[0], quotas[i].name)) { -+ *quotas[i].quota = val; -+ send_ack(conn, XS_CONTROL); -+ return 0; -+ } -+ } -+ -+ return EINVAL; -+} -+ -+static int quota_get(const void *ctx, struct connection *conn, -+ char **vec, int num) -+{ -+ if (num != 1) -+ return EINVAL; -+ -+ return domain_get_quota(ctx, conn, atoi(vec[0])); -+} -+ -+static int do_control_quota(void *ctx, struct connection *conn, -+ char **vec, int num) -+{ -+ if (num == 0) -+ return quota_show_current(ctx, conn, hard_quotas); -+ -+ if (!strcmp(vec[0], "set")) -+ return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas); -+ -+ return quota_get(ctx, conn, vec, num); -+} -+ -+static int do_control_quota_s(void *ctx, struct connection *conn, -+ char **vec, int num) -+{ -+ if (num == 0) -+ return quota_show_current(ctx, conn, soft_quotas); -+ -+ if (!strcmp(vec[0], "set")) -+ return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas); -+ -+ return EINVAL; -+} -+ - #ifdef __MINIOS__ - static int do_control_memreport(void *ctx, struct connection *conn, - char **vec, int num) -@@ -847,6 +956,8 @@ static struct cmd_s cmds[] = { - { "memreport", do_control_memreport, "[]" }, - #endif - { "print", do_control_print, "" }, -+ { "quota", do_control_quota, "[set |]" }, -+ { "quota-soft", do_control_quota_s, "[set ]" }, - { "help", do_control_help, "" }, - }; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 94fd561e9de4..e7c6886ccf47 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -31,6 +31,7 @@ - #include "xenstored_domain.h" - #include "xenstored_transaction.h" - #include "xenstored_watch.h" -+#include "xenstored_control.h" - - #include - #include -@@ -345,6 +346,38 @@ static struct domain *find_domain_struct(unsigned int domid) - return NULL; - } - -+int domain_get_quota(const void *ctx, struct connection *conn, -+ unsigned int domid) -+{ -+ struct domain *d = find_domain_struct(domid); -+ char *resp; -+ int ta; -+ -+ if (!d) -+ return ENOENT; -+ -+ ta = d->conn ? d->conn->transaction_started : 0; -+ resp = talloc_asprintf(ctx, "Domain %u:\n", domid); -+ if (!resp) -+ return ENOMEM; -+ -+#define ent(t, e) \ -+ resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \ -+ if (!resp) return ENOMEM -+ -+ ent(nodes, d->nbentry); -+ ent(watches, d->nbwatch); -+ ent(transactions, ta); -+ ent(outstanding, d->nboutstanding); -+ ent(memory, d->memory); -+ -+#undef ent -+ -+ send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1); -+ -+ return 0; -+} -+ - static struct domain *alloc_domain(const void *context, unsigned int domid) - { - struct domain *domain; -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 633c9a0a0a1f..904faa923afb 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -87,6 +87,8 @@ int domain_watch(struct connection *conn); - void domain_outstanding_inc(struct connection *conn); - void domain_outstanding_dec(struct connection *conn); - void domain_outstanding_domid_dec(unsigned int domid); -+int domain_get_quota(const void *ctx, struct connection *conn, -+ unsigned int domid); - - /* Special node permission handling. */ - int set_perms_special(struct connection *conn, const char *name, diff --git a/xsa376.patch b/xsa376.patch deleted file mode 100644 index 08e0bff..0000000 --- a/xsa376.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 02d3a57d6466363b316b60ffbba414a4a2cb90c5 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Thu, 25 Nov 2021 13:38:29 +0100 -Subject: [PATCH] SUPPORT.md: limit support statement for Linux and Windows - frontends - -Change the support state of Linux and Windows pv frontends from -"supported" to "supported with caveats" in order to reflect that the -frontends can probably be harmed by their respective backends. - -Some of the Linux frontends have been hardened already. - -This is XSA-376 - -Signed-off-by: Juergen Gross ---- - SUPPORT.md | 57 +++++++++++++++++++++++++++++++++++++++++++++--------- - 1 file changed, 48 insertions(+), 9 deletions(-) - -diff --git a/SUPPORT.md b/SUPPORT.md -index 3a34933c89..6e3e305b01 100644 ---- a/SUPPORT.md -+++ b/SUPPORT.md -@@ -411,7 +411,11 @@ Guest-side driver capable of speaking the Xen PV block protocol - Status, FreeBSD: Supported, Security support external - Status, NetBSD: Supported, Security support external - Status, OpenBSD: Supported, Security support external -- Status, Windows: Supported -+ Status, Windows: Supported, with caveats -+ -+Windows frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### Netfront - -@@ -421,20 +425,32 @@ Guest-side driver capable of speaking the Xen PV networking protocol - Status, FreeBSD: Supported, Security support external - Status, NetBSD: Supported, Security support external - Status, OpenBSD: Supported, Security support external -- Status, Windows: Supported -+ Status, Windows: Supported, with caveats -+ -+Windows frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### PV Framebuffer (frontend) - - Guest-side driver capable of speaking the Xen PV Framebuffer protocol - -- Status, Linux (xen-fbfront): Supported -+ Status, Linux (xen-fbfront): Supported, with caveats -+ -+Linux frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### PV display (frontend) - - Guest-side driver capable of speaking the Xen PV display protocol - -- Status, Linux: Supported (outside of "backend allocation" mode) -- Status, Linux: Experimental (in "backend allocation" mode) -+ Status, Linux, outside of "backend allocation" mode: Supported, with caveats -+ Status, Linux, "backend allocation" mode: Experimental -+ -+Linux frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### PV Console (frontend) - -@@ -443,7 +459,11 @@ Guest-side driver capable of speaking the Xen PV console protocol - Status, Linux (hvc_xen): Supported - Status, FreeBSD: Supported, Security support external - Status, NetBSD: Supported, Security support external -- Status, Windows: Supported -+ Status, Windows: Supported, with caveats -+ -+Windows frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### PV keyboard (frontend) - -@@ -451,11 +471,19 @@ Guest-side driver capable of speaking the Xen PV keyboard protocol. - Note that the "keyboard protocol" includes mouse / pointer / - multi-touch support as well. - -- Status, Linux (xen-kbdfront): Supported -+ Status, Linux (xen-kbdfront): Supported, with caveats -+ -+Linux frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### PV USB (frontend) - -- Status, Linux: Supported -+ Status, Linux: Supported, with caveats -+ -+Linux frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ### PV SCSI protocol (frontend) - -@@ -464,6 +492,10 @@ multi-touch support as well. - NB that while the PV SCSI frontend is in Linux and tested regularly, - there is currently no xl support. - -+Linux frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. -+ - ### PV TPM (frontend) - - Guest-side driver capable of speaking the Xen PV TPM protocol -@@ -486,7 +518,11 @@ Guest-side driver capable of making pv system calls - - Guest-side driver capable of speaking the Xen PV sound protocol - -- Status, Linux: Supported -+ Status, Linux: Supported, with caveats -+ -+Linux frontend currently trusts the backend; -+bugs in the frontend which allow backend to cause mischief will not be -+considered security vulnerabilities. - - ## Virtual device support, host side - -@@ -987,6 +1023,9 @@ are given the following labels: - - This feature is security supported - by a different organization (not the XenProject). -+ The extent of support is defined by that organization. -+ It might be limited, e.g. like described in **Supported, with caveats** -+ below. - See **External security support** below. - - * **Supported, with caveats** --- -2.26.2 - diff --git a/xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch b/xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch deleted file mode 100644 index 9aca0a7..0000000 --- a/xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch +++ /dev/null @@ -1,147 +0,0 @@ -From bd4a7db4001364fd03a80a2e73b81c46aaa44e9c Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 22 Aug 2022 01:35:09 +0000 -Subject: [PATCH 1/4] libxl, docs: Use arch-specific default paging memory - -The default paging memory (descibed in `shadow_memory` entry in xl -config) in libxl is used to determine the memory pool size for xl -guests. Currently this size is only used for x86, and contains a part -of RAM to shadow the resident processes. Since on Arm there is no -shadow mode guests, so the part of RAM to shadow the resident processes -is not necessary. Therefore, this commit splits the function -`libxl_get_required_shadow_memory()` to arch specific helpers and -renamed the helper to `libxl__arch_get_required_paging_memory()`. - -On x86, this helper calls the original value from -`libxl_get_required_shadow_memory()` so no functional change intended. - -On Arm, this helper returns 1MB per vcpu plus 4KB per MiB of RAM -for the P2M map and additional 512KB. - -Also update the xl.cfg documentation to add Arm documentation -according to code changes and correct the comment style following Xen -coding style. - -This is part of CVE-2022-33747 / XSA-409. - -Suggested-by: Julien Grall -Signed-off-by: Henry Wang -Reviewed-by: Anthony PERARD ---- - docs/man/xl.cfg.5.pod.in | 5 +++++ - tools/libs/light/libxl_arch.h | 4 ++++ - tools/libs/light/libxl_arm.c | 14 ++++++++++++++ - tools/libs/light/libxl_utils.c | 9 ++------- - tools/libs/light/libxl_x86.c | 13 +++++++++++++ - 5 files changed, 38 insertions(+), 7 deletions(-) - -diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in -index b98d1613987e..eda1e77ebd06 100644 ---- a/docs/man/xl.cfg.5.pod.in -+++ b/docs/man/xl.cfg.5.pod.in -@@ -1768,6 +1768,11 @@ are not using hardware assisted paging (i.e. you are using shadow - mode) and your guest workload consists of a very large number of - similar processes then increasing this value may improve performance. - -+On Arm, this field is used to determine the size of the guest P2M pages -+pool, and the default value is 1MB per vCPU plus 4KB per MB of RAM for -+the P2M map and additional 512KB for extended regions. Users should -+adjust this value if bigger P2M pool size is needed. -+ - =back - - =head3 Processor and Platform Features -diff --git a/tools/libs/light/libxl_arch.h b/tools/libs/light/libxl_arch.h -index 1522ecb97f72..5a060c2c3033 100644 ---- a/tools/libs/light/libxl_arch.h -+++ b/tools/libs/light/libxl_arch.h -@@ -90,6 +90,10 @@ void libxl__arch_update_domain_config(libxl__gc *gc, - libxl_domain_config *dst, - const libxl_domain_config *src); - -+_hidden -+unsigned long libxl__arch_get_required_paging_memory(unsigned long maxmem_kb, -+ unsigned int smp_cpus); -+ - #if defined(__i386__) || defined(__x86_64__) - - #define LAPIC_BASE_ADDRESS 0xfee00000 -diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c -index eef1de093914..73a95e83af24 100644 ---- a/tools/libs/light/libxl_arm.c -+++ b/tools/libs/light/libxl_arm.c -@@ -154,6 +154,20 @@ out: - return rc; - } - -+unsigned long libxl__arch_get_required_paging_memory(unsigned long maxmem_kb, -+ unsigned int smp_cpus) -+{ -+ /* -+ * 256 pages (1MB) per vcpu, -+ * plus 1 page per MiB of RAM for the P2M map, -+ * plus 1 page per MiB of extended region. This default value is 128 MiB -+ * which should be enough for domains that are not running backend. -+ * This is higher than the minimum that Xen would allocate if no value -+ * were given (but the Xen minimum is for safety, not performance). -+ */ -+ return 4 * (256 * smp_cpus + maxmem_kb / 1024 + 128); -+} -+ - static struct arch_info { - const char *guest_type; - const char *timer_compat; -diff --git a/tools/libs/light/libxl_utils.c b/tools/libs/light/libxl_utils.c -index 4699c4a0a36f..e276c0ee9cc3 100644 ---- a/tools/libs/light/libxl_utils.c -+++ b/tools/libs/light/libxl_utils.c -@@ -18,6 +18,7 @@ - #include - - #include "libxl_internal.h" -+#include "libxl_arch.h" - #include "_paths.h" - - #ifndef LIBXL_HAVE_NONCONST_LIBXL_BASENAME_RETURN_VALUE -@@ -39,13 +40,7 @@ char *libxl_basename(const char *name) - - unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus) - { -- /* 256 pages (1MB) per vcpu, -- plus 1 page per MiB of RAM for the P2M map, -- plus 1 page per MiB of RAM to shadow the resident processes. -- This is higher than the minimum that Xen would allocate if no value -- were given (but the Xen minimum is for safety, not performance). -- */ -- return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024)); -+ return libxl__arch_get_required_paging_memory(maxmem_kb, smp_cpus); - } - - char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid) -diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c -index 1feadebb1852..51362893cf98 100644 ---- a/tools/libs/light/libxl_x86.c -+++ b/tools/libs/light/libxl_x86.c -@@ -882,6 +882,19 @@ void libxl__arch_update_domain_config(libxl__gc *gc, - libxl_defbool_val(src->b_info.arch_x86.msr_relaxed)); - } - -+unsigned long libxl__arch_get_required_paging_memory(unsigned long maxmem_kb, -+ unsigned int smp_cpus) -+{ -+ /* -+ * 256 pages (1MB) per vcpu, -+ * plus 1 page per MiB of RAM for the P2M map, -+ * plus 1 page per MiB of RAM to shadow the resident processes. -+ * This is higher than the minimum that Xen would allocate if no value -+ * were given (but the Xen minimum is for safety, not performance). -+ */ -+ return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024)); -+} -+ - /* - * Local variables: - * mode: C --- -2.37.1 - diff --git a/xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch b/xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch deleted file mode 100644 index 8c03657..0000000 --- a/xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 419a4bbc20cf7c5d7d9dedae59fb8049922e6a2c Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 6 Jun 2022 06:17:28 +0000 -Subject: [PATCH 2/4] xen/arm: Construct the P2M pages pool for guests - -This commit constructs the p2m pages pool for guests from the -data structure and helper perspective. - -This is implemented by: - -- Adding a `struct paging_domain` which contains a freelist, a -counter variable and a spinlock to `struct arch_domain` to -indicate the free p2m pages and the number of p2m total pages in -the p2m pages pool. - -- Adding a helper `p2m_get_allocation` to get the p2m pool size. - -- Adding a helper `p2m_set_allocation` to set the p2m pages pool -size. This helper should be called before allocating memory for -a guest. - -- Adding a helper `p2m_teardown_allocation` to free the p2m pages -pool. This helper should be called during the xl domain destory. - -This is part of CVE-2022-33747 / XSA-409. - -Signed-off-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - xen/arch/arm/p2m.c | 88 ++++++++++++++++++++++++++++++++++++ - xen/include/asm-arm/domain.h | 10 ++++ - xen/include/asm-arm/p2m.h | 4 ++ - 3 files changed, 102 insertions(+) - -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index 3bcd1e897e88..79f3d37f5230 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -50,6 +50,92 @@ static uint64_t generate_vttbr(uint16_t vmid, mfn_t root_mfn) - return (mfn_to_maddr(root_mfn) | ((uint64_t)vmid << 48)); - } - -+/* Return the size of the pool, rounded up to the nearest MB */ -+unsigned int p2m_get_allocation(struct domain *d) -+{ -+ unsigned long nr_pages = ACCESS_ONCE(d->arch.paging.p2m_total_pages); -+ -+ return ROUNDUP(nr_pages, 1 << (20 - PAGE_SHIFT)) >> (20 - PAGE_SHIFT); -+} -+ -+/* -+ * Set the pool of pages to the required number of pages. -+ * Returns 0 for success, non-zero for failure. -+ * Call with d->arch.paging.lock held. -+ */ -+int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted) -+{ -+ struct page_info *pg; -+ -+ ASSERT(spin_is_locked(&d->arch.paging.lock)); -+ -+ for ( ; ; ) -+ { -+ if ( d->arch.paging.p2m_total_pages < pages ) -+ { -+ /* Need to allocate more memory from domheap */ -+ pg = alloc_domheap_page(NULL, 0); -+ if ( pg == NULL ) -+ { -+ printk(XENLOG_ERR "Failed to allocate P2M pages.\n"); -+ return -ENOMEM; -+ } -+ ACCESS_ONCE(d->arch.paging.p2m_total_pages) = -+ d->arch.paging.p2m_total_pages + 1; -+ page_list_add_tail(pg, &d->arch.paging.p2m_freelist); -+ } -+ else if ( d->arch.paging.p2m_total_pages > pages ) -+ { -+ /* Need to return memory to domheap */ -+ pg = page_list_remove_head(&d->arch.paging.p2m_freelist); -+ if( pg ) -+ { -+ ACCESS_ONCE(d->arch.paging.p2m_total_pages) = -+ d->arch.paging.p2m_total_pages - 1; -+ free_domheap_page(pg); -+ } -+ else -+ { -+ printk(XENLOG_ERR -+ "Failed to free P2M pages, P2M freelist is empty.\n"); -+ return -ENOMEM; -+ } -+ } -+ else -+ break; -+ -+ /* Check to see if we need to yield and try again */ -+ if ( preempted && general_preempt_check() ) -+ { -+ *preempted = true; -+ return -ERESTART; -+ } -+ } -+ -+ return 0; -+} -+ -+int p2m_teardown_allocation(struct domain *d) -+{ -+ int ret = 0; -+ bool preempted = false; -+ -+ spin_lock(&d->arch.paging.lock); -+ if ( d->arch.paging.p2m_total_pages != 0 ) -+ { -+ ret = p2m_set_allocation(d, 0, &preempted); -+ if ( preempted ) -+ { -+ spin_unlock(&d->arch.paging.lock); -+ return -ERESTART; -+ } -+ ASSERT(d->arch.paging.p2m_total_pages == 0); -+ } -+ spin_unlock(&d->arch.paging.lock); -+ -+ return ret; -+} -+ - /* Unlock the flush and do a P2M TLB flush if necessary */ - void p2m_write_unlock(struct p2m_domain *p2m) - { -@@ -1599,7 +1685,9 @@ int p2m_init(struct domain *d) - unsigned int cpu; - - rwlock_init(&p2m->lock); -+ spin_lock_init(&d->arch.paging.lock); - INIT_PAGE_LIST_HEAD(&p2m->pages); -+ INIT_PAGE_LIST_HEAD(&d->arch.paging.p2m_freelist); - - p2m->vmid = INVALID_VMID; - -diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h -index 9b3647587a04..c90daa65afa7 100644 ---- a/xen/include/asm-arm/domain.h -+++ b/xen/include/asm-arm/domain.h -@@ -40,6 +40,14 @@ struct vtimer { - uint64_t cval; - }; - -+struct paging_domain { -+ spinlock_t lock; -+ /* Free P2M pages from the pre-allocated P2M pool */ -+ struct page_list_head p2m_freelist; -+ /* Number of pages from the pre-allocated P2M pool */ -+ unsigned long p2m_total_pages; -+}; -+ - struct arch_domain - { - #ifdef CONFIG_ARM_64 -@@ -51,6 +59,8 @@ struct arch_domain - - struct hvm_domain hvm; - -+ struct paging_domain paging; -+ - struct vmmio vmmio; - - /* Continuable domain_relinquish_resources(). */ -diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h -index b3ba83283e11..c9598740bd02 100644 ---- a/xen/include/asm-arm/p2m.h -+++ b/xen/include/asm-arm/p2m.h -@@ -218,6 +218,10 @@ void p2m_restore_state(struct vcpu *n); - /* Print debugging/statistial info about a domain's p2m */ - void p2m_dump_info(struct domain *d); - -+unsigned int p2m_get_allocation(struct domain *d); -+int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted); -+int p2m_teardown_allocation(struct domain *d); -+ - static inline void p2m_write_lock(struct p2m_domain *p2m) - { - write_lock(&p2m->lock); --- -2.37.1 - diff --git a/xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch b/xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch deleted file mode 100644 index bb638e1..0000000 --- a/xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 332a9979d4dd0b047aa16db201c50fcedbd56743 Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 6 Jun 2022 06:17:29 +0000 -Subject: [PATCH 3/4] xen/arm, libxl: Implement XEN_DOMCTL_shadow_op for Arm - -This commit implements the `XEN_DOMCTL_shadow_op` support in Xen -for Arm. The p2m pages pool size for xl guests is supposed to be -determined by `XEN_DOMCTL_shadow_op`. Hence, this commit: - -- Introduces a function `p2m_domctl` and implements the subops -`XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION` and -`XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION` of `XEN_DOMCTL_shadow_op`. - -- Adds the `XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION` support in libxl. - -Therefore enabling the setting of shadow memory pool size -when creating a guest from xl and getting shadow memory pool size -from Xen. - -Note that the `XEN_DOMCTL_shadow_op` added in this commit is only -a dummy op, and the functionality of setting/getting p2m memory pool -size for xl guests will be added in following commits. - -This is part of CVE-2022-33747 / XSA-409. - -Signed-off-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - tools/libs/light/libxl_arm.c | 12 ++++++++++++ - xen/arch/arm/domctl.c | 32 ++++++++++++++++++++++++++++++++ - 2 files changed, 44 insertions(+) - -diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c -index 73a95e83af24..22a0c561bbc6 100644 ---- a/tools/libs/light/libxl_arm.c -+++ b/tools/libs/light/libxl_arm.c -@@ -131,6 +131,18 @@ int libxl__arch_domain_create(libxl__gc *gc, - libxl__domain_build_state *state, - uint32_t domid) - { -+ libxl_ctx *ctx = libxl__gc_owner(gc); -+ unsigned int shadow_mb = DIV_ROUNDUP(d_config->b_info.shadow_memkb, 1024); -+ -+ int r = xc_shadow_control(ctx->xch, domid, -+ XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, -+ &shadow_mb, 0); -+ if (r) { -+ LOGED(ERROR, domid, -+ "Failed to set %u MiB shadow allocation", shadow_mb); -+ return ERROR_FAIL; -+ } -+ - return 0; - } - -diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c -index 1baf25c3d98b..9bf72e693019 100644 ---- a/xen/arch/arm/domctl.c -+++ b/xen/arch/arm/domctl.c -@@ -47,11 +47,43 @@ static int handle_vuart_init(struct domain *d, - return rc; - } - -+static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc, -+ XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) -+{ -+ if ( unlikely(d == current->domain) ) -+ { -+ printk(XENLOG_ERR "Tried to do a p2m domctl op on itself.\n"); -+ return -EINVAL; -+ } -+ -+ if ( unlikely(d->is_dying) ) -+ { -+ printk(XENLOG_ERR "Tried to do a p2m domctl op on dying domain %u\n", -+ d->domain_id); -+ return -EINVAL; -+ } -+ -+ switch ( sc->op ) -+ { -+ case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION: -+ return 0; -+ case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION: -+ return 0; -+ default: -+ { -+ printk(XENLOG_ERR "Bad p2m domctl op %u\n", sc->op); -+ return -EINVAL; -+ } -+ } -+} -+ - long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, - XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) - { - switch ( domctl->cmd ) - { -+ case XEN_DOMCTL_shadow_op: -+ return p2m_domctl(d, &domctl->u.shadow_op, u_domctl); - case XEN_DOMCTL_cacheflush: - { - gfn_t s = _gfn(domctl->u.cacheflush.start_pfn); --- -2.37.1 - diff --git a/xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch b/xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch deleted file mode 100644 index 5366c8f..0000000 --- a/xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 39664d9ee041f96e9c7ee131ed8ef72a4d19c9f8 Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 6 Jun 2022 06:17:30 +0000 -Subject: [PATCH 4/4] xen/arm: Allocate and free P2M pages from the P2M pool - -This commit sets/tearsdown of p2m pages pool for non-privileged Arm -guests by calling `p2m_set_allocation` and `p2m_teardown_allocation`. - -- For dom0, P2M pages should come from heap directly instead of p2m -pool, so that the kernel may take advantage of the extended regions. - -- For xl guests, the setting of the p2m pool is called in -`XEN_DOMCTL_shadow_op` and the p2m pool is destroyed in -`domain_relinquish_resources`. Note that domctl->u.shadow_op.mb is -updated with the new size when setting the p2m pool. - -- For dom0less domUs, the setting of the p2m pool is called before -allocating memory during domain creation. Users can specify the p2m -pool size by `xen,domain-p2m-mem-mb` dts property. - -To actually allocate/free pages from the p2m pool, this commit adds -two helper functions namely `p2m_alloc_page` and `p2m_free_page` to -`struct p2m_domain`. By replacing the `alloc_domheap_page` and -`free_domheap_page` with these two helper functions, p2m pages can -be added/removed from the list of p2m pool rather than from the heap. - -Since page from `p2m_alloc_page` is cleaned, take the opportunity -to remove the redundant `clean_page` in `p2m_create_table`. - -This is part of CVE-2022-33747 / XSA-409. - -Signed-off-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - docs/misc/arm/device-tree/booting.txt | 8 ++++ - xen/arch/arm/domain.c | 6 +++ - xen/arch/arm/domain_build.c | 29 ++++++++++++++ - xen/arch/arm/domctl.c | 23 ++++++++++- - xen/arch/arm/p2m.c | 57 +++++++++++++++++++++++++-- - 5 files changed, 118 insertions(+), 5 deletions(-) - -diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt -index 71895663a4de..d92ccc56ffe0 100644 ---- a/docs/misc/arm/device-tree/booting.txt -+++ b/docs/misc/arm/device-tree/booting.txt -@@ -182,6 +182,14 @@ with the following properties: - Both #address-cells and #size-cells need to be specified because - both sub-nodes (described shortly) have reg properties. - -+- xen,domain-p2m-mem-mb -+ -+ Optional. A 32-bit integer specifying the amount of megabytes of RAM -+ used for the domain P2M pool. This is in-sync with the shadow_memory -+ option in xl.cfg. Leaving this field empty in device tree will lead to -+ the default size of domain P2M pool, i.e. 1MB per guest vCPU plus 4KB -+ per MB of guest RAM plus 512KB for guest extended regions. -+ - Under the "xen,domain" compatible node, one or more sub-nodes are present - for the DomU kernel and ramdisk. - -diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c -index 2694c39127c5..a818f33a1afa 100644 ---- a/xen/arch/arm/domain.c -+++ b/xen/arch/arm/domain.c -@@ -997,6 +997,7 @@ enum { - PROG_page, - PROG_mapping, - PROG_p2m, -+ PROG_p2m_pool, - PROG_done, - }; - -@@ -1062,6 +1063,11 @@ int domain_relinquish_resources(struct domain *d) - if ( ret ) - return ret; - -+ PROGRESS(p2m_pool): -+ ret = p2m_teardown_allocation(d); -+ if( ret ) -+ return ret; -+ - PROGRESS(done): - break; - -diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c -index d02bacbcd1ed..8aec3755ca5d 100644 ---- a/xen/arch/arm/domain_build.c -+++ b/xen/arch/arm/domain_build.c -@@ -2833,6 +2833,21 @@ static void __init find_gnttab_region(struct domain *d, - kinfo->gnttab_start, kinfo->gnttab_start + kinfo->gnttab_size); - } - -+static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb, -+ unsigned int smp_cpus) -+{ -+ /* -+ * Keep in sync with libxl__get_required_paging_memory(). -+ * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map, -+ * plus 128 pages to cover extended regions. -+ */ -+ unsigned long memkb = 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128); -+ -+ BUILD_BUG_ON(PAGE_SIZE != SZ_4K); -+ -+ return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); -+} -+ - static int __init construct_domain(struct domain *d, struct kernel_info *kinfo) - { - unsigned int i; -@@ -2924,6 +2939,8 @@ static int __init construct_domU(struct domain *d, - struct kernel_info kinfo = {}; - int rc; - u64 mem; -+ u32 p2m_mem_mb; -+ unsigned long p2m_pages; - - rc = dt_property_read_u64(node, "memory", &mem); - if ( !rc ) -@@ -2933,6 +2950,18 @@ static int __init construct_domU(struct domain *d, - } - kinfo.unassigned_mem = (paddr_t)mem * SZ_1K; - -+ rc = dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb); -+ /* If xen,domain-p2m-mem-mb is not specified, use the default value. */ -+ p2m_pages = rc ? -+ p2m_mem_mb << (20 - PAGE_SHIFT) : -+ domain_p2m_pages(mem, d->max_vcpus); -+ -+ spin_lock(&d->arch.paging.lock); -+ rc = p2m_set_allocation(d, p2m_pages, NULL); -+ spin_unlock(&d->arch.paging.lock); -+ if ( rc != 0 ) -+ return rc; -+ - printk("*** LOADING DOMU cpus=%u memory=%"PRIx64"KB ***\n", d->max_vcpus, mem); - - kinfo.vpl011 = dt_property_read_bool(node, "vpl011"); -diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c -index 9bf72e693019..c8fdeb124084 100644 ---- a/xen/arch/arm/domctl.c -+++ b/xen/arch/arm/domctl.c -@@ -50,6 +50,9 @@ static int handle_vuart_init(struct domain *d, - static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc, - XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) - { -+ long rc; -+ bool preempted = false; -+ - if ( unlikely(d == current->domain) ) - { - printk(XENLOG_ERR "Tried to do a p2m domctl op on itself.\n"); -@@ -66,9 +69,27 @@ static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc, - switch ( sc->op ) - { - case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION: -- return 0; -+ { -+ /* Allow and handle preemption */ -+ spin_lock(&d->arch.paging.lock); -+ rc = p2m_set_allocation(d, sc->mb << (20 - PAGE_SHIFT), &preempted); -+ spin_unlock(&d->arch.paging.lock); -+ -+ if ( preempted ) -+ /* Not finished. Set up to re-run the call. */ -+ rc = hypercall_create_continuation(__HYPERVISOR_domctl, "h", -+ u_domctl); -+ else -+ /* Finished. Return the new allocation. */ -+ sc->mb = p2m_get_allocation(d); -+ -+ return rc; -+ } - case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION: -+ { -+ sc->mb = p2m_get_allocation(d); - return 0; -+ } - default: - { - printk(XENLOG_ERR "Bad p2m domctl op %u\n", sc->op); -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index 79f3d37f5230..1bf9cbeb53cf 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -50,6 +50,54 @@ static uint64_t generate_vttbr(uint16_t vmid, mfn_t root_mfn) - return (mfn_to_maddr(root_mfn) | ((uint64_t)vmid << 48)); - } - -+static struct page_info *p2m_alloc_page(struct domain *d) -+{ -+ struct page_info *pg; -+ -+ spin_lock(&d->arch.paging.lock); -+ /* -+ * For hardware domain, there should be no limit in the number of pages that -+ * can be allocated, so that the kernel may take advantage of the extended -+ * regions. Hence, allocate p2m pages for hardware domains from heap. -+ */ -+ if ( is_hardware_domain(d) ) -+ { -+ pg = alloc_domheap_page(NULL, 0); -+ if ( pg == NULL ) -+ { -+ printk(XENLOG_G_ERR "Failed to allocate P2M pages for hwdom.\n"); -+ spin_unlock(&d->arch.paging.lock); -+ return NULL; -+ } -+ } -+ else -+ { -+ pg = page_list_remove_head(&d->arch.paging.p2m_freelist); -+ if ( unlikely(!pg) ) -+ { -+ spin_unlock(&d->arch.paging.lock); -+ return NULL; -+ } -+ d->arch.paging.p2m_total_pages--; -+ } -+ spin_unlock(&d->arch.paging.lock); -+ -+ return pg; -+} -+ -+static void p2m_free_page(struct domain *d, struct page_info *pg) -+{ -+ spin_lock(&d->arch.paging.lock); -+ if ( is_hardware_domain(d) ) -+ free_domheap_page(pg); -+ else -+ { -+ d->arch.paging.p2m_total_pages++; -+ page_list_add_tail(pg, &d->arch.paging.p2m_freelist); -+ } -+ spin_unlock(&d->arch.paging.lock); -+} -+ - /* Return the size of the pool, rounded up to the nearest MB */ - unsigned int p2m_get_allocation(struct domain *d) - { -@@ -751,7 +799,7 @@ static int p2m_create_table(struct p2m_domain *p2m, lpae_t *entry) - - ASSERT(!p2m_is_valid(*entry)); - -- page = alloc_domheap_page(NULL, 0); -+ page = p2m_alloc_page(p2m->domain); - if ( page == NULL ) - return -ENOMEM; - -@@ -878,7 +926,7 @@ static void p2m_free_entry(struct p2m_domain *p2m, - pg = mfn_to_page(mfn); - - page_list_del(pg, &p2m->pages); -- free_domheap_page(pg); -+ p2m_free_page(p2m->domain, pg); - } - - static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry, -@@ -902,7 +950,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry, - ASSERT(level < target); - ASSERT(p2m_is_superpage(*entry, level)); - -- page = alloc_domheap_page(NULL, 0); -+ page = p2m_alloc_page(p2m->domain); - if ( !page ) - return false; - -@@ -1641,7 +1689,7 @@ int p2m_teardown(struct domain *d) - - while ( (pg = page_list_remove_head(&p2m->pages)) ) - { -- free_domheap_page(pg); -+ p2m_free_page(p2m->domain, pg); - count++; - /* Arbitrarily preempt every 512 iterations */ - if ( !(count % 512) && hypercall_preempt_check() ) -@@ -1665,6 +1713,7 @@ void p2m_final_teardown(struct domain *d) - return; - - ASSERT(page_list_empty(&p2m->pages)); -+ ASSERT(page_list_empty(&d->arch.paging.p2m_freelist)); - - if ( p2m->root ) - free_domheap_pages(p2m->root, P2M_ROOT_ORDER); --- -2.37.1 - diff --git a/xsa410-4.16-01.patch b/xsa410-4.16-01.patch deleted file mode 100644 index 8f352ee..0000000 --- a/xsa410-4.16-01.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 4b4359122a414cc15156e13e3805988b71ff9da0 Mon Sep 17 00:00:00 2001 -From: Julien Grall -Date: Mon, 6 Jun 2022 06:17:25 +0000 -Subject: [PATCH 1/2] xen/arm: p2m: Prevent adding mapping when domain is dying - -During the domain destroy process, the domain will still be accessible -until it is fully destroyed. So does the P2M because we don't bail -out early if is_dying is non-zero. If a domain has permission to -modify the other domain's P2M (i.e. dom0, or a stubdomain), then -foreign mapping can be added past relinquish_p2m_mapping(). - -Therefore, we need to prevent mapping to be added when the domain -is dying. This commit prevents such adding of mapping by adding the -d->is_dying check to p2m_set_entry(). Also this commit enhances the -check in relinquish_p2m_mapping() to make sure that no mappings can -be added in the P2M after the P2M lock is released. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Julien Grall -Signed-off-by: Henry Wang -Tested-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - xen/arch/arm/p2m.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index fb71fa4c1c90..cbeff90f4371 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -1093,6 +1093,15 @@ int p2m_set_entry(struct p2m_domain *p2m, - { - int rc = 0; - -+ /* -+ * Any reference taken by the P2M mappings (e.g. foreign mapping) will -+ * be dropped in relinquish_p2m_mapping(). As the P2M will still -+ * be accessible after, we need to prevent mapping to be added when the -+ * domain is dying. -+ */ -+ if ( unlikely(p2m->domain->is_dying) ) -+ return -ENOMEM; -+ - while ( nr ) - { - unsigned long mask; -@@ -1610,6 +1619,8 @@ int relinquish_p2m_mapping(struct domain *d) - unsigned int order; - gfn_t start, end; - -+ BUG_ON(!d->is_dying); -+ /* No mappings can be added in the P2M after the P2M lock is released. */ - p2m_write_lock(p2m); - - start = p2m->lowest_mapped_gfn; --- -2.37.1 - diff --git a/xsa410-4.16-02.patch b/xsa410-4.16-02.patch deleted file mode 100644 index 7599a47..0000000 --- a/xsa410-4.16-02.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 0d5846490348fa09a0d0915d7c795685a016ce10 Mon Sep 17 00:00:00 2001 -From: Julien Grall -Date: Mon, 6 Jun 2022 06:17:26 +0000 -Subject: [PATCH 2/2] xen/arm: p2m: Handle preemption when freeing intermediate - page tables - -At the moment the P2M page tables will be freed when the domain structure -is freed without any preemption. As the P2M is quite large, iterating -through this may take more time than it is reasonable without intermediate -preemption (to run softirqs and perhaps scheduler). - -Split p2m_teardown() in two parts: one preemptible and called when -relinquishing the resources, the other one non-preemptible and called -when freeing the domain structure. - -As we are now freeing the P2M pages early, we also need to prevent -further allocation if someone call p2m_set_entry() past p2m_teardown() -(I wasn't able to prove this will never happen). This is done by -the checking domain->is_dying from previous patch in p2m_set_entry(). - -Similarly, we want to make sure that no-one can accessed the free -pages. Therefore the root is cleared before freeing pages. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Julien Grall -Signed-off-by: Henry Wang -Tested-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - xen/arch/arm/domain.c | 10 +++++++-- - xen/arch/arm/p2m.c | 47 ++++++++++++++++++++++++++++++++++++--- - xen/include/asm-arm/p2m.h | 13 +++++++++-- - 3 files changed, 63 insertions(+), 7 deletions(-) - -diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c -index 96e1b235501d..2694c39127c5 100644 ---- a/xen/arch/arm/domain.c -+++ b/xen/arch/arm/domain.c -@@ -789,10 +789,10 @@ fail: - void arch_domain_destroy(struct domain *d) - { - /* IOMMU page table is shared with P2M, always call -- * iommu_domain_destroy() before p2m_teardown(). -+ * iommu_domain_destroy() before p2m_final_teardown(). - */ - iommu_domain_destroy(d); -- p2m_teardown(d); -+ p2m_final_teardown(d); - domain_vgic_free(d); - domain_vuart_free(d); - free_xenheap_page(d->shared_info); -@@ -996,6 +996,7 @@ enum { - PROG_xen, - PROG_page, - PROG_mapping, -+ PROG_p2m, - PROG_done, - }; - -@@ -1056,6 +1057,11 @@ int domain_relinquish_resources(struct domain *d) - if ( ret ) - return ret; - -+ PROGRESS(p2m): -+ ret = p2m_teardown(d); -+ if ( ret ) -+ return ret; -+ - PROGRESS(done): - break; - -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index cbeff90f4371..3bcd1e897e88 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -1527,17 +1527,58 @@ static void p2m_free_vmid(struct domain *d) - spin_unlock(&vmid_alloc_lock); - } - --void p2m_teardown(struct domain *d) -+int p2m_teardown(struct domain *d) - { - struct p2m_domain *p2m = p2m_get_hostp2m(d); -+ unsigned long count = 0; - struct page_info *pg; -+ unsigned int i; -+ int rc = 0; -+ -+ p2m_write_lock(p2m); -+ -+ /* -+ * We are about to free the intermediate page-tables, so clear the -+ * root to prevent any walk to use them. -+ */ -+ for ( i = 0; i < P2M_ROOT_PAGES; i++ ) -+ clear_and_clean_page(p2m->root + i); -+ -+ /* -+ * The domain will not be scheduled anymore, so in theory we should -+ * not need to flush the TLBs. Do it for safety purpose. -+ * -+ * Note that all the devices have already been de-assigned. So we don't -+ * need to flush the IOMMU TLB here. -+ */ -+ p2m_force_tlb_flush_sync(p2m); -+ -+ while ( (pg = page_list_remove_head(&p2m->pages)) ) -+ { -+ free_domheap_page(pg); -+ count++; -+ /* Arbitrarily preempt every 512 iterations */ -+ if ( !(count % 512) && hypercall_preempt_check() ) -+ { -+ rc = -ERESTART; -+ break; -+ } -+ } -+ -+ p2m_write_unlock(p2m); -+ -+ return rc; -+} -+ -+void p2m_final_teardown(struct domain *d) -+{ -+ struct p2m_domain *p2m = p2m_get_hostp2m(d); - - /* p2m not actually initialized */ - if ( !p2m->domain ) - return; - -- while ( (pg = page_list_remove_head(&p2m->pages)) ) -- free_domheap_page(pg); -+ ASSERT(page_list_empty(&p2m->pages)); - - if ( p2m->root ) - free_domheap_pages(p2m->root, P2M_ROOT_ORDER); -diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h -index 8f11d9c97b5d..b3ba83283e11 100644 ---- a/xen/include/asm-arm/p2m.h -+++ b/xen/include/asm-arm/p2m.h -@@ -192,8 +192,17 @@ void setup_virt_paging(void); - /* Init the datastructures for later use by the p2m code */ - int p2m_init(struct domain *d); - --/* Return all the p2m resources to Xen. */ --void p2m_teardown(struct domain *d); -+/* -+ * The P2M resources are freed in two parts: -+ * - p2m_teardown() will be called when relinquish the resources. It -+ * will free large resources (e.g. intermediate page-tables) that -+ * requires preemption. -+ * - p2m_final_teardown() will be called when domain struct is been -+ * freed. This *cannot* be preempted and therefore one small -+ * resources should be freed here. -+ */ -+int p2m_teardown(struct domain *d); -+void p2m_final_teardown(struct domain *d); - - /* - * Remove mapping refcount on each mapping page in the p2m --- -2.37.1 - diff --git a/xsa410-4.16-03.patch b/xsa410-4.16-03.patch deleted file mode 100644 index 7411d90..0000000 --- a/xsa410-4.16-03.patch +++ /dev/null @@ -1,113 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: add option to skip root pagetable removal in p2m_teardown() - -Add a new parameter to p2m_teardown() in order to select whether the -root page table should also be freed. Note that all users are -adjusted to pass the parameter to remove the root page tables, so -behavior is not modified. - -No functional change intended. - -This is part of CVE-2022-33746 / XSA-410. - -Suggested-by: Julien Grall -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/include/asm-x86/p2m.h -+++ b/xen/include/asm-x86/p2m.h -@@ -574,7 +574,7 @@ int p2m_init(struct domain *d); - int p2m_alloc_table(struct p2m_domain *p2m); - - /* Return all the p2m resources to Xen. */ --void p2m_teardown(struct p2m_domain *p2m); -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root); - void p2m_final_teardown(struct domain *d); - - /* Add a page to a domain's p2m table */ ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -541,18 +541,18 @@ void hap_final_teardown(struct domain *d - } - - for ( i = 0; i < MAX_ALTP2M; i++ ) -- p2m_teardown(d->arch.altp2m_p2m[i]); -+ p2m_teardown(d->arch.altp2m_p2m[i], true); - } - - /* Destroy nestedp2m's first */ - for (i = 0; i < MAX_NESTEDP2M; i++) { -- p2m_teardown(d->arch.nested_p2m[i]); -+ p2m_teardown(d->arch.nested_p2m[i], true); - } - - if ( d->arch.paging.hap.total_pages != 0 ) - hap_teardown(d, NULL); - -- p2m_teardown(p2m_get_hostp2m(d)); -+ p2m_teardown(p2m_get_hostp2m(d), true); - /* Free any memory that the p2m teardown released */ - paging_lock(d); - hap_set_allocation(d, 0, NULL); ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -749,11 +749,11 @@ int p2m_alloc_table(struct p2m_domain *p - * hvm fixme: when adding support for pvh non-hardware domains, this path must - * cleanup any foreign p2m types (release refcnts on them). - */ --void p2m_teardown(struct p2m_domain *p2m) -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root) - /* Return all the p2m pages to Xen. - * We know we don't have any extra mappings to these pages */ - { -- struct page_info *pg; -+ struct page_info *pg, *root_pg = NULL; - struct domain *d; - - if (p2m == NULL) -@@ -763,10 +763,22 @@ void p2m_teardown(struct p2m_domain *p2m - - p2m_lock(p2m); - ASSERT(atomic_read(&d->shr_pages) == 0); -- p2m->phys_table = pagetable_null(); -+ -+ if ( remove_root ) -+ p2m->phys_table = pagetable_null(); -+ else if ( !pagetable_is_null(p2m->phys_table) ) -+ { -+ root_pg = pagetable_get_page(p2m->phys_table); -+ clear_domain_page(pagetable_get_mfn(p2m->phys_table)); -+ } - - while ( (pg = page_list_remove_head(&p2m->pages)) ) -- d->arch.paging.free_page(d, pg); -+ if ( pg != root_pg ) -+ d->arch.paging.free_page(d, pg); -+ -+ if ( root_pg ) -+ page_list_add(root_pg, &p2m->pages); -+ - p2m_unlock(p2m); - } - ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2701,7 +2701,7 @@ int shadow_enable(struct domain *d, u32 - paging_unlock(d); - out_unlocked: - if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) ) -- p2m_teardown(p2m); -+ p2m_teardown(p2m, true); - if ( rv != 0 && pg != NULL ) - { - pg->count_info &= ~PGC_count_mask; -@@ -2866,7 +2866,7 @@ void shadow_final_teardown(struct domain - shadow_teardown(d, NULL); - - /* It is now safe to pull down the p2m map. */ -- p2m_teardown(p2m_get_hostp2m(d)); -+ p2m_teardown(p2m_get_hostp2m(d), true); - /* Free any shadow memory that the p2m teardown released */ - paging_lock(d); - shadow_set_allocation(d, 0, NULL); diff --git a/xsa410-4.16-04.patch b/xsa410-4.16-04.patch deleted file mode 100644 index 2170b8e..0000000 --- a/xsa410-4.16-04.patch +++ /dev/null @@ -1,62 +0,0 @@ -From: Jan Beulich -Subject: x86/HAP: adjust monitor table related error handling - -hap_make_monitor_table() will return INVALID_MFN if it encounters an -error condition, but hap_update_paging_modes() wasn’t handling this -value, resulting in an inappropriate value being stored in -monitor_table. This would subsequently misguide at least -hap_vcpu_teardown(). Avoid this by bailing early. - -Further, when a domain has/was already crashed or (perhaps less -important as there's no such path known to lead here) is already dying, -avoid calling domain_crash() on it again - that's at best confusing. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Jan Beulich -Reviewed-by: Roger Pau Monné - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - - #include "private.h" - -@@ -405,8 +406,13 @@ static mfn_t hap_make_monitor_table(stru - return m4mfn; - - oom: -- printk(XENLOG_G_ERR "out of memory building monitor pagetable\n"); -- domain_crash(d); -+ if ( !d->is_dying && -+ (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) -+ { -+ printk(XENLOG_G_ERR "%pd: out of memory building monitor pagetable\n", -+ d); -+ domain_crash(d); -+ } - return INVALID_MFN; - } - -@@ -766,6 +772,9 @@ static void hap_update_paging_modes(stru - if ( pagetable_is_null(v->arch.hvm.monitor_table) ) - { - mfn_t mmfn = hap_make_monitor_table(v); -+ -+ if ( mfn_eq(mmfn, INVALID_MFN) ) -+ goto unlock; - v->arch.hvm.monitor_table = pagetable_from_mfn(mmfn); - make_cr3(v, mmfn); - hvm_update_host_cr3(v); -@@ -774,6 +783,7 @@ static void hap_update_paging_modes(stru - /* CR3 is effectively updated by a mode change. Flush ASIDs, etc. */ - hap_update_cr3(v, 0, false); - -+ unlock: - paging_unlock(d); - put_gfn(d, cr3_gfn); - } diff --git a/xsa410-4.16-05.patch b/xsa410-4.16-05.patch deleted file mode 100644 index dc626c7..0000000 --- a/xsa410-4.16-05.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: tolerate failure of sh_set_toplevel_shadow() - -Subsequently sh_set_toplevel_shadow() will be adjusted to install a -blank entry in case prealloc fails. There are, in fact, pre-existing -error paths which would put in place a blank entry. The 4- and 2-level -code in sh_update_cr3(), however, assume the top level entry to be -valid. - -Hence bail from the function in the unlikely event that it's not. Note -that 3-level logic works differently: In particular a guest is free to -supply a PDPTR pointing at 4 non-present (or otherwise deemed invalid) -entries. The guest will crash, but we already cope with that. - -Really mfn_valid() is likely wrong to use in sh_set_toplevel_shadow(), -and it should instead be !mfn_eq(gmfn, INVALID_MFN). Avoid such a change -in security context, but add a respective assertion. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2516,6 +2516,7 @@ void sh_set_toplevel_shadow(struct vcpu - /* Now figure out the new contents: is this a valid guest MFN? */ - if ( !mfn_valid(gmfn) ) - { -+ ASSERT(mfn_eq(gmfn, INVALID_MFN)); - new_entry = pagetable_null(); - goto install_new_entry; - } ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -3312,6 +3312,11 @@ sh_update_cr3(struct vcpu *v, int do_loc - if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 ) - guest_flush_tlb_mask(d, d->dirty_cpumask); - sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, sh_make_shadow); -+ if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) -+ { -+ ASSERT(d->is_dying || d->is_shutting_down); -+ return; -+ } - if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) ) - { - mfn_t smfn = pagetable_get_mfn(v->arch.paging.shadow.shadow_table[0]); -@@ -3370,6 +3375,11 @@ sh_update_cr3(struct vcpu *v, int do_loc - if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 ) - guest_flush_tlb_mask(d, d->dirty_cpumask); - sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, sh_make_shadow); -+ if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) -+ { -+ ASSERT(d->is_dying || d->is_shutting_down); -+ return; -+ } - #else - #error This should never happen - #endif diff --git a/xsa410-4.16-06.patch b/xsa410-4.16-06.patch deleted file mode 100644 index 8c89eb3..0000000 --- a/xsa410-4.16-06.patch +++ /dev/null @@ -1,255 +0,0 @@ -From: Roger Pau Monné -Subject: x86/shadow: tolerate failure in shadow_prealloc() - -Prevent _shadow_prealloc() from calling BUG() when unable to fulfill -the pre-allocation and instead return true/false. Modify -shadow_prealloc() to crash the domain on allocation failure (if the -domain is not already dying), as shadow cannot operate normally after -that. Modify callers to also gracefully handle {_,}shadow_prealloc() -failing to fulfill the request. - -Note this in turn requires adjusting the callers of -sh_make_monitor_table() also to handle it returning INVALID_MFN. -sh_update_paging_modes() is also modified to add additional error -paths in case of allocation failure, some of those will return with -null monitor page tables (and the domain likely crashed). This is no -different that current error paths, but the newly introduced ones are -more likely to trigger. - -The now added failure points in sh_update_paging_modes() also require -that on some error return paths the previous structures are cleared, -and thus monitor table is null. - -While there adjust the 'type' parameter type of shadow_prealloc() to -unsigned int rather than u32. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - #include "private.h" - - DEFINE_PER_CPU(uint32_t,trace_shadow_path_flags); -@@ -928,14 +929,15 @@ static inline void trace_shadow_prealloc - - /* Make sure there are at least count order-sized pages - * available in the shadow page pool. */ --static void _shadow_prealloc(struct domain *d, unsigned int pages) -+static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages) - { - struct vcpu *v; - struct page_info *sp, *t; - mfn_t smfn; - int i; - -- if ( d->arch.paging.shadow.free_pages >= pages ) return; -+ if ( d->arch.paging.shadow.free_pages >= pages ) -+ return true; - - /* Shouldn't have enabled shadows if we've no vcpus. */ - ASSERT(d->vcpu && d->vcpu[0]); -@@ -951,7 +953,8 @@ static void _shadow_prealloc(struct doma - sh_unpin(d, smfn); - - /* See if that freed up enough space */ -- if ( d->arch.paging.shadow.free_pages >= pages ) return; -+ if ( d->arch.paging.shadow.free_pages >= pages ) -+ return true; - } - - /* Stage two: all shadow pages are in use in hierarchies that are -@@ -974,7 +977,7 @@ static void _shadow_prealloc(struct doma - if ( d->arch.paging.shadow.free_pages >= pages ) - { - guest_flush_tlb_mask(d, d->dirty_cpumask); -- return; -+ return true; - } - } - } -@@ -987,7 +990,12 @@ static void _shadow_prealloc(struct doma - d->arch.paging.shadow.total_pages, - d->arch.paging.shadow.free_pages, - d->arch.paging.shadow.p2m_pages); -- BUG(); -+ -+ ASSERT(d->is_dying); -+ -+ guest_flush_tlb_mask(d, d->dirty_cpumask); -+ -+ return false; - } - - /* Make sure there are at least count pages of the order according to -@@ -995,9 +1003,19 @@ static void _shadow_prealloc(struct doma - * This must be called before any calls to shadow_alloc(). Since this - * will free existing shadows to make room, it must be called early enough - * to avoid freeing shadows that the caller is currently working on. */ --void shadow_prealloc(struct domain *d, u32 type, unsigned int count) -+bool shadow_prealloc(struct domain *d, unsigned int type, unsigned int count) - { -- return _shadow_prealloc(d, shadow_size(type) * count); -+ bool ret = _shadow_prealloc(d, shadow_size(type) * count); -+ -+ if ( !ret && !d->is_dying && -+ (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) -+ /* -+ * Failing to allocate memory required for shadow usage can only result in -+ * a domain crash, do it here rather that relying on every caller to do it. -+ */ -+ domain_crash(d); -+ -+ return ret; - } - - /* Deliberately free all the memory we can: this will tear down all of -@@ -1218,7 +1236,7 @@ void shadow_free(struct domain *d, mfn_t - static struct page_info * - shadow_alloc_p2m_page(struct domain *d) - { -- struct page_info *pg; -+ struct page_info *pg = NULL; - - /* This is called both from the p2m code (which never holds the - * paging lock) and the log-dirty code (which always does). */ -@@ -1236,16 +1254,18 @@ shadow_alloc_p2m_page(struct domain *d) - d->arch.paging.shadow.p2m_pages, - shadow_min_acceptable_pages(d)); - } -- paging_unlock(d); -- return NULL; -+ goto out; - } - -- shadow_prealloc(d, SH_type_p2m_table, 1); -+ if ( !shadow_prealloc(d, SH_type_p2m_table, 1) ) -+ goto out; -+ - pg = mfn_to_page(shadow_alloc(d, SH_type_p2m_table, 0)); - d->arch.paging.shadow.p2m_pages++; - d->arch.paging.shadow.total_pages--; - ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask)); - -+ out: - paging_unlock(d); - - return pg; -@@ -1336,7 +1356,9 @@ int shadow_set_allocation(struct domain - else if ( d->arch.paging.shadow.total_pages > pages ) - { - /* Need to return memory to domheap */ -- _shadow_prealloc(d, 1); -+ if ( !_shadow_prealloc(d, 1) ) -+ return -ENOMEM; -+ - sp = page_list_remove_head(&d->arch.paging.shadow.freelist); - ASSERT(sp); - /* -@@ -2334,12 +2356,13 @@ static void sh_update_paging_modes(struc - if ( mfn_eq(v->arch.paging.shadow.oos_snapshot[0], INVALID_MFN) ) - { - int i; -+ -+ if ( !shadow_prealloc(d, SH_type_oos_snapshot, SHADOW_OOS_PAGES) ) -+ return; -+ - for(i = 0; i < SHADOW_OOS_PAGES; i++) -- { -- shadow_prealloc(d, SH_type_oos_snapshot, 1); - v->arch.paging.shadow.oos_snapshot[i] = - shadow_alloc(d, SH_type_oos_snapshot, 0); -- } - } - #endif /* OOS */ - -@@ -2403,6 +2426,9 @@ static void sh_update_paging_modes(struc - mfn_t mmfn = sh_make_monitor_table( - v, v->arch.paging.mode->shadow.shadow_levels); - -+ if ( mfn_eq(mmfn, INVALID_MFN) ) -+ return; -+ - v->arch.hvm.monitor_table = pagetable_from_mfn(mmfn); - make_cr3(v, mmfn); - hvm_update_host_cr3(v); -@@ -2441,6 +2467,12 @@ static void sh_update_paging_modes(struc - v->arch.hvm.monitor_table = pagetable_null(); - new_mfn = sh_make_monitor_table( - v, v->arch.paging.mode->shadow.shadow_levels); -+ if ( mfn_eq(new_mfn, INVALID_MFN) ) -+ { -+ sh_destroy_monitor_table(v, old_mfn, -+ old_mode->shadow.shadow_levels); -+ return; -+ } - v->arch.hvm.monitor_table = pagetable_from_mfn(new_mfn); - SHADOW_PRINTK("new monitor table %"PRI_mfn "\n", - mfn_x(new_mfn)); -@@ -2526,7 +2558,12 @@ void sh_set_toplevel_shadow(struct vcpu - if ( !mfn_valid(smfn) ) - { - /* Make sure there's enough free shadow memory. */ -- shadow_prealloc(d, root_type, 1); -+ if ( !shadow_prealloc(d, root_type, 1) ) -+ { -+ new_entry = pagetable_null(); -+ goto install_new_entry; -+ } -+ - /* Shadow the page. */ - smfn = make_shadow(v, gmfn, root_type); - } ---- a/xen/arch/x86/mm/shadow/hvm.c -+++ b/xen/arch/x86/mm/shadow/hvm.c -@@ -700,7 +700,9 @@ mfn_t sh_make_monitor_table(const struct - ASSERT(!pagetable_get_pfn(v->arch.hvm.monitor_table)); - - /* Guarantee we can get the memory we need */ -- shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS); -+ if ( !shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS) ) -+ return INVALID_MFN; -+ - m4mfn = shadow_alloc(d, SH_type_monitor_table, 0); - mfn_to_page(m4mfn)->shadow_flags = 4; - ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -2440,9 +2440,14 @@ static int sh_page_fault(struct vcpu *v, - * Preallocate shadow pages *before* removing writable accesses - * otherwhise an OOS L1 might be demoted and promoted again with - * writable mappings. */ -- shadow_prealloc(d, -- SH_type_l1_shadow, -- GUEST_PAGING_LEVELS < 4 ? 1 : GUEST_PAGING_LEVELS - 1); -+ if ( !shadow_prealloc(d, SH_type_l1_shadow, -+ GUEST_PAGING_LEVELS < 4 -+ ? 1 : GUEST_PAGING_LEVELS - 1) ) -+ { -+ paging_unlock(d); -+ put_gfn(d, gfn_x(gfn)); -+ return 0; -+ } - - rc = gw_remove_write_accesses(v, va, &gw); - ---- a/xen/arch/x86/mm/shadow/private.h -+++ b/xen/arch/x86/mm/shadow/private.h -@@ -383,7 +383,8 @@ void shadow_promote(struct domain *d, mf - void shadow_demote(struct domain *d, mfn_t gmfn, u32 type); - - /* Shadow page allocation functions */ --void shadow_prealloc(struct domain *d, u32 shadow_type, unsigned int count); -+bool __must_check shadow_prealloc(struct domain *d, unsigned int shadow_type, -+ unsigned int count); - mfn_t shadow_alloc(struct domain *d, - u32 shadow_type, - unsigned long backpointer); diff --git a/xsa410-4.16-07.patch b/xsa410-4.16-07.patch deleted file mode 100644 index 9eea91c..0000000 --- a/xsa410-4.16-07.patch +++ /dev/null @@ -1,82 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: refuse new allocations for dying domains - -This will in particular prevent any attempts to add entries to the p2m, -once - in a subsequent change - non-root entries have been removed. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -245,6 +245,9 @@ static struct page_info *hap_alloc(struc - - ASSERT(paging_locked_by_me(d)); - -+ if ( unlikely(d->is_dying) ) -+ return NULL; -+ - pg = page_list_remove_head(&d->arch.paging.hap.freelist); - if ( unlikely(!pg) ) - return NULL; -@@ -281,7 +284,7 @@ static struct page_info *hap_alloc_p2m_p - d->arch.paging.hap.p2m_pages++; - ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask)); - } -- else if ( !d->arch.paging.p2m_alloc_failed ) -+ else if ( !d->arch.paging.p2m_alloc_failed && !d->is_dying ) - { - d->arch.paging.p2m_alloc_failed = 1; - dprintk(XENLOG_ERR, "d%i failed to allocate from HAP pool\n", ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -939,6 +939,10 @@ static bool __must_check _shadow_preallo - if ( d->arch.paging.shadow.free_pages >= pages ) - return true; - -+ if ( unlikely(d->is_dying) ) -+ /* No reclaim when the domain is dying, teardown will take care of it. */ -+ return false; -+ - /* Shouldn't have enabled shadows if we've no vcpus. */ - ASSERT(d->vcpu && d->vcpu[0]); - -@@ -991,7 +995,7 @@ static bool __must_check _shadow_preallo - d->arch.paging.shadow.free_pages, - d->arch.paging.shadow.p2m_pages); - -- ASSERT(d->is_dying); -+ ASSERT_UNREACHABLE(); - - guest_flush_tlb_mask(d, d->dirty_cpumask); - -@@ -1005,10 +1009,13 @@ static bool __must_check _shadow_preallo - * to avoid freeing shadows that the caller is currently working on. */ - bool shadow_prealloc(struct domain *d, unsigned int type, unsigned int count) - { -- bool ret = _shadow_prealloc(d, shadow_size(type) * count); -+ bool ret; -+ -+ if ( unlikely(d->is_dying) ) -+ return false; - -- if ( !ret && !d->is_dying && -- (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) -+ ret = _shadow_prealloc(d, shadow_size(type) * count); -+ if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) - /* - * Failing to allocate memory required for shadow usage can only result in - * a domain crash, do it here rather that relying on every caller to do it. -@@ -1238,6 +1245,9 @@ shadow_alloc_p2m_page(struct domain *d) - { - struct page_info *pg = NULL; - -+ if ( unlikely(d->is_dying) ) -+ return NULL; -+ - /* This is called both from the p2m code (which never holds the - * paging lock) and the log-dirty code (which always does). */ - paging_lock_recursive(d); diff --git a/xsa410-4.16-08.patch b/xsa410-4.16-08.patch deleted file mode 100644 index 92cdb49..0000000 --- a/xsa410-4.16-08.patch +++ /dev/null @@ -1,96 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: truly free paging pool memory for dying domains - -Modify {hap,shadow}_free to free the page immediately if the domain is -dying, so that pages don't accumulate in the pool when -{shadow,hap}_final_teardown() get called. This is to limit the amount of -work which needs to be done there (in a non-preemptable manner). - -Note the call to shadow_free() in shadow_free_p2m_page() is moved after -increasing total_pages, so that the decrease done in shadow_free() in -case the domain is dying doesn't underflow the counter, even if just for -a short interval. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -265,6 +265,18 @@ static void hap_free(struct domain *d, m - - ASSERT(paging_locked_by_me(d)); - -+ /* -+ * For dying domains, actually free the memory here. This way less work is -+ * left to hap_final_teardown(), which cannot easily have preemption checks -+ * added. -+ */ -+ if ( unlikely(d->is_dying) ) -+ { -+ free_domheap_page(pg); -+ d->arch.paging.hap.total_pages--; -+ return; -+ } -+ - d->arch.paging.hap.free_pages++; - page_list_add_tail(pg, &d->arch.paging.hap.freelist); - } ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -1187,6 +1187,7 @@ mfn_t shadow_alloc(struct domain *d, - void shadow_free(struct domain *d, mfn_t smfn) - { - struct page_info *next = NULL, *sp = mfn_to_page(smfn); -+ bool dying = ACCESS_ONCE(d->is_dying); - struct page_list_head *pin_list; - unsigned int pages; - u32 shadow_type; -@@ -1229,11 +1230,32 @@ void shadow_free(struct domain *d, mfn_t - * just before the allocator hands the page out again. */ - page_set_tlbflush_timestamp(sp); - perfc_decr(shadow_alloc_count); -- page_list_add_tail(sp, &d->arch.paging.shadow.freelist); -+ -+ /* -+ * For dying domains, actually free the memory here. This way less -+ * work is left to shadow_final_teardown(), which cannot easily have -+ * preemption checks added. -+ */ -+ if ( unlikely(dying) ) -+ { -+ /* -+ * The backpointer field (sh.back) used by shadow code aliases the -+ * domain owner field, unconditionally clear it here to avoid -+ * free_domheap_page() attempting to parse it. -+ */ -+ page_set_owner(sp, NULL); -+ free_domheap_page(sp); -+ } -+ else -+ page_list_add_tail(sp, &d->arch.paging.shadow.freelist); -+ - sp = next; - } - -- d->arch.paging.shadow.free_pages += pages; -+ if ( unlikely(dying) ) -+ d->arch.paging.shadow.total_pages -= pages; -+ else -+ d->arch.paging.shadow.free_pages += pages; - } - - /* Divert a page from the pool to be used by the p2m mapping. -@@ -1303,9 +1325,9 @@ shadow_free_p2m_page(struct domain *d, s - * paging lock) and the log-dirty code (which always does). */ - paging_lock_recursive(d); - -- shadow_free(d, page_to_mfn(pg)); - d->arch.paging.shadow.p2m_pages--; - d->arch.paging.shadow.total_pages++; -+ shadow_free(d, page_to_mfn(pg)); - - paging_unlock(d); - } diff --git a/xsa410-4.16-09.patch b/xsa410-4.16-09.patch deleted file mode 100644 index 60259e1..0000000 --- a/xsa410-4.16-09.patch +++ /dev/null @@ -1,159 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: free the paging memory pool preemptively - -The paging memory pool is currently freed in two different places: -from {shadow,hap}_teardown() via domain_relinquish_resources() and -from {shadow,hap}_final_teardown() via complete_domain_destroy(). -While the former does handle preemption, the later doesn't. - -Attempt to move as much p2m related freeing as possible to happen -before the call to {shadow,hap}_teardown(), so that most memory can be -freed in a preemptive way. In order to avoid causing issues to -existing callers leave the root p2m page tables set and free them in -{hap,shadow}_final_teardown(). Also modify {hap,shadow}_free to free -the page immediately if the domain is dying, so that pages don't -accumulate in the pool when {shadow,hap}_final_teardown() get called. - -Move altp2m_vcpu_disable_ve() to be done in hap_teardown(), as that's -the place where altp2m_active gets disabled now. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/domain.c -+++ b/xen/arch/x86/domain.c -@@ -38,7 +38,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -2381,12 +2380,6 @@ int domain_relinquish_resources(struct d - vpmu_destroy(v); - } - -- if ( altp2m_active(d) ) -- { -- for_each_vcpu ( d, v ) -- altp2m_vcpu_disable_ve(v); -- } -- - if ( is_pv_domain(d) ) - { - for_each_vcpu ( d, v ) ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -546,24 +547,8 @@ void hap_final_teardown(struct domain *d - unsigned int i; - - if ( hvm_altp2m_supported() ) -- { -- d->arch.altp2m_active = 0; -- -- if ( d->arch.altp2m_eptp ) -- { -- free_xenheap_page(d->arch.altp2m_eptp); -- d->arch.altp2m_eptp = NULL; -- } -- -- if ( d->arch.altp2m_visible_eptp ) -- { -- free_xenheap_page(d->arch.altp2m_visible_eptp); -- d->arch.altp2m_visible_eptp = NULL; -- } -- - for ( i = 0; i < MAX_ALTP2M; i++ ) - p2m_teardown(d->arch.altp2m_p2m[i], true); -- } - - /* Destroy nestedp2m's first */ - for (i = 0; i < MAX_NESTEDP2M; i++) { -@@ -578,6 +563,8 @@ void hap_final_teardown(struct domain *d - paging_lock(d); - hap_set_allocation(d, 0, NULL); - ASSERT(d->arch.paging.hap.p2m_pages == 0); -+ ASSERT(d->arch.paging.hap.free_pages == 0); -+ ASSERT(d->arch.paging.hap.total_pages == 0); - paging_unlock(d); - } - -@@ -603,6 +590,7 @@ void hap_vcpu_teardown(struct vcpu *v) - void hap_teardown(struct domain *d, bool *preempted) - { - struct vcpu *v; -+ unsigned int i; - - ASSERT(d->is_dying); - ASSERT(d != current->domain); -@@ -611,6 +599,28 @@ void hap_teardown(struct domain *d, bool - for_each_vcpu ( d, v ) - hap_vcpu_teardown(v); - -+ /* Leave the root pt in case we get further attempts to modify the p2m. */ -+ if ( hvm_altp2m_supported() ) -+ { -+ if ( altp2m_active(d) ) -+ for_each_vcpu ( d, v ) -+ altp2m_vcpu_disable_ve(v); -+ -+ d->arch.altp2m_active = 0; -+ -+ FREE_XENHEAP_PAGE(d->arch.altp2m_eptp); -+ FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); -+ -+ for ( i = 0; i < MAX_ALTP2M; i++ ) -+ p2m_teardown(d->arch.altp2m_p2m[i], false); -+ } -+ -+ /* Destroy nestedp2m's after altp2m. */ -+ for ( i = 0; i < MAX_NESTEDP2M; i++ ) -+ p2m_teardown(d->arch.nested_p2m[i], false); -+ -+ p2m_teardown(p2m_get_hostp2m(d), false); -+ - paging_lock(d); /* Keep various asserts happy */ - - if ( d->arch.paging.hap.total_pages != 0 ) ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2824,8 +2824,17 @@ void shadow_teardown(struct domain *d, b - for_each_vcpu ( d, v ) - shadow_vcpu_teardown(v); - -+ p2m_teardown(p2m_get_hostp2m(d), false); -+ - paging_lock(d); - -+ /* -+ * Reclaim all shadow memory so that shadow_set_allocation() doesn't find -+ * in-use pages, as _shadow_prealloc() will no longer try to reclaim pages -+ * because the domain is dying. -+ */ -+ shadow_blow_tables(d); -+ - #if (SHADOW_OPTIMIZATIONS & (SHOPT_VIRTUAL_TLB|SHOPT_OUT_OF_SYNC)) - /* Free the virtual-TLB array attached to each vcpu */ - for_each_vcpu(d, v) -@@ -2946,6 +2955,9 @@ void shadow_final_teardown(struct domain - d->arch.paging.shadow.total_pages, - d->arch.paging.shadow.free_pages, - d->arch.paging.shadow.p2m_pages); -+ ASSERT(!d->arch.paging.shadow.total_pages); -+ ASSERT(!d->arch.paging.shadow.free_pages); -+ ASSERT(!d->arch.paging.shadow.p2m_pages); - paging_unlock(d); - } - diff --git a/xsa410-4.16-10.patch b/xsa410-4.16-10.patch deleted file mode 100644 index 258b7ff..0000000 --- a/xsa410-4.16-10.patch +++ /dev/null @@ -1,171 +0,0 @@ -From: Julien Grall -Subject: xen/x86: p2m: Add preemption in p2m_teardown() - -The list p2m->pages contain all the pages used by the P2M. On large -instance this can be quite large and the time spent to call -d->arch.paging.free_page() will take more than 1ms for a 80GB guest -on a Xen running in nested environment on a c5.metal. - -By extrapolation, it would take > 100ms for a 8TB guest (what we -current security support). So add some preemption in p2m_teardown() -and propagate to the callers. Note there are 3 places where -the preemption is not enabled: - - hap_final_teardown()/shadow_final_teardown(): We are - preventing update the P2M once the domain is dying (so - no more pages could be allocated) and most of the P2M pages - will be freed in preemptive manneer when relinquishing the - resources. So this is fine to disable preemption. - - shadow_enable(): This is fine because it will undo the allocation - that may have been made by p2m_alloc_table() (so only the root - page table). - -The preemption is arbitrarily checked every 1024 iterations. - -Note that with the current approach, Xen doesn't keep track on whether -the alt/nested P2Ms have been cleared. So there are some redundant work. -However, this is not expected to incurr too much overhead (the P2M lock -shouldn't be contended during teardown). So this is optimization is -left outside of the security event. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Julien Grall -Signed-off-by: Jan Beulich - ---- a/xen/include/asm-x86/p2m.h -+++ b/xen/include/asm-x86/p2m.h -@@ -574,7 +574,7 @@ int p2m_init(struct domain *d); - int p2m_alloc_table(struct p2m_domain *p2m); - - /* Return all the p2m resources to Xen. */ --void p2m_teardown(struct p2m_domain *p2m, bool remove_root); -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted); - void p2m_final_teardown(struct domain *d); - - /* Add a page to a domain's p2m table */ ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -548,17 +548,17 @@ void hap_final_teardown(struct domain *d - - if ( hvm_altp2m_supported() ) - for ( i = 0; i < MAX_ALTP2M; i++ ) -- p2m_teardown(d->arch.altp2m_p2m[i], true); -+ p2m_teardown(d->arch.altp2m_p2m[i], true, NULL); - - /* Destroy nestedp2m's first */ - for (i = 0; i < MAX_NESTEDP2M; i++) { -- p2m_teardown(d->arch.nested_p2m[i], true); -+ p2m_teardown(d->arch.nested_p2m[i], true, NULL); - } - - if ( d->arch.paging.hap.total_pages != 0 ) - hap_teardown(d, NULL); - -- p2m_teardown(p2m_get_hostp2m(d), true); -+ p2m_teardown(p2m_get_hostp2m(d), true, NULL); - /* Free any memory that the p2m teardown released */ - paging_lock(d); - hap_set_allocation(d, 0, NULL); -@@ -612,14 +612,24 @@ void hap_teardown(struct domain *d, bool - FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); - - for ( i = 0; i < MAX_ALTP2M; i++ ) -- p2m_teardown(d->arch.altp2m_p2m[i], false); -+ { -+ p2m_teardown(d->arch.altp2m_p2m[i], false, preempted); -+ if ( preempted && *preempted ) -+ return; -+ } - } - - /* Destroy nestedp2m's after altp2m. */ - for ( i = 0; i < MAX_NESTEDP2M; i++ ) -- p2m_teardown(d->arch.nested_p2m[i], false); -+ { -+ p2m_teardown(d->arch.nested_p2m[i], false, preempted); -+ if ( preempted && *preempted ) -+ return; -+ } - -- p2m_teardown(p2m_get_hostp2m(d), false); -+ p2m_teardown(p2m_get_hostp2m(d), false, preempted); -+ if ( preempted && *preempted ) -+ return; - - paging_lock(d); /* Keep various asserts happy */ - ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -749,12 +749,13 @@ int p2m_alloc_table(struct p2m_domain *p - * hvm fixme: when adding support for pvh non-hardware domains, this path must - * cleanup any foreign p2m types (release refcnts on them). - */ --void p2m_teardown(struct p2m_domain *p2m, bool remove_root) -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted) - /* Return all the p2m pages to Xen. - * We know we don't have any extra mappings to these pages */ - { - struct page_info *pg, *root_pg = NULL; - struct domain *d; -+ unsigned int i = 0; - - if (p2m == NULL) - return; -@@ -773,8 +774,19 @@ void p2m_teardown(struct p2m_domain *p2m - } - - while ( (pg = page_list_remove_head(&p2m->pages)) ) -- if ( pg != root_pg ) -- d->arch.paging.free_page(d, pg); -+ { -+ if ( pg == root_pg ) -+ continue; -+ -+ d->arch.paging.free_page(d, pg); -+ -+ /* Arbitrarily check preemption every 1024 iterations */ -+ if ( preempted && !(++i % 1024) && general_preempt_check() ) -+ { -+ *preempted = true; -+ break; -+ } -+ } - - if ( root_pg ) - page_list_add(root_pg, &p2m->pages); ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2770,8 +2770,12 @@ int shadow_enable(struct domain *d, u32 - out_locked: - paging_unlock(d); - out_unlocked: -+ /* -+ * This is fine to ignore the preemption here because only the root -+ * will be allocated by p2m_alloc_table(). -+ */ - if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) ) -- p2m_teardown(p2m, true); -+ p2m_teardown(p2m, true, NULL); - if ( rv != 0 && pg != NULL ) - { - pg->count_info &= ~PGC_count_mask; -@@ -2824,7 +2828,9 @@ void shadow_teardown(struct domain *d, b - for_each_vcpu ( d, v ) - shadow_vcpu_teardown(v); - -- p2m_teardown(p2m_get_hostp2m(d), false); -+ p2m_teardown(p2m_get_hostp2m(d), false, preempted); -+ if ( preempted && *preempted ) -+ return; - - paging_lock(d); - -@@ -2945,7 +2951,7 @@ void shadow_final_teardown(struct domain - shadow_teardown(d, NULL); - - /* It is now safe to pull down the p2m map. */ -- p2m_teardown(p2m_get_hostp2m(d), true); -+ p2m_teardown(p2m_get_hostp2m(d), true, NULL); - /* Free any shadow memory that the p2m teardown released */ - paging_lock(d); - shadow_set_allocation(d, 0, NULL); diff --git a/xsa411.patch b/xsa411.patch deleted file mode 100644 index 50dcae4..0000000 --- a/xsa411.patch +++ /dev/null @@ -1,55 +0,0 @@ -From: Jan Beulich -Subject: gnttab: correct locking on transitive grant copy error path - -While the comment next to the lock dropping in preparation of -recursively calling acquire_grant_for_copy() mistakenly talks about the -rd == td case (excluded a few lines further up), the same concerns apply -to the calling of release_grant_for_copy() on a subsequent error path. - -This is CVE-2022-33748 / XSA-411. - -Fixes: ad48fb963dbf ("gnttab: fix transitive grant handling") -Signed-off-by: Jan Beulich ---- -v2: Extend code comment. - ---- a/xen/common/grant_table.c -+++ b/xen/common/grant_table.c -@@ -2622,9 +2622,8 @@ acquire_grant_for_copy( - trans_domid); - - /* -- * acquire_grant_for_copy() could take the lock on the -- * remote table (if rd == td), so we have to drop the lock -- * here and reacquire. -+ * acquire_grant_for_copy() will take the lock on the remote table, -+ * so we have to drop the lock here and reacquire. - */ - active_entry_release(act); - grant_read_unlock(rgt); -@@ -2661,11 +2660,25 @@ acquire_grant_for_copy( - act->trans_gref != trans_gref || - !act->is_sub_page)) ) - { -+ /* -+ * Like above for acquire_grant_for_copy() we need to drop and then -+ * re-acquire the locks here to prevent lock order inversion issues. -+ * Unlike for acquire_grant_for_copy() we don't need to re-check -+ * anything, as release_grant_for_copy() doesn't depend on the grant -+ * table entry: It only updates internal state and the status flags. -+ */ -+ active_entry_release(act); -+ grant_read_unlock(rgt); -+ - release_grant_for_copy(td, trans_gref, readonly); - rcu_unlock_domain(td); -+ -+ grant_read_lock(rgt); -+ act = active_entry_acquire(rgt, gref); - reduce_status_for_pin(rd, act, status, readonly); - active_entry_release(act); - grant_read_unlock(rgt); -+ - put_page(*page); - *page = NULL; - return ERESTART; diff --git a/xsa412-4.16.patch b/xsa412-4.16.patch deleted file mode 100644 index f37fc21..0000000 --- a/xsa412-4.16.patch +++ /dev/null @@ -1,245 +0,0 @@ -From: Andrew Cooper -Subject: x86/vmx: Revert "VMX: use a single, global APIC access page" - -The claim "No accesses would ever go to this page." is false. A consequence -of how Intel's APIC Acceleration works, and Xen's choice to have per-domain -P2Ms (rather than per-vCPU P2Ms) means that the APIC page is fully read-write -to any vCPU which is not in xAPIC mode. - -This reverts commit 58850b9074d3e7affdf3bc94c84e417ecfa4d165. - -This is XSA-412 / CVE-2022-42327. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c -index d429d76c18c9..3f4276531322 100644 ---- a/xen/arch/x86/hvm/vmx/vmx.c -+++ b/xen/arch/x86/hvm/vmx/vmx.c -@@ -66,7 +66,8 @@ boolean_param("force-ept", opt_force_ept); - static void vmx_ctxt_switch_from(struct vcpu *v); - static void vmx_ctxt_switch_to(struct vcpu *v); - --static int alloc_vlapic_mapping(void); -+static int vmx_alloc_vlapic_mapping(struct domain *d); -+static void vmx_free_vlapic_mapping(struct domain *d); - static void vmx_install_vlapic_mapping(struct vcpu *v); - static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr, - unsigned int flags); -@@ -77,8 +78,6 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content); - static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content); - static void vmx_invlpg(struct vcpu *v, unsigned long linear); - --static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER; -- - /* Values for domain's ->arch.hvm_domain.pi_ops.flags. */ - #define PI_CSW_FROM (1u << 0) - #define PI_CSW_TO (1u << 1) -@@ -402,6 +401,7 @@ static int vmx_domain_initialise(struct domain *d) - .to = vmx_ctxt_switch_to, - .tail = vmx_do_resume, - }; -+ int rc; - - d->arch.ctxt_switch = &csw; - -@@ -411,15 +411,24 @@ static int vmx_domain_initialise(struct domain *d) - */ - d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp; - -+ if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 ) -+ return rc; -+ - return 0; - } - -+static void vmx_domain_relinquish_resources(struct domain *d) -+{ -+ vmx_free_vlapic_mapping(d); -+} -+ - static void domain_creation_finished(struct domain *d) - { - gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE); -+ mfn_t apic_access_mfn = d->arch.hvm.vmx.apic_access_mfn; - bool ipat; - -- if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) ) -+ if ( mfn_eq(apic_access_mfn, _mfn(0)) ) - return; - - ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat, -@@ -2481,6 +2490,7 @@ static struct hvm_function_table __initdata vmx_function_table = { - .cpu_up_prepare = vmx_cpu_up_prepare, - .cpu_dead = vmx_cpu_dead, - .domain_initialise = vmx_domain_initialise, -+ .domain_relinquish_resources = vmx_domain_relinquish_resources, - .domain_creation_finished = domain_creation_finished, - .vcpu_initialise = vmx_vcpu_initialise, - .vcpu_destroy = vmx_vcpu_destroy, -@@ -2731,7 +2741,7 @@ const struct hvm_function_table * __init start_vmx(void) - { - set_in_cr4(X86_CR4_VMXE); - -- if ( vmx_vmcs_init() || alloc_vlapic_mapping() ) -+ if ( vmx_vmcs_init() ) - { - printk("VMX: failed to initialise.\n"); - return NULL; -@@ -3305,36 +3315,55 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content) - return X86EMUL_EXCEPTION; - } - --static int __init alloc_vlapic_mapping(void) -+static int vmx_alloc_vlapic_mapping(struct domain *d) - { - struct page_info *pg; - mfn_t mfn; - -- if ( !cpu_has_vmx_virtualize_apic_accesses ) -+ if ( !has_vlapic(d) || !cpu_has_vmx_virtualize_apic_accesses ) - return 0; - -- pg = alloc_domheap_page(NULL, 0); -+ pg = alloc_domheap_page(d, MEMF_no_refcount); - if ( !pg ) - return -ENOMEM; - -- /* -- * Signal to shadow code that this page cannot be refcounted. This also -- * makes epte_get_entry_emt() recognize this page as "special". -- */ -- page_suppress_refcounting(pg); -+ if ( !get_page_and_type(pg, d, PGT_writable_page) ) -+ { -+ /* -+ * The domain can't possibly know about this page yet, so failure -+ * here is a clear indication of something fishy going on. -+ */ -+ domain_crash(d); -+ return -ENODATA; -+ } - - mfn = page_to_mfn(pg); - clear_domain_page(mfn); -- apic_access_mfn = mfn; -+ d->arch.hvm.vmx.apic_access_mfn = mfn; - - return 0; - } - -+static void vmx_free_vlapic_mapping(struct domain *d) -+{ -+ mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn; -+ -+ d->arch.hvm.vmx.apic_access_mfn = _mfn(0); -+ if ( !mfn_eq(mfn, _mfn(0)) ) -+ { -+ struct page_info *pg = mfn_to_page(mfn); -+ -+ put_page_alloc_ref(pg); -+ put_page_and_type(pg); -+ } -+} -+ - static void vmx_install_vlapic_mapping(struct vcpu *v) - { -+ mfn_t apic_access_mfn = v->domain->arch.hvm.vmx.apic_access_mfn; - paddr_t virt_page_ma, apic_page_ma; - -- if ( !has_vlapic(v->domain) || mfn_eq(apic_access_mfn, INVALID_MFN) ) -+ if ( mfn_eq(apic_access_mfn, _mfn(0)) ) - return; - - ASSERT(cpu_has_vmx_virtualize_apic_accesses); -diff --git a/xen/arch/x86/mm/shadow/set.c b/xen/arch/x86/mm/shadow/set.c -index 87e9c6eeb219..bd6c68b547c9 100644 ---- a/xen/arch/x86/mm/shadow/set.c -+++ b/xen/arch/x86/mm/shadow/set.c -@@ -101,14 +101,6 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type) - owner = page_get_owner(pg); - } - -- /* -- * Check whether refcounting is suppressed on this page. For example, -- * VMX'es APIC access MFN is just a surrogate page. It doesn't actually -- * get accessed, and hence there's no need to refcount it. -- */ -- if ( pg && page_refcounting_suppressed(pg) ) -- return 0; -- - if ( owner == dom_io ) - owner = NULL; - -diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h -index 6970e7d6ea4a..814a4018535a 100644 ---- a/xen/arch/x86/mm/shadow/types.h -+++ b/xen/arch/x86/mm/shadow/types.h -@@ -276,16 +276,9 @@ int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e, - static void inline - shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d) - { -- mfn_t mfn = shadow_l1e_get_mfn(sl1e); -- - if ( !shadow_mode_refcounts(d) ) - return; - -- if ( mfn_valid(mfn) && -- /* See the respective comment in shadow_get_page_from_l1e(). */ -- page_refcounting_suppressed(mfn_to_page(mfn)) ) -- return; -- - put_page_from_l1e(sl1e, d); - } - -diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h -index 03c9ccf627ab..8073af323b96 100644 ---- a/xen/include/asm-x86/hvm/vmx/vmcs.h -+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h -@@ -58,6 +58,7 @@ struct ept_data { - #define _VMX_DOMAIN_PML_ENABLED 0 - #define VMX_DOMAIN_PML_ENABLED (1ul << _VMX_DOMAIN_PML_ENABLED) - struct vmx_domain { -+ mfn_t apic_access_mfn; - /* VMX_DOMAIN_* */ - unsigned int status; - -diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h -index 7bdf9c2290d8..e1bcea57a8f5 100644 ---- a/xen/include/asm-x86/mm.h -+++ b/xen/include/asm-x86/mm.h -@@ -83,7 +83,7 @@ - #define PGC_state_offlined PG_mask(2, 6) - #define PGC_state_free PG_mask(3, 6) - #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st) --/* Page is not reference counted (see below for caveats) */ -+/* Page is not reference counted */ - #define _PGC_extra PG_shift(7) - #define PGC_extra PG_mask(1, 7) - -@@ -375,24 +375,6 @@ void zap_ro_mpt(mfn_t mfn); - - bool is_iomem_page(mfn_t mfn); - --/* -- * Pages with no owner which may get passed to functions wanting to -- * refcount them can be marked PGC_extra to bypass this refcounting (which -- * would fail due to the lack of an owner). -- * -- * (For pages with owner PGC_extra has different meaning.) -- */ --static inline void page_suppress_refcounting(struct page_info *pg) --{ -- ASSERT(!page_get_owner(pg)); -- pg->count_info |= PGC_extra; --} -- --static inline bool page_refcounting_suppressed(const struct page_info *pg) --{ -- return !page_get_owner(pg) && (pg->count_info & PGC_extra); --} -- - struct platform_bad_page { - unsigned long mfn; - unsigned int order; diff --git a/xsa414.patch b/xsa414.patch deleted file mode 100644 index 27ab0c2..0000000 --- a/xsa414.patch +++ /dev/null @@ -1,112 +0,0 @@ -From: Julien Grall -Subject: tools/xenstore: create_node: Don't defer work to undo any changes on - failure - -XSA-115 extended destroy_node() to update the node accounting for the -connection. The implementation is assuming the connection is the parent -of the node, however all the nodes are allocated using a separate context -(see process_message()). This will result to crash (or corrupt) xenstored -as the pointer is wrongly used. - -In case of an error, any changes to the database or update to the -accounting will now be reverted in create_node() by calling directly -destroy_node(). This has the nice advantage to remove the loop to unset -the destructors in case of success. - -Take the opportunity to free the nodes right now as they are not -going to be reachable (the function returns NULL) and are just wasting -resources. - -This is XSA-414 / CVE-2022-42309. - -Reported-by: Julien Grall -Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation") -Signed-off-by: Julien Grall -Reviewed-by: Juergen Gross - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 8867f93431d4..c30d14cbf2ab 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1084,9 +1084,8 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - return NULL; - } - --static int destroy_node(void *_node) -+static int destroy_node(struct connection *conn, struct node *node) - { -- struct node *node = _node; - TDB_DATA key; - - if (streq(node->name, "/")) -@@ -1095,7 +1094,7 @@ static int destroy_node(void *_node) - set_tdb_key(node->name, &key); - tdb_delete(tdb_ctx, key); - -- domain_entry_dec(talloc_parent(node), node); -+ domain_entry_dec(conn, node); - - return 0; - } -@@ -1104,7 +1103,8 @@ static struct node *create_node(struct connection *conn, const void *ctx, - const char *name, - void *data, unsigned int datalen) - { -- struct node *node, *i; -+ struct node *node, *i, *j; -+ int ret; - - node = construct_node(conn, ctx, name); - if (!node) -@@ -1126,23 +1126,40 @@ static struct node *create_node(struct connection *conn, const void *ctx, - /* i->parent is set for each new node, so check quota. */ - if (i->parent && - domain_entry(conn) >= quota_nb_entry_per_domain) { -- errno = ENOSPC; -- return NULL; -+ ret = ENOSPC; -+ goto err; - } -- if (write_node(conn, i, false)) -- return NULL; - -- /* Account for new node, set destructor for error case. */ -- if (i->parent) { -+ ret = write_node(conn, i, false); -+ if (ret) -+ goto err; -+ -+ /* Account for new node */ -+ if (i->parent) - domain_entry_inc(conn, i); -- talloc_set_destructor(i, destroy_node); -- } - } - -- /* OK, now remove destructors so they stay around */ -- for (i = node; i->parent; i = i->parent) -- talloc_set_destructor(i, NULL); - return node; -+ -+err: -+ /* -+ * We failed to update TDB for some of the nodes. Undo any work that -+ * have already been done. -+ */ -+ for (j = node; j != i; j = j->parent) -+ destroy_node(conn, j); -+ -+ /* We don't need to keep the nodes around, so free them. */ -+ i = node; -+ while (i) { -+ j = i; -+ i = i->parent; -+ talloc_free(j); -+ } -+ -+ errno = ret; -+ -+ return NULL; - } - - /* path, data... */ diff --git a/xsa415.patch b/xsa415.patch deleted file mode 100644 index b6f6971..0000000 --- a/xsa415.patch +++ /dev/null @@ -1,134 +0,0 @@ -From: Julien Grall -Subject: tools/xenstore: Fail a transaction if it is not possible to create a - node - -Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved -out from copying the entire database everytime a new transaction is -opened to track the list of nodes changed. - -The content of all the nodes accessed during a transaction will be -temporarily stored in TDB using a different key. - -The function create_node() may write/update multiple nodes if the child -doesn't exist. In case of a failure, the function will revert any -changes (this include any update to TDB). Unfortunately, the function -which reverts the changes (i.e. destroy_node()) will not use the correct -key to delete any update or even request the transaction to fail. - -This means that if a client decide to go ahead with committing the -transaction, orphan nodes will be created because they were not linked -to an existing node (create_node() will write the nodes backwards). - -Once some nodes have been partially updated in a transaction, it is not -easily possible to undo any changes. So rather than continuing and hit -weird issue while committing, it is much saner to fail the transaction. - -This will have an impact on any client that decides to commit even if it -can't write a node. Although, it is not clear why a normal client would -want to do that... - -Lastly, update destroy_node() to use the correct key for deleting the -node. Rather than recreating it (this will allocate memory and -therefore fail), stash the key in the structure node. - -This is XSA-415 / CVE-2022-42310. - -Reported-by: Julien Grall -Signed-off-by: Julien Grall -Reviewed-by: Juergen Gross - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index c30d14cbf2ab..55b79e4c032e 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -562,15 +562,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - return 0; - } - -+/* -+ * Write the node. If the node is written, caller can find the key used in -+ * node->key. This can later be used if the change needs to be reverted. -+ */ - static int write_node(struct connection *conn, struct node *node, - bool no_quota_check) - { -- TDB_DATA key; -- -- if (access_node(conn, node, NODE_ACCESS_WRITE, &key)) -+ if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key)) - return errno; - -- return write_node_raw(conn, &key, node, no_quota_check); -+ return write_node_raw(conn, &node->key, node, no_quota_check); - } - - unsigned int perm_for_conn(struct connection *conn, -@@ -1086,16 +1088,21 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - - static int destroy_node(struct connection *conn, struct node *node) - { -- TDB_DATA key; -- - if (streq(node->name, "/")) - corrupt(NULL, "Destroying root node!"); - -- set_tdb_key(node->name, &key); -- tdb_delete(tdb_ctx, key); -+ tdb_delete(tdb_ctx, node->key); - - domain_entry_dec(conn, node); - -+ /* -+ * It is not possible to easily revert the changes in a transaction. -+ * So if the failure happens in a transaction, mark it as fail to -+ * prevent any commit. -+ */ -+ if ( conn->transaction ) -+ fail_transaction(conn->transaction); -+ - return 0; - } - -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 742812a97469..7d0fe77e7989 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -155,6 +155,8 @@ struct node_perms { - - struct node { - const char *name; -+ /* Key used to update TDB */ -+ TDB_DATA key; - - /* Parent (optional) */ - struct node *parent; -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index cd07fb0f218b..faf6c930e42a 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid) - list_add_tail(&d->list, &trans->changed_domains); - } - -+void fail_transaction(struct transaction *trans) -+{ -+ trans->fail = true; -+} -+ - void conn_delete_all_transactions(struct connection *conn) - { - struct transaction *trans; -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 43a162bea3f3..14062730e3c9 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node, - int transaction_prepend(struct connection *conn, const char *name, - TDB_DATA *key); - -+/* Mark the transaction as failed. This will prevent it to be committed. */ -+void fail_transaction(struct transaction *trans); -+ - void conn_delete_all_transactions(struct connection *conn); - int check_transactions(struct hashtable *hash); - diff --git a/xsa416-4.16.patch b/xsa416-4.16.patch deleted file mode 100644 index 0df409a..0000000 --- a/xsa416-4.16.patch +++ /dev/null @@ -1,704 +0,0 @@ -From 80d128b14482d2e9342184d2d9949367851c4d14 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: don't use conn->in as context for temporary - allocations - -Using the struct buffered data pointer of the current processed request -for temporary data allocations has a major drawback: the used area (and -with that the temporary data) is freed only after the response of the -request has been written to the ring page or has been read via the -socket. This can happen much later in case a guest isn't reading its -responses fast enough. - -As the temporary data can be safely freed after creating the response, -add a temporary context for that purpose and use that for allocating -the temporary memory, as it was already the case before commit -cc0612464896 ("xenstore: add small default data buffer to internal -struct"). - -Some sub-functions need to gain the "const" attribute for the talloc -context. - -This is XSA-416 / CVE-2022-42319. - -Reported-by: Julien Grall -Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct") -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c -index 1031a81c3874..d0350c6ad861 100644 ---- a/tools/xenstore/xenstored_control.c -+++ b/tools/xenstore/xenstored_control.c -@@ -155,7 +155,7 @@ bool lu_is_pending(void) - - struct cmd_s { - char *cmd; -- int (*func)(void *, struct connection *, char **, int); -+ int (*func)(const void *, struct connection *, char **, int); - char *pars; - /* - * max_pars can be used to limit the size of the parameter vector, -@@ -167,7 +167,7 @@ struct cmd_s { - unsigned int max_pars; - }; - --static int do_control_check(void *ctx, struct connection *conn, -+static int do_control_check(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num) -@@ -179,7 +179,7 @@ static int do_control_check(void *ctx, struct connection *conn, - return 0; - } - --static int do_control_log(void *ctx, struct connection *conn, -+static int do_control_log(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num != 1) -@@ -281,7 +281,7 @@ static int quota_get(const void *ctx, struct connection *conn, - return domain_get_quota(ctx, conn, atoi(vec[0])); - } - --static int do_control_quota(void *ctx, struct connection *conn, -+static int do_control_quota(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num == 0) -@@ -293,7 +293,7 @@ static int do_control_quota(void *ctx, struct connection *conn, - return quota_get(ctx, conn, vec, num); - } - --static int do_control_quota_s(void *ctx, struct connection *conn, -+static int do_control_quota_s(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num == 0) -@@ -306,7 +306,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn, - } - - #ifdef __MINIOS__ --static int do_control_memreport(void *ctx, struct connection *conn, -+static int do_control_memreport(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num) -@@ -318,7 +318,7 @@ static int do_control_memreport(void *ctx, struct connection *conn, - return 0; - } - #else --static int do_control_logfile(void *ctx, struct connection *conn, -+static int do_control_logfile(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num != 1) -@@ -333,7 +333,7 @@ static int do_control_logfile(void *ctx, struct connection *conn, - return 0; - } - --static int do_control_memreport(void *ctx, struct connection *conn, -+static int do_control_memreport(const void *ctx, struct connection *conn, - char **vec, int num) - { - FILE *fp; -@@ -373,7 +373,7 @@ static int do_control_memreport(void *ctx, struct connection *conn, - } - #endif - --static int do_control_print(void *ctx, struct connection *conn, -+static int do_control_print(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num != 1) -@@ -875,7 +875,7 @@ static const char *lu_start(const void *ctx, struct connection *conn, - return NULL; - } - --static int do_control_lu(void *ctx, struct connection *conn, -+static int do_control_lu(const void *ctx, struct connection *conn, - char **vec, int num) - { - const char *ret = NULL; -@@ -922,7 +922,7 @@ static int do_control_lu(void *ctx, struct connection *conn, - } - #endif - --static int do_control_help(void *, struct connection *, char **, int); -+static int do_control_help(const void *, struct connection *, char **, int); - - static struct cmd_s cmds[] = { - { "check", do_control_check, "" }, -@@ -961,7 +961,7 @@ static struct cmd_s cmds[] = { - { "help", do_control_help, "" }, - }; - --static int do_control_help(void *ctx, struct connection *conn, -+static int do_control_help(const void *ctx, struct connection *conn, - char **vec, int num) - { - int cmd, len = 0; -@@ -997,7 +997,8 @@ static int do_control_help(void *ctx, struct connection *conn, - return 0; - } - --int do_control(struct connection *conn, struct buffered_data *in) -+int do_control(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - unsigned int cmd, num, off; - char **vec = NULL; -@@ -1017,11 +1018,11 @@ int do_control(struct connection *conn, struct buffered_data *in) - num = xs_count_strings(in->buffer, in->used); - if (cmds[cmd].max_pars) - num = min(num, cmds[cmd].max_pars); -- vec = talloc_array(in, char *, num); -+ vec = talloc_array(ctx, char *, num); - if (!vec) - return ENOMEM; - if (get_strings(in, vec, num) < num) - return EIO; - -- return cmds[cmd].func(in, conn, vec + 1, num - 1); -+ return cmds[cmd].func(ctx, conn, vec + 1, num - 1); - } -diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h -index 98b6fbcea2b1..a8cb76559ba1 100644 ---- a/tools/xenstore/xenstored_control.h -+++ b/tools/xenstore/xenstored_control.h -@@ -16,7 +16,8 @@ - along with this program; If not, see . - */ - --int do_control(struct connection *conn, struct buffered_data *in); -+int do_control(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - void lu_read_state(void); - - struct connection *lu_get_connection(void); -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 16504de42017..411cc0e44714 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1248,11 +1248,13 @@ static struct node *get_node_canonicalized(struct connection *conn, - return get_node(conn, ctx, *canonical_name, perm); - } - --static int send_directory(struct connection *conn, struct buffered_data *in) -+static int send_directory(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - -- node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, onearg(in), NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1261,7 +1263,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in) - return 0; - } - --static int send_directory_part(struct connection *conn, -+static int send_directory_part(const void *ctx, struct connection *conn, - struct buffered_data *in) - { - unsigned int off, len, maxlen, genlen; -@@ -1273,7 +1275,8 @@ static int send_directory_part(struct connection *conn, - return EINVAL; - - /* First arg is node name. */ -- node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, in->buffer, NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1300,7 +1303,7 @@ static int send_directory_part(struct connection *conn, - break; - } - -- data = talloc_array(in, char, genlen + len + 1); -+ data = talloc_array(ctx, char, genlen + len + 1); - if (!data) - return ENOMEM; - -@@ -1316,11 +1319,13 @@ static int send_directory_part(struct connection *conn, - return 0; - } - --static int do_read(struct connection *conn, struct buffered_data *in) -+static int do_read(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - -- node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, onearg(in), NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1510,7 +1515,8 @@ static struct node *create_node(struct connection *conn, const void *ctx, - } - - /* path, data... */ --static int do_write(struct connection *conn, struct buffered_data *in) -+static int do_write(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - unsigned int offset, datalen; - struct node *node; -@@ -1524,12 +1530,12 @@ static int do_write(struct connection *conn, struct buffered_data *in) - offset = strlen(vec[0]) + 1; - datalen = in->used - offset; - -- node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE); -+ node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE); - if (!node) { - /* No permissions, invalid input? */ - if (errno != ENOENT) - return errno; -- node = create_node(conn, in, name, in->buffer + offset, -+ node = create_node(conn, ctx, name, in->buffer + offset, - datalen); - if (!node) - return errno; -@@ -1540,18 +1546,19 @@ static int do_write(struct connection *conn, struct buffered_data *in) - return errno; - } - -- fire_watches(conn, in, name, node, false, NULL); -+ fire_watches(conn, ctx, name, node, false, NULL); - send_ack(conn, XS_WRITE); - - return 0; - } - --static int do_mkdir(struct connection *conn, struct buffered_data *in) -+static int do_mkdir(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - char *name; - -- node = get_node_canonicalized(conn, in, onearg(in), &name, -+ node = get_node_canonicalized(conn, ctx, onearg(in), &name, - XS_PERM_WRITE); - - /* If it already exists, fine. */ -@@ -1561,10 +1568,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in) - return errno; - if (!name) - return ENOMEM; -- node = create_node(conn, in, name, NULL, 0); -+ node = create_node(conn, ctx, name, NULL, 0); - if (!node) - return errno; -- fire_watches(conn, in, name, node, false, NULL); -+ fire_watches(conn, ctx, name, node, false, NULL); - } - send_ack(conn, XS_MKDIR); - -@@ -1662,24 +1669,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - } - - --static int do_rm(struct connection *conn, struct buffered_data *in) -+static int do_rm(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - int ret; - char *name; - char *parentname; - -- node = get_node_canonicalized(conn, in, onearg(in), &name, -+ node = get_node_canonicalized(conn, ctx, onearg(in), &name, - XS_PERM_WRITE); - if (!node) { - /* Didn't exist already? Fine, if parent exists. */ - if (errno == ENOENT) { - if (!name) - return ENOMEM; -- parentname = get_parent(in, name); -+ parentname = get_parent(ctx, name); - if (!parentname) - return errno; -- node = read_node(conn, in, parentname); -+ node = read_node(conn, ctx, parentname); - if (node) { - send_ack(conn, XS_RM); - return 0; -@@ -1694,7 +1702,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in) - if (streq(name, "/")) - return EINVAL; - -- ret = _rm(conn, in, node, name); -+ ret = _rm(conn, ctx, node, name); - if (ret) - return ret; - -@@ -1704,13 +1712,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in) - } - - --static int do_get_perms(struct connection *conn, struct buffered_data *in) -+static int do_get_perms(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - char *strings; - unsigned int len; - -- node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, onearg(in), NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1723,7 +1733,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in) - return 0; - } - --static int do_set_perms(struct connection *conn, struct buffered_data *in) -+static int do_set_perms(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node_perms perms, old_perms; - char *name, *permstr; -@@ -1740,7 +1751,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - - permstr = in->buffer + strlen(in->buffer) + 1; - -- perms.p = talloc_array(in, struct xs_permissions, perms.num); -+ perms.p = talloc_array(ctx, struct xs_permissions, perms.num); - if (!perms.p) - return ENOMEM; - if (!xs_strings_to_perms(perms.p, perms.num, permstr)) -@@ -1755,7 +1766,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - } - - /* We must own node to do this (tools can do this too). */ -- node = get_node_canonicalized(conn, in, in->buffer, &name, -+ node = get_node_canonicalized(conn, ctx, in->buffer, &name, - XS_PERM_WRITE | XS_PERM_OWNER); - if (!node) - return errno; -@@ -1790,7 +1801,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - return errno; - } - -- fire_watches(conn, in, name, node, false, &old_perms); -+ fire_watches(conn, ctx, name, node, false, &old_perms); - send_ack(conn, XS_SET_PERMS); - - return 0; -@@ -1798,7 +1809,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - - static struct { - const char *str; -- int (*func)(struct connection *conn, struct buffered_data *in); -+ int (*func)(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - unsigned int flags; - #define XS_FLAG_NOTID (1U << 0) /* Ignore transaction id. */ - #define XS_FLAG_PRIV (1U << 1) /* Privileged domain only. */ -@@ -1874,6 +1886,7 @@ static void process_message(struct connection *conn, struct buffered_data *in) - struct transaction *trans; - enum xsd_sockmsg_type type = in->hdr.msg.type; - int ret; -+ void *ctx; - - /* At least send_error() and send_reply() expects conn->in == in */ - assert(conn->in == in); -@@ -1898,10 +1911,17 @@ static void process_message(struct connection *conn, struct buffered_data *in) - return; - } - -+ ctx = talloc_new(NULL); -+ if (!ctx) { -+ send_error(conn, ENOMEM); -+ return; -+ } -+ - assert(conn->transaction == NULL); - conn->transaction = trans; - -- ret = wire_funcs[type].func(conn, in); -+ ret = wire_funcs[type].func(ctx, conn, in); -+ talloc_free(ctx); - if (ret) - send_error(conn, ret); - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index e7c6886ccf47..fb732d0a14c3 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -330,7 +330,7 @@ bool domain_is_unprivileged(struct connection *conn) - domid_is_unprivileged(conn->domain->domid); - } - --static char *talloc_domain_path(void *context, unsigned int domid) -+static char *talloc_domain_path(const void *context, unsigned int domid) - { - return talloc_asprintf(context, "/local/domain/%u", domid); - } -@@ -534,7 +534,8 @@ static struct domain *introduce_domain(const void *ctx, - } - - /* domid, gfn, evtchn, path */ --int do_introduce(struct connection *conn, struct buffered_data *in) -+int do_introduce(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct domain *domain; - char *vec[3]; -@@ -552,7 +553,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in) - if (port <= 0) - return EINVAL; - -- domain = introduce_domain(in, domid, port, false); -+ domain = introduce_domain(ctx, domid, port, false); - if (!domain) - return errno; - -@@ -575,7 +576,8 @@ static struct domain *find_connected_domain(unsigned int domid) - return domain; - } - --int do_set_target(struct connection *conn, struct buffered_data *in) -+int do_set_target(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - char *vec[2]; - unsigned int domid, tdomid; -@@ -619,7 +621,8 @@ static struct domain *onearg_domain(struct connection *conn, - } - - /* domid */ --int do_release(struct connection *conn, struct buffered_data *in) -+int do_release(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct domain *domain; - -@@ -634,7 +637,8 @@ int do_release(struct connection *conn, struct buffered_data *in) - return 0; - } - --int do_resume(struct connection *conn, struct buffered_data *in) -+int do_resume(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct domain *domain; - -@@ -649,7 +653,8 @@ int do_resume(struct connection *conn, struct buffered_data *in) - return 0; - } - --int do_get_domain_path(struct connection *conn, struct buffered_data *in) -+int do_get_domain_path(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - char *path; - const char *domid_str = onearg(in); -@@ -657,18 +662,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in) - if (!domid_str) - return EINVAL; - -- path = talloc_domain_path(conn, atoi(domid_str)); -+ path = talloc_domain_path(ctx, atoi(domid_str)); - if (!path) - return errno; - - send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1); - -- talloc_free(path); -- - return 0; - } - --int do_is_domain_introduced(struct connection *conn, struct buffered_data *in) -+int do_is_domain_introduced(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - int result; - unsigned int domid; -@@ -689,7 +693,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in) - } - - /* Allow guest to reset all watches */ --int do_reset_watches(struct connection *conn, struct buffered_data *in) -+int do_reset_watches(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - conn_delete_all_watches(conn); - conn_delete_all_transactions(conn); -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 904faa923afb..b9e152890149 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -24,25 +24,32 @@ void handle_event(void); - void check_domains(void); - - /* domid, mfn, eventchn, path */ --int do_introduce(struct connection *conn, struct buffered_data *in); -+int do_introduce(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_is_domain_introduced(struct connection *conn, struct buffered_data *in); -+int do_is_domain_introduced(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_release(struct connection *conn, struct buffered_data *in); -+int do_release(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_resume(struct connection *conn, struct buffered_data *in); -+int do_resume(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid, target */ --int do_set_target(struct connection *conn, struct buffered_data *in); -+int do_set_target(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_get_domain_path(struct connection *conn, struct buffered_data *in); -+int do_get_domain_path(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* Allow guest to reset all watches */ --int do_reset_watches(struct connection *conn, struct buffered_data *in); -+int do_reset_watches(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - void domain_init(int evtfd); - void dom0_init(void); -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 28774813de83..3e3eb47326cc 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id) - return ERR_PTR(-ENOENT); - } - --int do_transaction_start(struct connection *conn, struct buffered_data *in) -+int do_transaction_start(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct transaction *trans, *exists; - char id_str[20]; -@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in) - conn->transaction_started > quota_max_transaction) - return ENOSPC; - -- /* Attach transaction to input for autofree until it's complete */ -- trans = talloc_zero(in, struct transaction); -+ /* Attach transaction to ctx for autofree until it's complete */ -+ trans = talloc_zero(ctx, struct transaction); - if (!trans) - return ENOMEM; - -@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update) - return 0; - } - --int do_transaction_end(struct connection *conn, struct buffered_data *in) -+int do_transaction_end(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - const char *arg = onearg(in); - struct transaction *trans; -@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in) - if (!conn->transaction_started) - conn->ta_start_time = 0; - -- /* Attach transaction to in for auto-cleanup */ -- talloc_steal(in, trans); -+ /* Attach transaction to ctx for auto-cleanup */ -+ talloc_steal(ctx, trans); - - if (streq(arg, "T")) { - if (trans->fail) -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index e3cbd6b23095..39d7f81c5127 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -29,8 +29,10 @@ struct transaction; - - extern uint64_t generation; - --int do_transaction_start(struct connection *conn, struct buffered_data *node); --int do_transaction_end(struct connection *conn, struct buffered_data *in); -+int do_transaction_start(const void *ctx, struct connection *conn, -+ struct buffered_data *node); -+int do_transaction_end(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - struct transaction *transaction_lookup(struct connection *conn, uint32_t id); - -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 85362bcce314..316c08b7f754 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token, - return NULL; - } - --int do_watch(struct connection *conn, struct buffered_data *in) -+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in) - { - struct watch *watch; - char *vec[2]; -@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in) - if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) - return EINVAL; - -- errno = check_watch_path(conn, in, &(vec[0]), &relative); -+ errno = check_watch_path(conn, ctx, &(vec[0]), &relative); - if (errno) - return errno; - -@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in) - return 0; - } - --int do_unwatch(struct connection *conn, struct buffered_data *in) -+int do_unwatch(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct watch *watch; - char *node, *vec[2]; -@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in) - if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) - return EINVAL; - -- node = xenstore_canonicalize(conn, in, vec[0]); -+ node = xenstore_canonicalize(conn, ctx, vec[0]); - if (!node) - return ENOMEM; - list_for_each_entry(watch, &conn->watches, list) { -diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h -index 0e693f0839cd..091890edca96 100644 ---- a/tools/xenstore/xenstored_watch.h -+++ b/tools/xenstore/xenstored_watch.h -@@ -21,8 +21,10 @@ - - #include "xenstored_core.h" - --int do_watch(struct connection *conn, struct buffered_data *in); --int do_unwatch(struct connection *conn, struct buffered_data *in); -+int do_watch(const void *ctx, struct connection *conn, -+ struct buffered_data *in); -+int do_unwatch(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* Fire all watches: !exact means all the children are affected (ie. rm). */ - void fire_watches(struct connection *conn, const void *tmp, const char *name, diff --git a/xsa417.patch b/xsa417.patch deleted file mode 100644 index 3f10bf7..0000000 --- a/xsa417.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 67d5ecd609b8f12346eadb40e547cd7e01d825dc Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: fix checking node permissions - -Today chk_domain_generation() is being used to check whether a node -permission entry is still valid or whether it is referring to a domain -no longer existing. This is done by comparing the node's and the -domain's generation count. - -In case no struct domain is existing for a checked domain, but the -domain itself is valid, chk_domain_generation() assumes it is being -called due to the first node created for a new domain and it will -return success. - -This might be wrong in case the checked permission is related to an -old domain, which has just been replaced with a new domain using the -same domid. - -Fix that by letting chk_domain_generation() fail in case a struct -domain isn't found. In order to cover the case of the first node for -a new domain try to allocate the needed struct domain explicitly when -processing the related SET_PERMS command. In case a referenced domain -isn't existing, flag the related permission to be ignored right away. - -This is XSA-417 / CVE-2022-42320. - -Reported-by: Juergen Gross -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 66bbeaf6bfb0..a0c176fa203e 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1753,6 +1753,11 @@ static int do_set_perms(const void *ctx, struct connection *conn, - if (!xs_strings_to_perms(perms.p, perms.num, permstr)) - return errno; - -+ if (domain_alloc_permrefs(&perms) < 0) -+ return ENOMEM; -+ if (perms.p[0].perms & XS_PERM_IGNORE) -+ return ENOENT; -+ - /* First arg is node name. */ - if (strstarts(in->buffer, "@")) { - if (set_perms_special(conn, in->buffer, &perms)) -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index b9ff4ded8360..98b401fdec30 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -907,7 +907,6 @@ int domain_entry_inc(struct connection *conn, struct node *node) - * count (used for testing whether a node permission is older than a domain). - * - * Return values: -- * -1: error - * 0: domain has higher generation count (it is younger than a node with the - * given count), or domain isn't existing any longer - * 1: domain is older than the node -@@ -915,20 +914,38 @@ int domain_entry_inc(struct connection *conn, struct node *node) - static int chk_domain_generation(unsigned int domid, uint64_t gen) - { - struct domain *d; -- xc_dominfo_t dominfo; - - if (!xc_handle && domid == 0) - return 1; - - d = find_domain_struct(domid); -- if (d) -- return (d->generation <= gen) ? 1 : 0; - -- if (!get_domain_info(domid, &dominfo)) -- return 0; -+ return (d && d->generation <= gen) ? 1 : 0; -+} - -- d = alloc_domain(NULL, domid); -- return d ? 1 : -1; -+/* -+ * Allocate all missing struct domain referenced by a permission set. -+ * Any permission entries for not existing domains will be marked to be -+ * ignored. -+ */ -+int domain_alloc_permrefs(struct node_perms *perms) -+{ -+ unsigned int i, domid; -+ struct domain *d; -+ xc_dominfo_t dominfo; -+ -+ for (i = 0; i < perms->num; i++) { -+ domid = perms->p[i].id; -+ d = find_domain_struct(domid); -+ if (!d) { -+ if (!get_domain_info(domid, &dominfo)) -+ perms->p[i].perms |= XS_PERM_IGNORE; -+ else if (!alloc_domain(NULL, domid)) -+ return ENOMEM; -+ } -+ } -+ -+ return 0; - } - - /* -@@ -941,8 +958,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node) - int ret; - - ret = chk_domain_generation(node->perms.p[0].id, node->generation); -- if (ret < 0) -- return errno; - - /* If the owner doesn't exist any longer give it to priv domain. */ - if (!ret) { -@@ -959,8 +974,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node) - continue; - ret = chk_domain_generation(node->perms.p[i].id, - node->generation); -- if (ret < 0) -- return errno; - if (!ret) - node->perms.p[i].perms |= XS_PERM_IGNORE; - } -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 209442190911..7fe0a21d9e45 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -63,6 +63,7 @@ bool domain_is_unprivileged(struct connection *conn); - - /* Remove node permissions for no longer existing domains. */ - int domain_adjust_node_perms(struct connection *conn, struct node *node); -+int domain_alloc_permrefs(struct node_perms *perms); - - /* Quota manipulation */ - int domain_entry_inc(struct connection *conn, struct node *); diff --git a/xsa418-4.16-01.patch b/xsa418-4.16-01.patch deleted file mode 100644 index c4a17b4..0000000 --- a/xsa418-4.16-01.patch +++ /dev/null @@ -1,119 +0,0 @@ -From d1e6dca486599ab914af7b38b3782b237d3d603b Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:11 +0200 -Subject: tools/xenstore: remove recursion from construct_node() - -In order to reduce stack usage due to recursion, switch -construct_node() to use a loop instead. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index c676ee4e4e4f..3907c35643e9 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1377,45 +1377,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name) - static struct node *construct_node(struct connection *conn, const void *ctx, - const char *name) - { -- struct node *parent, *node; -- char *parentname = get_parent(ctx, name); -+ const char **names = NULL; -+ unsigned int levels = 0; -+ struct node *node = NULL; -+ struct node *parent = NULL; -+ const char *parentname = talloc_strdup(ctx, name); - - if (!parentname) - return NULL; - -- /* If parent doesn't exist, create it. */ -- parent = read_node(conn, parentname, parentname); -- if (!parent && errno == ENOENT) -- parent = construct_node(conn, ctx, parentname); -- if (!parent) -- return NULL; -+ /* Walk the path up until an existing node is found. */ -+ while (!parent) { -+ names = talloc_realloc(ctx, names, const char *, levels + 1); -+ if (!names) -+ goto nomem; - -- /* Add child to parent. */ -- if (add_child(ctx, parent, name)) -- goto nomem; -+ /* -+ * names[0] is the name of the node to construct initially, -+ * names[1] is its parent, and so on. -+ */ -+ names[levels] = parentname; -+ parentname = get_parent(ctx, parentname); -+ if (!parentname) -+ return NULL; - -- /* Allocate node */ -- node = talloc(ctx, struct node); -- if (!node) -- goto nomem; -- node->name = talloc_strdup(node, name); -- if (!node->name) -- goto nomem; -+ /* Try to read parent node until we found an existing one. */ -+ parent = read_node(conn, ctx, parentname); -+ if (!parent && (errno != ENOENT || !strcmp(parentname, "/"))) -+ return NULL; - -- /* Inherit permissions, except unprivileged domains own what they create */ -- node->perms.num = parent->perms.num; -- node->perms.p = talloc_memdup(node, parent->perms.p, -- node->perms.num * sizeof(*node->perms.p)); -- if (!node->perms.p) -- goto nomem; -- if (domain_is_unprivileged(conn)) -- node->perms.p[0].id = conn->id; -+ levels++; -+ } -+ -+ /* Walk the path down again constructing the missing nodes. */ -+ for (; levels > 0; levels--) { -+ /* Add child to parent. */ -+ if (add_child(ctx, parent, names[levels - 1])) -+ goto nomem; -+ -+ /* Allocate node */ -+ node = talloc(ctx, struct node); -+ if (!node) -+ goto nomem; -+ node->name = talloc_steal(node, names[levels - 1]); -+ -+ /* Inherit permissions, unpriv domains own what they create. */ -+ node->perms.num = parent->perms.num; -+ node->perms.p = talloc_memdup(node, parent->perms.p, -+ node->perms.num * -+ sizeof(*node->perms.p)); -+ if (!node->perms.p) -+ goto nomem; -+ if (domain_is_unprivileged(conn)) -+ node->perms.p[0].id = conn->id; -+ -+ /* No children, no data */ -+ node->children = node->data = NULL; -+ node->childlen = node->datalen = 0; -+ node->acc.memory = 0; -+ node->parent = parent; -+ -+ parent = node; -+ } - -- /* No children, no data */ -- node->children = node->data = NULL; -- node->childlen = node->datalen = 0; -- node->acc.memory = 0; -- node->parent = parent; - return node; - - nomem: diff --git a/xsa418-4.16-02.patch b/xsa418-4.16-02.patch deleted file mode 100644 index 874bab2..0000000 --- a/xsa418-4.16-02.patch +++ /dev/null @@ -1,103 +0,0 @@ -From c13d85a2fe94bbf3cb8186b89324c5d1b4f9a61f Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:11 +0200 -Subject: tools/xenstore: don't let remove_child_entry() call corrupt() - -In case of write_node() returning an error, remove_child_entry() will -call corrupt() today. This could result in an endless recursion, as -remove_child_entry() is called by corrupt(), too: - -corrupt() - check_store() - check_store_() - remove_child_entry() - -Fix that by letting remove_child_entry() return an error instead and -let the caller decide what to do. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 3907c35643e9..f433a45dc217 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1608,15 +1608,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total) - memmove(mem + off, mem + off + len, total - off - len); - } - --static void remove_child_entry(struct connection *conn, struct node *node, -- size_t offset) -+static int remove_child_entry(struct connection *conn, struct node *node, -+ size_t offset) - { - size_t childlen = strlen(node->children + offset); - - memdel(node->children, offset, childlen + 1, node->childlen); - node->childlen -= childlen + 1; -- if (write_node(conn, node, true)) -- corrupt(conn, "Can't update parent node '%s'", node->name); -+ -+ return write_node(conn, node, true); - } - - static void delete_child(struct connection *conn, -@@ -1626,7 +1626,9 @@ static void delete_child(struct connection *conn, - - for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) { - if (streq(node->children+i, childname)) { -- remove_child_entry(conn, node, i); -+ if (remove_child_entry(conn, node, i)) -+ corrupt(conn, "Can't update parent node '%s'", -+ node->name); - return; - } - } -@@ -2325,6 +2327,17 @@ int remember_string(struct hashtable *hash, const char *str) - return hashtable_insert(hash, k, (void *)1); - } - -+static int rm_child_entry(struct node *node, size_t off, size_t len) -+{ -+ if (!recovery) -+ return off; -+ -+ if (remove_child_entry(NULL, node, off)) -+ log("check_store: child entry could not be removed from '%s'", -+ node->name); -+ -+ return off - len - 1; -+} - - /** - * A node has a children field that names the children of the node, separated -@@ -2377,12 +2390,7 @@ static int check_store_(const char *name, struct hashtable *reachable) - if (hashtable_search(children, childname)) { - log("check_store: '%s' is duplicated!", - childname); -- -- if (recovery) { -- remove_child_entry(NULL, node, -- i); -- i -= childlen + 1; -- } -+ i = rm_child_entry(node, i, childlen); - } - else { - if (!remember_string(children, -@@ -2399,11 +2407,7 @@ static int check_store_(const char *name, struct hashtable *reachable) - } else if (errno != ENOMEM) { - log("check_store: No child '%s' found!\n", - childname); -- -- if (recovery) { -- remove_child_entry(NULL, node, i); -- i -= childlen + 1; -- } -+ i = rm_child_entry(node, i, childlen); - } else { - log("check_store: ENOMEM"); - ret = ENOMEM; diff --git a/xsa418-4.16-03.patch b/xsa418-4.16-03.patch deleted file mode 100644 index 321ccf0..0000000 --- a/xsa418-4.16-03.patch +++ /dev/null @@ -1,243 +0,0 @@ -From aac9b51b6fbbbd16c910f69365345528c5bec106 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:11 +0200 -Subject: tools/xenstore: add generic treewalk function - -Add a generic function to walk the complete node tree. It will start -at "/" and descend recursively into each child, calling a function -specified by the caller. Depending on the return value of the user -specified function the walk will be aborted, continued, or the current -child will be skipped by not descending into its children. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index f433a45dc217..2cda3ee375ab 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1838,6 +1838,135 @@ static int do_set_perms(const void *ctx, struct connection *conn, - return 0; - } - -+static char *child_name(const void *ctx, const char *s1, const char *s2) -+{ -+ if (strcmp(s1, "/")) -+ return talloc_asprintf(ctx, "%s/%s", s1, s2); -+ return talloc_asprintf(ctx, "/%s", s2); -+} -+ -+static int rm_from_parent(struct connection *conn, struct node *parent, -+ const char *name) -+{ -+ size_t off; -+ -+ if (!parent) -+ return WALK_TREE_ERROR_STOP; -+ -+ for (off = parent->childoff - 1; off && parent->children[off - 1]; -+ off--); -+ if (remove_child_entry(conn, parent, off)) { -+ log("treewalk: child entry could not be removed from '%s'", -+ parent->name); -+ return WALK_TREE_ERROR_STOP; -+ } -+ parent->childoff = off; -+ -+ return WALK_TREE_OK; -+} -+ -+static int walk_call_func(const void *ctx, struct connection *conn, -+ struct node *node, struct node *parent, void *arg, -+ int (*func)(const void *ctx, struct connection *conn, -+ struct node *node, void *arg)) -+{ -+ int ret; -+ -+ if (!func) -+ return WALK_TREE_OK; -+ -+ ret = func(ctx, conn, node, arg); -+ if (ret == WALK_TREE_RM_CHILDENTRY && parent) -+ ret = rm_from_parent(conn, parent, node->name); -+ -+ return ret; -+} -+ -+int walk_node_tree(const void *ctx, struct connection *conn, const char *root, -+ struct walk_funcs *funcs, void *arg) -+{ -+ int ret = 0; -+ void *tmpctx; -+ char *name; -+ struct node *node = NULL; -+ struct node *parent = NULL; -+ -+ tmpctx = talloc_new(ctx); -+ if (!tmpctx) { -+ errno = ENOMEM; -+ return WALK_TREE_ERROR_STOP; -+ } -+ name = talloc_strdup(tmpctx, root); -+ if (!name) { -+ errno = ENOMEM; -+ talloc_free(tmpctx); -+ return WALK_TREE_ERROR_STOP; -+ } -+ -+ /* Continue the walk until an error is returned. */ -+ while (ret >= 0) { -+ /* node == NULL possible only for the initial loop iteration. */ -+ if (node) { -+ /* Go one step up if ret or if last child finished. */ -+ if (ret || node->childoff >= node->childlen) { -+ parent = node->parent; -+ /* Call function AFTER processing a node. */ -+ ret = walk_call_func(ctx, conn, node, parent, -+ arg, funcs->exit); -+ /* Last node, so exit loop. */ -+ if (!parent) -+ break; -+ talloc_free(node); -+ /* Continue with parent. */ -+ node = parent; -+ continue; -+ } -+ /* Get next child of current node. */ -+ name = child_name(tmpctx, node->name, -+ node->children + node->childoff); -+ if (!name) { -+ ret = WALK_TREE_ERROR_STOP; -+ break; -+ } -+ /* Point to next child. */ -+ node->childoff += strlen(node->children + -+ node->childoff) + 1; -+ /* Descent into children. */ -+ parent = node; -+ } -+ /* Read next node (root node or next child). */ -+ node = read_node(conn, tmpctx, name); -+ if (!node) { -+ /* Child not found - should not happen! */ -+ /* ENOENT case can be handled by supplied function. */ -+ if (errno == ENOENT && funcs->enoent) -+ ret = funcs->enoent(ctx, conn, parent, name, -+ arg); -+ else -+ ret = WALK_TREE_ERROR_STOP; -+ if (!parent) -+ break; -+ if (ret == WALK_TREE_RM_CHILDENTRY) -+ ret = rm_from_parent(conn, parent, name); -+ if (ret < 0) -+ break; -+ talloc_free(name); -+ node = parent; -+ continue; -+ } -+ talloc_free(name); -+ node->parent = parent; -+ node->childoff = 0; -+ /* Call function BEFORE processing a node. */ -+ ret = walk_call_func(ctx, conn, node, parent, arg, -+ funcs->enter); -+ } -+ -+ talloc_free(tmpctx); -+ -+ return ret < 0 ? ret : WALK_TREE_OK; -+} -+ - static struct { - const char *str; - int (*func)(const void *ctx, struct connection *conn, -@@ -2305,18 +2434,6 @@ static int keys_equal_fn(void *key1, void *key2) - return 0 == strcmp((char *)key1, (char *)key2); - } - -- --static char *child_name(const char *s1, const char *s2) --{ -- if (strcmp(s1, "/")) { -- return talloc_asprintf(NULL, "%s/%s", s1, s2); -- } -- else { -- return talloc_asprintf(NULL, "/%s", s2); -- } --} -- -- - int remember_string(struct hashtable *hash, const char *str) - { - char *k = malloc(strlen(str) + 1); -@@ -2376,7 +2493,7 @@ static int check_store_(const char *name, struct hashtable *reachable) - while (i < node->childlen && !ret) { - struct node *childnode; - size_t childlen = strlen(node->children + i); -- char * childname = child_name(node->name, -+ char * childname = child_name(NULL, node->name, - node->children + i); - - if (!childname) { -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index bfd3fc1e9df3..2d9942171d92 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -202,6 +202,7 @@ struct node { - - /* Children, each nul-terminated. */ - unsigned int childlen; -+ unsigned int childoff; /* Used by walk_node_tree() internally. */ - char *children; - - /* Allocation information for node currently in store. */ -@@ -338,6 +339,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn, - const struct xs_state_connection *sc); - void read_state_node(const void *ctx, const void *state); - -+/* -+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for -+ * each node. funcs->enter() is being called when entering a node, so before -+ * any of the children of the node is processed. funcs->exit() is being -+ * called when leaving the node, so after all children have been processed. -+ * funcs->enoent() is being called when a node isn't existing. -+ * funcs->*() return values: -+ * < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value -+ * in case WALK_TREE_ERROR_STOP is returned, errno should be set -+ * WALK_TREE_OK: tree walk is continuing -+ * WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but -+ * walk continues -+ * WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write -+ * the modified parent node back to the data base, implies to not descend -+ * below the current node, but to continue the walk -+ * funcs->*() is allowed to modify the node it is called for in the data base. -+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK -+ * in order to avoid descending into no longer existing children. -+ */ -+/* Return values for funcs->*() and walk_node_tree(). */ -+#define WALK_TREE_SUCCESS_STOP -100 /* Stop walk early, no error. */ -+#define WALK_TREE_ERROR_STOP -1 /* Stop walk due to error. */ -+#define WALK_TREE_OK 0 /* No error. */ -+/* Return value for funcs->*() only. */ -+#define WALK_TREE_SKIP_CHILDREN 1 /* Don't recurse below current node. */ -+#define WALK_TREE_RM_CHILDENTRY 2 /* Remove child entry from parent. */ -+ -+struct walk_funcs { -+ int (*enter)(const void *ctx, struct connection *conn, -+ struct node *node, void *arg); -+ int (*exit)(const void *ctx, struct connection *conn, -+ struct node *node, void *arg); -+ int (*enoent)(const void *ctx, struct connection *conn, -+ struct node *parent, char *name, void *arg); -+}; -+ -+int walk_node_tree(const void *ctx, struct connection *conn, const char *root, -+ struct walk_funcs *funcs, void *arg); -+ - #endif /* _XENSTORED_CORE_H */ - - /* diff --git a/xsa418-4.16-04.patch b/xsa418-4.16-04.patch deleted file mode 100644 index 95de88f..0000000 --- a/xsa418-4.16-04.patch +++ /dev/null @@ -1,108 +0,0 @@ -From bdc931fb5dcebbd8d0e44b5d8bd3fb9106ee8596 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: simplify check_store() - -check_store() is using a hash table for storing all node names it has -found via walking the tree. Additionally it using another hash table -for all children of a node to detect duplicate child names. - -Simplify that by dropping the second hash table as the first one is -already holding all the needed information. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 2cda3ee375ab..760f3c16c794 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2477,50 +2477,34 @@ static int check_store_(const char *name, struct hashtable *reachable) - if (node) { - size_t i = 0; - -- struct hashtable * children = -- create_hashtable(16, hash_from_key_fn, keys_equal_fn); -- if (!children) { -- log("check_store create table: ENOMEM"); -- return ENOMEM; -- } -- - if (!remember_string(reachable, name)) { -- hashtable_destroy(children, 0); - log("check_store: ENOMEM"); - return ENOMEM; - } - - while (i < node->childlen && !ret) { -- struct node *childnode; -+ struct node *childnode = NULL; - size_t childlen = strlen(node->children + i); -- char * childname = child_name(NULL, node->name, -- node->children + i); -+ char *childname = child_name(NULL, node->name, -+ node->children + i); - - if (!childname) { - log("check_store: ENOMEM"); - ret = ENOMEM; - break; - } -+ -+ if (hashtable_search(reachable, childname)) { -+ log("check_store: '%s' is duplicated!", -+ childname); -+ i = rm_child_entry(node, i, childlen); -+ goto next; -+ } -+ - childnode = read_node(NULL, childname, childname); -- -+ - if (childnode) { -- if (hashtable_search(children, childname)) { -- log("check_store: '%s' is duplicated!", -- childname); -- i = rm_child_entry(node, i, childlen); -- } -- else { -- if (!remember_string(children, -- childname)) { -- log("check_store: ENOMEM"); -- talloc_free(childnode); -- talloc_free(childname); -- ret = ENOMEM; -- break; -- } -- ret = check_store_(childname, -- reachable); -- } -+ ret = check_store_(childname, reachable); - } else if (errno != ENOMEM) { - log("check_store: No child '%s' found!\n", - childname); -@@ -2530,19 +2514,18 @@ static int check_store_(const char *name, struct hashtable *reachable) - ret = ENOMEM; - } - -+ next: - talloc_free(childnode); - talloc_free(childname); - i += childlen + 1; - } - -- hashtable_destroy(children, 0 /* Don't free values (they are -- all (void *)1) */); - talloc_free(node); - } else if (errno != ENOMEM) { - /* Impossible, because no database should ever be without the - root, and otherwise, we've just checked in our caller - (which made a recursive call to get here). */ -- -+ - log("check_store: No child '%s' found: impossible!", name); - } else { - log("check_store: ENOMEM"); diff --git a/xsa418-4.16-05.patch b/xsa418-4.16-05.patch deleted file mode 100644 index fca551e..0000000 --- a/xsa418-4.16-05.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 27817f0a7d6802be04e8f43a0900b02f881b28b2 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: use treewalk for check_store() - -Instead of doing an open tree walk using call recursion, use -walk_node_tree() when checking the store for inconsistencies. - -This will reduce code size and avoid many nesting levels of function -calls which could potentially exhaust the stack. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 760f3c16c794..efdd1888fd78 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2444,18 +2444,6 @@ int remember_string(struct hashtable *hash, const char *str) - return hashtable_insert(hash, k, (void *)1); - } - --static int rm_child_entry(struct node *node, size_t off, size_t len) --{ -- if (!recovery) -- return off; -- -- if (remove_child_entry(NULL, node, off)) -- log("check_store: child entry could not be removed from '%s'", -- node->name); -- -- return off - len - 1; --} -- - /** - * A node has a children field that names the children of the node, separated - * by NULs. We check whether there are entries in there that are duplicated -@@ -2469,70 +2457,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len) - * As we go, we record each node in the given reachable hashtable. These - * entries will be used later in clean_store. - */ --static int check_store_(const char *name, struct hashtable *reachable) -+static int check_store_step(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) - { -- struct node *node = read_node(NULL, name, name); -- int ret = 0; -- -- if (node) { -- size_t i = 0; -- -- if (!remember_string(reachable, name)) { -- log("check_store: ENOMEM"); -- return ENOMEM; -- } -- -- while (i < node->childlen && !ret) { -- struct node *childnode = NULL; -- size_t childlen = strlen(node->children + i); -- char *childname = child_name(NULL, node->name, -- node->children + i); -- -- if (!childname) { -- log("check_store: ENOMEM"); -- ret = ENOMEM; -- break; -- } -+ struct hashtable *reachable = arg; - -- if (hashtable_search(reachable, childname)) { -- log("check_store: '%s' is duplicated!", -- childname); -- i = rm_child_entry(node, i, childlen); -- goto next; -- } -- -- childnode = read_node(NULL, childname, childname); -- -- if (childnode) { -- ret = check_store_(childname, reachable); -- } else if (errno != ENOMEM) { -- log("check_store: No child '%s' found!\n", -- childname); -- i = rm_child_entry(node, i, childlen); -- } else { -- log("check_store: ENOMEM"); -- ret = ENOMEM; -- } -+ if (hashtable_search(reachable, (void *)node->name)) { -+ log("check_store: '%s' is duplicated!", node->name); -+ return recovery ? WALK_TREE_RM_CHILDENTRY -+ : WALK_TREE_SKIP_CHILDREN; -+ } - -- next: -- talloc_free(childnode); -- talloc_free(childname); -- i += childlen + 1; -- } -+ if (!remember_string(reachable, node->name)) -+ return WALK_TREE_ERROR_STOP; - -- talloc_free(node); -- } else if (errno != ENOMEM) { -- /* Impossible, because no database should ever be without the -- root, and otherwise, we've just checked in our caller -- (which made a recursive call to get here). */ -+ return WALK_TREE_OK; -+} - -- log("check_store: No child '%s' found: impossible!", name); -- } else { -- log("check_store: ENOMEM"); -- ret = ENOMEM; -- } -+static int check_store_enoent(const void *ctx, struct connection *conn, -+ struct node *parent, char *name, void *arg) -+{ -+ log("check_store: node '%s' not found", name); - -- return ret; -+ return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK; - } - - -@@ -2581,24 +2528,28 @@ static void clean_store(struct hashtable *reachable) - - void check_store(void) - { -- char * root = talloc_strdup(NULL, "/"); -- struct hashtable * reachable = -- create_hashtable(16, hash_from_key_fn, keys_equal_fn); -- -+ struct hashtable *reachable; -+ struct walk_funcs walkfuncs = { -+ .enter = check_store_step, -+ .enoent = check_store_enoent, -+ }; -+ -+ reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn); - if (!reachable) { - log("check_store: ENOMEM"); - return; - } - - log("Checking store ..."); -- if (!check_store_(root, reachable) && -- !check_transactions(reachable)) -+ if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) { -+ if (errno == ENOMEM) -+ log("check_store: ENOMEM"); -+ } else if (!check_transactions(reachable)) - clean_store(reachable); - log("Checking store complete."); - - hashtable_destroy(reachable, 0 /* Don't free values (they are all - (void *)1) */); -- talloc_free(root); - } - - diff --git a/xsa418-4.16-06.patch b/xsa418-4.16-06.patch deleted file mode 100644 index d46c057..0000000 --- a/xsa418-4.16-06.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 6ea0ffbd88b11f23779d763501ec1370b590bb2a Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: use treewalk for deleting nodes - -Instead of doing an open tree walk using call recursion, use -walk_node_tree() when deleting a sub-tree of nodes. - -This will reduce code size and avoid many nesting levels of function -calls which could potentially exhaust the stack. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index efdd1888fd78..58fb651542ec 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1334,21 +1334,6 @@ static int do_read(const void *ctx, struct connection *conn, - return 0; - } - --static void delete_node_single(struct connection *conn, struct node *node) --{ -- TDB_DATA key; -- -- if (access_node(conn, node, NODE_ACCESS_DELETE, &key)) -- return; -- -- if (do_tdb_delete(conn, &key, &node->acc) != 0) { -- corrupt(conn, "Could not delete '%s'", node->name); -- return; -- } -- -- domain_entry_dec(conn, node); --} -- - /* Must not be / */ - static char *basename(const char *name) - { -@@ -1619,69 +1604,59 @@ static int remove_child_entry(struct connection *conn, struct node *node, - return write_node(conn, node, true); - } - --static void delete_child(struct connection *conn, -- struct node *node, const char *childname) -+static int delete_child(struct connection *conn, -+ struct node *node, const char *childname) - { - unsigned int i; - - for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) { - if (streq(node->children+i, childname)) { -- if (remove_child_entry(conn, node, i)) -- corrupt(conn, "Can't update parent node '%s'", -- node->name); -- return; -+ errno = remove_child_entry(conn, node, i) ? EIO : 0; -+ return errno; - } - } - corrupt(conn, "Can't find child '%s' in %s", childname, node->name); -+ -+ errno = EIO; -+ return errno; - } - --static int delete_node(struct connection *conn, const void *ctx, -- struct node *parent, struct node *node, bool watch_exact) -+static int delnode_sub(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) - { -- char *name; -+ const char *root = arg; -+ bool watch_exact; -+ int ret; -+ TDB_DATA key; - -- /* Delete children. */ -- while (node->childlen) { -- struct node *child; -+ /* Any error here will probably be repeated for all following calls. */ -+ ret = access_node(conn, node, NODE_ACCESS_DELETE, &key); -+ if (ret > 0) -+ return WALK_TREE_SUCCESS_STOP; - -- name = talloc_asprintf(node, "%s/%s", node->name, -- node->children); -- child = name ? read_node(conn, node, name) : NULL; -- if (child) { -- if (delete_node(conn, ctx, node, child, true)) -- return errno; -- } else { -- trace("delete_node: Error deleting child '%s/%s'!\n", -- node->name, node->children); -- /* Quit deleting. */ -- errno = ENOMEM; -- return errno; -- } -- talloc_free(name); -- } -+ /* In case of error stop the walk. */ -+ if (!ret && do_tdb_delete(conn, &key, &node->acc)) -+ return WALK_TREE_SUCCESS_STOP; - - /* - * Fire the watches now, when we can still see the node permissions. - * This fine as we are single threaded and the next possible read will - * be handled only after the node has been really removed. -- */ -+ */ -+ watch_exact = strcmp(root, node->name); - fire_watches(conn, ctx, node->name, node, watch_exact, NULL); -- delete_node_single(conn, node); -- delete_child(conn, parent, basename(node->name)); -- talloc_free(node); - -- return 0; -+ domain_entry_dec(conn, node); -+ -+ return WALK_TREE_RM_CHILDENTRY; - } - --static int _rm(struct connection *conn, const void *ctx, struct node *node, -- const char *name) -+static int _rm(struct connection *conn, const void *ctx, const char *name) - { -- /* -- * Deleting node by node, so the result is always consistent even in -- * case of a failure. -- */ - struct node *parent; - char *parentname = get_parent(ctx, name); -+ struct walk_funcs walkfuncs = { .exit = delnode_sub }; -+ int ret; - - if (!parentname) - return errno; -@@ -1689,9 +1664,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - parent = read_node(conn, ctx, parentname); - if (!parent) - return read_node_can_propagate_errno() ? errno : EINVAL; -- node->parent = parent; - -- return delete_node(conn, ctx, parent, node, false); -+ ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name); -+ if (ret < 0) { -+ if (ret == WALK_TREE_ERROR_STOP) { -+ corrupt(conn, "error when deleting sub-nodes of %s\n", -+ name); -+ errno = EIO; -+ } -+ return errno; -+ } -+ -+ if (delete_child(conn, parent, basename(name))) -+ return errno; -+ -+ return 0; - } - - -@@ -1728,7 +1715,7 @@ static int do_rm(const void *ctx, struct connection *conn, - if (streq(name, "/")) - return EINVAL; - -- ret = _rm(conn, ctx, node, name); -+ ret = _rm(conn, ctx, name); - if (ret) - return ret; - diff --git a/xsa418-4.16-07.patch b/xsa418-4.16-07.patch deleted file mode 100644 index 9600d8c..0000000 --- a/xsa418-4.16-07.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 1ee281b18b52bec87335ea64ee74cc159e63d036 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: use treewalk for creating node records - -Instead of doing an open tree walk using call recursion, use -walk_node_tree() when creating the node records during a live update. - -This will reduce code size and avoid many nesting levels of function -calls which could potentially exhaust the stack. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 58fb651542ec..05d349778bb4 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -3120,101 +3120,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms, - return NULL; - } - --static const char *dump_state_node_tree(FILE *fp, char *path, -- unsigned int path_max_len) -+struct dump_node_data { -+ FILE *fp; -+ const char *err; -+}; -+ -+static int dump_state_node_err(struct dump_node_data *data, const char *err) - { -- unsigned int pathlen, childlen, p = 0; -+ data->err = err; -+ return WALK_TREE_ERROR_STOP; -+} -+ -+static int dump_state_node(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) -+{ -+ struct dump_node_data *data = arg; -+ FILE *fp = data->fp; -+ unsigned int pathlen; - struct xs_state_record_header head; - struct xs_state_node sn; -- TDB_DATA key, data; -- const struct xs_tdb_record_hdr *hdr; -- const char *child; - const char *ret; - -- pathlen = strlen(path) + 1; -- -- set_tdb_key(path, &key); -- data = tdb_fetch(tdb_ctx, key); -- if (data.dptr == NULL) -- return "Error reading node"; -- -- /* Clean up in case of failure. */ -- talloc_steal(path, data.dptr); -- -- hdr = (void *)data.dptr; -+ pathlen = strlen(node->name) + 1; - - head.type = XS_STATE_TYPE_NODE; - head.length = sizeof(sn); - sn.conn_id = 0; - sn.ta_id = 0; - sn.ta_access = 0; -- sn.perm_n = hdr->num_perms; -+ sn.perm_n = node->perms.num; - sn.path_len = pathlen; -- sn.data_len = hdr->datalen; -- head.length += hdr->num_perms * sizeof(*sn.perms); -+ sn.data_len = node->datalen; -+ head.length += node->perms.num * sizeof(*sn.perms); - head.length += pathlen; -- head.length += hdr->datalen; -+ head.length += node->datalen; - head.length = ROUNDUP(head.length, 3); - - if (fwrite(&head, sizeof(head), 1, fp) != 1) -- return "Dump node state error"; -+ return dump_state_node_err(data, "Dump node head error"); - if (fwrite(&sn, sizeof(sn), 1, fp) != 1) -- return "Dump node state error"; -+ return dump_state_node_err(data, "Dump node state error"); - -- ret = dump_state_node_perms(fp, hdr->perms, hdr->num_perms); -+ ret = dump_state_node_perms(fp, node->perms.p, node->perms.num); - if (ret) -- return ret; -+ return dump_state_node_err(data, ret); -+ -+ if (fwrite(node->name, pathlen, 1, fp) != 1) -+ return dump_state_node_err(data, "Dump node path error"); - -- if (fwrite(path, pathlen, 1, fp) != 1) -- return "Dump node path error"; -- if (hdr->datalen && -- fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1) -- return "Dump node data error"; -+ if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1) -+ return dump_state_node_err(data, "Dump node data error"); - - ret = dump_state_align(fp); - if (ret) -- return ret; -+ return dump_state_node_err(data, ret); - -- child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen; -- -- /* -- * Use path for constructing children paths. -- * As we don't write out nodes without having written their parent -- * already we will never clobber a part of the path we'll need later. -- */ -- pathlen--; -- if (path[pathlen - 1] != '/') { -- path[pathlen] = '/'; -- pathlen++; -- } -- while (p < hdr->childlen) { -- childlen = strlen(child) + 1; -- if (pathlen + childlen > path_max_len) -- return "Dump node path length error"; -- strcpy(path + pathlen, child); -- ret = dump_state_node_tree(fp, path, path_max_len); -- if (ret) -- return ret; -- p += childlen; -- child += childlen; -- } -- -- talloc_free(data.dptr); -- -- return NULL; -+ return WALK_TREE_OK; - } - - const char *dump_state_nodes(FILE *fp, const void *ctx) - { -- char *path; -- -- path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX + 1); -- if (!path) -- return "Path buffer allocation error"; -+ struct dump_node_data data = { -+ .fp = fp, -+ .err = "Dump node walk error" -+ }; -+ struct walk_funcs walkfuncs = { .enter = dump_state_node }; - -- strcpy(path, "/"); -+ if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data)) -+ return data.err; - -- return dump_state_node_tree(fp, path, XENSTORE_ABS_PATH_MAX + 1); -+ return NULL; - } - - void read_state_global(const void *ctx, const void *state) diff --git a/xsa419-oxenstored.patch b/xsa419-oxenstored.patch deleted file mode 100644 index 0ac365d..0000000 --- a/xsa419-oxenstored.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 09228369a549427294febe351372d7227e624da1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:06 +0100 -Subject: tools/ocaml/xenstored: Fix quota bypass on domain shutdown -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of -any nodes left after a domain is shutdown (e.g. outside its /local/domain/N -tree). - -However Dom0 has no quota on purpose, so this opened up another potential -attack vector. Avoid it by deleting these nodes instead of assigning them to -Dom0. - -This is part of XSA-419 / CVE-2022-42323. - -Reported-by: Juergen Gross -Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains") -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml -index e8a16221f8fa..84f2503e8e29 100644 ---- a/tools/ocaml/xenstored/perms.ml -+++ b/tools/ocaml/xenstored/perms.ml -@@ -64,8 +64,7 @@ let get_owner perm = perm.owner - * *) - let remove_domid ~domid perm = - let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in -- let owner = if perm.owner = domid then 0 else perm.owner in -- { perm with acl; owner } -+ if perm.owner = domid then None else Some { perm with acl; owner = perm.owner } - - let default0 = create 0 NONE [] - -diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml -index 20e67b142746..70f0c83de404 100644 ---- a/tools/ocaml/xenstored/store.ml -+++ b/tools/ocaml/xenstored/store.ml -@@ -87,10 +87,21 @@ let check_owner node connection = - - let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children - --(** [recurse_map f tree] applies [f] on each node in the tree recursively *) --let recurse_map f = -+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively, -+ possibly removing some nodes. -+ Note that the nodes removed this way won't generate watch events. -+*) -+let recurse_filter_map f = -+ let invalid = -1 in -+ let is_valid _ node = node.perms.owner <> invalid in - let rec walk node = -- f { node with children = SymbolMap.map walk node.children } -+ (* Map.filter_map is Ocaml 4.11+ only *) -+ let node = -+ { node with children = -+ SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in -+ match f node with -+ | Some keep -> keep -+ | None -> { node with perms = {node.perms with owner = invalid } } - in - walk - -@@ -444,11 +455,13 @@ let setperms store perm path nperms = - - let reset_permissions store domid = - Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid; -- store.root <- Node.recurse_map (fun node -> -- let perms = Perms.Node.remove_domid ~domid node.perms in -- if perms <> node.perms then -- Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); -- { node with perms } -+ store.root <- Node.recurse_filter_map (fun node -> -+ match Perms.Node.remove_domid ~domid node.perms with -+ | None -> None -+ | Some perms -> -+ if perms <> node.perms then -+ Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); -+ Some { node with perms } - ) store.root - - type ops = { diff --git a/xsa419-xenstored-01.patch b/xsa419-xenstored-01.patch deleted file mode 100644 index 3409790..0000000 --- a/xsa419-xenstored-01.patch +++ /dev/null @@ -1,289 +0,0 @@ -From e4250bf8b39ed73623c75b0f1436ac7c1d45aba7 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: remove nodes owned by destroyed domain - -In case a domain is removed from Xenstore, remove all nodes owned by -it per default. - -This tackles the problem that nodes might be created by a domain -outside its home path in Xenstore, leading to Xenstore hogging more -and more memory. Domain quota don't work in this case if the guest is -rebooting in between. - -Since XSA-322 ownership of such stale nodes is transferred to dom0, -which is helping against unintended access, but not against OOM of -Xenstore. - -As a fallback for weird cases add a Xenstore start parameter for -keeping today's way to handle stale nodes, adding the risk of Xenstore -hitting an OOM situation. - -This is part of XSA-419 / CVE-2022-42322. - -Reported-by: Juergen Gross -Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains") -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index bdc14679adf5..13e48aaa731c 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -80,6 +80,7 @@ static bool verbose = false; - LIST_HEAD(connections); - int tracefd = -1; - static bool recovery = true; -+bool keep_orphans = false; - static int reopen_log_pipe[2]; - static int reopen_log_pipe0_pollfd_idx = -1; - char *tracefile = NULL; -@@ -753,7 +754,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - node->perms.p = hdr->perms; - node->acc.domid = node->perms.p[0].id; - node->acc.memory = data.dsize; -- if (domain_adjust_node_perms(conn, node)) -+ if (domain_adjust_node_perms(node)) - goto error; - - /* If owner is gone reset currently accounted memory size. */ -@@ -796,7 +797,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - void *p; - struct xs_tdb_record_hdr *hdr; - -- if (domain_adjust_node_perms(conn, node)) -+ if (domain_adjust_node_perms(node)) - return errno; - - data.dsize = sizeof(*hdr) -@@ -1647,7 +1648,7 @@ static int delnode_sub(const void *ctx, struct connection *conn, - return WALK_TREE_RM_CHILDENTRY; - } - --static int _rm(struct connection *conn, const void *ctx, const char *name) -+int rm_node(struct connection *conn, const void *ctx, const char *name) - { - struct node *parent; - char *parentname = get_parent(ctx, name); -@@ -1711,7 +1712,7 @@ static int do_rm(const void *ctx, struct connection *conn, - if (streq(name, "/")) - return EINVAL; - -- ret = _rm(conn, ctx, name); -+ ret = rm_node(conn, ctx, name); - if (ret) - return ret; - -@@ -2618,6 +2619,8 @@ static void usage(void) - " -R, --no-recovery to request that no recovery should be attempted when\n" - " the store is corrupted (debug only),\n" - " -I, --internal-db store database in memory, not on disk\n" -+" -K, --keep-orphans don't delete nodes owned by a domain when the\n" -+" domain is deleted (this is a security risk!)\n" - " -V, --verbose to request verbose execution.\n"); - } - -@@ -2642,6 +2645,7 @@ static struct option options[] = { - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, -+ { "keep-orphans", 0, NULL, 'K' }, - { "verbose", 0, NULL, 'V' }, - { "watch-nb", 1, NULL, 'W' }, - #ifndef NO_LIVE_UPDATE -@@ -2721,7 +2725,7 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U", -+ while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U", - options, NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2757,6 +2761,9 @@ int main(int argc, char *argv[]) - case 'I': - tdb_flags = TDB_INTERNAL|TDB_NOLOCK; - break; -+ case 'K': -+ keep_orphans = true; -+ break; - case 'V': - verbose = true; - break; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index acb00ad96914..37006d508dbf 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -240,6 +240,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - struct node *read_node(struct connection *conn, const void *ctx, - const char *name); - -+/* Remove a node and its children. */ -+int rm_node(struct connection *conn, const void *ctx, const char *name); -+ - void setup_structure(bool live_update); - struct connection *new_connection(const struct interface_funcs *funcs); - struct connection *get_connection_by_id(unsigned int conn_id); -@@ -284,6 +287,7 @@ extern int quota_req_outstanding; - extern int quota_trans_nodes; - extern int quota_memory_per_domain_soft; - extern int quota_memory_per_domain_hard; -+extern bool keep_orphans; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 98b401fdec30..84b7817cd5e6 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -227,10 +227,64 @@ static void unmap_interface(void *interface) - xengnttab_unmap(*xgt_handle, interface, 1); - } - -+static int domain_tree_remove_sub(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) -+{ -+ struct domain *domain = arg; -+ TDB_DATA key; -+ int ret = WALK_TREE_OK; -+ -+ if (node->perms.p[0].id != domain->domid) -+ return WALK_TREE_OK; -+ -+ if (keep_orphans) { -+ set_tdb_key(node->name, &key); -+ domain->nbentry--; -+ node->perms.p[0].id = priv_domid; -+ node->acc.memory = 0; -+ domain_entry_inc(NULL, node); -+ if (write_node_raw(NULL, &key, node, true)) { -+ /* That's unfortunate. We only can try to continue. */ -+ syslog(LOG_ERR, -+ "error when moving orphaned node %s to dom0\n", -+ node->name); -+ } else -+ trace("orphaned node %s moved to dom0\n", node->name); -+ } else { -+ if (rm_node(NULL, ctx, node->name)) { -+ /* That's unfortunate. We only can try to continue. */ -+ syslog(LOG_ERR, -+ "error when deleting orphaned node %s\n", -+ node->name); -+ } else -+ trace("orphaned node %s deleted\n", node->name); -+ -+ /* Skip children in all cases in order to avoid more errors. */ -+ ret = WALK_TREE_SKIP_CHILDREN; -+ } -+ -+ return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP; -+} -+ -+static void domain_tree_remove(struct domain *domain) -+{ -+ int ret; -+ struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub }; -+ -+ if (domain->nbentry > 0) { -+ ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain); -+ if (ret == WALK_TREE_ERROR_STOP) -+ syslog(LOG_ERR, -+ "error when looking for orphaned nodes\n"); -+ } -+} -+ - static int destroy_domain(void *_domain) - { - struct domain *domain = _domain; - -+ domain_tree_remove(domain); -+ - list_del(&domain->list); - - if (!domain->introduced) -@@ -883,15 +937,15 @@ int domain_entry_inc(struct connection *conn, struct node *node) - struct domain *d; - unsigned int domid; - -- if (!conn) -+ if (!node->perms.p) - return 0; - -- domid = node->perms.p ? node->perms.p[0].id : conn->id; -+ domid = node->perms.p[0].id; - -- if (conn->transaction) { -+ if (conn && conn->transaction) { - transaction_entry_inc(conn->transaction, domid); - } else { -- d = (domid == conn->id && conn->domain) ? conn->domain -+ d = (conn && domid == conn->id && conn->domain) ? conn->domain - : find_or_alloc_existing_domain(domid); - if (d) - d->nbentry++; -@@ -952,23 +1006,11 @@ int domain_alloc_permrefs(struct node_perms *perms) - * Remove permissions for no longer existing domains in order to avoid a new - * domain with the same domid inheriting the permissions. - */ --int domain_adjust_node_perms(struct connection *conn, struct node *node) -+int domain_adjust_node_perms(struct node *node) - { - unsigned int i; - int ret; - -- ret = chk_domain_generation(node->perms.p[0].id, node->generation); -- -- /* If the owner doesn't exist any longer give it to priv domain. */ -- if (!ret) { -- /* -- * In theory we'd need to update the number of dom0 nodes here, -- * but we could be called for a read of the node. So better -- * avoid the risk to overflow the node count of dom0. -- */ -- node->perms.p[0].id = priv_domid; -- } -- - for (i = 1; i < node->perms.num; i++) { - if (node->perms.p[i].perms & XS_PERM_IGNORE) - continue; -@@ -986,15 +1028,15 @@ void domain_entry_dec(struct connection *conn, struct node *node) - struct domain *d; - unsigned int domid; - -- if (!conn) -+ if (!node->perms.p) - return; - - domid = node->perms.p ? node->perms.p[0].id : conn->id; - -- if (conn->transaction) { -+ if (conn && conn->transaction) { - transaction_entry_dec(conn->transaction, domid); - } else { -- d = (domid == conn->id && conn->domain) ? conn->domain -+ d = (conn && domid == conn->id && conn->domain) ? conn->domain - : find_domain_struct(domid); - if (d) { - d->nbentry--; -@@ -1113,7 +1155,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check) - * exist, as accounting is done either for a domain related to - * the current connection, or for the domain owning a node - * (which is always existing, as the owner of the node is -- * tested to exist and replaced by domid 0 if not). -+ * tested to exist and deleted or replaced by domid 0 if not). - * So not finding the related domain MUST be an error in the - * data base. - */ -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 7fe0a21d9e45..b38c82991dc6 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -62,7 +62,7 @@ const char *get_implicit_path(const struct connection *conn); - bool domain_is_unprivileged(struct connection *conn); - - /* Remove node permissions for no longer existing domains. */ --int domain_adjust_node_perms(struct connection *conn, struct node *node); -+int domain_adjust_node_perms(struct node *node); - int domain_alloc_permrefs(struct node_perms *perms); - - /* Quota manipulation */ diff --git a/xsa419-xenstored-02.patch b/xsa419-xenstored-02.patch deleted file mode 100644 index e5d46a2..0000000 --- a/xsa419-xenstored-02.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 929da557efea6c7d2340467d9a7fdae7fda6d2b1 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:13 +0200 -Subject: tools/xenstore: make the internal memory data base the default - -Having a file backed data base has the only advantage of being capable -to dump the contents of it while Xenstore is running, and potentially -using less swap space in case the data base can't be kept in memory. - -It has the major disadvantage of a huge performance overhead: switching -to keep the data base in memory only speeds up live update of xenstored -with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk -of this configuration will be reduced from 7 seconds to 280 msecs -(measured by "xenstore-control check"). - -So make the internal memory data base the default and enhance the -"--internal-db" command line parameter to take an optional parameter -allowing to switch the internal data base back to the file based one. - -This is part of XSA-419. - -Reported-by: Juergen Gross -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c -index 2d9ab6f1c583..04e351ca29a8 100644 ---- a/tools/helpers/init-xenstore-domain.c -+++ b/tools/helpers/init-xenstore-domain.c -@@ -222,9 +222,9 @@ static int build(xc_interface *xch) - } - - if ( param ) -- snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param); -+ snprintf(cmdline, 512, "--event %d %s", rv, param); - else -- snprintf(cmdline, 512, "--event %d --internal-db", rv); -+ snprintf(cmdline, 512, "--event %d", rv); - - dom->guest_domid = domid; - dom->cmdline = xc_dom_strdup(dom, cmdline); -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 13e48aaa731c..36fb4a832834 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2308,7 +2308,7 @@ static void accept_connection(int sock) - } - #endif - --static int tdb_flags; -+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK; - - /* We create initial nodes manually. */ - static void manual_node(const char *name, const char *child) -@@ -2618,7 +2618,8 @@ static void usage(void) - " watch-event: time a watch-event is kept pending\n" - " -R, --no-recovery to request that no recovery should be attempted when\n" - " the store is corrupted (debug only),\n" --" -I, --internal-db store database in memory, not on disk\n" -+" -I, --internal-db [on|off] store database in memory, not on disk, default is\n" -+" memory, with \"--internal-db off\" it is on disk\n" - " -K, --keep-orphans don't delete nodes owned by a domain when the\n" - " domain is deleted (this is a security risk!)\n" - " -V, --verbose to request verbose execution.\n"); -@@ -2644,7 +2645,7 @@ static struct option options[] = { - { "quota-soft", 1, NULL, 'q' }, - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, -- { "internal-db", 0, NULL, 'I' }, -+ { "internal-db", 2, NULL, 'I' }, - { "keep-orphans", 0, NULL, 'K' }, - { "verbose", 0, NULL, 'V' }, - { "watch-nb", 1, NULL, 'W' }, -@@ -2725,7 +2726,8 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U", -+ while ((opt = getopt_long(argc, argv, -+ "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U", - options, NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2759,7 +2761,8 @@ int main(int argc, char *argv[]) - tracefile = optarg; - break; - case 'I': -- tdb_flags = TDB_INTERNAL|TDB_NOLOCK; -+ if (optarg && !strcmp(optarg, "off")) -+ tdb_flags = 0; - break; - case 'K': - keep_orphans = true; diff --git a/xsa419-xenstored-03.patch b/xsa419-xenstored-03.patch deleted file mode 100644 index 38130c0..0000000 --- a/xsa419-xenstored-03.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 54e63b7e7c42e4f975163809a01574e78552a6ab Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:13 +0200 -Subject: docs: enhance xenstore.txt with permissions description -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The permission scheme of Xenstore nodes is not really covered by -docs/misc/xenstore.txt, other than referring to the Xen wiki. - -Add a paragraph explaining the permissions of nodes, and especially -mentioning removal of nodes when a domain has been removed from -Xenstore. - -This is part of XSA-419. - -Reported-by: Juergen Gross -Signed-off-by: Juergen Gross -Reviewed-by: Edwin Török -Acked-by: Julien Grall - -diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt -index 988ef89cba2d..44428ae3a755 100644 ---- a/docs/misc/xenstore.txt -+++ b/docs/misc/xenstore.txt -@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep - them to within 2048 bytes. (See XENSTORE_*_PATH_MAX in xs_wire.h.) - - -+Each node has one or multiple permission entries. Permissions are -+granted by domain-id, the first permission entry of each node specifies -+the owner of the node. Permissions of a node can be changed by the -+owner of the node, the owner can only be modified by the control -+domain (usually domain id 0). The owner always has the right to read -+and write the node, while other permissions can be setup to allow -+read and/or write access. When a domain is being removed from Xenstore -+nodes owned by that domain will be removed together with all of those -+nodes' children. -+ -+ - Communication with xenstore is via either sockets, or event channel - and shared memory, as specified in io/xs_wire.h: each message in - either direction is a header formatted as a struct xsd_sockmsg diff --git a/xsa420.patch b/xsa420.patch deleted file mode 100644 index 5d00dc2..0000000 --- a/xsa420.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 210879456769ca211c6630f47399ca7a61a37f35 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:05 +0100 -Subject: tools/ocaml: Ensure packet size is never negative -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Integers in Ocaml have 63 or 31 bits of signed precision. - -On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits -within a 63-bit signed integer. - -In 32-bit builds of Ocaml, this goes wrong. The C uint32_t is truncated -first (loses the top bit), then has a unsigned/signed mismatch. - -A "negative" value (i.e. a packet on the ring of between 1G and 2G in size) -will trigger an exception later in Bytes.make in xb.ml, and because the packet -is not removed from the ring, the exception re-triggers on every subsequent -query, creating a livelock. - -Fix both the source of the exception in Xb, and as defence in depth, mark the -domain as bad for any Invalid_argument exceptions to avoid the risk of -livelock. - -This is XSA-420 / CVE-2022-42324. - -Reported-by: Juergen Gross -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml -index b6e2a716e263..3aa8927eb7f0 100644 ---- a/tools/ocaml/libs/xb/partial.ml -+++ b/tools/ocaml/libs/xb/partial.ml -@@ -36,7 +36,7 @@ let of_string s = - This will leave the guest connection is a bad state and will - be hard to recover from without restarting the connection - (ie rebooting the guest) *) -- let dlen = min xenstore_payload_max dlen in -+ let dlen = max 0 (min xenstore_payload_max dlen) in - { - tid = tid; - rid = rid; -@@ -46,8 +46,8 @@ let of_string s = - } - - let append pkt s sz = -- if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer"; -- Buffer.add_string pkt.buf (String.sub s 0 sz) -+ if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer"; -+ Buffer.add_substring pkt.buf s 0 sz - - let to_complete pkt = - pkt.len - (Buffer.length pkt.buf) -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 5f439fe59f47..f3a71b24ad94 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -722,7 +722,7 @@ let do_input store cons doms con = - History.reconnect con; - info "%s reconnection complete" (Connection.get_domstr con); - None -- | Failure exp -> -+ | Invalid_argument exp | Failure exp -> - error "caught exception %s" exp; - error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con)); - Connection.mark_as_bad con; diff --git a/xsa421-01.patch b/xsa421-01.patch deleted file mode 100644 index 10960ba..0000000 --- a/xsa421-01.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 9166869e7e6530befddfd8bb46ff37436a38efc1 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:13 +0200 -Subject: tools/xenstore: fix deleting node in transaction - -In case a node has been created in a transaction and it is later -deleted in the same transaction, the transaction will be terminated -with an error. - -As this error is encountered only when handling the deleted node at -transaction finalization, the transaction will have been performed -partially and without updating the accounting information. This will -enable a malicious guest to create arbitrary number of nodes. - -This is part of XSA-421 / CVE-2022-42325. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Tested-by: Julien Grall -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 3e3eb47326cc..7ffe21bb5285 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn, - true); - talloc_free(data.dptr); - } else { -- ret = do_tdb_delete(conn, &key, NULL); -+ /* -+ * A node having been created and later deleted -+ * in this transaction will have no generation -+ * information stored. -+ */ -+ ret = (i->generation == NO_GENERATION) -+ ? 0 : do_tdb_delete(conn, &key, NULL); - } - if (ret) - goto err; diff --git a/xsa421-02.patch b/xsa421-02.patch deleted file mode 100644 index 1a0b5cd..0000000 --- a/xsa421-02.patch +++ /dev/null @@ -1,401 +0,0 @@ -From 09fc22fea8a4689c5e563ba4a2fa959282071792 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:14 +0200 -Subject: tools/xenstore: harden transaction finalization against errors - -When finalizing a transaction, any error occurring after checking for -conflicts will result in the transaction being performed only -partially today. Additionally accounting data will not be updated at -the end of the transaction, which might result in further problems -later. - -Avoid those problems by multiple modifications: - -- free any transaction specific nodes which don't need to be committed - as they haven't been written during the transaction as soon as their - generation count has been verified, this will reduce the risk of - out-of-memory situations - -- store the transaction specific node name in struct accessed_node in - order to avoid the need to allocate additional memory for it when - finalizing the transaction - -- don't stop the transaction finalization when hitting an error - condition, but try to continue to handle all modified nodes - -- in case of a detected error do the accounting update as needed and - call the data base checking only after that - -- if writing a node in a transaction is failing (e.g. due to a failed - quota check), fail the transaction, as prior changes to struct - accessed_node can't easily be undone in that case - -This is part of XSA-421 / CVE-2022-42326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall -Tested-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 36fb4a832834..476d5c6d51bd 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -723,8 +723,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - return NULL; - } - -- if (transaction_prepend(conn, name, &key)) -- return NULL; -+ transaction_prepend(conn, name, &key); - - data = tdb_fetch(tdb_ctx, key); - -@@ -842,10 +841,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - static int write_node(struct connection *conn, struct node *node, - bool no_quota_check) - { -+ int ret; -+ - if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key)) - return errno; - -- return write_node_raw(conn, &node->key, node, no_quota_check); -+ ret = write_node_raw(conn, &node->key, node, no_quota_check); -+ if (ret && conn && conn->transaction) { -+ /* -+ * Reverting access_node() is hard, so just fail the -+ * transaction. -+ */ -+ fail_transaction(conn->transaction); -+ } -+ -+ return ret; - } - - unsigned int perm_for_conn(struct connection *conn, -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 7ffe21bb5285..ac854197cadb 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -114,7 +114,8 @@ struct accessed_node - struct list_head list; - - /* The name of the node. */ -- char *node; -+ char *trans_name; /* Transaction specific name. */ -+ char *node; /* Main data base name. */ - - /* Generation count (or NO_GENERATION) for conflict checking. */ - uint64_t generation; -@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans, - * Prepend the transaction to name if node has been modified in the current - * transaction. - */ --int transaction_prepend(struct connection *conn, const char *name, -- TDB_DATA *key) -+void transaction_prepend(struct connection *conn, const char *name, -+ TDB_DATA *key) - { -- char *tdb_name; -+ struct accessed_node *i; - -- if (!conn || !conn->transaction || -- !find_accessed_node(conn->transaction, name)) { -- set_tdb_key(name, key); -- return 0; -+ if (conn && conn->transaction) { -+ i = find_accessed_node(conn->transaction, name); -+ if (i) { -+ set_tdb_key(i->trans_name, key); -+ return; -+ } - } - -- tdb_name = transaction_get_node_name(conn->transaction, -- conn->transaction, name); -- if (!tdb_name) -- return errno; -- -- set_tdb_key(tdb_name, key); -- -- return 0; -+ set_tdb_key(name, key); - } - - /* -@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node, - struct accessed_node *i = NULL; - struct transaction *trans; - TDB_DATA local_key; -- const char *trans_name = NULL; - int ret; - bool introduce = false; - -@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node, - - trans = conn->transaction; - -- trans_name = transaction_get_node_name(node, trans, node->name); -- if (!trans_name) -- goto nomem; -- - i = find_accessed_node(trans, node->name); - if (!i) { - if (trans->nodes >= quota_trans_nodes && -@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node, - i = talloc_zero(trans, struct accessed_node); - if (!i) - goto nomem; -- i->node = talloc_strdup(i, node->name); -- if (!i->node) -+ i->trans_name = transaction_get_node_name(i, trans, node->name); -+ if (!i->trans_name) - goto nomem; -+ i->node = strchr(i->trans_name, '/') + 1; - if (node->generation != NO_GENERATION && node->perms.num) { - i->perms.p = talloc_array(i, struct xs_permissions, - node->perms.num); -@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node, - i->generation = node->generation; - i->check_gen = true; - if (node->generation != NO_GENERATION) { -- set_tdb_key(trans_name, &local_key); -+ set_tdb_key(i->trans_name, &local_key); - ret = write_node_raw(conn, &local_key, node, true); - if (ret) - goto err; -@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node, - return -1; - - if (key) { -- set_tdb_key(trans_name, key); -+ set_tdb_key(i->trans_name, key); - if (type == NODE_ACCESS_WRITE) - i->ta_node = true; - if (type == NODE_ACCESS_DELETE) -@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node, - nomem: - ret = ENOMEM; - err: -- talloc_free((void *)trans_name); - talloc_free(i); - trans->fail = true; - errno = ret; -@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact) - * base. - */ - static int finalize_transaction(struct connection *conn, -- struct transaction *trans) -+ struct transaction *trans, bool *is_corrupt) - { -- struct accessed_node *i; -+ struct accessed_node *i, *n; - TDB_DATA key, ta_key, data; - struct xs_tdb_record_hdr *hdr; - uint64_t gen; -- char *trans_name; -- int ret; - -- list_for_each_entry(i, &trans->accessed, list) { -- if (!i->check_gen) -- continue; -+ list_for_each_entry_safe(i, n, &trans->accessed, list) { -+ if (i->check_gen) { -+ set_tdb_key(i->node, &key); -+ data = tdb_fetch(tdb_ctx, key); -+ hdr = (void *)data.dptr; -+ if (!data.dptr) { -+ if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST) -+ return EIO; -+ gen = NO_GENERATION; -+ } else -+ gen = hdr->generation; -+ talloc_free(data.dptr); -+ if (i->generation != gen) -+ return EAGAIN; -+ } - -- set_tdb_key(i->node, &key); -- data = tdb_fetch(tdb_ctx, key); -- hdr = (void *)data.dptr; -- if (!data.dptr) { -- if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST) -- return EIO; -- gen = NO_GENERATION; -- } else -- gen = hdr->generation; -- talloc_free(data.dptr); -- if (i->generation != gen) -- return EAGAIN; -+ /* Entries for unmodified nodes can be removed early. */ -+ if (!i->modified) { -+ if (i->ta_node) { -+ set_tdb_key(i->trans_name, &ta_key); -+ if (do_tdb_delete(conn, &ta_key, NULL)) -+ return EIO; -+ } -+ list_del(&i->list); -+ talloc_free(i); -+ } - } - - while ((i = list_top(&trans->accessed, struct accessed_node, list))) { -- trans_name = transaction_get_node_name(i, trans, i->node); -- if (!trans_name) -- /* We are doomed: the transaction is only partial. */ -- goto err; -- -- set_tdb_key(trans_name, &ta_key); -- -- if (i->modified) { -- set_tdb_key(i->node, &key); -- if (i->ta_node) { -- data = tdb_fetch(tdb_ctx, ta_key); -- if (!data.dptr) -- goto err; -+ set_tdb_key(i->node, &key); -+ if (i->ta_node) { -+ set_tdb_key(i->trans_name, &ta_key); -+ data = tdb_fetch(tdb_ctx, ta_key); -+ if (data.dptr) { - hdr = (void *)data.dptr; - hdr->generation = ++generation; -- ret = do_tdb_write(conn, &key, &data, NULL, -- true); -+ *is_corrupt |= do_tdb_write(conn, &key, &data, -+ NULL, true); - talloc_free(data.dptr); -+ if (do_tdb_delete(conn, &ta_key, NULL)) -+ *is_corrupt = true; - } else { -- /* -- * A node having been created and later deleted -- * in this transaction will have no generation -- * information stored. -- */ -- ret = (i->generation == NO_GENERATION) -- ? 0 : do_tdb_delete(conn, &key, NULL); -- } -- if (ret) -- goto err; -- if (i->fire_watch) { -- fire_watches(conn, trans, i->node, NULL, -- i->watch_exact, -- i->perms.p ? &i->perms : NULL); -+ *is_corrupt = true; - } -+ } else { -+ /* -+ * A node having been created and later deleted -+ * in this transaction will have no generation -+ * information stored. -+ */ -+ *is_corrupt |= (i->generation == NO_GENERATION) -+ ? false -+ : do_tdb_delete(conn, &key, NULL); - } -+ if (i->fire_watch) -+ fire_watches(conn, trans, i->node, NULL, i->watch_exact, -+ i->perms.p ? &i->perms : NULL); - -- if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL)) -- goto err; - list_del(&i->list); - talloc_free(i); - } - - return 0; -- --err: -- corrupt(conn, "Partial transaction"); -- return EIO; - } - - static int destroy_transaction(void *_transaction) - { - struct transaction *trans = _transaction; - struct accessed_node *i; -- char *trans_name; - TDB_DATA key; - - wrl_ntransactions--; - trace_destroy(trans, "transaction"); - while ((i = list_top(&trans->accessed, struct accessed_node, list))) { - if (i->ta_node) { -- trans_name = transaction_get_node_name(i, trans, -- i->node); -- if (trans_name) { -- set_tdb_key(trans_name, &key); -- do_tdb_delete(trans->conn, &key, NULL); -- } -+ set_tdb_key(i->trans_name, &key); -+ do_tdb_delete(trans->conn, &key, NULL); - } - list_del(&i->list); - talloc_free(i); -@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn, - { - const char *arg = onearg(in); - struct transaction *trans; -+ bool is_corrupt = false; - int ret; - - if (!arg || (!streq(arg, "T") && !streq(arg, "F"))) -@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn, - ret = transaction_fix_domains(trans, false); - if (ret) - return ret; -- if (finalize_transaction(conn, trans)) -- return EAGAIN; -+ ret = finalize_transaction(conn, trans, &is_corrupt); -+ if (ret) -+ return ret; - - wrl_apply_debit_trans_commit(conn); - - /* fix domain entry for each changed domain */ - transaction_fix_domains(trans, true); -+ -+ if (is_corrupt) -+ corrupt(conn, "transaction inconsistency"); - } - send_ack(conn, XS_TRANSACTION_END); - -@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash) - struct connection *conn; - struct transaction *trans; - struct accessed_node *i; -- char *tname, *tnode; -+ char *tname; - - list_for_each_entry(conn, &connections, list) { - list_for_each_entry(trans, &conn->transaction_list, list) { -@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash) - list_for_each_entry(i, &trans->accessed, list) { - if (!i->ta_node) - continue; -- tnode = transaction_get_node_name(tname, trans, -- i->node); -- if (!tnode || !remember_string(hash, tnode)) -+ if (!remember_string(hash, i->trans_name)) - goto nomem; -- talloc_free(tnode); - } - - talloc_free(tname); -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 39d7f81c5127..3417303f9427 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node, - void queue_watches(struct connection *conn, const char *name, bool watch_exact); - - /* Prepend the transaction to name if appropriate. */ --int transaction_prepend(struct connection *conn, const char *name, -- TDB_DATA *key); -+void transaction_prepend(struct connection *conn, const char *name, -+ TDB_DATA *key); - - /* Mark the transaction as failed. This will prevent it to be committed. */ - void fail_transaction(struct transaction *trans); diff --git a/xsa422-4.16-1.patch b/xsa422-4.16-1.patch deleted file mode 100644 index 1d36873..0000000 --- a/xsa422-4.16-1.patch +++ /dev/null @@ -1,70 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Enumeration for IBPB_RET - -The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB -does flush the RSB/RAS too. - -This is part of XSA-422 / CVE-2022-23824. - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich - -diff --git a/tools/libs/light/libxl_cpuid.c b/tools/libs/light/libxl_cpuid.c -index bf6fdee360a9..691d5c6b2a68 100644 ---- a/tools/libs/light/libxl_cpuid.c -+++ b/tools/libs/light/libxl_cpuid.c -@@ -289,6 +289,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str) - {"ssb-no", 0x80000008, NA, CPUID_REG_EBX, 26, 1}, - {"psfd", 0x80000008, NA, CPUID_REG_EBX, 28, 1}, - {"btc-no", 0x80000008, NA, CPUID_REG_EBX, 29, 1}, -+ {"ibpb-ret", 0x80000008, NA, CPUID_REG_EBX, 30, 1}, - - {"nc", 0x80000008, NA, CPUID_REG_ECX, 0, 8}, - {"apicidsize", 0x80000008, NA, CPUID_REG_ECX, 12, 4}, -diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c -index fe22f5f5b68b..cd094427dd4c 100644 ---- a/tools/misc/xen-cpuid.c -+++ b/tools/misc/xen-cpuid.c -@@ -159,6 +159,7 @@ static const char *const str_e8b[32] = - [24] = "amd-ssbd", [25] = "virt-ssbd", - [26] = "ssb-no", - [28] = "psfd", [29] = "btc-no", -+ [30] = "ibpb-ret", - }; - - static const char *const str_7d0[32] = -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 0f4bad3d3abb..16a562d3a172 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -419,7 +419,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps) - * Hardware read-only information, stating immunity to certain issues, or - * suggestions of which mitigation to use. - */ -- printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", -+ printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (caps & ARCH_CAPS_RDCL_NO) ? " RDCL_NO" : "", - (caps & ARCH_CAPS_IBRS_ALL) ? " IBRS_ALL" : "", - (caps & ARCH_CAPS_RSBA) ? " RSBA" : "", -@@ -436,7 +436,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps) - (e8b & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS)) ? " STIBP_ALWAYS" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS_FAST)) ? " IBRS_FAST" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "", -- (e8b & cpufeat_mask(X86_FEATURE_BTC_NO)) ? " BTC_NO" : ""); -+ (e8b & cpufeat_mask(X86_FEATURE_BTC_NO)) ? " BTC_NO" : "", -+ (e8b & cpufeat_mask(X86_FEATURE_IBPB_RET)) ? " IBPB_RET" : ""); - - /* Hardware features which need driving to mitigate issues. */ - printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n", -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index e7b8167800a2..e0731221404c 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -267,6 +267,7 @@ XEN_CPUFEATURE(VIRT_SSBD, 8*32+25) /* MSR_VIRT_SPEC_CTRL.SSBD */ - XEN_CPUFEATURE(SSB_NO, 8*32+26) /*A Hardware not vulnerable to SSB */ - XEN_CPUFEATURE(PSFD, 8*32+28) /*S MSR_SPEC_CTRL.PSFD */ - XEN_CPUFEATURE(BTC_NO, 8*32+29) /*A Hardware not vulnerable to Branch Type Confusion */ -+XEN_CPUFEATURE(IBPB_RET, 8*32+30) /*A IBPB clears RSB/RAS too. */ - - /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */ - XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A AVX512 Neural Network Instructions */ diff --git a/xsa422-4.16-2.patch b/xsa422-4.16-2.patch deleted file mode 100644 index a1a2f8d..0000000 --- a/xsa422-4.16-2.patch +++ /dev/null @@ -1,100 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS - -Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to -using MSR_PRED_CMD for a new guest context, even if it only has one user -presently. - -Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context() -with a manual fixup for hardware which mis-implements IBPB. - -This is part of XSA-422 / CVE-2022-23824. - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich - -diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c -index 7e536b0d82f5..891d86c7655c 100644 ---- a/xen/arch/x86/asm-macros.c -+++ b/xen/arch/x86/asm-macros.c -@@ -1,2 +1,3 @@ - #include - #include -+#include -diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c -index 3fab2364be8d..3080cde62b5b 100644 ---- a/xen/arch/x86/domain.c -+++ b/xen/arch/x86/domain.c -@@ -2092,7 +2092,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next) - */ - if ( *last_id != next_id ) - { -- wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB); -+ spec_ctrl_new_guest_context(); - *last_id = next_id; - } - } -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 16a562d3a172..90d86fe5cb47 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -805,6 +805,14 @@ static void __init ibpb_calculations(void) - } - - /* -+ * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS. Future -+ * CPUs are expected to enumerate IBPB_RET when this has been fixed. -+ * Until then, cover the difference with the software sequence. -+ */ -+ if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) ) -+ setup_force_cpu_cap(X86_BUG_IBPB_NO_RET); -+ -+ /* - * IBPB-on-entry mitigations for Branch Type Confusion. - * - * IBPB && !BTC_NO selects all AMD/Hygon hardware, not known to be safe, -diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h -index 672c9ee22ba2..ecc1bb09505a 100644 ---- a/xen/include/asm-x86/cpufeatures.h -+++ b/xen/include/asm-x86/cpufeatures.h -@@ -49,6 +49,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM, X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for - #define X86_BUG_FPU_PTRS X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */ - #define X86_BUG_NULL_SEG X86_BUG( 1) /* NULL-ing a selector preserves the base and limit. */ - #define X86_BUG_CLFLUSH_MFENCE X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */ -+#define X86_BUG_IBPB_NO_RET X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */ - - /* Total number of capability words, inc synth and bug words. */ - #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */ -diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h -index 9403b81dc7af..6a77c3937844 100644 ---- a/xen/include/asm-x86/spec_ctrl.h -+++ b/xen/include/asm-x86/spec_ctrl.h -@@ -65,6 +65,28 @@ - void init_speculation_mitigations(void); - void spec_ctrl_init_domain(struct domain *d); - -+/* -+ * Switch to a new guest prediction context. -+ * -+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code -+ * which has previously run on this CPU can't attack subsequent guest code. -+ * -+ * As this flushes the RSB/RAS, it destroys the predictions of the calling -+ * context. For best performace, arrange for this to be used when we're going -+ * to jump out of the current context, e.g. with reset_stack_and_jump(). -+ * -+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS -+ * manually. -+ */ -+static always_inline void spec_ctrl_new_guest_context(void) -+{ -+ wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB); -+ -+ /* (ab)use alternative_input() to specify clobbers. */ -+ alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET, -+ : "rax", "rcx"); -+} -+ - extern int8_t opt_ibpb_ctxt_switch; - extern bool opt_ssbd; - extern int8_t opt_eager_fpu; From 158b3ce973c1130ee91c5a80060017e6a6c41cc0 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 19 Dec 2022 19:58:48 +0000 Subject: [PATCH 02/99] update to xen-4.16.3 --- .gitignore | 2 +- sources | 2 +- xen.canonicalize.patch | 4 +- xen.spec | 128 +-- xsa326-4.16-oxenstored-01.patch | 55 -- xsa326-4.16-oxenstored-02.patch | 94 -- xsa326-4.16-oxenstored-03.patch | 119 --- xsa326-4.16-oxenstored-04.patch | 85 -- xsa326-4.16-oxenstored-05.patch | 214 ----- xsa326-4.16-oxenstored-06.patch | 127 --- xsa326-4.16-oxenstored-07.patch | 872 ------------------ xsa326-4.16-oxenstored-08.patch | 49 - xsa326-4.16-xenstored-01.patch | 205 ---- xsa326-4.16-xenstored-02.patch | 108 --- xsa326-4.16-xenstored-03.patch | 192 ---- xsa326-4.16-xenstored-04.patch | 302 ------ xsa326-4.16-xenstored-05.patch | 443 --------- xsa326-4.16-xenstored-06.patch | 85 -- xsa326-4.16-xenstored-07.patch | 53 -- xsa326-4.16-xenstored-08.patch | 326 ------- xsa326-4.16-xenstored-09.patch | 244 ----- xsa326-4.16-xenstored-10.patch | 88 -- xsa326-4.16-xenstored-11.patch | 280 ------ xsa326-4.16-xenstored-12.patch | 76 -- xsa326-4.16-xenstored-13.patch | 89 -- xsa326-4.16-xenstored-14.patch | 334 ------- xsa326-4.16-xenstored-15.patch | 54 -- xsa326-4.16-xenstored-16.patch | 238 ----- ...-arch-specific-default-paging-memory.patch | 147 --- ...struct-the-P2M-pages-pool-for-guests.patch | 187 ---- ...plement-XEN_DOMCTL_shadow_op-for-Arm.patch | 106 --- ...-and-free-P2M-pages-from-the-P2M-poo.patch | 287 ------ xsa410-4.16-01.patch | 59 -- xsa410-4.16-02.patch | 165 ---- xsa410-4.16-03.patch | 113 --- xsa410-4.16-04.patch | 62 -- xsa410-4.16-05.patch | 60 -- xsa410-4.16-06.patch | 255 ----- xsa410-4.16-07.patch | 82 -- xsa410-4.16-08.patch | 96 -- xsa410-4.16-09.patch | 159 ---- xsa410-4.16-10.patch | 171 ---- xsa411.patch | 55 -- xsa412-4.16.patch | 245 ----- xsa414.patch | 112 --- xsa415.patch | 134 --- xsa416-4.16.patch | 704 -------------- xsa417.patch | 135 --- xsa418-4.16-01.patch | 119 --- xsa418-4.16-02.patch | 103 --- xsa418-4.16-03.patch | 243 ----- xsa418-4.16-04.patch | 108 --- xsa418-4.16-05.patch | 164 ---- xsa418-4.16-06.patch | 174 ---- xsa418-4.16-07.patch | 163 ---- xsa419-oxenstored.patch | 85 -- xsa419-xenstored-01.patch | 289 ------ xsa419-xenstored-02.patch | 93 -- xsa419-xenstored-03.patch | 44 - xsa420.patch | 68 -- xsa421-01.patch | 40 - xsa421-02.patch | 401 -------- xsa422-4.16-1.patch | 70 -- xsa422-4.16-2.patch | 100 -- 64 files changed, 10 insertions(+), 10456 deletions(-) delete mode 100644 xsa326-4.16-oxenstored-01.patch delete mode 100644 xsa326-4.16-oxenstored-02.patch delete mode 100644 xsa326-4.16-oxenstored-03.patch delete mode 100644 xsa326-4.16-oxenstored-04.patch delete mode 100644 xsa326-4.16-oxenstored-05.patch delete mode 100644 xsa326-4.16-oxenstored-06.patch delete mode 100644 xsa326-4.16-oxenstored-07.patch delete mode 100644 xsa326-4.16-oxenstored-08.patch delete mode 100644 xsa326-4.16-xenstored-01.patch delete mode 100644 xsa326-4.16-xenstored-02.patch delete mode 100644 xsa326-4.16-xenstored-03.patch delete mode 100644 xsa326-4.16-xenstored-04.patch delete mode 100644 xsa326-4.16-xenstored-05.patch delete mode 100644 xsa326-4.16-xenstored-06.patch delete mode 100644 xsa326-4.16-xenstored-07.patch delete mode 100644 xsa326-4.16-xenstored-08.patch delete mode 100644 xsa326-4.16-xenstored-09.patch delete mode 100644 xsa326-4.16-xenstored-10.patch delete mode 100644 xsa326-4.16-xenstored-11.patch delete mode 100644 xsa326-4.16-xenstored-12.patch delete mode 100644 xsa326-4.16-xenstored-13.patch delete mode 100644 xsa326-4.16-xenstored-14.patch delete mode 100644 xsa326-4.16-xenstored-15.patch delete mode 100644 xsa326-4.16-xenstored-16.patch delete mode 100644 xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch delete mode 100644 xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch delete mode 100644 xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch delete mode 100644 xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch delete mode 100644 xsa410-4.16-01.patch delete mode 100644 xsa410-4.16-02.patch delete mode 100644 xsa410-4.16-03.patch delete mode 100644 xsa410-4.16-04.patch delete mode 100644 xsa410-4.16-05.patch delete mode 100644 xsa410-4.16-06.patch delete mode 100644 xsa410-4.16-07.patch delete mode 100644 xsa410-4.16-08.patch delete mode 100644 xsa410-4.16-09.patch delete mode 100644 xsa410-4.16-10.patch delete mode 100644 xsa411.patch delete mode 100644 xsa412-4.16.patch delete mode 100644 xsa414.patch delete mode 100644 xsa415.patch delete mode 100644 xsa416-4.16.patch delete mode 100644 xsa417.patch delete mode 100644 xsa418-4.16-01.patch delete mode 100644 xsa418-4.16-02.patch delete mode 100644 xsa418-4.16-03.patch delete mode 100644 xsa418-4.16-04.patch delete mode 100644 xsa418-4.16-05.patch delete mode 100644 xsa418-4.16-06.patch delete mode 100644 xsa418-4.16-07.patch delete mode 100644 xsa419-oxenstored.patch delete mode 100644 xsa419-xenstored-01.patch delete mode 100644 xsa419-xenstored-02.patch delete mode 100644 xsa419-xenstored-03.patch delete mode 100644 xsa420.patch delete mode 100644 xsa421-01.patch delete mode 100644 xsa421-02.patch delete mode 100644 xsa422-4.16-1.patch delete mode 100644 xsa422-4.16-2.patch diff --git a/.gitignore b/.gitignore index f41c7f1..3d1112b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.16.2.tar.gz +/xen-4.16.3.tar.gz diff --git a/sources b/sources index f6803eb..b3ba74d 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.16.2.tar.gz) = b6cd036c1073798dffa167ca14c954fbdfb4c0ef99662f7c435e7e5de687d1bde8856ff6bd030d0d2e661bd17ab631551f01b2cc728cad7e70b59aaa6e692783 +SHA512 (xen-4.16.3.tar.gz) = b8cbd6f95681de5f824ada2d3cbe0653a38514a18df0dafcf811fb255219c7abec96f46217bdb0c83e1119f685da9a6af7194eeaa94f1cc3c892702782133b4f diff --git a/xen.canonicalize.patch b/xen.canonicalize.patch index e339530..f3ae37d 100644 --- a/xen.canonicalize.patch +++ b/xen.canonicalize.patch @@ -13,8 +13,8 @@ if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) return EINVAL; -- node = canonicalize(conn, in, vec[0]); -+ node = xenstore_canonicalize(conn, in, vec[0]); +- node = canonicalize(conn, ctx, vec[0]); ++ node = xenstore_canonicalize(conn, ctx, vec[0]); if (!node) return ENOMEM; list_for_each_entry(watch, &conn->watches, list) { diff --git a/xen.spec b/xen.spec index 27ed461..f2f311e 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.16.2 -Release: 4%{?dist} +Version: 4.16.3 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,66 +111,6 @@ Patch43: xen.gcc11.fixes.patch Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch -Patch47: xsa410-4.16-01.patch -Patch48: xsa410-4.16-02.patch -Patch49: xsa410-4.16-03.patch -Patch50: xsa410-4.16-04.patch -Patch51: xsa410-4.16-05.patch -Patch52: xsa410-4.16-06.patch -Patch53: xsa410-4.16-07.patch -Patch54: xsa410-4.16-08.patch -Patch55: xsa410-4.16-09.patch -Patch56: xsa410-4.16-10.patch -Patch57: xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch -Patch58: xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch -Patch59: xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch -Patch60: xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch -Patch61: xsa411.patch -Patch62: xsa412-4.16.patch -Patch63: xsa414.patch -Patch64: xsa415.patch -Patch65: xsa326-4.16-oxenstored-01.patch -Patch66: xsa326-4.16-oxenstored-02.patch -Patch67: xsa326-4.16-oxenstored-03.patch -Patch68: xsa326-4.16-oxenstored-04.patch -Patch69: xsa326-4.16-oxenstored-05.patch -Patch70: xsa326-4.16-oxenstored-06.patch -Patch71: xsa326-4.16-oxenstored-07.patch -Patch72: xsa326-4.16-oxenstored-08.patch -Patch73: xsa326-4.16-xenstored-01.patch -Patch74: xsa326-4.16-xenstored-02.patch -Patch75: xsa326-4.16-xenstored-03.patch -Patch76: xsa326-4.16-xenstored-04.patch -Patch77: xsa326-4.16-xenstored-05.patch -Patch78: xsa326-4.16-xenstored-06.patch -Patch79: xsa326-4.16-xenstored-07.patch -Patch80: xsa326-4.16-xenstored-08.patch -Patch81: xsa326-4.16-xenstored-09.patch -Patch82: xsa326-4.16-xenstored-10.patch -Patch83: xsa326-4.16-xenstored-11.patch -Patch84: xsa326-4.16-xenstored-12.patch -Patch85: xsa326-4.16-xenstored-13.patch -Patch86: xsa326-4.16-xenstored-14.patch -Patch87: xsa326-4.16-xenstored-15.patch -Patch88: xsa326-4.16-xenstored-16.patch -Patch89: xsa416-4.16.patch -Patch90: xsa417.patch -Patch91: xsa418-4.16-01.patch -Patch92: xsa418-4.16-02.patch -Patch93: xsa418-4.16-03.patch -Patch94: xsa418-4.16-04.patch -Patch95: xsa418-4.16-05.patch -Patch96: xsa418-4.16-06.patch -Patch97: xsa418-4.16-07.patch -Patch98: xsa419-oxenstored.patch -Patch99: xsa419-xenstored-01.patch -Patch100: xsa419-xenstored-02.patch -Patch101: xsa419-xenstored-03.patch -Patch102: xsa420.patch -Patch103: xsa421-01.patch -Patch104: xsa421-02.patch -Patch105: xsa422-4.16-1.patch -Patch106: xsa422-4.16-2.patch %if %build_qemutrad @@ -383,66 +323,6 @@ manage Xen virtual machines. %patch44 -p1 %patch45 -p1 %patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 -%patch54 -p1 -%patch55 -p1 -%patch56 -p1 -%patch57 -p1 -%patch58 -p1 -%patch59 -p1 -%patch60 -p1 -%patch61 -p1 -%patch62 -p1 -%patch63 -p1 -%patch64 -p1 -%patch65 -p1 -%patch66 -p1 -%patch67 -p1 -%patch68 -p1 -%patch69 -p1 -%patch70 -p1 -%patch71 -p1 -%patch72 -p1 -%patch73 -p1 -%patch74 -p1 -%patch75 -p1 -%patch76 -p1 -%patch77 -p1 -%patch78 -p1 -%patch79 -p1 -%patch80 -p1 -%patch81 -p1 -%patch82 -p1 -%patch83 -p1 -%patch84 -p1 -%patch85 -p1 -%patch86 -p1 -%patch87 -p1 -%patch88 -p1 -%patch89 -p1 -%patch90 -p1 -%patch91 -p1 -%patch92 -p1 -%patch93 -p1 -%patch94 -p1 -%patch95 -p1 -%patch96 -p1 -%patch97 -p1 -%patch98 -p1 -%patch99 -p1 -%patch100 -p1 -%patch101 -p1 -%patch102 -p1 -%patch103 -p1 -%patch104 -p1 -%patch105 -p1 -%patch106 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -1058,6 +938,10 @@ fi %endif %changelog +* Mon Dec 19 2022 Michael Young - 4.16.3-1 +- update to xen-4.16.3 + remove or adjust patches now included or superceded upstream + * Tue Nov 08 2022 Michael Young - 4.16.2-4 - x86: Multiple speculative security issues [XSA-422, CVE-2022-23824] diff --git a/xsa326-4.16-oxenstored-01.patch b/xsa326-4.16-oxenstored-01.patch deleted file mode 100644 index 848a5d0..0000000 --- a/xsa326-4.16-oxenstored-01.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 8d6bb4ac40619877130533b11655829101b31d04 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:01 +0100 -Subject: tools/ocaml/xenstored: Synchronise defaults with oxenstore.conf.in -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We currently have 2 different set of defaults in upstream Xen git tree: -* defined in the source code, only used if there is no config file -* defined in the oxenstored.conf.in upstream Xen - -An oxenstored.conf file is not mandatory, and if missing, maxrequests in -particular has an unsafe default. - -Resync the defaults from oxenstored.conf.in into the source code. - -This is part of XSA-326 / CVE-2022-42316. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml -index ebe18b8e312c..6b06f808595b 100644 ---- a/tools/ocaml/xenstored/define.ml -+++ b/tools/ocaml/xenstored/define.ml -@@ -21,9 +21,9 @@ let xs_daemon_socket = Paths.xen_run_stored ^ "/socket" - - let default_config_dir = Paths.xen_config_dir - --let maxwatch = ref (50) --let maxtransaction = ref (20) --let maxrequests = ref (-1) (* maximum requests per transaction *) -+let maxwatch = ref (100) -+let maxtransaction = ref (10) -+let maxrequests = ref (1024) (* maximum requests per transaction *) - - let conflict_burst_limit = ref 5.0 - let conflict_max_history_seconds = ref 0.05 -diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml -index abcac912805a..6e3d6401ae89 100644 ---- a/tools/ocaml/xenstored/quota.ml -+++ b/tools/ocaml/xenstored/quota.ml -@@ -20,8 +20,8 @@ exception Transaction_opened - - let warn fmt = Logging.warn "quota" fmt - let activate = ref true --let maxent = ref (10000) --let maxsize = ref (4096) -+let maxent = ref (1000) -+let maxsize = ref (2048) - - type t = { - maxent: int; (* max entities per domU *) diff --git a/xsa326-4.16-oxenstored-02.patch b/xsa326-4.16-oxenstored-02.patch deleted file mode 100644 index 7680efb..0000000 --- a/xsa326-4.16-oxenstored-02.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 78d5af44ab13bb18c87b6ad75e505bd374379cb3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Thu, 28 Jul 2022 17:08:15 +0100 -Subject: tools/ocaml/xenstored: Check for maxrequests before performing - operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Previously we'd perform the operation, record the updated tree in the -transaction record, then try to insert a watchop path and the reply packet. - -If we exceeded max requests we would've returned EQUOTA, but still: -* have performed the operation on the transaction's tree -* have recorded the watchop, making this queue effectively unbounded - -It is better if we check whether we'd have room to store the operation before -performing the transaction, and raise EQUOTA there. Then the transaction -record won't grow. - -This is part of XSA-326 / CVE-2022-42317. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 27790d4a5c41..dd58e6979cf9 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -389,6 +389,7 @@ let input_handle_error ~cons ~doms ~fct ~con ~t ~req = - let reply_error e = - Packet.Error e in - try -+ Transaction.check_quota_exn ~perm:(Connection.get_perm con) t; - fct con t doms cons req.Packet.data - with - | Define.Invalid_path -> reply_error "EINVAL" -@@ -681,9 +682,10 @@ let process_packet ~store ~cons ~doms ~con ~req = - in - - let response = try -+ Transaction.check_quota_exn ~perm:(Connection.get_perm con) t; - if tid <> Transaction.none then - (* Remember the request and response for this operation in case we need to replay the transaction *) -- Transaction.add_operation ~perm:(Connection.get_perm con) t req response; -+ Transaction.add_operation t req response; - response - with Quota.Limit_reached -> - Packet.Error "EQUOTA" -diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml -index 17b1bdf2eaf9..294143e2335b 100644 ---- a/tools/ocaml/xenstored/transaction.ml -+++ b/tools/ocaml/xenstored/transaction.ml -@@ -85,6 +85,7 @@ type t = { - oldroot: Store.Node.t; - mutable paths: (Xenbus.Xb.Op.operation * Store.Path.t) list; - mutable operations: (Packet.request * Packet.response) list; -+ mutable quota_reached: bool; - mutable read_lowpath: Store.Path.t option; - mutable write_lowpath: Store.Path.t option; - } -@@ -127,6 +128,7 @@ let make ?(internal=false) id store = - oldroot = Store.get_root store; - paths = []; - operations = []; -+ quota_reached = false; - read_lowpath = None; - write_lowpath = None; - } in -@@ -143,13 +145,19 @@ let get_root t = Store.get_root t.store - - let is_read_only t = t.paths = [] - let add_wop t ty path = t.paths <- (ty, path) :: t.paths --let add_operation ~perm t request response = -+let get_operations t = List.rev t.operations -+ -+let check_quota_exn ~perm t = - if !Define.maxrequests >= 0 - && not (Perms.Connection.is_dom0 perm) -- && List.length t.operations >= !Define.maxrequests -- then raise Quota.Limit_reached; -+ && (t.quota_reached || List.length t.operations >= !Define.maxrequests) -+ then begin -+ t.quota_reached <- true; -+ raise Quota.Limit_reached; -+ end -+ -+let add_operation t request response = - t.operations <- (request, response) :: t.operations --let get_operations t = List.rev t.operations - let set_read_lowpath t path = t.read_lowpath <- get_lowest path t.read_lowpath - let set_write_lowpath t path = t.write_lowpath <- get_lowest path t.write_lowpath - diff --git a/xsa326-4.16-oxenstored-03.patch b/xsa326-4.16-oxenstored-03.patch deleted file mode 100644 index 0b42411..0000000 --- a/xsa326-4.16-oxenstored-03.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 600c45e49c2060e077c06ab19078da89aa8e2e08 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:07 +0100 -Subject: tools/ocaml: GC parameter tuning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -By default the OCaml garbage collector would return memory to the OS only -after unused memory is 5x live memory. Tweak this to 120% instead, which -would match the major GC speed. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml -index 6b06f808595b..ba63a8147e09 100644 ---- a/tools/ocaml/xenstored/define.ml -+++ b/tools/ocaml/xenstored/define.ml -@@ -25,6 +25,7 @@ let maxwatch = ref (100) - let maxtransaction = ref (10) - let maxrequests = ref (1024) (* maximum requests per transaction *) - -+let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *) - let conflict_burst_limit = ref 5.0 - let conflict_max_history_seconds = ref 0.05 - let conflict_rate_limit_is_aggregate = ref true -diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml -index d44ae673c42a..3b57ad016dfb 100644 ---- a/tools/ocaml/xenstored/xenstored.ml -+++ b/tools/ocaml/xenstored/xenstored.ml -@@ -104,6 +104,7 @@ let parse_config filename = - ("quota-maxsize", Config.Set_int Quota.maxsize); - ("quota-maxrequests", Config.Set_int Define.maxrequests); - ("quota-path-max", Config.Set_int Define.path_max); -+ ("gc-max-overhead", Config.Set_int Define.gc_max_overhead); - ("test-eagain", Config.Set_bool Transaction.test_eagain); - ("persistent", Config.Set_bool Disk.enable); - ("xenstored-log-file", Config.String Logging.set_xenstored_log_destination); -@@ -265,6 +266,67 @@ let to_file store cons fds file = - (fun () -> close_out channel) - end - -+(* -+ By default OCaml's GC only returns memory to the OS when it exceeds a -+ configurable 'max overhead' setting. -+ The default is 500%, that is 5/6th of the OCaml heap needs to be free -+ and only 1/6th live for a compaction to be triggerred that would -+ release memory back to the OS. -+ If the limit is not hit then the OCaml process can reuse that memory -+ for its own purposes, but other processes won't be able to use it. -+ -+ There is also a 'space overhead' setting that controls how much work -+ each major GC slice does, and by default aims at having no more than -+ 80% or 120% (depending on version) garbage values compared to live -+ values. -+ This doesn't have as much relevance to memory returned to the OS as -+ long as space_overhead <= max_overhead, because compaction is only -+ triggerred at the end of major GC cycles. -+ -+ The defaults are too large once the program starts using ~100MiB of -+ memory, at which point ~500MiB would be unavailable to other processes -+ (which would be fine if this was the main process in this VM, but it is -+ not). -+ -+ Max overhead can also be set to 0, however this is for testing purposes -+ only (setting it lower than 'space overhead' wouldn't help because the -+ major GC wouldn't run fast enough, and compaction does have a -+ performance cost: we can only compact contiguous regions, so memory has -+ to be moved around). -+ -+ Max overhead controls how often the heap is compacted, which is useful -+ if there are burst of activity followed by long periods of idle state, -+ or if a domain quits, etc. Compaction returns memory to the OS. -+ -+ wasted = live * space_overhead / 100 -+ -+ For globally overriding the GC settings one can use OCAMLRUNPARAM, -+ however we provide a config file override to be consistent with other -+ oxenstored settings. -+ -+ One might want to dynamically adjust the overhead setting based on used -+ memory, i.e. to use a fixed upper bound in bytes, not percentage. However -+ measurements show that such adjustments increase GC overhead massively, -+ while still not guaranteeing that memory is returned any more quickly -+ than with a percentage based setting. -+ -+ The allocation policy could also be tweaked, e.g. first fit would reduce -+ fragmentation and thus memory usage, but the documentation warns that it -+ can be sensibly slower, and indeed one of our own testcases can trigger -+ such a corner case where it is multiple times slower, so it is best to keep -+ the default allocation policy (next-fit/best-fit depending on version). -+ -+ There are other tweaks that can be attempted in the future, e.g. setting -+ 'ulimit -v' to 75% of RAM, however getting the kernel to actually return -+ NULL from allocations is difficult even with that setting, and without a -+ NULL the emergency GC won't be triggerred. -+ Perhaps cgroup limits could help, but for now tweak the safest only. -+*) -+ -+let tweak_gc () = -+ Gc.set { (Gc.get ()) with Gc.max_overhead = !Define.gc_max_overhead } -+ -+ - let _ = - let cf = do_argv in - let pidfile = -@@ -274,6 +336,8 @@ let _ = - default_pidfile - in - -+ tweak_gc (); -+ - (try - Unixext.mkdir_rec (Filename.dirname pidfile) 0o755 - with _ -> diff --git a/xsa326-4.16-oxenstored-04.patch b/xsa326-4.16-oxenstored-04.patch deleted file mode 100644 index 0f2534b..0000000 --- a/xsa326-4.16-oxenstored-04.patch +++ /dev/null @@ -1,85 +0,0 @@ -From fd6d9cd3d20e496bdbf3e0a07354f65de0bcf4ae Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Fri, 29 Jul 2022 18:53:29 +0100 -Subject: tools/ocaml/libs/xb: hide type of Xb.t -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Hiding the type will make it easier to change the implementation -in the future without breaking code that relies on it. - -No functional change. - -Signed-off-by: Edwin Török -Acked-by: Christian Lindig -(cherry picked from commit 7ade30a1451734d041363c750a65d322e25b47ba) - -Reported-by: Julien Grall -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 104d319d7747..8404ddd8a682 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -196,6 +196,9 @@ let peek_output con = Queue.peek con.pkt_out - let input_len con = Queue.length con.pkt_in - let has_in_packet con = Queue.length con.pkt_in > 0 - let get_in_packet con = Queue.pop con.pkt_in -+let has_partial_input con = match con.partial_in with -+ | HaveHdr _ -> true -+ | NoHdr (n, _) -> n < Partial.header_size () - let has_more_input con = - match con.backend with - | Fd _ -> false -diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli -index 3a00da6cddc1..794e35bb343e 100644 ---- a/tools/ocaml/libs/xb/xb.mli -+++ b/tools/ocaml/libs/xb/xb.mli -@@ -66,13 +66,7 @@ type backend_mmap = { - type backend_fd = { fd : Unix.file_descr; } - type backend = Fd of backend_fd | Xenmmap of backend_mmap - type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes --type t = { -- backend : backend; -- pkt_in : Packet.t Queue.t; -- pkt_out : Packet.t Queue.t; -- mutable partial_in : partial_buf; -- mutable partial_out : string; --} -+type t - val init_partial_in : unit -> partial_buf - val reconnect : t -> unit - val queue : t -> Packet.t -> unit -@@ -97,6 +91,7 @@ val has_output : t -> bool - val peek_output : t -> Packet.t - val input_len : t -> int - val has_in_packet : t -> bool -+val has_partial_input : t -> bool - val get_in_packet : t -> Packet.t - val has_more_input : t -> bool - val is_selectable : t -> bool -diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml -index 65f99ea6f28a..38b47363a173 100644 ---- a/tools/ocaml/xenstored/connection.ml -+++ b/tools/ocaml/xenstored/connection.ml -@@ -125,9 +125,7 @@ let get_perm con = - let set_target con target_domid = - con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid - --let is_backend_mmap con = match con.xb.Xenbus.Xb.backend with -- | Xenbus.Xb.Xenmmap _ -> true -- | _ -> false -+let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb - - let send_reply con tid rid ty data = - if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then -@@ -280,9 +278,7 @@ let get_transaction con tid = - - let do_input con = Xenbus.Xb.input con.xb - let has_input con = Xenbus.Xb.has_in_packet con.xb --let has_partial_input con = match con.xb.Xenbus.Xb.partial_in with -- | HaveHdr _ -> true -- | NoHdr (n, _) -> n < Xenbus.Partial.header_size () -+let has_partial_input con = Xenbus.Xb.has_partial_input con.xb - let pop_in con = Xenbus.Xb.get_in_packet con.xb - let has_more_input con = Xenbus.Xb.has_more_input con.xb - diff --git a/xsa326-4.16-oxenstored-05.patch b/xsa326-4.16-oxenstored-05.patch deleted file mode 100644 index 8b253a9..0000000 --- a/xsa326-4.16-oxenstored-05.patch +++ /dev/null @@ -1,214 +0,0 @@ -From f13fe5903361953e4ccf8602b9c8df7e64568d55 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:02 +0100 -Subject: tools/ocaml: Change Xb.input to return Packet.t option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The queue here would only ever hold at most one element. This will simplify -follow-up patches. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 8404ddd8a682..165fd4a1edf4 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -45,7 +45,6 @@ type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes - type t = - { - backend: backend; -- pkt_in: Packet.t Queue.t; - pkt_out: Packet.t Queue.t; - mutable partial_in: partial_buf; - mutable partial_out: string; -@@ -62,7 +61,6 @@ let reconnect t = match t.backend with - Xs_ring.close backend.mmap; - backend.eventchn_notify (); - (* Clear our old connection state *) -- Queue.clear t.pkt_in; - Queue.clear t.pkt_out; - t.partial_in <- init_partial_in (); - t.partial_out <- "" -@@ -124,7 +122,6 @@ let output con = - - (* NB: can throw Reconnect *) - let input con = -- let newpacket = ref false in - let to_read = - match con.partial_in with - | HaveHdr partial_pkt -> Partial.to_complete partial_pkt -@@ -143,21 +140,19 @@ let input con = - if Partial.to_complete partial_pkt = 0 then ( - let pkt = Packet.of_partialpkt partial_pkt in - con.partial_in <- init_partial_in (); -- Queue.push pkt con.pkt_in; -- newpacket := true -- ) -+ Some pkt -+ ) else None - | NoHdr (i, buf) -> - (* we complete the partial header *) - if sz > 0 then - Bytes.blit b 0 buf (Partial.header_size () - i) sz; - con.partial_in <- if sz = i then -- HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf) -- ); -- !newpacket -+ HaveHdr (Partial.of_string (Bytes.to_string buf)) else NoHdr (i - sz, buf); -+ None -+ ) - - let newcon backend = { - backend = backend; -- pkt_in = Queue.create (); - pkt_out = Queue.create (); - partial_in = init_partial_in (); - partial_out = ""; -@@ -193,9 +188,6 @@ let has_output con = has_new_output con || has_old_output con - - let peek_output con = Queue.peek con.pkt_out - --let input_len con = Queue.length con.pkt_in --let has_in_packet con = Queue.length con.pkt_in > 0 --let get_in_packet con = Queue.pop con.pkt_in - let has_partial_input con = match con.partial_in with - | HaveHdr _ -> true - | NoHdr (n, _) -> n < Partial.header_size () -diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli -index 794e35bb343e..91c682162cea 100644 ---- a/tools/ocaml/libs/xb/xb.mli -+++ b/tools/ocaml/libs/xb/xb.mli -@@ -77,7 +77,7 @@ val write_fd : backend_fd -> 'a -> string -> int -> int - val write_mmap : backend_mmap -> 'a -> string -> int -> int - val write : t -> string -> int -> int - val output : t -> bool --val input : t -> bool -+val input : t -> Packet.t option - val newcon : backend -> t - val open_fd : Unix.file_descr -> t - val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t -@@ -89,10 +89,7 @@ val has_new_output : t -> bool - val has_old_output : t -> bool - val has_output : t -> bool - val peek_output : t -> Packet.t --val input_len : t -> int --val has_in_packet : t -> bool - val has_partial_input : t -> bool --val get_in_packet : t -> Packet.t - val has_more_input : t -> bool - val is_selectable : t -> bool - val get_fd : t -> Unix.file_descr -diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml -index d982fb24dbb1..451f8b38dbcc 100644 ---- a/tools/ocaml/libs/xs/xsraw.ml -+++ b/tools/ocaml/libs/xs/xsraw.ml -@@ -94,26 +94,18 @@ let pkt_send con = - done - - (* receive one packet - can sleep *) --let pkt_recv con = -- let workdone = ref false in -- while not !workdone -- do -- workdone := Xb.input con.xb -- done; -- Xb.get_in_packet con.xb -+let rec pkt_recv con = -+ match Xb.input con.xb with -+ | Some packet -> packet -+ | None -> pkt_recv con - - let pkt_recv_timeout con timeout = - let fd = Xb.get_fd con.xb in - let r, _, _ = Unix.select [ fd ] [] [] timeout in - if r = [] then - true, None -- else ( -- let workdone = Xb.input con.xb in -- if workdone then -- false, (Some (Xb.get_in_packet con.xb)) -- else -- false, None -- ) -+ else -+ false, Xb.input con.xb - - let queue_watchevent con data = - let ls = split_string ~limit:2 '\000' data in -diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml -index 38b47363a173..cc20e047d2b9 100644 ---- a/tools/ocaml/xenstored/connection.ml -+++ b/tools/ocaml/xenstored/connection.ml -@@ -277,9 +277,7 @@ let get_transaction con tid = - Hashtbl.find con.transactions tid - - let do_input con = Xenbus.Xb.input con.xb --let has_input con = Xenbus.Xb.has_in_packet con.xb - let has_partial_input con = Xenbus.Xb.has_partial_input con.xb --let pop_in con = Xenbus.Xb.get_in_packet con.xb - let has_more_input con = Xenbus.Xb.has_more_input con.xb - - let has_output con = Xenbus.Xb.has_output con.xb -@@ -307,7 +305,7 @@ let is_bad con = match con.dom with None -> false | Some dom -> Domain.is_bad_do - Restrictions below can be relaxed once xenstored learns to dump more - of its live state in a safe way *) - let has_extra_connection_data con = -- let has_in = has_input con || has_partial_input con in -+ let has_in = has_partial_input con in - let has_out = has_output con in - let has_socket = con.dom = None in - let has_nondefault_perms = make_perm con.dom <> con.perm in -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 6a3435c265d3..2d67456a2aa0 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -195,10 +195,9 @@ let parse_live_update args = - | _ when Unix.gettimeofday () < t.deadline -> false - | l -> - warn "timeout reached: have to wait, migrate or shutdown %d domains:" (List.length l); -- let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, in: %b, out: %b, perm: %s" -+ let msgs = List.rev_map (fun con -> Printf.sprintf "%s: %d tx, out: %b, perm: %s" - (Connection.get_domstr con) - (Connection.number_of_transactions con) -- (Connection.has_input con) - (Connection.has_output con) - (Connection.get_perm con |> Perms.Connection.to_string) - ) l in -@@ -705,16 +704,17 @@ let do_input store cons doms con = - info "%s requests a reconnect" (Connection.get_domstr con); - History.reconnect con; - info "%s reconnection complete" (Connection.get_domstr con); -- false -+ None - | Failure exp -> - error "caught exception %s" exp; - error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con)); - Connection.mark_as_bad con; -- false -+ None - in - -- if newpacket then ( -- let packet = Connection.pop_in con in -+ match newpacket with -+ | None -> () -+ | Some packet -> - let tid, rid, ty, data = Xenbus.Xb.Packet.unpack packet in - let req = {Packet.tid=tid; Packet.rid=rid; Packet.ty=ty; Packet.data=data} in - -@@ -724,8 +724,7 @@ let do_input store cons doms con = - (Xenbus.Xb.Op.to_string ty) (sanitize_data data); *) - process_packet ~store ~cons ~doms ~con ~req; - write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data; -- Connection.incr_ops con; -- ) -+ Connection.incr_ops con - - let do_output _store _cons _doms con = - if Connection.has_output con then ( diff --git a/xsa326-4.16-oxenstored-06.patch b/xsa326-4.16-oxenstored-06.patch deleted file mode 100644 index c8ebc34..0000000 --- a/xsa326-4.16-oxenstored-06.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 2440a8b69a118fe14e73eb6cab4a050922866f1a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:03 +0100 -Subject: tools/ocaml/xb: Add BoundedQueue -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Ensures we cannot store more than [capacity] elements in a [Queue]. Replacing -all Queue with this module will then ensure at compile time that all Queues -are correctly bound checked. - -Each element in the queue has a class with its own limits. This, in a -subsequent change, will ensure that command responses can proceed during a -flood of watch events. - -No functional change. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 165fd4a1edf4..4197a3888a68 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -17,6 +17,98 @@ - module Op = struct include Op end - module Packet = struct include Packet end - -+module BoundedQueue : sig -+ type ('a, 'b) t -+ -+ (** [create ~capacity ~classify ~limit] creates a queue with maximum [capacity] elements. -+ This is burst capacity, each element is further classified according to [classify], -+ and each class can have its own [limit]. -+ [capacity] is enforced as an overall limit. -+ The [limit] can be dynamic, and can be smaller than the number of elements already queued of that class, -+ in which case those elements are considered to use "burst capacity". -+ *) -+ val create: capacity:int -> classify:('a -> 'b) -> limit:('b -> int) -> ('a, 'b) t -+ -+ (** [clear q] discards all elements from [q] *) -+ val clear: ('a, 'b) t -> unit -+ -+ (** [can_push q] when [length q < capacity]. *) -+ val can_push: ('a, 'b) t -> 'b -> bool -+ -+ (** [push e q] adds [e] at the end of queue [q] if [can_push q], or returns [None]. *) -+ val push: 'a -> ('a, 'b) t -> unit option -+ -+ (** [pop q] removes and returns first element in [q], or raises [Queue.Empty]. *) -+ val pop: ('a, 'b) t -> 'a -+ -+ (** [peek q] returns the first element in [q], or raises [Queue.Empty]. *) -+ val peek : ('a, 'b) t -> 'a -+ -+ (** [length q] returns the current number of elements in [q] *) -+ val length: ('a, 'b) t -> int -+ -+ (** [debug string_of_class q] prints queue usage statistics in an unspecified internal format. *) -+ val debug: ('b -> string) -> (_, 'b) t -> string -+end = struct -+ type ('a, 'b) t = -+ { q: 'a Queue.t -+ ; capacity: int -+ ; classify: 'a -> 'b -+ ; limit: 'b -> int -+ ; class_count: ('b, int) Hashtbl.t -+ } -+ -+ let create ~capacity ~classify ~limit = -+ { capacity; q = Queue.create (); classify; limit; class_count = Hashtbl.create 3 } -+ -+ let get_count t classification = try Hashtbl.find t.class_count classification with Not_found -> 0 -+ -+ let can_push_internal t classification class_count = -+ Queue.length t.q < t.capacity && class_count < t.limit classification -+ -+ let ok = Some () -+ -+ let push e t = -+ let classification = t.classify e in -+ let class_count = get_count t classification in -+ if can_push_internal t classification class_count then begin -+ Queue.push e t.q; -+ Hashtbl.replace t.class_count classification (class_count + 1); -+ ok -+ end -+ else -+ None -+ -+ let can_push t classification = -+ can_push_internal t classification @@ get_count t classification -+ -+ let clear t = -+ Queue.clear t.q; -+ Hashtbl.reset t.class_count -+ -+ let pop t = -+ let e = Queue.pop t.q in -+ let classification = t.classify e in -+ let () = match get_count t classification - 1 with -+ | 0 -> Hashtbl.remove t.class_count classification (* reduces memusage *) -+ | n -> Hashtbl.replace t.class_count classification n -+ in -+ e -+ -+ let peek t = Queue.peek t.q -+ let length t = Queue.length t.q -+ -+ let debug string_of_class t = -+ let b = Buffer.create 128 in -+ Printf.bprintf b "BoundedQueue capacity: %d, used: {" t.capacity; -+ Hashtbl.iter (fun packet_class count -> -+ Printf.bprintf b " %s: %d" (string_of_class packet_class) count -+ ) t.class_count; -+ Printf.bprintf b "}"; -+ Buffer.contents b -+end -+ -+ - exception End_of_file - exception Eagain - exception Noent diff --git a/xsa326-4.16-oxenstored-07.patch b/xsa326-4.16-oxenstored-07.patch deleted file mode 100644 index ef02467..0000000 --- a/xsa326-4.16-oxenstored-07.patch +++ /dev/null @@ -1,872 +0,0 @@ -From bc0f05e6f3a3c93c853ceffd1f6d2022dc30fb77 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:04 +0100 -Subject: tools/ocaml: Limit maximum in-flight requests / outstanding replies -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Introduce a limit on the number of outstanding reply packets in the xenbus -queue. This limits the number of in-flight requests: when the output queue is -full we'll stop processing inputs until the output queue has room again. - -To avoid a busy loop on the Unix socket we only add it to the watched input -file descriptor set if we'd be able to call `input` on it. Even though Dom0 -is trusted and exempt from quotas a flood of events might cause a backlog -where events are produced faster than daemons in Dom0 can consume them, which -could lead to an unbounded queue size and OOM. - -Therefore the xenbus queue limit must apply to all connections, Dom0 is not -exempt from it, although if everything works correctly it will eventually -catch up. - -This prevents a malicious guest from sending more commands while it has -outstanding watch events or command replies in its input ring. However if it -can cause the generation of watch events by other means (e.g. by Dom0, or -another cooperative guest) and stop reading its own ring then watch events -would've queued up without limit. - -The xenstore protocol doesn't have a back-pressure mechanism, and doesn't -allow dropping watch events. In fact, dropping watch events is known to break -some pieces of normal functionality. This leaves little choice to safely -implement the xenstore protocol without exposing the xenstore daemon to -out-of-memory attacks. - -Implement the fix as pipes with bounded buffers: -* Use a bounded buffer for watch events -* The watch structure will have a bounded receiving pipe of watch events -* The source will have an "overflow" pipe of pending watch events it couldn't - deliver - -Items are queued up on one end and are sent as far along the pipe as possible: - - source domain -> watch -> xenbus of target -> xenstore ring/socket of target - -If the pipe is "full" at any point then back-pressure is applied and we prevent -more items from being queued up. For the source domain this means that we'll -stop accepting new commands as long as its pipe buffer is not empty. - -Before we try to enqueue an item we first check whether it is possible to send -it further down the pipe, by attempting to recursively flush the pipes. This -ensures that we retain the order of events as much as possible. - -We might break causality of watch events if the target domain's queue is full -and we need to start using the watch's queue. This is a breaking change in -the xenstore protocol, but only for domains which are not processing their -incoming ring as expected. - -When a watch is deleted its entire pending queue is dropped (no code is needed -for that, because it is part of the 'watch' type). - -There is a cache of watches that have pending events that we attempt to flush -at every cycle if possible. - -Introduce 3 limits here: -* quota-maxwatchevents on watch event destination: when this is hit the - source will not be allowed to queue up more watch events. -* quota-maxoustanding which is the number of responses not read from the ring: - once exceeded, no more inputs are processed until all outstanding replies - are consumed by the client. -* overflow queue on the watch event source: all watches that cannot be stored - on destination are queued up here, a single command can trigger multiple - watches (e.g. due to recursion). - -The overflow queue currently doesn't have an upper bound, it is difficult to -accurately calculate one as it depends on whether you are Dom0 and how many -watches each path has registered and how many watch events you can trigger -with a single command (e.g. a commit). However these events were already -using memory, this just moves them elsewhere, and as long as we correctly -block a domain it shouldn't result in unbounded memory usage. - -Note that Dom0 is not excluded from these checks, it is important that Dom0 is -especially not excluded when it is the source, since there are many ways in -which a guest could trigger Dom0 to send it watch events. - -This should protect against malicious frontends as long as the backend follows -the PV xenstore protocol and only exposes paths needed by the frontend, and -changes those paths at most once as a reaction to guest events, or protocol -state. - -The queue limits are per watch, and per domain-pair, so even if one -communication channel would be "blocked", others would keep working, and the -domain itself won't get blocked as long as it doesn't overflow the queue of -watch events. - -Similarly a malicious backend could cause the frontend to get blocked, but -this watch queue protects the frontend as well as long as it follows the PV -protocol. (Although note that protection against malicious backends is only a -best effort at the moment) - -This is part of XSA-326 / CVE-2022-42318. - -Reported-by: Julien Grall -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/xb.ml b/tools/ocaml/libs/xb/xb.ml -index 4197a3888a68..b292ed7a874d 100644 ---- a/tools/ocaml/libs/xb/xb.ml -+++ b/tools/ocaml/libs/xb/xb.ml -@@ -134,14 +134,44 @@ type backend = Fd of backend_fd | Xenmmap of backend_mmap - - type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes - -+(* -+ separate capacity reservation for replies and watch events: -+ this allows a domain to keep working even when under a constant flood of -+ watch events -+*) -+type capacity = { maxoutstanding: int; maxwatchevents: int } -+ -+module Queue = BoundedQueue -+ -+type packet_class = -+ | CommandReply -+ | Watchevent -+ -+let string_of_packet_class = function -+ | CommandReply -> "command_reply" -+ | Watchevent -> "watch_event" -+ - type t = - { - backend: backend; -- pkt_out: Packet.t Queue.t; -+ pkt_out: (Packet.t, packet_class) Queue.t; - mutable partial_in: partial_buf; - mutable partial_out: string; -+ capacity: capacity - } - -+let to_read con = -+ match con.partial_in with -+ | HaveHdr partial_pkt -> Partial.to_complete partial_pkt -+ | NoHdr (i, _) -> i -+ -+let debug t = -+ Printf.sprintf "XenBus state: partial_in: %d needed, partial_out: %d bytes, pkt_out: %d packets, %s" -+ (to_read t) -+ (String.length t.partial_out) -+ (Queue.length t.pkt_out) -+ (BoundedQueue.debug string_of_packet_class t.pkt_out) -+ - let init_partial_in () = NoHdr - (Partial.header_size (), Bytes.make (Partial.header_size()) '\000') - -@@ -199,7 +229,8 @@ let output con = - let s = if String.length con.partial_out > 0 then - con.partial_out - else if Queue.length con.pkt_out > 0 then -- Packet.to_string (Queue.pop con.pkt_out) -+ let pkt = Queue.pop con.pkt_out in -+ Packet.to_string pkt - else - "" in - (* send data from s, and save the unsent data to partial_out *) -@@ -212,12 +243,15 @@ let output con = - (* after sending one packet, partial is empty *) - con.partial_out = "" - -+(* we can only process an input packet if we're guaranteed to have room -+ to store the response packet *) -+let can_input con = Queue.can_push con.pkt_out CommandReply -+ - (* NB: can throw Reconnect *) - let input con = -- let to_read = -- match con.partial_in with -- | HaveHdr partial_pkt -> Partial.to_complete partial_pkt -- | NoHdr (i, _) -> i in -+ if not (can_input con) then None -+ else -+ let to_read = to_read con in - - (* try to get more data from input stream *) - let b = Bytes.make to_read '\000' in -@@ -243,11 +277,22 @@ let input con = - None - ) - --let newcon backend = { -+let classify t = -+ match t.Packet.ty with -+ | Op.Watchevent -> Watchevent -+ | _ -> CommandReply -+ -+let newcon ~capacity backend = -+ let limit = function -+ | CommandReply -> capacity.maxoutstanding -+ | Watchevent -> capacity.maxwatchevents -+ in -+ { - backend = backend; -- pkt_out = Queue.create (); -+ pkt_out = Queue.create ~capacity:(capacity.maxoutstanding + capacity.maxwatchevents) ~classify ~limit; - partial_in = init_partial_in (); - partial_out = ""; -+ capacity = capacity; - } - - let open_fd fd = newcon (Fd { fd = fd; }) -diff --git a/tools/ocaml/libs/xb/xb.mli b/tools/ocaml/libs/xb/xb.mli -index 91c682162cea..71b2754ca788 100644 ---- a/tools/ocaml/libs/xb/xb.mli -+++ b/tools/ocaml/libs/xb/xb.mli -@@ -66,10 +66,11 @@ type backend_mmap = { - type backend_fd = { fd : Unix.file_descr; } - type backend = Fd of backend_fd | Xenmmap of backend_mmap - type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * bytes -+type capacity = { maxoutstanding: int; maxwatchevents: int } - type t - val init_partial_in : unit -> partial_buf - val reconnect : t -> unit --val queue : t -> Packet.t -> unit -+val queue : t -> Packet.t -> unit option - val read_fd : backend_fd -> 'a -> bytes -> int -> int - val read_mmap : backend_mmap -> 'a -> bytes -> int -> int - val read : t -> bytes -> int -> int -@@ -78,13 +79,14 @@ val write_mmap : backend_mmap -> 'a -> string -> int -> int - val write : t -> string -> int -> int - val output : t -> bool - val input : t -> Packet.t option --val newcon : backend -> t --val open_fd : Unix.file_descr -> t --val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> t -+val newcon : capacity:capacity -> backend -> t -+val open_fd : Unix.file_descr -> capacity:capacity -> t -+val open_mmap : Xenmmap.mmap_interface -> (unit -> unit) -> capacity:capacity -> t - val close : t -> unit - val is_fd : t -> bool - val is_mmap : t -> bool - val output_len : t -> int -+val can_input: t -> bool - val has_new_output : t -> bool - val has_old_output : t -> bool - val has_output : t -> bool -@@ -93,3 +95,4 @@ val has_partial_input : t -> bool - val has_more_input : t -> bool - val is_selectable : t -> bool - val get_fd : t -> Unix.file_descr -+val debug: t -> string -diff --git a/tools/ocaml/libs/xs/queueop.ml b/tools/ocaml/libs/xs/queueop.ml -index 9ff5bbd529ce..4e532cdaeacb 100644 ---- a/tools/ocaml/libs/xs/queueop.ml -+++ b/tools/ocaml/libs/xs/queueop.ml -@@ -16,9 +16,10 @@ - open Xenbus - - let data_concat ls = (String.concat "\000" ls) ^ "\000" -+let queue con pkt = let r = Xb.queue con pkt in assert (r <> None) - let queue_path ty (tid: int) (path: string) con = - let data = data_concat [ path; ] in -- Xb.queue con (Xb.Packet.create tid 0 ty data) -+ queue con (Xb.Packet.create tid 0 ty data) - - (* operations *) - let directory tid path con = queue_path Xb.Op.Directory tid path con -@@ -27,48 +28,48 @@ let read tid path con = queue_path Xb.Op.Read tid path con - let getperms tid path con = queue_path Xb.Op.Getperms tid path con - - let debug commands con = -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands)) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Debug (data_concat commands)) - - let watch path data con = - let data = data_concat [ path; data; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Watch data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Watch data) - - let unwatch path data con = - let data = data_concat [ path; data; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Unwatch data) - - let transaction_start con = -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat [])) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Transaction_start (data_concat [])) - - let transaction_end tid commit con = - let data = data_concat [ (if commit then "T" else "F"); ] in -- Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data) -+ queue con (Xb.Packet.create tid 0 Xb.Op.Transaction_end data) - - let introduce domid mfn port con = - let data = data_concat [ Printf.sprintf "%u" domid; - Printf.sprintf "%nu" mfn; - string_of_int port; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Introduce data) - - let release domid con = - let data = data_concat [ Printf.sprintf "%u" domid; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Release data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Release data) - - let resume domid con = - let data = data_concat [ Printf.sprintf "%u" domid; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Resume data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Resume data) - - let getdomainpath domid con = - let data = data_concat [ Printf.sprintf "%u" domid; ] in -- Xb.queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data) -+ queue con (Xb.Packet.create 0 0 Xb.Op.Getdomainpath data) - - let write tid path value con = - let data = path ^ "\000" ^ value (* no NULL at the end *) in -- Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Write data) -+ queue con (Xb.Packet.create tid 0 Xb.Op.Write data) - - let mkdir tid path con = queue_path Xb.Op.Mkdir tid path con - let rm tid path con = queue_path Xb.Op.Rm tid path con - - let setperms tid path perms con = - let data = data_concat [ path; perms ] in -- Xb.queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data) -+ queue con (Xb.Packet.create tid 0 Xb.Op.Setperms data) -diff --git a/tools/ocaml/libs/xs/xsraw.ml b/tools/ocaml/libs/xs/xsraw.ml -index 451f8b38dbcc..cbd17280600c 100644 ---- a/tools/ocaml/libs/xs/xsraw.ml -+++ b/tools/ocaml/libs/xs/xsraw.ml -@@ -36,8 +36,10 @@ type con = { - let close con = - Xb.close con.xb - -+let capacity = { Xb.maxoutstanding = 1; maxwatchevents = 0; } -+ - let open_fd fd = { -- xb = Xb.open_fd fd; -+ xb = Xb.open_fd ~capacity fd; - watchevents = Queue.create (); - } - -diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml -index cc20e047d2b9..9624a5f9da2c 100644 ---- a/tools/ocaml/xenstored/connection.ml -+++ b/tools/ocaml/xenstored/connection.ml -@@ -20,12 +20,84 @@ open Stdext - - let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *) - -+type 'a bounded_sender = 'a -> unit option -+(** a bounded sender accepts an ['a] item and returns: -+ None - if there is no room to accept the item -+ Some () - if it has successfully accepted/sent the item -+ *) -+ -+module BoundedPipe : sig -+ type 'a t -+ -+ (** [create ~capacity ~destination] creates a bounded pipe with a -+ local buffer holding at most [capacity] items. Once the buffer is -+ full it will not accept further items. items from the pipe are -+ flushed into [destination] as long as it accepts items. The -+ destination could be another pipe. -+ *) -+ val create: capacity:int -> destination:'a bounded_sender -> 'a t -+ -+ (** [is_empty t] returns whether the local buffer of [t] is empty. *) -+ val is_empty : _ t -> bool -+ -+ (** [length t] the number of items in the internal buffer *) -+ val length: _ t -> int -+ -+ (** [flush_pipe t] sends as many items from the local buffer as possible, -+ which could be none. *) -+ val flush_pipe: _ t -> unit -+ -+ (** [push t item] tries to [flush_pipe] and then push [item] -+ into the pipe if its [capacity] allows. -+ Returns [None] if there is no more room -+ *) -+ val push : 'a t -> 'a bounded_sender -+end = struct -+ (* items are enqueued in [q], and then flushed to [connect_to] *) -+ type 'a t = -+ { q: 'a Queue.t -+ ; destination: 'a bounded_sender -+ ; capacity: int -+ } -+ -+ let create ~capacity ~destination = -+ { q = Queue.create (); capacity; destination } -+ -+ let rec flush_pipe t = -+ if not Queue.(is_empty t.q) then -+ let item = Queue.peek t.q in -+ match t.destination item with -+ | None -> () (* no room *) -+ | Some () -> -+ (* successfully sent item to next stage *) -+ let _ = Queue.pop t.q in -+ (* continue trying to send more items *) -+ flush_pipe t -+ -+ let push t item = -+ (* first try to flush as many items from this pipe as possible to make room, -+ it is important to do this first to preserve the order of the items -+ *) -+ flush_pipe t; -+ if Queue.length t.q < t.capacity then begin -+ (* enqueue, instead of sending directly. -+ this ensures that [out] sees the items in the same order as we receive them -+ *) -+ Queue.push item t.q; -+ Some (flush_pipe t) -+ end else None -+ -+ let is_empty t = Queue.is_empty t.q -+ let length t = Queue.length t.q -+end -+ - type watch = { - con: t; - token: string; - path: string; - base: string; - is_relative: bool; -+ pending_watchevents: Xenbus.Xb.Packet.t BoundedPipe.t; - } - - and t = { -@@ -38,8 +110,36 @@ and t = { - anonid: int; - mutable stat_nb_ops: int; - mutable perm: Perms.Connection.t; -+ pending_source_watchevents: (watch * Xenbus.Xb.Packet.t) BoundedPipe.t - } - -+module Watch = struct -+ module T = struct -+ type t = watch -+ -+ let compare w1 w2 = -+ (* cannot compare watches from different connections *) -+ assert (w1.con == w2.con); -+ match String.compare w1.token w2.token with -+ | 0 -> String.compare w1.path w2.path -+ | n -> n -+ end -+ module Set = Set.Make(T) -+ -+ let flush_events t = -+ BoundedPipe.flush_pipe t.pending_watchevents; -+ not (BoundedPipe.is_empty t.pending_watchevents) -+ -+ let pending_watchevents t = -+ BoundedPipe.length t.pending_watchevents -+end -+ -+let source_flush_watchevents t = -+ BoundedPipe.flush_pipe t.pending_source_watchevents -+ -+let source_pending_watchevents t = -+ BoundedPipe.length t.pending_source_watchevents -+ - let mark_as_bad con = - match con.dom with - |None -> () -@@ -67,7 +167,8 @@ let watch_create ~con ~path ~token = { - token = token; - path = path; - base = get_path con; -- is_relative = path.[0] <> '/' && path.[0] <> '@' -+ is_relative = path.[0] <> '/' && path.[0] <> '@'; -+ pending_watchevents = BoundedPipe.create ~capacity:!Define.maxwatchevents ~destination:(Xenbus.Xb.queue con.xb) - } - - let get_con w = w.con -@@ -93,6 +194,9 @@ let make_perm dom = - Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid - - let create xbcon dom = -+ let destination (watch, pkt) = -+ BoundedPipe.push watch.pending_watchevents pkt -+ in - let id = - match dom with - | None -> let old = !anon_id_next in incr anon_id_next; old -@@ -109,6 +213,16 @@ let create xbcon dom = - anonid = id; - stat_nb_ops = 0; - perm = make_perm dom; -+ -+ (* the actual capacity will be lower, this is used as an overflow -+ buffer: anything that doesn't fit elsewhere gets put here, only -+ limited by the amount of watches that you can generate with a -+ single xenstore command (which is finite, although possibly very -+ large in theory for Dom0). Once the pipe here has any contents the -+ domain is blocked from sending more commands until it is empty -+ again though. -+ *) -+ pending_source_watchevents = BoundedPipe.create ~capacity:Sys.max_array_length ~destination - } - in - Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con); -@@ -127,11 +241,17 @@ let set_target con target_domid = - - let is_backend_mmap con = Xenbus.Xb.is_mmap con.xb - --let send_reply con tid rid ty data = -+let packet_of con tid rid ty data = - if (String.length data) > xenstore_payload_max && (is_backend_mmap con) then -- Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000") -+ Xenbus.Xb.Packet.create tid rid Xenbus.Xb.Op.Error "E2BIG\000" - else -- Xenbus.Xb.queue con.xb (Xenbus.Xb.Packet.create tid rid ty data) -+ Xenbus.Xb.Packet.create tid rid ty data -+ -+let send_reply con tid rid ty data = -+ let result = Xenbus.Xb.queue con.xb (packet_of con tid rid ty data) in -+ (* should never happen: we only process an input packet when there is room for an output packet *) -+ (* and the limit for replies is different from the limit for watch events *) -+ assert (result <> None) - - let send_error con tid rid err = send_reply con tid rid Xenbus.Xb.Op.Error (err ^ "\000") - let send_ack con tid rid ty = send_reply con tid rid ty "OK\000" -@@ -181,11 +301,11 @@ let del_watch con path token = - apath, w - - let del_watches con = -- Hashtbl.clear con.watches; -+ Hashtbl.reset con.watches; - con.nb_watches <- 0 - - let del_transactions con = -- Hashtbl.clear con.transactions -+ Hashtbl.reset con.transactions - - let list_watches con = - let ll = Hashtbl.fold -@@ -208,21 +328,29 @@ let lookup_watch_perm path = function - let lookup_watch_perms oldroot root path = - lookup_watch_perm path oldroot @ lookup_watch_perm path (Some root) - --let fire_single_watch_unchecked watch = -+let fire_single_watch_unchecked source watch = - let data = Utils.join_by_null [watch.path; watch.token; ""] in -- send_reply watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data -+ let pkt = packet_of watch.con Transaction.none 0 Xenbus.Xb.Op.Watchevent data in -+ -+ match BoundedPipe.push source.pending_source_watchevents (watch, pkt) with -+ | Some () -> () (* packet queued *) -+ | None -> -+ (* a well behaved Dom0 shouldn't be able to trigger this, -+ if it happens it is likely a Dom0 bug causing runaway memory usage -+ *) -+ failwith "watch event overflow, cannot happen" - --let fire_single_watch (oldroot, root) watch = -+let fire_single_watch source (oldroot, root) watch = - let abspath = get_watch_path watch.con watch.path |> Store.Path.of_string in - let perms = lookup_watch_perms oldroot root abspath in - if Perms.can_fire_watch watch.con.perm perms then -- fire_single_watch_unchecked watch -+ fire_single_watch_unchecked source watch - else - let perms = perms |> List.map (Perms.Node.to_string ~sep:" ") |> String.concat ", " in - let con = get_domstr watch.con in - Logging.watch_not_fired ~con perms (Store.Path.to_string abspath) - --let fire_watch roots watch path = -+let fire_watch source roots watch path = - let new_path = - if watch.is_relative && path.[0] = '/' - then begin -@@ -232,7 +360,7 @@ let fire_watch roots watch path = - end else - path - in -- fire_single_watch roots { watch with path = new_path } -+ fire_single_watch source roots { watch with path = new_path } - - (* Search for a valid unused transaction id. *) - let rec valid_transaction_id con proposed_id = -@@ -280,6 +408,7 @@ let do_input con = Xenbus.Xb.input con.xb - let has_partial_input con = Xenbus.Xb.has_partial_input con.xb - let has_more_input con = Xenbus.Xb.has_more_input con.xb - -+let can_input con = Xenbus.Xb.can_input con.xb && BoundedPipe.is_empty con.pending_source_watchevents - let has_output con = Xenbus.Xb.has_output con.xb - let has_old_output con = Xenbus.Xb.has_old_output con.xb - let has_new_output con = Xenbus.Xb.has_new_output con.xb -@@ -323,7 +452,7 @@ let prevents_live_update con = not (is_bad con) - && (has_extra_connection_data con || has_transaction_data con) - - let has_more_work con = -- has_more_input con || not (has_old_output con) && has_new_output con -+ (has_more_input con && can_input con) || not (has_old_output con) && has_new_output con - - let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1 - -diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml -index 3c7429fe7f61..7d68c583b43a 100644 ---- a/tools/ocaml/xenstored/connections.ml -+++ b/tools/ocaml/xenstored/connections.ml -@@ -22,22 +22,30 @@ type t = { - domains: (int, Connection.t) Hashtbl.t; - ports: (Xeneventchn.t, Connection.t) Hashtbl.t; - mutable watches: Connection.watch list Trie.t; -+ mutable has_pending_watchevents: Connection.Watch.Set.t - } - - let create () = { - anonymous = Hashtbl.create 37; - domains = Hashtbl.create 37; - ports = Hashtbl.create 37; -- watches = Trie.create () -+ watches = Trie.create (); -+ has_pending_watchevents = Connection.Watch.Set.empty; - } - -+let get_capacity () = -+ (* not multiplied by maxwatch on purpose: 2nd queue in watch itself! *) -+ { Xenbus.Xb.maxoutstanding = !Define.maxoutstanding; maxwatchevents = !Define.maxwatchevents } -+ - let add_anonymous cons fd = -- let xbcon = Xenbus.Xb.open_fd fd in -+ let capacity = get_capacity () in -+ let xbcon = Xenbus.Xb.open_fd fd ~capacity in - let con = Connection.create xbcon None in - Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con - - let add_domain cons dom = -- let xbcon = Xenbus.Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in -+ let capacity = get_capacity () in -+ let xbcon = Xenbus.Xb.open_mmap ~capacity (Domain.get_interface dom) (fun () -> Domain.notify dom) in - let con = Connection.create xbcon (Some dom) in - Hashtbl.add cons.domains (Domain.get_id dom) con; - match Domain.get_port dom with -@@ -48,7 +56,9 @@ let select ?(only_if = (fun _ -> true)) cons = - Hashtbl.fold (fun _ con (ins, outs) -> - if (only_if con) then ( - let fd = Connection.get_fd con in -- (fd :: ins, if Connection.has_output con then fd :: outs else outs) -+ let in_fds = if Connection.can_input con then fd :: ins else ins in -+ let out_fds = if Connection.has_output con then fd :: outs else outs in -+ in_fds, out_fds - ) else (ins, outs) - ) - cons.anonymous ([], []) -@@ -67,10 +77,17 @@ let del_watches_of_con con watches = - | [] -> None - | ws -> Some ws - -+let del_watches cons con = -+ Connection.del_watches con; -+ cons.watches <- Trie.map (del_watches_of_con con) cons.watches; -+ cons.has_pending_watchevents <- -+ cons.has_pending_watchevents |> Connection.Watch.Set.filter @@ fun w -> -+ Connection.get_con w != con -+ - let del_anonymous cons con = - try - Hashtbl.remove cons.anonymous (Connection.get_fd con); -- cons.watches <- Trie.map (del_watches_of_con con) cons.watches; -+ del_watches cons con; - Connection.close con - with exn -> - debug "del anonymous %s" (Printexc.to_string exn) -@@ -85,7 +102,7 @@ let del_domain cons id = - | Some p -> Hashtbl.remove cons.ports p - | None -> ()) - | None -> ()); -- cons.watches <- Trie.map (del_watches_of_con con) cons.watches; -+ del_watches cons con; - Connection.close con - with exn -> - debug "del domain %u: %s" id (Printexc.to_string exn) -@@ -136,31 +153,33 @@ let del_watch cons con path token = - cons.watches <- Trie.set cons.watches key watches; - watch - --let del_watches cons con = -- Connection.del_watches con; -- cons.watches <- Trie.map (del_watches_of_con con) cons.watches -- - (* path is absolute *) --let fire_watches ?oldroot root cons path recurse = -+let fire_watches ?oldroot source root cons path recurse = - let key = key_of_path path in - let path = Store.Path.to_string path in - let roots = oldroot, root in - let fire_watch _ = function - | None -> () -- | Some watches -> List.iter (fun w -> Connection.fire_watch roots w path) watches -+ | Some watches -> List.iter (fun w -> Connection.fire_watch source roots w path) watches - in - let fire_rec _x = function - | None -> () - | Some watches -> -- List.iter (Connection.fire_single_watch roots) watches -+ List.iter (Connection.fire_single_watch source roots) watches - in - Trie.iter_path fire_watch cons.watches key; - if recurse then - Trie.iter fire_rec (Trie.sub cons.watches key) - -+let send_watchevents cons con = -+ cons.has_pending_watchevents <- -+ cons.has_pending_watchevents |> Connection.Watch.Set.filter Connection.Watch.flush_events; -+ Connection.source_flush_watchevents con -+ - let fire_spec_watches root cons specpath = -+ let source = find_domain cons 0 in - iter cons (fun con -> -- List.iter (Connection.fire_single_watch (None, root)) (Connection.get_watches con specpath)) -+ List.iter (Connection.fire_single_watch source (None, root)) (Connection.get_watches con specpath)) - - let set_target cons domain target_domain = - let con = find_domain cons domain in -@@ -197,6 +216,16 @@ let debug cons = - let domains = Hashtbl.fold (fun _ con accu -> Connection.debug con :: accu) cons.domains [] in - String.concat "" (domains @ anonymous) - -+let debug_watchevents cons con = -+ (* == (physical equality) -+ has to be used here because w.con.xb.backend might contain a [unit->unit] value causing regular -+ comparison to fail due to having a 'functional value' which cannot be compared. -+ *) -+ let s = cons.has_pending_watchevents |> Connection.Watch.Set.filter (fun w -> w.con == con) in -+ let pending = s |> Connection.Watch.Set.elements -+ |> List.map (fun w -> Connection.Watch.pending_watchevents w) |> List.fold_left (+) 0 in -+ Printf.sprintf "Watches with pending events: %d, pending events total: %d" (Connection.Watch.Set.cardinal s) pending -+ - let filter ~f cons = - let fold _ v acc = if f v then v :: acc else acc in - [] -diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml -index ba63a8147e09..327b6d795ec7 100644 ---- a/tools/ocaml/xenstored/define.ml -+++ b/tools/ocaml/xenstored/define.ml -@@ -24,6 +24,13 @@ let default_config_dir = Paths.xen_config_dir - let maxwatch = ref (100) - let maxtransaction = ref (10) - let maxrequests = ref (1024) (* maximum requests per transaction *) -+let maxoutstanding = ref (1024) (* maximum outstanding requests, i.e. in-flight requests / domain *) -+let maxwatchevents = ref (1024) -+(* -+ maximum outstanding watch events per watch, -+ recommended >= maxoutstanding to avoid blocking backend transactions due to -+ malicious frontends -+ *) - - let gc_max_overhead = ref 120 (* 120% see comment in xenstored.ml *) - let conflict_burst_limit = ref 5.0 -diff --git a/tools/ocaml/xenstored/oxenstored.conf.in b/tools/ocaml/xenstored/oxenstored.conf.in -index 4ae48e42d47d..9d034e744b4b 100644 ---- a/tools/ocaml/xenstored/oxenstored.conf.in -+++ b/tools/ocaml/xenstored/oxenstored.conf.in -@@ -62,6 +62,8 @@ quota-maxwatch = 100 - quota-transaction = 10 - quota-maxrequests = 1024 - quota-path-max = 1024 -+quota-maxoutstanding = 1024 -+quota-maxwatchevents = 1024 - - # Activate filed base backend - persistent = false -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 2d67456a2aa0..6dcedfda86e4 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -57,7 +57,7 @@ let split_one_path data con = - | path :: "" :: [] -> Store.Path.create path (Connection.get_path con) - | _ -> raise Invalid_Cmd_Args - --let process_watch t cons = -+let process_watch source t cons = - let oldroot = t.Transaction.oldroot in - let newroot = Store.get_root t.store in - let ops = Transaction.get_paths t |> List.rev in -@@ -67,8 +67,9 @@ let process_watch t cons = - | Xenbus.Xb.Op.Rm -> true, None, oldroot - | Xenbus.Xb.Op.Setperms -> false, Some oldroot, newroot - | _ -> raise (Failure "huh ?") in -- Connections.fire_watches ?oldroot root cons (snd op) recurse in -- List.iter (fun op -> do_op_watch op cons) ops -+ Connections.fire_watches ?oldroot source root cons (snd op) recurse in -+ List.iter (fun op -> do_op_watch op cons) ops; -+ Connections.send_watchevents cons source - - let create_implicit_path t perm path = - let dirname = Store.Path.get_parent path in -@@ -234,6 +235,20 @@ let do_debug con t _domains cons data = - | "watches" :: _ -> - let watches = Connections.debug cons in - Some (watches ^ "\000") -+ | "xenbus" :: domid :: _ -> -+ let domid = int_of_string domid in -+ let con = Connections.find_domain cons domid in -+ let s = Printf.sprintf "xenbus: %s; overflow queue length: %d, can_input: %b, has_more_input: %b, has_old_output: %b, has_new_output: %b, has_more_work: %b. pending: %s" -+ (Xenbus.Xb.debug con.xb) -+ (Connection.source_pending_watchevents con) -+ (Connection.can_input con) -+ (Connection.has_more_input con) -+ (Connection.has_old_output con) -+ (Connection.has_new_output con) -+ (Connection.has_more_work con) -+ (Connections.debug_watchevents cons con) -+ in -+ Some s - | "mfn" :: domid :: _ -> - let domid = int_of_string domid in - let con = Connections.find_domain cons domid in -@@ -342,7 +357,7 @@ let reply_ack fct con t doms cons data = - fct con t doms cons data; - Packet.Ack (fun () -> - if Transaction.get_id t = Transaction.none then -- process_watch t cons -+ process_watch con t cons - ) - - let reply_data fct con t doms cons data = -@@ -501,7 +516,7 @@ let do_watch con t _domains cons data = - Packet.Ack (fun () -> - (* xenstore.txt says this watch is fired immediately, - implying even if path doesn't exist or is unreadable *) -- Connection.fire_single_watch_unchecked watch) -+ Connection.fire_single_watch_unchecked con watch) - - let do_unwatch con _t _domains cons data = - let (node, token) = -@@ -532,7 +547,7 @@ let do_transaction_end con t domains cons data = - if not success then - raise Transaction_again; - if commit then begin -- process_watch t cons; -+ process_watch con t cons; - match t.Transaction.ty with - | Transaction.No -> - () (* no need to record anything *) -@@ -699,7 +714,8 @@ let process_packet ~store ~cons ~doms ~con ~req = - let do_input store cons doms con = - let newpacket = - try -- Connection.do_input con -+ if Connection.can_input con then Connection.do_input con -+ else None - with Xenbus.Xb.Reconnect -> - info "%s requests a reconnect" (Connection.get_domstr con); - History.reconnect con; -@@ -727,6 +743,7 @@ let do_input store cons doms con = - Connection.incr_ops con - - let do_output _store _cons _doms con = -+ Connection.source_flush_watchevents con; - if Connection.has_output con then ( - if Connection.has_new_output con then ( - let packet = Connection.peek_output con in -diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml -index 3b57ad016dfb..c799e20f1145 100644 ---- a/tools/ocaml/xenstored/xenstored.ml -+++ b/tools/ocaml/xenstored/xenstored.ml -@@ -103,6 +103,8 @@ let parse_config filename = - ("quota-maxentity", Config.Set_int Quota.maxent); - ("quota-maxsize", Config.Set_int Quota.maxsize); - ("quota-maxrequests", Config.Set_int Define.maxrequests); -+ ("quota-maxoutstanding", Config.Set_int Define.maxoutstanding); -+ ("quota-maxwatchevents", Config.Set_int Define.maxwatchevents); - ("quota-path-max", Config.Set_int Define.path_max); - ("gc-max-overhead", Config.Set_int Define.gc_max_overhead); - ("test-eagain", Config.Set_bool Transaction.test_eagain); diff --git a/xsa326-4.16-oxenstored-08.patch b/xsa326-4.16-oxenstored-08.patch deleted file mode 100644 index 8a47200..0000000 --- a/xsa326-4.16-oxenstored-08.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 09aa10649f75a262028e9a9b7d859ef7efb23d54 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Thu, 29 Sep 2022 13:07:35 +0200 -Subject: SUPPORT.md: clarify support of untrusted driver domains with - oxenstored - -Add a support statement for the scope of support regarding different -Xenstore variants. Especially oxenstored does not (yet) have security -support of untrusted driver domains, as those might drive oxenstored -out of memory by creating lots of watch events for the guests they are -servicing. - -Add a statement regarding Live Update support of oxenstored. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: George Dunlap -Acked-by: Julien Grall -Reviewed-by: Christian Lindig - -diff --git a/SUPPORT.md b/SUPPORT.md -index 85726102eab8..7d0cb34c8f6f 100644 ---- a/SUPPORT.md -+++ b/SUPPORT.md -@@ -179,13 +179,18 @@ Support for running qemu-xen device model in a linux stubdomain. - - Status: Tech Preview - --## Liveupdate of C xenstored daemon -+## Xenstore - -- Status: Tech Preview -+### C xenstored daemon - --## Liveupdate of OCaml xenstored daemon -+ Status: Supported -+ Status, Liveupdate: Tech Preview - -- Status: Tech Preview -+### OCaml xenstored daemon -+ -+ Status: Supported -+ Status, untrusted driver domains: Supported, not security supported -+ Status, Liveupdate: Not functional - - ## Toolstack/3rd party - diff --git a/xsa326-4.16-xenstored-01.patch b/xsa326-4.16-xenstored-01.patch deleted file mode 100644 index b4a4b0e..0000000 --- a/xsa326-4.16-xenstored-01.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 5192f13a41661b1c1b9e0889d57c0f5b41925c39 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: split up send_reply() - -Today send_reply() is used for both, normal request replies and watch -events. - -Split it up into send_reply() and send_event(). This will be used to -add some event specific handling. - -add_event() can be merged into send_event(), removing the need for an -intermediate memory allocation. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index e9c9695fd16e..249ad5ec6fb1 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -767,49 +767,32 @@ static void send_error(struct connection *conn, int error) - void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - const void *data, unsigned int len) - { -- struct buffered_data *bdata; -+ struct buffered_data *bdata = conn->in; -+ -+ assert(type != XS_WATCH_EVENT); - - if ( len > XENSTORE_PAYLOAD_MAX ) { - send_error(conn, E2BIG); - return; - } - -- /* Replies reuse the request buffer, events need a new one. */ -- if (type != XS_WATCH_EVENT) { -- bdata = conn->in; -- /* Drop asynchronous responses, e.g. errors for watch events. */ -- if (!bdata) -- return; -- bdata->inhdr = true; -- bdata->used = 0; -- conn->in = NULL; -- } else { -- /* Message is a child of the connection for auto-cleanup. */ -- bdata = new_buffer(conn); -+ if (!bdata) -+ return; -+ bdata->inhdr = true; -+ bdata->used = 0; - -- /* -- * Allocation failure here is unfortunate: we have no way to -- * tell anybody about it. -- */ -- if (!bdata) -- return; -- } - if (len <= DEFAULT_BUFFER_SIZE) - bdata->buffer = bdata->default_buffer; -- else -+ else { - bdata->buffer = talloc_array(bdata, char, len); -- if (!bdata->buffer) { -- if (type == XS_WATCH_EVENT) { -- /* Same as above: no way to tell someone. */ -- talloc_free(bdata); -+ if (!bdata->buffer) { -+ send_error(conn, ENOMEM); - return; - } -- /* re-establish request buffer for sending ENOMEM. */ -- conn->in = bdata; -- send_error(conn, ENOMEM); -- return; - } - -+ conn->in = NULL; -+ - /* Update relevant header fields and fill in the message body. */ - bdata->hdr.msg.type = type; - bdata->hdr.msg.len = len; -@@ -817,8 +800,39 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+} - -- return; -+/* -+ * Send a watch event. -+ * As this is not directly related to the current command, errors can't be -+ * reported. -+ */ -+void send_event(struct connection *conn, const char *path, const char *token) -+{ -+ struct buffered_data *bdata; -+ unsigned int len; -+ -+ len = strlen(path) + 1 + strlen(token) + 1; -+ /* Don't try to send over-long events. */ -+ if (len > XENSTORE_PAYLOAD_MAX) -+ return; -+ -+ bdata = new_buffer(conn); -+ if (!bdata) -+ return; -+ -+ bdata->buffer = talloc_array(bdata, char, len); -+ if (!bdata->buffer) { -+ talloc_free(bdata); -+ return; -+ } -+ strcpy(bdata->buffer, path); -+ strcpy(bdata->buffer + strlen(path) + 1, token); -+ bdata->hdr.msg.type = XS_WATCH_EVENT; -+ bdata->hdr.msg.len = len; -+ -+ /* Queue for later transmission. */ -+ list_add_tail(&bdata->list, &conn->out_list); - } - - /* Some routines (write, mkdir, etc) just need a non-error return */ -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 0004fa848c83..9af9af4390bd 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -187,6 +187,7 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset); - - void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - const void *data, unsigned int len); -+void send_event(struct connection *conn, const char *path, const char *token); - - /* Some routines (write, mkdir, etc) just need a non-error return */ - void send_ack(struct connection *conn, enum xsd_sockmsg_type type); -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index aca0a71bada1..99a2c266b28a 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -86,35 +86,6 @@ static const char *get_watch_path(const struct watch *watch, const char *name) - } - - /* -- * Send a watch event. -- * Temporary memory allocations are done with ctx. -- */ --static void add_event(struct connection *conn, -- const void *ctx, -- struct watch *watch, -- const char *name) --{ -- /* Data to send (node\0token\0). */ -- unsigned int len; -- char *data; -- -- name = get_watch_path(watch, name); -- -- len = strlen(name) + 1 + strlen(watch->token) + 1; -- /* Don't try to send over-long events. */ -- if (len > XENSTORE_PAYLOAD_MAX) -- return; -- -- data = talloc_array(ctx, char, len); -- if (!data) -- return; -- strcpy(data, name); -- strcpy(data + strlen(name) + 1, watch->token); -- send_reply(conn, XS_WATCH_EVENT, data, len); -- talloc_free(data); --} -- --/* - * Check permissions of a specific watch to fire: - * Either the node itself or its parent have to be readable by the connection - * the watch has been setup for. In case a watch event is created due to -@@ -190,10 +161,14 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - list_for_each_entry(watch, &i->watches, list) { - if (exact) { - if (streq(name, watch->node)) -- add_event(i, ctx, watch, name); -+ send_event(i, -+ get_watch_path(watch, name), -+ watch->token); - } else { - if (is_child(name, watch->node)) -- add_event(i, ctx, watch, name); -+ send_event(i, -+ get_watch_path(watch, name), -+ watch->token); - } - } - } -@@ -292,7 +267,7 @@ int do_watch(struct connection *conn, struct buffered_data *in) - send_ack(conn, XS_WATCH); - - /* We fire once up front: simplifies clients and restart. */ -- add_event(conn, in, watch, watch->node); -+ send_event(conn, get_watch_path(watch, watch->node), watch->token); - - return 0; - } diff --git a/xsa326-4.16-xenstored-02.patch b/xsa326-4.16-xenstored-02.patch deleted file mode 100644 index 540ab03..0000000 --- a/xsa326-4.16-xenstored-02.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0a4c86f8a8febd85610496470123adfc4fbc1c5d Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: add helpers to free struct buffered_data - -Add two helpers for freeing struct buffered_data: free_buffered_data() -for freeing one instance and conn_free_buffered_data() for freeing all -instances for a connection. - -This is avoiding duplicated code and will help later when more actions -are needed when freeing a struct buffered_data. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 249ad5ec6fb1..527a1ebdeded 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -211,6 +211,21 @@ void reopen_log(void) - } - } - -+static void free_buffered_data(struct buffered_data *out, -+ struct connection *conn) -+{ -+ list_del(&out->list); -+ talloc_free(out); -+} -+ -+void conn_free_buffered_data(struct connection *conn) -+{ -+ struct buffered_data *out; -+ -+ while ((out = list_top(&conn->out_list, struct buffered_data, list))) -+ free_buffered_data(out, conn); -+} -+ - static bool write_messages(struct connection *conn) - { - int ret; -@@ -254,8 +269,7 @@ static bool write_messages(struct connection *conn) - - trace_io(conn, out, 1); - -- list_del(&out->list); -- talloc_free(out); -+ free_buffered_data(out, conn); - - return true; - } -@@ -1506,18 +1520,12 @@ static struct { - */ - void ignore_connection(struct connection *conn) - { -- struct buffered_data *out, *tmp; -- - trace("CONN %p ignored\n", conn); - - conn->is_ignored = true; - conn_delete_all_watches(conn); - conn_delete_all_transactions(conn); -- -- list_for_each_entry_safe(out, tmp, &conn->out_list, list) { -- list_del(&out->list); -- talloc_free(out); -- } -+ conn_free_buffered_data(conn); - - talloc_free(conn->in); - conn->in = NULL; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 9af9af4390bd..e7ee87825c3b 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -276,6 +276,8 @@ int remember_string(struct hashtable *hash, const char *str); - - void set_tdb_key(const char *name, TDB_DATA *key); - -+void conn_free_buffered_data(struct connection *conn); -+ - const char *dump_state_global(FILE *fp); - const char *dump_state_buffered_data(FILE *fp, const struct connection *c, - struct xs_state_connection *sc); -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index d03c7d93a9e7..93c4c1edcdd1 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -411,15 +411,10 @@ static struct domain *find_domain_by_domid(unsigned int domid) - static void domain_conn_reset(struct domain *domain) - { - struct connection *conn = domain->conn; -- struct buffered_data *out; - - conn_delete_all_watches(conn); - conn_delete_all_transactions(conn); -- -- while ((out = list_top(&conn->out_list, struct buffered_data, list))) { -- list_del(&out->list); -- talloc_free(out); -- } -+ conn_free_buffered_data(conn); - - talloc_free(conn->in); - diff --git a/xsa326-4.16-xenstored-03.patch b/xsa326-4.16-xenstored-03.patch deleted file mode 100644 index a3a0d81..0000000 --- a/xsa326-4.16-xenstored-03.patch +++ /dev/null @@ -1,192 +0,0 @@ -From a6c4198242bf69bea1825492b7665b559023390c Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: reduce number of watch events - -When removing a watched node outside of a transaction, two watch events -are being produced instead of just a single one. - -When finalizing a transaction watch events can be generated for each -node which is being modified, even if outside a transaction such -modifications might not have resulted in a watch event. - -This happens e.g.: - -- for nodes which are only modified due to added/removed child entries -- for nodes being removed or created implicitly (e.g. creation of a/b/c - is implicitly creating a/b, resulting in watch events for a, a/b and - a/b/c instead of a/b/c only) - -Avoid these additional watch events, in order to reduce the needed -memory inside Xenstore for queueing them. - -This is being achieved by adding event flags to struct accessed_node -specifying whether an event should be triggered, and whether it should -be an exact match of the modified path. Both flags can be set from -fire_watches() instead of implying them only. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 527a1ebdeded..bf2243873901 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1295,7 +1295,7 @@ static void delete_child(struct connection *conn, - } - - static int delete_node(struct connection *conn, const void *ctx, -- struct node *parent, struct node *node) -+ struct node *parent, struct node *node, bool watch_exact) - { - char *name; - -@@ -1307,7 +1307,7 @@ static int delete_node(struct connection *conn, const void *ctx, - node->children); - child = name ? read_node(conn, node, name) : NULL; - if (child) { -- if (delete_node(conn, ctx, node, child)) -+ if (delete_node(conn, ctx, node, child, true)) - return errno; - } else { - trace("delete_node: Error deleting child '%s/%s'!\n", -@@ -1319,7 +1319,12 @@ static int delete_node(struct connection *conn, const void *ctx, - talloc_free(name); - } - -- fire_watches(conn, ctx, node->name, node, true, NULL); -+ /* -+ * Fire the watches now, when we can still see the node permissions. -+ * This fine as we are single threaded and the next possible read will -+ * be handled only after the node has been really removed. -+ */ -+ fire_watches(conn, ctx, node->name, node, watch_exact, NULL); - delete_node_single(conn, node); - delete_child(conn, parent, basename(node->name)); - talloc_free(node); -@@ -1345,13 +1350,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - return (errno == ENOMEM) ? ENOMEM : EINVAL; - node->parent = parent; - -- /* -- * Fire the watches now, when we can still see the node permissions. -- * This fine as we are single threaded and the next possible read will -- * be handled only after the node has been really removed. -- */ -- fire_watches(conn, ctx, name, node, false, NULL); -- return delete_node(conn, ctx, parent, node); -+ return delete_node(conn, ctx, parent, node, false); - } - - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index faf6c930e42a..54432907fc76 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -130,6 +130,10 @@ struct accessed_node - - /* Transaction node in data base? */ - bool ta_node; -+ -+ /* Watch event flags. */ -+ bool fire_watch; -+ bool watch_exact; - }; - - struct changed_domain -@@ -324,6 +328,29 @@ int access_node(struct connection *conn, struct node *node, - } - - /* -+ * A watch event should be fired for a node modified inside a transaction. -+ * Set the corresponding information. A non-exact event is replacing an exact -+ * one, but not the other way round. -+ */ -+void queue_watches(struct connection *conn, const char *name, bool watch_exact) -+{ -+ struct accessed_node *i; -+ -+ i = find_accessed_node(conn->transaction, name); -+ if (!i) { -+ conn->transaction->fail = true; -+ return; -+ } -+ -+ if (!i->fire_watch) { -+ i->fire_watch = true; -+ i->watch_exact = watch_exact; -+ } else if (!watch_exact) { -+ i->watch_exact = false; -+ } -+} -+ -+/* - * Finalize transaction: - * Walk through accessed nodes and check generation against global data. - * If all entries match, read the transaction entries and write them without -@@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn, - ret = tdb_store(tdb_ctx, key, data, - TDB_REPLACE); - talloc_free(data.dptr); -- if (ret) -- goto err; -- fire_watches(conn, trans, i->node, NULL, false, -- i->perms.p ? &i->perms : NULL); - } else { -- fire_watches(conn, trans, i->node, NULL, false, -+ ret = tdb_delete(tdb_ctx, key); -+ } -+ if (ret) -+ goto err; -+ if (i->fire_watch) { -+ fire_watches(conn, trans, i->node, NULL, -+ i->watch_exact, - i->perms.p ? &i->perms : NULL); -- if (tdb_delete(tdb_ctx, key)) -- goto err; - } - } - -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 14062730e3c9..0093cac807e3 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid); - int access_node(struct connection *conn, struct node *node, - enum node_access_type type, TDB_DATA *key); - -+/* Queue watches for a modified node. */ -+void queue_watches(struct connection *conn, const char *name, bool watch_exact); -+ - /* Prepend the transaction to name if appropriate. */ - int transaction_prepend(struct connection *conn, const char *name, - TDB_DATA *key); -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 99a2c266b28a..205d9d8ea116 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -29,6 +29,7 @@ - #include "xenstore_lib.h" - #include "utils.h" - #include "xenstored_domain.h" -+#include "xenstored_transaction.h" - - extern int quota_nb_watch_per_domain; - -@@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - struct connection *i; - struct watch *watch; - -- /* During transactions, don't fire watches. */ -- if (conn && conn->transaction) -+ /* During transactions, don't fire watches, but queue them. */ -+ if (conn && conn->transaction) { -+ queue_watches(conn, name, exact); - return; -+ } - - /* Create an event for each watch. */ - list_for_each_entry(i, &connections, list) { diff --git a/xsa326-4.16-xenstored-04.patch b/xsa326-4.16-xenstored-04.patch deleted file mode 100644 index facbba4..0000000 --- a/xsa326-4.16-xenstored-04.patch +++ /dev/null @@ -1,302 +0,0 @@ -From 2feed737530592688382c655680982e10951c1ec Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:07 +0200 -Subject: tools/xenstore: let unread watch events time out - -A future modification will limit the number of outstanding requests -for a domain, where "outstanding" means that the response of the -request or any resulting watch event hasn't been consumed yet. - -In order to avoid a malicious guest being capable to block other guests -by not reading watch events, add a timeout for watch events. In case a -watch event hasn't been consumed after this timeout, it is being -deleted. Set the default timeout to 20 seconds (a random value being -not too high). - -In order to support to specify other timeout values in future, use a -generic command line option for that purpose: - ---timeout|-w watch-event= - -This is part of XSA-326 / CVE-2022-42311. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index bf2243873901..45244c021cd3 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -108,6 +108,8 @@ int quota_max_transaction = 10; - int quota_nb_perms_per_node = 5; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; - -+unsigned int timeout_watch_event_msec = 20000; -+ - void trace(const char *fmt, ...) - { - va_list arglist; -@@ -211,19 +213,92 @@ void reopen_log(void) - } - } - -+static uint64_t get_now_msec(void) -+{ -+ struct timespec now_ts; -+ -+ if (clock_gettime(CLOCK_MONOTONIC, &now_ts)) -+ barf_perror("Could not find time (clock_gettime failed)"); -+ -+ return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; -+} -+ - static void free_buffered_data(struct buffered_data *out, - struct connection *conn) - { -+ struct buffered_data *req; -+ - list_del(&out->list); -+ -+ /* -+ * Update conn->timeout_msec with the next found timeout value in the -+ * queued pending requests. -+ */ -+ if (out->timeout_msec) { -+ conn->timeout_msec = 0; -+ list_for_each_entry(req, &conn->out_list, list) { -+ if (req->timeout_msec) { -+ conn->timeout_msec = req->timeout_msec; -+ break; -+ } -+ } -+ } -+ - talloc_free(out); - } - -+static void check_event_timeout(struct connection *conn, uint64_t msecs, -+ int *ptimeout) -+{ -+ uint64_t delta; -+ struct buffered_data *out, *tmp; -+ -+ if (!conn->timeout_msec) -+ return; -+ -+ delta = conn->timeout_msec - msecs; -+ if (conn->timeout_msec <= msecs) { -+ delta = 0; -+ list_for_each_entry_safe(out, tmp, &conn->out_list, list) { -+ /* -+ * Only look at buffers with timeout and no data -+ * already written to the ring. -+ */ -+ if (out->timeout_msec && out->inhdr && !out->used) { -+ if (out->timeout_msec > msecs) { -+ conn->timeout_msec = out->timeout_msec; -+ delta = conn->timeout_msec - msecs; -+ break; -+ } -+ -+ /* -+ * Free out without updating conn->timeout_msec, -+ * as the update is done in this loop already. -+ */ -+ out->timeout_msec = 0; -+ trace("watch event path %s for domain %u timed out\n", -+ out->buffer, conn->id); -+ free_buffered_data(out, conn); -+ } -+ } -+ if (!delta) { -+ conn->timeout_msec = 0; -+ return; -+ } -+ } -+ -+ if (*ptimeout == -1 || *ptimeout > delta) -+ *ptimeout = delta; -+} -+ - void conn_free_buffered_data(struct connection *conn) - { - struct buffered_data *out; - - while ((out = list_top(&conn->out_list, struct buffered_data, list))) - free_buffered_data(out, conn); -+ -+ conn->timeout_msec = 0; - } - - static bool write_messages(struct connection *conn) -@@ -411,6 +486,7 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout) - { - struct connection *conn; - struct wrl_timestampt now; -+ uint64_t msecs; - - if (fds) - memset(fds, 0, sizeof(struct pollfd) * current_array_size); -@@ -431,10 +507,12 @@ static void initialize_fds(int *p_sock_pollfd_idx, int *ptimeout) - - wrl_gettime_now(&now); - wrl_log_periodic(now); -+ msecs = get_now_msec(); - - list_for_each_entry(conn, &connections, list) { - if (conn->domain) { - wrl_check_timeout(conn->domain, now, ptimeout); -+ check_event_timeout(conn, msecs, ptimeout); - if (conn_can_read(conn) || - (conn_can_write(conn) && - !list_empty(&conn->out_list))) -@@ -794,6 +872,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - return; - bdata->inhdr = true; - bdata->used = 0; -+ bdata->timeout_msec = 0; - - if (len <= DEFAULT_BUFFER_SIZE) - bdata->buffer = bdata->default_buffer; -@@ -845,6 +924,12 @@ void send_event(struct connection *conn, const char *path, const char *token) - bdata->hdr.msg.type = XS_WATCH_EVENT; - bdata->hdr.msg.len = len; - -+ if (timeout_watch_event_msec && domain_is_unprivileged(conn)) { -+ bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; -+ if (!conn->timeout_msec) -+ conn->timeout_msec = bdata->timeout_msec; -+ } -+ - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); - } -@@ -2201,6 +2286,9 @@ static void usage(void) - " -t, --transaction limit the number of transaction allowed per domain,\n" - " -A, --perm-nb limit the number of permissions per node,\n" - " -M, --path-max limit the allowed Xenstore node path length,\n" -+" -w, --timeout = set the timeout in seconds for ,\n" -+" allowed timeout candidates are:\n" -+" watch-event: time a watch-event is kept pending\n" - " -R, --no-recovery to request that no recovery should be attempted when\n" - " the store is corrupted (debug only),\n" - " -I, --internal-db store database in memory, not on disk\n" -@@ -2223,6 +2311,7 @@ static struct option options[] = { - { "transaction", 1, NULL, 't' }, - { "perm-nb", 1, NULL, 'A' }, - { "path-max", 1, NULL, 'M' }, -+ { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, - { "verbose", 0, NULL, 'V' }, -@@ -2236,6 +2325,39 @@ int dom0_domid = 0; - int dom0_event = 0; - int priv_domid = 0; - -+static int get_optval_int(const char *arg) -+{ -+ char *end; -+ long val; -+ -+ val = strtol(arg, &end, 10); -+ if (!*arg || *end || val < 0 || val > INT_MAX) -+ barf("invalid parameter value \"%s\"\n", arg); -+ -+ return val; -+} -+ -+static bool what_matches(const char *arg, const char *what) -+{ -+ unsigned int what_len = strlen(what); -+ -+ return !strncmp(arg, what, what_len) && arg[what_len] == '='; -+} -+ -+static void set_timeout(const char *arg) -+{ -+ const char *eq = strchr(arg, '='); -+ int val; -+ -+ if (!eq) -+ barf("quotas must be specified via =\n"); -+ val = get_optval_int(eq + 1); -+ if (what_matches(arg, "watch-event")) -+ timeout_watch_event_msec = val * 1000; -+ else -+ barf("unknown timeout \"%s\"\n", arg); -+} -+ - int main(int argc, char *argv[]) - { - int opt; -@@ -2250,7 +2372,7 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:U", options, -+ while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options, - NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2300,6 +2422,9 @@ int main(int argc, char *argv[]) - quota_max_path_len = min(XENSTORE_REL_PATH_MAX, - quota_max_path_len); - break; -+ case 'w': -+ set_timeout(optarg); -+ break; - case 'e': - dom0_event = strtol(optarg, NULL, 10); - break; -@@ -2741,6 +2866,12 @@ static void add_buffered_data(struct buffered_data *bdata, - barf("error restoring buffered data"); - - memcpy(bdata->buffer, data, len); -+ if (bdata->hdr.msg.type == XS_WATCH_EVENT && timeout_watch_event_msec && -+ domain_is_unprivileged(conn)) { -+ bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; -+ if (!conn->timeout_msec) -+ conn->timeout_msec = bdata->timeout_msec; -+ } - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index e7ee87825c3b..8a81fc693f01 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - - #include "xenstore_lib.h" -@@ -67,6 +68,8 @@ struct buffered_data - char raw[sizeof(struct xsd_sockmsg)]; - } hdr; - -+ uint64_t timeout_msec; -+ - /* The actual data. */ - char *buffer; - char default_buffer[DEFAULT_BUFFER_SIZE]; -@@ -118,6 +121,7 @@ struct connection - - /* Buffered output data */ - struct list_head out_list; -+ uint64_t timeout_msec; - - /* Transaction context for current request (NULL if none). */ - struct transaction *transaction; -@@ -244,6 +248,8 @@ extern int dom0_event; - extern int priv_domid; - extern int quota_nb_entry_per_domain; - -+extern unsigned int timeout_watch_event_msec; -+ - /* Map the kernel's xenstore page. */ - void *xenbus_map(void); - void unmap_xenbus(void *interface); diff --git a/xsa326-4.16-xenstored-05.patch b/xsa326-4.16-xenstored-05.patch deleted file mode 100644 index 77f9c25..0000000 --- a/xsa326-4.16-xenstored-05.patch +++ /dev/null @@ -1,443 +0,0 @@ -From 2eee122a45eb4a218596b103ce7f0759a824cf2e Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: limit outstanding requests - -Add another quota for limiting the number of outstanding requests of a -guest. As the way to specify quotas on the command line is becoming -rather nasty, switch to a new scheme using [--quota|-Q] = -allowing to add more quotas in future easily. - -Set the default value to 20 (basically a random value not seeming to -be too high or too low). - -A request is said to be outstanding if any message generated by this -request (the direct response plus potential watch events) is not yet -completely stored into a ring buffer. The initial watch event sent as -a result of registering a watch is an exception. - -Note that across a live update the relation to buffered watch events -for other domains is lost. - -Use talloc_zero() for allocating the domain structure in order to have -all per-domain quota zeroed initially. - -This is part of XSA-326 / CVE-2022-42312. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 45244c021cd3..488d540f3a32 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -107,6 +107,7 @@ int quota_max_entry_size = 2048; /* 2K */ - int quota_max_transaction = 10; - int quota_nb_perms_per_node = 5; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; -+int quota_req_outstanding = 20; - - unsigned int timeout_watch_event_msec = 20000; - -@@ -223,12 +224,24 @@ static uint64_t get_now_msec(void) - return now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; - } - -+/* -+ * Remove a struct buffered_data from the list of outgoing data. -+ * A struct buffered_data related to a request having caused watch events to be -+ * sent is kept until all those events have been written out. -+ * Each watch event is referencing the related request via pend.req, while the -+ * number of watch events caused by a request is kept in pend.ref.event_cnt -+ * (those two cases are mutually exclusive, so the two fields can share memory -+ * via a union). -+ * The struct buffered_data is freed only if no related watch event is -+ * referencing it. The related return data can be freed right away. -+ */ - static void free_buffered_data(struct buffered_data *out, - struct connection *conn) - { - struct buffered_data *req; - - list_del(&out->list); -+ out->on_out_list = false; - - /* - * Update conn->timeout_msec with the next found timeout value in the -@@ -244,6 +257,30 @@ static void free_buffered_data(struct buffered_data *out, - } - } - -+ if (out->hdr.msg.type == XS_WATCH_EVENT) { -+ req = out->pend.req; -+ if (req) { -+ req->pend.ref.event_cnt--; -+ if (!req->pend.ref.event_cnt && !req->on_out_list) { -+ if (req->on_ref_list) { -+ domain_outstanding_domid_dec( -+ req->pend.ref.domid); -+ list_del(&req->list); -+ } -+ talloc_free(req); -+ } -+ } -+ } else if (out->pend.ref.event_cnt) { -+ /* Hang out off from conn. */ -+ talloc_steal(NULL, out); -+ if (out->buffer != out->default_buffer) -+ talloc_free(out->buffer); -+ list_add(&out->list, &conn->ref_list); -+ out->on_ref_list = true; -+ return; -+ } else -+ domain_outstanding_dec(conn); -+ - talloc_free(out); - } - -@@ -405,6 +442,7 @@ int delay_request(struct connection *conn, struct buffered_data *in, - static int destroy_conn(void *_conn) - { - struct connection *conn = _conn; -+ struct buffered_data *req; - - /* Flush outgoing if possible, but don't block. */ - if (!conn->domain) { -@@ -418,6 +456,11 @@ static int destroy_conn(void *_conn) - break; - close(conn->fd); - } -+ -+ conn_free_buffered_data(conn); -+ list_for_each_entry(req, &conn->ref_list, list) -+ req->on_ref_list = false; -+ - if (conn->target) - talloc_unlink(conn, conn->target); - list_del(&conn->list); -@@ -893,6 +936,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+ bdata->on_out_list = true; -+ domain_outstanding_inc(conn); - } - - /* -@@ -900,7 +945,8 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - * As this is not directly related to the current command, errors can't be - * reported. - */ --void send_event(struct connection *conn, const char *path, const char *token) -+void send_event(struct buffered_data *req, struct connection *conn, -+ const char *path, const char *token) - { - struct buffered_data *bdata; - unsigned int len; -@@ -930,8 +976,13 @@ void send_event(struct connection *conn, const char *path, const char *token) - conn->timeout_msec = bdata->timeout_msec; - } - -+ bdata->pend.req = req; -+ if (req) -+ req->pend.ref.event_cnt++; -+ - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+ bdata->on_out_list = true; - } - - /* Some routines (write, mkdir, etc) just need a non-error return */ -@@ -1740,6 +1791,7 @@ static void handle_input(struct connection *conn) - return; - } - in = conn->in; -+ in->pend.ref.domid = conn->id; - - /* Not finished header yet? */ - if (in->inhdr) { -@@ -1808,6 +1860,7 @@ struct connection *new_connection(const struct interface_funcs *funcs) - new->is_stalled = false; - new->transaction_started = 0; - INIT_LIST_HEAD(&new->out_list); -+ INIT_LIST_HEAD(&new->ref_list); - INIT_LIST_HEAD(&new->watches); - INIT_LIST_HEAD(&new->transaction_list); - INIT_LIST_HEAD(&new->delayed); -@@ -2286,6 +2339,9 @@ static void usage(void) - " -t, --transaction limit the number of transaction allowed per domain,\n" - " -A, --perm-nb limit the number of permissions per node,\n" - " -M, --path-max limit the allowed Xenstore node path length,\n" -+" -Q, --quota = set the quota to the value , allowed\n" -+" quotas are:\n" -+" outstanding: number of outstanding requests\n" - " -w, --timeout = set the timeout in seconds for ,\n" - " allowed timeout candidates are:\n" - " watch-event: time a watch-event is kept pending\n" -@@ -2311,6 +2367,7 @@ static struct option options[] = { - { "transaction", 1, NULL, 't' }, - { "perm-nb", 1, NULL, 'A' }, - { "path-max", 1, NULL, 'M' }, -+ { "quota", 1, NULL, 'Q' }, - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, -@@ -2358,6 +2415,20 @@ static void set_timeout(const char *arg) - barf("unknown timeout \"%s\"\n", arg); - } - -+static void set_quota(const char *arg) -+{ -+ const char *eq = strchr(arg, '='); -+ int val; -+ -+ if (!eq) -+ barf("quotas must be specified via =\n"); -+ val = get_optval_int(eq + 1); -+ if (what_matches(arg, "outstanding")) -+ quota_req_outstanding = val; -+ else -+ barf("unknown quota \"%s\"\n", arg); -+} -+ - int main(int argc, char *argv[]) - { - int opt; -@@ -2372,8 +2443,8 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:T:RVW:w:U", options, -- NULL)) != -1) { -+ while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U", -+ options, NULL)) != -1) { - switch (opt) { - case 'D': - no_domain_init = true; -@@ -2422,6 +2493,9 @@ int main(int argc, char *argv[]) - quota_max_path_len = min(XENSTORE_REL_PATH_MAX, - quota_max_path_len); - break; -+ case 'Q': -+ set_quota(optarg); -+ break; - case 'w': - set_timeout(optarg); - break; -@@ -2875,6 +2949,14 @@ static void add_buffered_data(struct buffered_data *bdata, - - /* Queue for later transmission. */ - list_add_tail(&bdata->list, &conn->out_list); -+ bdata->on_out_list = true; -+ /* -+ * Watch events are never "outstanding", but the request causing them -+ * are instead kept "outstanding" until all watch events caused by that -+ * request have been delivered. -+ */ -+ if (bdata->hdr.msg.type != XS_WATCH_EVENT) -+ domain_outstanding_inc(conn); - } - - void read_state_buffered_data(const void *ctx, struct connection *conn, -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 8a81fc693f01..db09f463a657 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -56,6 +56,8 @@ struct xs_state_connection; - struct buffered_data - { - struct list_head list; -+ bool on_out_list; -+ bool on_ref_list; - - /* Are we still doing the header? */ - bool inhdr; -@@ -63,6 +65,17 @@ struct buffered_data - /* How far are we? */ - unsigned int used; - -+ /* Outstanding request accounting. */ -+ union { -+ /* ref is being used for requests. */ -+ struct { -+ unsigned int event_cnt; /* # of outstanding events. */ -+ unsigned int domid; /* domid of request. */ -+ } ref; -+ /* req is being used for watch events. */ -+ struct buffered_data *req; /* request causing event. */ -+ } pend; -+ - union { - struct xsd_sockmsg msg; - char raw[sizeof(struct xsd_sockmsg)]; -@@ -123,6 +136,9 @@ struct connection - struct list_head out_list; - uint64_t timeout_msec; - -+ /* Referenced requests no longer pending. */ -+ struct list_head ref_list; -+ - /* Transaction context for current request (NULL if none). */ - struct transaction *transaction; - -@@ -191,7 +207,8 @@ unsigned int get_string(const struct buffered_data *data, unsigned int offset); - - void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - const void *data, unsigned int len); --void send_event(struct connection *conn, const char *path, const char *token); -+void send_event(struct buffered_data *req, struct connection *conn, -+ const char *path, const char *token); - - /* Some routines (write, mkdir, etc) just need a non-error return */ - void send_ack(struct connection *conn, enum xsd_sockmsg_type type); -@@ -247,6 +264,7 @@ extern int dom0_domid; - extern int dom0_event; - extern int priv_domid; - extern int quota_nb_entry_per_domain; -+extern int quota_req_outstanding; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 93c4c1edcdd1..850085a92c76 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -78,6 +78,9 @@ struct domain - /* number of watch for this domain */ - int nbwatch; - -+ /* Number of outstanding requests. */ -+ int nboutstanding; -+ - /* write rate limit */ - wrl_creditt wrl_credit; /* [ -wrl_config_writecost, +_dburst ] */ - struct wrl_timestampt wrl_timestamp; -@@ -183,8 +186,12 @@ static bool domain_can_read(struct connection *conn) - { - struct xenstore_domain_interface *intf = conn->domain->interface; - -- if (domain_is_unprivileged(conn) && conn->domain->wrl_credit < 0) -- return false; -+ if (domain_is_unprivileged(conn)) { -+ if (conn->domain->wrl_credit < 0) -+ return false; -+ if (conn->domain->nboutstanding >= quota_req_outstanding) -+ return false; -+ } - - return (intf->req_cons != intf->req_prod); - } -@@ -331,7 +338,7 @@ static struct domain *alloc_domain(const void *context, unsigned int domid) - { - struct domain *domain; - -- domain = talloc(context, struct domain); -+ domain = talloc_zero(context, struct domain); - if (!domain) { - errno = ENOMEM; - return NULL; -@@ -392,9 +399,6 @@ static int new_domain(struct domain *domain, int port, bool restore) - domain->conn->domain = domain; - domain->conn->id = domain->domid; - -- domain->nbentry = 0; -- domain->nbwatch = 0; -- - return 0; - } - -@@ -938,6 +942,28 @@ int domain_watch(struct connection *conn) - : 0; - } - -+void domain_outstanding_inc(struct connection *conn) -+{ -+ if (!conn || !conn->domain) -+ return; -+ conn->domain->nboutstanding++; -+} -+ -+void domain_outstanding_dec(struct connection *conn) -+{ -+ if (!conn || !conn->domain) -+ return; -+ conn->domain->nboutstanding--; -+} -+ -+void domain_outstanding_domid_dec(unsigned int domid) -+{ -+ struct domain *d = find_domain_by_domid(domid); -+ -+ if (d) -+ d->nboutstanding--; -+} -+ - static wrl_creditt wrl_config_writecost = WRL_FACTOR; - static wrl_creditt wrl_config_rate = WRL_RATE * WRL_FACTOR; - static wrl_creditt wrl_config_dburst = WRL_DBURST * WRL_FACTOR; -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 1e929b8f8c6f..4f51b005291a 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -64,6 +64,9 @@ int domain_entry(struct connection *conn); - void domain_watch_inc(struct connection *conn); - void domain_watch_dec(struct connection *conn); - int domain_watch(struct connection *conn); -+void domain_outstanding_inc(struct connection *conn); -+void domain_outstanding_dec(struct connection *conn); -+void domain_outstanding_domid_dec(unsigned int domid); - - /* Special node permission handling. */ - int set_perms_special(struct connection *conn, const char *name, -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 205d9d8ea116..0755ffa375ba 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -142,6 +142,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - struct node *node, bool exact, struct node_perms *perms) - { - struct connection *i; -+ struct buffered_data *req; - struct watch *watch; - - /* During transactions, don't fire watches, but queue them. */ -@@ -150,6 +151,8 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - return; - } - -+ req = domain_is_unprivileged(conn) ? conn->in : NULL; -+ - /* Create an event for each watch. */ - list_for_each_entry(i, &connections, list) { - /* introduce/release domain watches */ -@@ -164,12 +167,12 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, - list_for_each_entry(watch, &i->watches, list) { - if (exact) { - if (streq(name, watch->node)) -- send_event(i, -+ send_event(req, i, - get_watch_path(watch, name), - watch->token); - } else { - if (is_child(name, watch->node)) -- send_event(i, -+ send_event(req, i, - get_watch_path(watch, name), - watch->token); - } -@@ -269,8 +272,12 @@ int do_watch(struct connection *conn, struct buffered_data *in) - trace_create(watch, "watch"); - send_ack(conn, XS_WATCH); - -- /* We fire once up front: simplifies clients and restart. */ -- send_event(conn, get_watch_path(watch, watch->node), watch->token); -+ /* -+ * We fire once up front: simplifies clients and restart. -+ * This event will not be linked to the XS_WATCH request. -+ */ -+ send_event(NULL, conn, get_watch_path(watch, watch->node), -+ watch->token); - - return 0; - } diff --git a/xsa326-4.16-xenstored-06.patch b/xsa326-4.16-xenstored-06.patch deleted file mode 100644 index b2be7ce..0000000 --- a/xsa326-4.16-xenstored-06.patch +++ /dev/null @@ -1,85 +0,0 @@ -From c8057cb483abf2cd4060b39616423e19283fbd0a Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: don't buffer multiple identical watch events - -A guest not reading its Xenstore response buffer fast enough might -pile up lots of Xenstore watch events buffered. Reduce the generated -load by dropping new events which already have an identical copy -pending. - -The special events "@..." are excluded from that handling as there are -known use cases where the handler is relying on each event to be sent -individually. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 488d540f3a32..f1fa97b8cf50 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -916,6 +916,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - bdata->inhdr = true; - bdata->used = 0; - bdata->timeout_msec = 0; -+ bdata->watch_event = false; - - if (len <= DEFAULT_BUFFER_SIZE) - bdata->buffer = bdata->default_buffer; -@@ -948,7 +949,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - void send_event(struct buffered_data *req, struct connection *conn, - const char *path, const char *token) - { -- struct buffered_data *bdata; -+ struct buffered_data *bdata, *bd; - unsigned int len; - - len = strlen(path) + 1 + strlen(token) + 1; -@@ -970,12 +971,29 @@ void send_event(struct buffered_data *req, struct connection *conn, - bdata->hdr.msg.type = XS_WATCH_EVENT; - bdata->hdr.msg.len = len; - -+ /* -+ * Check whether an identical event is pending already. -+ * Special events are excluded from that check. -+ */ -+ if (path[0] != '@') { -+ list_for_each_entry(bd, &conn->out_list, list) { -+ if (bd->watch_event && bd->hdr.msg.len == len && -+ !memcmp(bdata->buffer, bd->buffer, len)) { -+ trace("dropping duplicate watch %s %s for domain %u\n", -+ path, token, conn->id); -+ talloc_free(bdata); -+ return; -+ } -+ } -+ } -+ - if (timeout_watch_event_msec && domain_is_unprivileged(conn)) { - bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; - if (!conn->timeout_msec) - conn->timeout_msec = bdata->timeout_msec; - } - -+ bdata->watch_event = true; - bdata->pend.req = req; - if (req) - req->pend.ref.event_cnt++; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index db09f463a657..b9b50e81c7b4 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -62,6 +62,9 @@ struct buffered_data - /* Are we still doing the header? */ - bool inhdr; - -+ /* Is this a watch event? */ -+ bool watch_event; -+ - /* How far are we? */ - unsigned int used; - diff --git a/xsa326-4.16-xenstored-07.patch b/xsa326-4.16-xenstored-07.patch deleted file mode 100644 index dfcdc14..0000000 --- a/xsa326-4.16-xenstored-07.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 5eac692b841633be3e85f0125c59fa02af103989 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: fix connection->id usage - -Don't use conn->id for privilege checks, but domain_is_unprivileged(). - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c -index 7b4300ef7777..adb8d51b043b 100644 ---- a/tools/xenstore/xenstored_control.c -+++ b/tools/xenstore/xenstored_control.c -@@ -891,7 +891,7 @@ int do_control(struct connection *conn, struct buffered_data *in) - unsigned int cmd, num, off; - char **vec = NULL; - -- if (conn->id != 0) -+ if (domain_is_unprivileged(conn)) - return EACCES; - - off = get_string(in, 0); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index b9b50e81c7b4..b1a70488b989 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -123,7 +123,7 @@ struct connection - /* The index of pollfd in global pollfd array */ - int pollfd_idx; - -- /* Who am I? 0 for socket connections. */ -+ /* Who am I? Domid of connection. */ - unsigned int id; - - /* Is this connection ignored? */ -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 54432907fc76..ee1b09031a3b 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -477,7 +477,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in) - if (conn->transaction) - return EBUSY; - -- if (conn->id && conn->transaction_started > quota_max_transaction) -+ if (domain_is_unprivileged(conn) && -+ conn->transaction_started > quota_max_transaction) - return ENOSPC; - - /* Attach transaction to input for autofree until it's complete */ diff --git a/xsa326-4.16-xenstored-08.patch b/xsa326-4.16-xenstored-08.patch deleted file mode 100644 index 5aa12c8..0000000 --- a/xsa326-4.16-xenstored-08.patch +++ /dev/null @@ -1,326 +0,0 @@ -From f9f3171441b5fcb3339cf612400794fc26cd2ec2 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:08 +0200 -Subject: tools/xenstore: simplify and fix per domain node accounting - -The accounting of nodes can be simplified now that each connection -holds the associated domid. - -Fix the node accounting to cover nodes created for a domain before it -has been introduced. This requires to react properly to an allocation -failure inside domain_entry_inc() by returning an error code. - -Especially in error paths the node accounting has to be fixed in some -cases. - -This is part of XSA-326 / CVE-2022-42313. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index f1fa97b8cf50..692d863fce35 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -638,7 +638,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - - /* Permissions are struct xs_permissions. */ - node->perms.p = hdr->perms; -- if (domain_adjust_node_perms(node)) { -+ if (domain_adjust_node_perms(conn, node)) { - talloc_free(node); - return NULL; - } -@@ -660,7 +660,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - void *p; - struct xs_tdb_record_hdr *hdr; - -- if (domain_adjust_node_perms(node)) -+ if (domain_adjust_node_perms(conn, node)) - return errno; - - data.dsize = sizeof(*hdr) -@@ -1272,13 +1272,17 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - return NULL; - } - --static int destroy_node(struct connection *conn, struct node *node) -+static void destroy_node_rm(struct node *node) - { - if (streq(node->name, "/")) - corrupt(NULL, "Destroying root node!"); - - tdb_delete(tdb_ctx, node->key); -+} - -+static int destroy_node(struct connection *conn, struct node *node) -+{ -+ destroy_node_rm(node); - domain_entry_dec(conn, node); - - /* -@@ -1328,8 +1332,12 @@ static struct node *create_node(struct connection *conn, const void *ctx, - goto err; - - /* Account for new node */ -- if (i->parent) -- domain_entry_inc(conn, i); -+ if (i->parent) { -+ if (domain_entry_inc(conn, i)) { -+ destroy_node_rm(i); -+ return NULL; -+ } -+ } - } - - return node; -@@ -1614,10 +1622,27 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - old_perms = node->perms; - domain_entry_dec(conn, node); - node->perms = perms; -- domain_entry_inc(conn, node); -+ if (domain_entry_inc(conn, node)) { -+ node->perms = old_perms; -+ /* -+ * This should never fail because we had a reference on the -+ * domain before and Xenstored is single-threaded. -+ */ -+ domain_entry_inc(conn, node); -+ return ENOMEM; -+ } -+ -+ if (write_node(conn, node, false)) { -+ int saved_errno = errno; - -- if (write_node(conn, node, false)) -+ domain_entry_dec(conn, node); -+ node->perms = old_perms; -+ /* No failure possible as above. */ -+ domain_entry_inc(conn, node); -+ -+ errno = saved_errno; - return errno; -+ } - - fire_watches(conn, in, name, node, false, &old_perms); - send_ack(conn, XS_SET_PERMS); -@@ -3122,7 +3147,9 @@ void read_state_node(const void *ctx, const void *state) - set_tdb_key(name, &key); - if (write_node_raw(NULL, &key, node, true)) - barf("write node error restoring node"); -- domain_entry_inc(&conn, node); -+ -+ if (domain_entry_inc(&conn, node)) -+ barf("node accounting error restoring node"); - - talloc_free(node); - } -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 850085a92c76..260952e09096 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -16,6 +16,7 @@ - along with this program; If not, see . - */ - -+#include - #include - #include - #include -@@ -363,6 +364,18 @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid) - return domain ? : alloc_domain(ctx, domid); - } - -+static struct domain *find_or_alloc_existing_domain(unsigned int domid) -+{ -+ struct domain *domain; -+ xc_dominfo_t dominfo; -+ -+ domain = find_domain_struct(domid); -+ if (!domain && get_domain_info(domid, &dominfo)) -+ domain = alloc_domain(NULL, domid); -+ -+ return domain; -+} -+ - static int new_domain(struct domain *domain, int port, bool restore) - { - int rc; -@@ -782,30 +795,28 @@ void domain_deinit(void) - xenevtchn_unbind(xce_handle, virq_port); - } - --void domain_entry_inc(struct connection *conn, struct node *node) -+int domain_entry_inc(struct connection *conn, struct node *node) - { - struct domain *d; -+ unsigned int domid; - - if (!conn) -- return; -+ return 0; - -- if (node->perms.p && node->perms.p[0].id != conn->id) { -- if (conn->transaction) { -- transaction_entry_inc(conn->transaction, -- node->perms.p[0].id); -- } else { -- d = find_domain_by_domid(node->perms.p[0].id); -- if (d) -- d->nbentry++; -- } -- } else if (conn->domain) { -- if (conn->transaction) { -- transaction_entry_inc(conn->transaction, -- conn->domain->domid); -- } else { -- conn->domain->nbentry++; -- } -+ domid = node->perms.p ? node->perms.p[0].id : conn->id; -+ -+ if (conn->transaction) { -+ transaction_entry_inc(conn->transaction, domid); -+ } else { -+ d = (domid == conn->id && conn->domain) ? conn->domain -+ : find_or_alloc_existing_domain(domid); -+ if (d) -+ d->nbentry++; -+ else -+ return ENOMEM; - } -+ -+ return 0; - } - - /* -@@ -841,7 +852,7 @@ static int chk_domain_generation(unsigned int domid, uint64_t gen) - * Remove permissions for no longer existing domains in order to avoid a new - * domain with the same domid inheriting the permissions. - */ --int domain_adjust_node_perms(struct node *node) -+int domain_adjust_node_perms(struct connection *conn, struct node *node) - { - unsigned int i; - int ret; -@@ -851,8 +862,14 @@ int domain_adjust_node_perms(struct node *node) - return errno; - - /* If the owner doesn't exist any longer give it to priv domain. */ -- if (!ret) -+ if (!ret) { -+ /* -+ * In theory we'd need to update the number of dom0 nodes here, -+ * but we could be called for a read of the node. So better -+ * avoid the risk to overflow the node count of dom0. -+ */ - node->perms.p[0].id = priv_domid; -+ } - - for (i = 1; i < node->perms.num; i++) { - if (node->perms.p[i].perms & XS_PERM_IGNORE) -@@ -871,25 +888,25 @@ int domain_adjust_node_perms(struct node *node) - void domain_entry_dec(struct connection *conn, struct node *node) - { - struct domain *d; -+ unsigned int domid; - - if (!conn) - return; - -- if (node->perms.p && node->perms.p[0].id != conn->id) { -- if (conn->transaction) { -- transaction_entry_dec(conn->transaction, -- node->perms.p[0].id); -- } else { -- d = find_domain_by_domid(node->perms.p[0].id); -- if (d && d->nbentry) -- d->nbentry--; -- } -- } else if (conn->domain && conn->domain->nbentry) { -- if (conn->transaction) { -- transaction_entry_dec(conn->transaction, -- conn->domain->domid); -+ domid = node->perms.p ? node->perms.p[0].id : conn->id; -+ -+ if (conn->transaction) { -+ transaction_entry_dec(conn->transaction, domid); -+ } else { -+ d = (domid == conn->id && conn->domain) ? conn->domain -+ : find_domain_struct(domid); -+ if (d) { -+ d->nbentry--; - } else { -- conn->domain->nbentry--; -+ errno = ENOENT; -+ corrupt(conn, -+ "Node \"%s\" owned by non-existing domain %u\n", -+ node->name, domid); - } - } - } -@@ -899,13 +916,23 @@ int domain_entry_fix(unsigned int domid, int num, bool update) - struct domain *d; - int cnt; - -- d = find_domain_by_domid(domid); -- if (!d) -- return 0; -+ if (update) { -+ d = find_domain_struct(domid); -+ assert(d); -+ } else { -+ /* -+ * We are called first with update == false in order to catch -+ * any error. So do a possible allocation and check for error -+ * only in this case, as in the case of update == true nothing -+ * can go wrong anymore as the allocation already happened. -+ */ -+ d = find_or_alloc_existing_domain(domid); -+ if (!d) -+ return -1; -+ } - - cnt = d->nbentry + num; -- if (cnt < 0) -- cnt = 0; -+ assert(cnt >= 0); - - if (update) - d->nbentry = cnt; -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 4f51b005291a..d6519904d831 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -54,10 +54,10 @@ const char *get_implicit_path(const struct connection *conn); - bool domain_is_unprivileged(struct connection *conn); - - /* Remove node permissions for no longer existing domains. */ --int domain_adjust_node_perms(struct node *node); -+int domain_adjust_node_perms(struct connection *conn, struct node *node); - - /* Quota manipulation */ --void domain_entry_inc(struct connection *conn, struct node *); -+int domain_entry_inc(struct connection *conn, struct node *); - void domain_entry_dec(struct connection *conn, struct node *); - int domain_entry_fix(unsigned int domid, int num, bool update); - int domain_entry(struct connection *conn); -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index ee1b09031a3b..86caf6c398be 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -519,8 +519,12 @@ static int transaction_fix_domains(struct transaction *trans, bool update) - - list_for_each_entry(d, &trans->changed_domains, list) { - cnt = domain_entry_fix(d->domid, d->nbentry, update); -- if (!update && cnt >= quota_nb_entry_per_domain) -- return ENOSPC; -+ if (!update) { -+ if (cnt >= quota_nb_entry_per_domain) -+ return ENOSPC; -+ if (cnt < 0) -+ return ENOMEM; -+ } - } - - return 0; diff --git a/xsa326-4.16-xenstored-09.patch b/xsa326-4.16-xenstored-09.patch deleted file mode 100644 index e2c163c..0000000 --- a/xsa326-4.16-xenstored-09.patch +++ /dev/null @@ -1,244 +0,0 @@ -From 71aac6f7e89d5c101adb9e82eea7031e16d34e46 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: limit max number of nodes accessed in a transaction - -Today a guest is free to access as many nodes in a single transaction -as it wants. This can lead to unbounded memory consumption in Xenstore -as there is the need to keep track of all nodes having been accessed -during a transaction. - -In oxenstored the number of requests in a transaction is being limited -via a quota maxrequests (default is 1024). As multiple accesses of a -node are not problematic in C Xenstore, limit the number of accessed -nodes. - -In order to let read_node() detect a quota error in case too many nodes -are being accessed, check the return value of access_node() and return -NULL in case an error has been seen. Introduce __must_check and add it -to the access_node() prototype. - -This is part of XSA-326 / CVE-2022-42314. - -Reported-by: Julien Grall -Suggested-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/include/xen-tools/libs.h b/tools/include/xen-tools/libs.h -index a16e0c380709..bafc90e2f603 100644 ---- a/tools/include/xen-tools/libs.h -+++ b/tools/include/xen-tools/libs.h -@@ -63,4 +63,8 @@ - #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) - #endif - -+#ifndef __must_check -+#define __must_check __attribute__((__warn_unused_result__)) -+#endif -+ - #endif /* __XEN_TOOLS_LIBS__ */ -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 692d863fce35..f835aa1b2f1f 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -106,6 +106,7 @@ int quota_nb_watch_per_domain = 128; - int quota_max_entry_size = 2048; /* 2K */ - int quota_max_transaction = 10; - int quota_nb_perms_per_node = 5; -+int quota_trans_nodes = 1024; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; - int quota_req_outstanding = 20; - -@@ -595,6 +596,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - TDB_DATA key, data; - struct xs_tdb_record_hdr *hdr; - struct node *node; -+ int err; - - node = talloc(ctx, struct node); - if (!node) { -@@ -616,14 +618,13 @@ struct node *read_node(struct connection *conn, const void *ctx, - if (data.dptr == NULL) { - if (tdb_error(tdb_ctx) == TDB_ERR_NOEXIST) { - node->generation = NO_GENERATION; -- access_node(conn, node, NODE_ACCESS_READ, NULL); -- errno = ENOENT; -+ err = access_node(conn, node, NODE_ACCESS_READ, NULL); -+ errno = err ? : ENOENT; - } else { - log("TDB error on read: %s", tdb_errorstr(tdb_ctx)); - errno = EIO; - } -- talloc_free(node); -- return NULL; -+ goto error; - } - - node->parent = NULL; -@@ -638,19 +639,36 @@ struct node *read_node(struct connection *conn, const void *ctx, - - /* Permissions are struct xs_permissions. */ - node->perms.p = hdr->perms; -- if (domain_adjust_node_perms(conn, node)) { -- talloc_free(node); -- return NULL; -- } -+ if (domain_adjust_node_perms(conn, node)) -+ goto error; - - /* Data is binary blob (usually ascii, no nul). */ - node->data = node->perms.p + hdr->num_perms; - /* Children is strings, nul separated. */ - node->children = node->data + node->datalen; - -- access_node(conn, node, NODE_ACCESS_READ, NULL); -+ if (access_node(conn, node, NODE_ACCESS_READ, NULL)) -+ goto error; - - return node; -+ -+ error: -+ err = errno; -+ talloc_free(node); -+ errno = err; -+ return NULL; -+} -+ -+static bool read_node_can_propagate_errno(void) -+{ -+ /* -+ * 2 error cases for read_node() can always be propagated up: -+ * ENOMEM, because this has nothing to do with the node being in the -+ * data base or not, but is caused by a general lack of memory. -+ * ENOSPC, because this is related to hitting quota limits which need -+ * to be respected. -+ */ -+ return errno == ENOMEM || errno == ENOSPC; - } - - int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, -@@ -767,7 +785,7 @@ static int ask_parents(struct connection *conn, const void *ctx, - node = read_node(conn, ctx, name); - if (node) - break; -- if (errno == ENOMEM) -+ if (read_node_can_propagate_errno()) - return errno; - } while (!streq(name, "/")); - -@@ -829,7 +847,7 @@ static struct node *get_node(struct connection *conn, - } - } - /* Clean up errno if they weren't supposed to know. */ -- if (!node && errno != ENOMEM) -+ if (!node && !read_node_can_propagate_errno()) - errno = errno_from_parents(conn, ctx, name, errno, perm); - return node; - } -@@ -1235,7 +1253,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - - /* If parent doesn't exist, create it. */ - parent = read_node(conn, parentname, parentname); -- if (!parent) -+ if (!parent && errno == ENOENT) - parent = construct_node(conn, ctx, parentname); - if (!parent) - return NULL; -@@ -1509,7 +1527,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - - parent = read_node(conn, ctx, parentname); - if (!parent) -- return (errno == ENOMEM) ? ENOMEM : EINVAL; -+ return read_node_can_propagate_errno() ? errno : EINVAL; - node->parent = parent; - - return delete_node(conn, ctx, parent, node, false); -@@ -1539,7 +1557,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in) - return 0; - } - /* Restore errno, just in case. */ -- if (errno != ENOMEM) -+ if (!read_node_can_propagate_errno()) - errno = ENOENT; - } - return errno; -@@ -2384,6 +2402,8 @@ static void usage(void) - " -M, --path-max limit the allowed Xenstore node path length,\n" - " -Q, --quota = set the quota to the value , allowed\n" - " quotas are:\n" -+" transaction-nodes: number of accessed node per\n" -+" transaction\n" - " outstanding: number of outstanding requests\n" - " -w, --timeout = set the timeout in seconds for ,\n" - " allowed timeout candidates are:\n" -@@ -2468,6 +2488,8 @@ static void set_quota(const char *arg) - val = get_optval_int(eq + 1); - if (what_matches(arg, "outstanding")) - quota_req_outstanding = val; -+ else if (what_matches(arg, "transaction-nodes")) -+ quota_trans_nodes = val; - else - barf("unknown quota \"%s\"\n", arg); - } -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index b1a70488b989..245f9258235f 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -268,6 +268,7 @@ extern int dom0_event; - extern int priv_domid; - extern int quota_nb_entry_per_domain; - extern int quota_req_outstanding; -+extern int quota_trans_nodes; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 86caf6c398be..7bd41eb475e3 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -156,6 +156,9 @@ struct transaction - /* Connection-local identifier for this transaction. */ - uint32_t id; - -+ /* Node counter. */ -+ unsigned int nodes; -+ - /* Generation when transaction started. */ - uint64_t generation; - -@@ -260,6 +263,11 @@ int access_node(struct connection *conn, struct node *node, - - i = find_accessed_node(trans, node->name); - if (!i) { -+ if (trans->nodes >= quota_trans_nodes && -+ domain_is_unprivileged(conn)) { -+ ret = ENOSPC; -+ goto err; -+ } - i = talloc_zero(trans, struct accessed_node); - if (!i) - goto nomem; -@@ -297,6 +305,7 @@ int access_node(struct connection *conn, struct node *node, - i->ta_node = true; - } - } -+ trans->nodes++; - list_add_tail(&i->list, &trans->accessed); - } - -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 0093cac807e3..e3cbd6b23095 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -39,8 +39,8 @@ void transaction_entry_inc(struct transaction *trans, unsigned int domid); - void transaction_entry_dec(struct transaction *trans, unsigned int domid); - - /* This node was accessed. */ --int access_node(struct connection *conn, struct node *node, -- enum node_access_type type, TDB_DATA *key); -+int __must_check access_node(struct connection *conn, struct node *node, -+ enum node_access_type type, TDB_DATA *key); - - /* Queue watches for a modified node. */ - void queue_watches(struct connection *conn, const char *name, bool watch_exact); diff --git a/xsa326-4.16-xenstored-10.patch b/xsa326-4.16-xenstored-10.patch deleted file mode 100644 index 30e6b50..0000000 --- a/xsa326-4.16-xenstored-10.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 90013d6a735491a7b93a6832eb2a51e5633254f5 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: move the call of setup_structure() to dom0 - introduction - -Setting up the basic structure when introducing dom0 has the advantage -to be able to add proper node memory accounting for the added nodes -later. - -This makes it possible to do proper node accounting, too. - -An additional requirement to make that work fine is to correct the -owner of the created nodes to be dom0_domid instead of domid 0. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index f835aa1b2f1f..5171d34c947e 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2039,7 +2039,8 @@ static int tdb_flags; - static void manual_node(const char *name, const char *child) - { - struct node *node; -- struct xs_permissions perms = { .id = 0, .perms = XS_PERM_NONE }; -+ struct xs_permissions perms = { .id = dom0_domid, -+ .perms = XS_PERM_NONE }; - - node = talloc_zero(NULL, struct node); - if (!node) -@@ -2078,7 +2079,7 @@ static void tdb_logger(TDB_CONTEXT *tdb, int level, const char * fmt, ...) - } - } - --static void setup_structure(bool live_update) -+void setup_structure(bool live_update) - { - char *tdbname; - -@@ -2101,6 +2102,7 @@ static void setup_structure(bool live_update) - manual_node("/", "tool"); - manual_node("/tool", "xenstored"); - manual_node("/tool/xenstored", NULL); -+ domain_entry_fix(dom0_domid, 3, true); - } - - check_store(); -@@ -2614,9 +2616,6 @@ int main(int argc, char *argv[]) - - init_pipe(reopen_log_pipe); - -- /* Setup the database */ -- setup_structure(live_update); -- - /* Listen to hypervisor. */ - if (!no_domain_init && !live_update) { - domain_init(-1); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 245f9258235f..2c77ec7ee0f4 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -231,6 +231,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - struct node *read_node(struct connection *conn, const void *ctx, - const char *name); - -+void setup_structure(bool live_update); - struct connection *new_connection(const struct interface_funcs *funcs); - struct connection *get_connection_by_id(unsigned int conn_id); - void ignore_connection(struct connection *conn); -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 260952e09096..f04b7aae8a32 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -470,6 +470,9 @@ static struct domain *introduce_domain(const void *ctx, - } - domain->interface = interface; - -+ if (is_master_domain) -+ setup_structure(restore); -+ - /* Now domain belongs to its connection. */ - talloc_steal(domain->conn, domain); - diff --git a/xsa326-4.16-xenstored-11.patch b/xsa326-4.16-xenstored-11.patch deleted file mode 100644 index 49f1497..0000000 --- a/xsa326-4.16-xenstored-11.patch +++ /dev/null @@ -1,280 +0,0 @@ -From 6af17b8bf52b9dfdc6a5ecd3efbcea9fddd57d91 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: add infrastructure to keep track of per domain memory - usage - -The amount of memory a domain can consume in Xenstore is limited by -various quota today, but even with sane quota a domain can still -consume rather large memory quantities. - -Add the infrastructure for keeping track of the amount of memory a -domain is consuming in Xenstore. Note that this is only the memory a -domain has direct control over, so any internal administration data -needed by Xenstore only is not being accounted for. - -There are two quotas defined: a soft quota which will result in a -warning issued via syslog() when it is exceeded, and a hard quota -resulting in a stop of accepting further requests or watch events as -long as the hard quota would be violated by accepting those. - -Setting any of those quotas to 0 will disable it. - -As default values use 2MB per domain for the soft limit (this basically -covers the allowed case to create 1000 nodes needing 2kB each), and -2.5MB for the hard limit. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 5171d34c947e..b2bf6740d430 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -109,6 +109,8 @@ int quota_nb_perms_per_node = 5; - int quota_trans_nodes = 1024; - int quota_max_path_len = XENSTORE_REL_PATH_MAX; - int quota_req_outstanding = 20; -+int quota_memory_per_domain_soft = 2 * 1024 * 1024; /* 2 MB */ -+int quota_memory_per_domain_hard = 2 * 1024 * 1024 + 512 * 1024; /* 2.5 MB */ - - unsigned int timeout_watch_event_msec = 20000; - -@@ -2406,7 +2408,14 @@ static void usage(void) - " quotas are:\n" - " transaction-nodes: number of accessed node per\n" - " transaction\n" -+" memory: total used memory per domain for nodes,\n" -+" transactions, watches and requests, above\n" -+" which Xenstore will stop talking to domain\n" - " outstanding: number of outstanding requests\n" -+" -q, --quota-soft = set a soft quota to the value ,\n" -+" causing a warning to be issued via syslog() if the\n" -+" limit is violated, allowed quotas are:\n" -+" memory: see above\n" - " -w, --timeout = set the timeout in seconds for ,\n" - " allowed timeout candidates are:\n" - " watch-event: time a watch-event is kept pending\n" -@@ -2433,6 +2442,7 @@ static struct option options[] = { - { "perm-nb", 1, NULL, 'A' }, - { "path-max", 1, NULL, 'M' }, - { "quota", 1, NULL, 'Q' }, -+ { "quota-soft", 1, NULL, 'q' }, - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, -@@ -2480,7 +2490,7 @@ static void set_timeout(const char *arg) - barf("unknown timeout \"%s\"\n", arg); - } - --static void set_quota(const char *arg) -+static void set_quota(const char *arg, bool soft) - { - const char *eq = strchr(arg, '='); - int val; -@@ -2488,11 +2498,16 @@ static void set_quota(const char *arg) - if (!eq) - barf("quotas must be specified via =\n"); - val = get_optval_int(eq + 1); -- if (what_matches(arg, "outstanding")) -+ if (what_matches(arg, "outstanding") && !soft) - quota_req_outstanding = val; -- else if (what_matches(arg, "transaction-nodes")) -+ else if (what_matches(arg, "transaction-nodes") && !soft) - quota_trans_nodes = val; -- else -+ else if (what_matches(arg, "memory")) { -+ if (soft) -+ quota_memory_per_domain_soft = val; -+ else -+ quota_memory_per_domain_hard = val; -+ } else - barf("unknown quota \"%s\"\n", arg); - } - -@@ -2510,7 +2525,7 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:T:RVW:w:U", -+ while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U", - options, NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2561,7 +2576,10 @@ int main(int argc, char *argv[]) - quota_max_path_len); - break; - case 'Q': -- set_quota(optarg); -+ set_quota(optarg, false); -+ break; -+ case 'q': -+ set_quota(optarg, true); - break; - case 'w': - set_timeout(optarg); -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 2c77ec7ee0f4..373af18297bf 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -270,6 +270,8 @@ extern int priv_domid; - extern int quota_nb_entry_per_domain; - extern int quota_req_outstanding; - extern int quota_trans_nodes; -+extern int quota_memory_per_domain_soft; -+extern int quota_memory_per_domain_hard; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index f04b7aae8a32..94fd561e9de4 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -76,6 +76,13 @@ struct domain - /* number of entry from this domain in the store */ - int nbentry; - -+ /* Amount of memory allocated for this domain. */ -+ int memory; -+ bool soft_quota_reported; -+ bool hard_quota_reported; -+ time_t mem_last_msg; -+#define MEM_WARN_MINTIME_SEC 10 -+ - /* number of watch for this domain */ - int nbwatch; - -@@ -192,6 +199,9 @@ static bool domain_can_read(struct connection *conn) - return false; - if (conn->domain->nboutstanding >= quota_req_outstanding) - return false; -+ if (conn->domain->memory >= quota_memory_per_domain_hard && -+ quota_memory_per_domain_hard) -+ return false; - } - - return (intf->req_cons != intf->req_prod); -@@ -950,6 +960,89 @@ int domain_entry(struct connection *conn) - : 0; - } - -+static bool domain_chk_quota(struct domain *domain, int mem) -+{ -+ time_t now; -+ -+ if (!domain || !domid_is_unprivileged(domain->domid) || -+ (domain->conn && domain->conn->is_ignored)) -+ return false; -+ -+ now = time(NULL); -+ -+ if (mem >= quota_memory_per_domain_hard && -+ quota_memory_per_domain_hard) { -+ if (domain->hard_quota_reported) -+ return true; -+ syslog(LOG_ERR, "Domain %u exceeds hard memory quota, Xenstore interface to domain stalled\n", -+ domain->domid); -+ domain->mem_last_msg = now; -+ domain->hard_quota_reported = true; -+ return true; -+ } -+ -+ if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) { -+ if (domain->hard_quota_reported) { -+ domain->mem_last_msg = now; -+ domain->hard_quota_reported = false; -+ syslog(LOG_INFO, "Domain %u below hard memory quota again\n", -+ domain->domid); -+ } -+ if (mem >= quota_memory_per_domain_soft && -+ quota_memory_per_domain_soft && -+ !domain->soft_quota_reported) { -+ domain->mem_last_msg = now; -+ domain->soft_quota_reported = true; -+ syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n", -+ domain->domid); -+ } -+ if (mem < quota_memory_per_domain_soft && -+ domain->soft_quota_reported) { -+ domain->mem_last_msg = now; -+ domain->soft_quota_reported = false; -+ syslog(LOG_INFO, "Domain %u below soft memory quota again\n", -+ domain->domid); -+ } -+ -+ } -+ -+ return false; -+} -+ -+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check) -+{ -+ struct domain *domain; -+ -+ domain = find_domain_struct(domid); -+ if (domain) { -+ /* -+ * domain_chk_quota() will print warning and also store whether -+ * the soft/hard quota has been hit. So check no_quota_check -+ * *after*. -+ */ -+ if (domain_chk_quota(domain, domain->memory + mem) && -+ !no_quota_check) -+ return ENOMEM; -+ domain->memory += mem; -+ } else { -+ /* -+ * The domain the memory is to be accounted for should always -+ * exist, as accounting is done either for a domain related to -+ * the current connection, or for the domain owning a node -+ * (which is always existing, as the owner of the node is -+ * tested to exist and replaced by domid 0 if not). -+ * So not finding the related domain MUST be an error in the -+ * data base. -+ */ -+ errno = ENOENT; -+ corrupt(NULL, "Accounting called for non-existing domain %u\n", -+ domid); -+ return ENOENT; -+ } -+ -+ return 0; -+} -+ - void domain_watch_inc(struct connection *conn) - { - if (!conn || !conn->domain) -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index d6519904d831..633c9a0a0a1f 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -61,6 +61,26 @@ int domain_entry_inc(struct connection *conn, struct node *); - void domain_entry_dec(struct connection *conn, struct node *); - int domain_entry_fix(unsigned int domid, int num, bool update); - int domain_entry(struct connection *conn); -+int domain_memory_add(unsigned int domid, int mem, bool no_quota_check); -+ -+/* -+ * domain_memory_add_chk(): to be used when memory quota should be checked. -+ * Not to be used when specifying a negative mem value, as lowering the used -+ * memory should always be allowed. -+ */ -+static inline int domain_memory_add_chk(unsigned int domid, int mem) -+{ -+ return domain_memory_add(domid, mem, false); -+} -+/* -+ * domain_memory_add_nochk(): to be used when memory quota should not be -+ * checked, e.g. when lowering memory usage, or in an error case for undoing -+ * a previous memory adjustment. -+ */ -+static inline void domain_memory_add_nochk(unsigned int domid, int mem) -+{ -+ domain_memory_add(domid, mem, true); -+} - void domain_watch_inc(struct connection *conn); - void domain_watch_dec(struct connection *conn); - int domain_watch(struct connection *conn); diff --git a/xsa326-4.16-xenstored-12.patch b/xsa326-4.16-xenstored-12.patch deleted file mode 100644 index 517f2a0..0000000 --- a/xsa326-4.16-xenstored-12.patch +++ /dev/null @@ -1,76 +0,0 @@ -From ae7042f024af7584251f776a12d9bb24d13fecaf Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:09 +0200 -Subject: tools/xenstore: add memory accounting for responses - -Add the memory accounting for queued responses. - -In case adding a watch event for a guest is causing the hard memory -quota of that guest to be violated, the event is dropped. This will -ensure that it is impossible to drive another guest past its memory -quota by generating insane amounts of events for that guest. This is -especially important for protecting driver domains from that attack -vector. - -This is part of XSA-326 / CVE-2022-42315. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index b2bf6740d430..ecab6cfbbe15 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -260,6 +260,8 @@ static void free_buffered_data(struct buffered_data *out, - } - } - -+ domain_memory_add_nochk(conn->id, -out->hdr.msg.len - sizeof(out->hdr)); -+ - if (out->hdr.msg.type == XS_WATCH_EVENT) { - req = out->pend.req; - if (req) { -@@ -938,11 +940,14 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, - bdata->timeout_msec = 0; - bdata->watch_event = false; - -- if (len <= DEFAULT_BUFFER_SIZE) -+ if (len <= DEFAULT_BUFFER_SIZE) { - bdata->buffer = bdata->default_buffer; -- else { -+ /* Don't check quota, path might be used for returning error. */ -+ domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr)); -+ } else { - bdata->buffer = talloc_array(bdata, char, len); -- if (!bdata->buffer) { -+ if (!bdata->buffer || -+ domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) { - send_error(conn, ENOMEM); - return; - } -@@ -1007,6 +1012,11 @@ void send_event(struct buffered_data *req, struct connection *conn, - } - } - -+ if (domain_memory_add_chk(conn->id, len + sizeof(bdata->hdr))) { -+ talloc_free(bdata); -+ return; -+ } -+ - if (timeout_watch_event_msec && domain_is_unprivileged(conn)) { - bdata->timeout_msec = get_now_msec() + timeout_watch_event_msec; - if (!conn->timeout_msec) -@@ -3039,6 +3049,12 @@ static void add_buffered_data(struct buffered_data *bdata, - */ - if (bdata->hdr.msg.type != XS_WATCH_EVENT) - domain_outstanding_inc(conn); -+ /* -+ * We are restoring the state after Live-Update and the new quota may -+ * be smaller. So ignore it. The limit will be applied for any resource -+ * after the state has been fully restored. -+ */ -+ domain_memory_add_nochk(conn->id, len + sizeof(bdata->hdr)); - } - - void read_state_buffered_data(const void *ctx, struct connection *conn, diff --git a/xsa326-4.16-xenstored-13.patch b/xsa326-4.16-xenstored-13.patch deleted file mode 100644 index c37dd1e..0000000 --- a/xsa326-4.16-xenstored-13.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 4628ae0a56b037dcdc8a3e42c543c5b9fd9990cf Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add memory accounting for watches - -Add the memory accounting for registered watches. - -When a socket connection is destroyed, the associated watches are -removed, too. In order to keep memory accounting correct the watches -must be removed explicitly via a call of conn_delete_all_watches() from -destroy_conn(). - -This is part of XSA-326 / CVE-2022-42315. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index ecab6cfbbe15..d86942f5aa77 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -463,6 +463,7 @@ static int destroy_conn(void *_conn) - } - - conn_free_buffered_data(conn); -+ conn_delete_all_watches(conn); - list_for_each_entry(req, &conn->ref_list, list) - req->on_ref_list = false; - -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 0755ffa375ba..fdf9b2d653a0 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -211,7 +211,7 @@ static int check_watch_path(struct connection *conn, const void *ctx, - } - - static struct watch *add_watch(struct connection *conn, char *path, char *token, -- bool relative) -+ bool relative, bool no_quota_check) - { - struct watch *watch; - -@@ -222,6 +222,9 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token, - watch->token = talloc_strdup(watch, token); - if (!watch->node || !watch->token) - goto nomem; -+ if (domain_memory_add(conn->id, strlen(path) + strlen(token), -+ no_quota_check)) -+ goto nomem; - - if (relative) - watch->relative_path = get_implicit_path(conn); -@@ -265,7 +268,7 @@ int do_watch(struct connection *conn, struct buffered_data *in) - if (domain_watch(conn) > quota_nb_watch_per_domain) - return E2BIG; - -- watch = add_watch(conn, vec[0], vec[1], relative); -+ watch = add_watch(conn, vec[0], vec[1], relative, false); - if (!watch) - return errno; - -@@ -296,6 +299,8 @@ int do_unwatch(struct connection *conn, struct buffered_data *in) - list_for_each_entry(watch, &conn->watches, list) { - if (streq(watch->node, node) && streq(watch->token, vec[1])) { - list_del(&watch->list); -+ domain_memory_add_nochk(conn->id, -strlen(watch->node) - -+ strlen(watch->token)); - talloc_free(watch); - domain_watch_dec(conn); - send_ack(conn, XS_UNWATCH); -@@ -311,6 +316,8 @@ void conn_delete_all_watches(struct connection *conn) - - while ((watch = list_top(&conn->watches, struct watch, list))) { - list_del(&watch->list); -+ domain_memory_add_nochk(conn->id, -strlen(watch->node) - -+ strlen(watch->token)); - talloc_free(watch); - domain_watch_dec(conn); - } -@@ -373,7 +380,7 @@ void read_state_watch(const void *ctx, const void *state) - if (!path) - barf("allocation error for read watch"); - -- if (!add_watch(conn, path, token, relative)) -+ if (!add_watch(conn, path, token, relative, true)) - barf("error adding watch"); - } - diff --git a/xsa326-4.16-xenstored-14.patch b/xsa326-4.16-xenstored-14.patch deleted file mode 100644 index df898c4..0000000 --- a/xsa326-4.16-xenstored-14.patch +++ /dev/null @@ -1,334 +0,0 @@ -From b8bd74e5e962955211ab0c5c1924ebf2bb526799 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add memory accounting for nodes - -Add the memory accounting for Xenstore nodes. In order to make this -not too complicated allow for some sloppiness when writing nodes. Any -hard quota violation will result in no further requests to be accepted. - -This is part of XSA-326 / CVE-2022-42315. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index d86942f5aa77..16504de42017 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -591,6 +591,117 @@ void set_tdb_key(const char *name, TDB_DATA *key) - key->dsize = strlen(name); - } - -+static void get_acc_data(TDB_DATA *key, struct node_account_data *acc) -+{ -+ TDB_DATA old_data; -+ struct xs_tdb_record_hdr *hdr; -+ -+ if (acc->memory < 0) { -+ old_data = tdb_fetch(tdb_ctx, *key); -+ /* No check for error, as the node might not exist. */ -+ if (old_data.dptr == NULL) { -+ acc->memory = 0; -+ } else { -+ hdr = (void *)old_data.dptr; -+ acc->memory = old_data.dsize; -+ acc->domid = hdr->perms[0].id; -+ } -+ talloc_free(old_data.dptr); -+ } -+} -+ -+/* -+ * Per-transaction nodes need to be accounted for the transaction owner. -+ * Those nodes are stored in the data base with the transaction generation -+ * count prepended (e.g. 123/local/domain/...). So testing for the node's -+ * key not to start with "/" is sufficient. -+ */ -+static unsigned int get_acc_domid(struct connection *conn, TDB_DATA *key, -+ unsigned int domid) -+{ -+ return (!conn || key->dptr[0] == '/') ? domid : conn->id; -+} -+ -+int do_tdb_write(struct connection *conn, TDB_DATA *key, TDB_DATA *data, -+ struct node_account_data *acc, bool no_quota_check) -+{ -+ struct xs_tdb_record_hdr *hdr = (void *)data->dptr; -+ struct node_account_data old_acc = {}; -+ unsigned int old_domid, new_domid; -+ int ret; -+ -+ if (!acc) -+ old_acc.memory = -1; -+ else -+ old_acc = *acc; -+ -+ get_acc_data(key, &old_acc); -+ old_domid = get_acc_domid(conn, key, old_acc.domid); -+ new_domid = get_acc_domid(conn, key, hdr->perms[0].id); -+ -+ /* -+ * Don't check for ENOENT, as we want to be able to switch orphaned -+ * nodes to new owners. -+ */ -+ if (old_acc.memory) -+ domain_memory_add_nochk(old_domid, -+ -old_acc.memory - key->dsize); -+ ret = domain_memory_add(new_domid, data->dsize + key->dsize, -+ no_quota_check); -+ if (ret) { -+ /* Error path, so no quota check. */ -+ if (old_acc.memory) -+ domain_memory_add_nochk(old_domid, -+ old_acc.memory + key->dsize); -+ return ret; -+ } -+ -+ /* TDB should set errno, but doesn't even set ecode AFAICT. */ -+ if (tdb_store(tdb_ctx, *key, *data, TDB_REPLACE) != 0) { -+ domain_memory_add_nochk(new_domid, -data->dsize - key->dsize); -+ /* Error path, so no quota check. */ -+ if (old_acc.memory) -+ domain_memory_add_nochk(old_domid, -+ old_acc.memory + key->dsize); -+ errno = EIO; -+ return errno; -+ } -+ -+ if (acc) { -+ /* Don't use new_domid, as it might be a transaction node. */ -+ acc->domid = hdr->perms[0].id; -+ acc->memory = data->dsize; -+ } -+ -+ return 0; -+} -+ -+int do_tdb_delete(struct connection *conn, TDB_DATA *key, -+ struct node_account_data *acc) -+{ -+ struct node_account_data tmp_acc; -+ unsigned int domid; -+ -+ if (!acc) { -+ acc = &tmp_acc; -+ acc->memory = -1; -+ } -+ -+ get_acc_data(key, acc); -+ -+ if (tdb_delete(tdb_ctx, *key)) { -+ errno = EIO; -+ return errno; -+ } -+ -+ if (acc->memory) { -+ domid = get_acc_domid(conn, key, acc->domid); -+ domain_memory_add_nochk(domid, -acc->memory - key->dsize); -+ } -+ -+ return 0; -+} -+ - /* - * If it fails, returns NULL and sets errno. - * Temporary memory allocations will be done with ctx. -@@ -644,9 +755,15 @@ struct node *read_node(struct connection *conn, const void *ctx, - - /* Permissions are struct xs_permissions. */ - node->perms.p = hdr->perms; -+ node->acc.domid = node->perms.p[0].id; -+ node->acc.memory = data.dsize; - if (domain_adjust_node_perms(conn, node)) - goto error; - -+ /* If owner is gone reset currently accounted memory size. */ -+ if (node->acc.domid != node->perms.p[0].id) -+ node->acc.memory = 0; -+ - /* Data is binary blob (usually ascii, no nul). */ - node->data = node->perms.p + hdr->num_perms; - /* Children is strings, nul separated. */ -@@ -715,12 +832,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - p += node->datalen; - memcpy(p, node->children, node->childlen); - -- /* TDB should set errno, but doesn't even set ecode AFAICT. */ -- if (tdb_store(tdb_ctx, *key, data, TDB_REPLACE) != 0) { -- corrupt(conn, "Write of %s failed", key->dptr); -- errno = EIO; -- return errno; -- } -+ if (do_tdb_write(conn, key, &data, &node->acc, no_quota_check)) -+ return EIO; -+ - return 0; - } - -@@ -1222,7 +1336,7 @@ static void delete_node_single(struct connection *conn, struct node *node) - if (access_node(conn, node, NODE_ACCESS_DELETE, &key)) - return; - -- if (tdb_delete(tdb_ctx, key) != 0) { -+ if (do_tdb_delete(conn, &key, &node->acc) != 0) { - corrupt(conn, "Could not delete '%s'", node->name); - return; - } -@@ -1295,6 +1409,7 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - /* No children, no data */ - node->children = node->data = NULL; - node->childlen = node->datalen = 0; -+ node->acc.memory = 0; - node->parent = parent; - return node; - -@@ -1303,17 +1418,17 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - return NULL; - } - --static void destroy_node_rm(struct node *node) -+static void destroy_node_rm(struct connection *conn, struct node *node) - { - if (streq(node->name, "/")) - corrupt(NULL, "Destroying root node!"); - -- tdb_delete(tdb_ctx, node->key); -+ do_tdb_delete(conn, &node->key, &node->acc); - } - - static int destroy_node(struct connection *conn, struct node *node) - { -- destroy_node_rm(node); -+ destroy_node_rm(conn, node); - domain_entry_dec(conn, node); - - /* -@@ -1365,7 +1480,7 @@ static struct node *create_node(struct connection *conn, const void *ctx, - /* Account for new node */ - if (i->parent) { - if (domain_entry_inc(conn, i)) { -- destroy_node_rm(i); -+ destroy_node_rm(conn, i); - return NULL; - } - } -@@ -2291,7 +2406,7 @@ static int clean_store_(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA val, - if (!hashtable_search(reachable, name)) { - log("clean_store: '%s' is orphaned!", name); - if (recovery) { -- tdb_delete(tdb, key); -+ do_tdb_delete(NULL, &key, NULL); - } - } - -@@ -3149,6 +3264,7 @@ void read_state_node(const void *ctx, const void *state) - if (!node) - barf("allocation error restoring node"); - -+ node->acc.memory = 0; - node->name = name; - node->generation = ++generation; - node->datalen = sn->data_len; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 373af18297bf..da9ecce67f31 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -176,6 +176,11 @@ struct node_perms { - struct xs_permissions *p; - }; - -+struct node_account_data { -+ unsigned int domid; -+ int memory; /* -1 if unknown */ -+}; -+ - struct node { - const char *name; - /* Key used to update TDB */ -@@ -198,6 +203,9 @@ struct node { - /* Children, each nul-terminated. */ - unsigned int childlen; - char *children; -+ -+ /* Allocation information for node currently in store. */ -+ struct node_account_data acc; - }; - - /* Return the only argument in the input. */ -@@ -306,6 +314,10 @@ extern xengnttab_handle **xgt_handle; - int remember_string(struct hashtable *hash, const char *str); - - void set_tdb_key(const char *name, TDB_DATA *key); -+int do_tdb_write(struct connection *conn, TDB_DATA *key, TDB_DATA *data, -+ struct node_account_data *acc, bool no_quota_check); -+int do_tdb_delete(struct connection *conn, TDB_DATA *key, -+ struct node_account_data *acc); - - void conn_free_buffered_data(struct connection *conn); - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 7bd41eb475e3..ace9a11d77bb 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -153,6 +153,9 @@ struct transaction - /* List of all transactions active on this connection. */ - struct list_head list; - -+ /* Connection this transaction is associated with. */ -+ struct connection *conn; -+ - /* Connection-local identifier for this transaction. */ - uint32_t id; - -@@ -286,6 +289,8 @@ int access_node(struct connection *conn, struct node *node, - - introduce = true; - i->ta_node = false; -+ /* acc.memory < 0 means "unknown, get size from TDB". */ -+ node->acc.memory = -1; - - /* - * Additional transaction-specific node for read type. We only -@@ -410,11 +415,11 @@ static int finalize_transaction(struct connection *conn, - goto err; - hdr = (void *)data.dptr; - hdr->generation = ++generation; -- ret = tdb_store(tdb_ctx, key, data, -- TDB_REPLACE); -+ ret = do_tdb_write(conn, &key, &data, NULL, -+ true); - talloc_free(data.dptr); - } else { -- ret = tdb_delete(tdb_ctx, key); -+ ret = do_tdb_delete(conn, &key, NULL); - } - if (ret) - goto err; -@@ -425,7 +430,7 @@ static int finalize_transaction(struct connection *conn, - } - } - -- if (i->ta_node && tdb_delete(tdb_ctx, ta_key)) -+ if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL)) - goto err; - list_del(&i->list); - talloc_free(i); -@@ -453,7 +458,7 @@ static int destroy_transaction(void *_transaction) - i->node); - if (trans_name) { - set_tdb_key(trans_name, &key); -- tdb_delete(tdb_ctx, key); -+ do_tdb_delete(trans->conn, &key, NULL); - } - } - list_del(&i->list); -@@ -497,6 +502,7 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in) - - INIT_LIST_HEAD(&trans->accessed); - INIT_LIST_HEAD(&trans->changed_domains); -+ trans->conn = conn; - trans->fail = false; - trans->generation = ++generation; - diff --git a/xsa326-4.16-xenstored-15.patch b/xsa326-4.16-xenstored-15.patch deleted file mode 100644 index 8a42a36..0000000 --- a/xsa326-4.16-xenstored-15.patch +++ /dev/null @@ -1,54 +0,0 @@ -From c55a1ea0a5ea7f6a3dc850cb015a49ba9ec571ab Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add exports for quota variables - -Some quota variables are not exported via header files. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index da9ecce67f31..bfd3fc1e9df3 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -275,6 +275,11 @@ extern TDB_CONTEXT *tdb_ctx; - extern int dom0_domid; - extern int dom0_event; - extern int priv_domid; -+extern int quota_nb_watch_per_domain; -+extern int quota_max_transaction; -+extern int quota_max_entry_size; -+extern int quota_nb_perms_per_node; -+extern int quota_max_path_len; - extern int quota_nb_entry_per_domain; - extern int quota_req_outstanding; - extern int quota_trans_nodes; -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index ace9a11d77bb..28774813de83 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -175,7 +175,6 @@ struct transaction - bool fail; - }; - --extern int quota_max_transaction; - uint64_t generation; - - static struct accessed_node *find_accessed_node(struct transaction *trans, -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index fdf9b2d653a0..85362bcce314 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -31,8 +31,6 @@ - #include "xenstored_domain.h" - #include "xenstored_transaction.h" - --extern int quota_nb_watch_per_domain; -- - struct watch - { - /* Watches on this connection */ diff --git a/xsa326-4.16-xenstored-16.patch b/xsa326-4.16-xenstored-16.patch deleted file mode 100644 index c2a8953..0000000 --- a/xsa326-4.16-xenstored-16.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 05cc2af50ba43431d6d50aff758e968833aab9c6 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: add control command for setting and showing quota - -Add a xenstore-control command "quota" to: -- show current quota settings -- change quota settings -- show current quota related values of a domain - -Note that in the case the new quota is lower than existing one, -Xenstored may continue to handle requests from a domain exceeding the -new limit (depends on which one has been broken) and the amount of -resource used will not change. However the domain will not be able to -create more resource (associated to the quota) until it is back to below -the limit. - -This is part of XSA-326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt -index 334dc8b6fdf5..a7d006519ae8 100644 ---- a/docs/misc/xenstore.txt -+++ b/docs/misc/xenstore.txt -@@ -366,6 +366,17 @@ CONTROL |[|] - print| - print to syslog (xenstore runs as daemon) or - to console (xenstore runs as stubdom) -+ quota|[set |] -+ without parameters: print the current quota settings -+ with "set ": set the quota to new value -+ (The admin should make sure all the domain usage is -+ below the quota. If it is not, then Xenstored may continue to -+ handle requests from the domain as long as the resource -+ violating the new quota setting isn't increased further) -+ with "": print quota related accounting data for -+ the domain -+ quota-soft|[set ] -+ like the "quota" command, but for soft-quota. - help - return list of supported commands for CONTROL - -diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c -index adb8d51b043b..1031a81c3874 100644 ---- a/tools/xenstore/xenstored_control.c -+++ b/tools/xenstore/xenstored_control.c -@@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn, - return 0; - } - -+struct quota { -+ const char *name; -+ int *quota; -+ const char *descr; -+}; -+ -+static const struct quota hard_quotas[] = { -+ { "nodes", "a_nb_entry_per_domain, "Nodes per domain" }, -+ { "watches", "a_nb_watch_per_domain, "Watches per domain" }, -+ { "transactions", "a_max_transaction, "Transactions per domain" }, -+ { "outstanding", "a_req_outstanding, -+ "Outstanding requests per domain" }, -+ { "transaction-nodes", "a_trans_nodes, -+ "Max. number of accessed nodes per transaction" }, -+ { "memory", "a_memory_per_domain_hard, -+ "Total Xenstore memory per domain (error level)" }, -+ { "node-size", "a_max_entry_size, "Max. size of a node" }, -+ { "path-max", "a_max_path_len, "Max. length of a node path" }, -+ { "permissions", "a_nb_perms_per_node, -+ "Max. number of permissions per node" }, -+ { NULL, NULL, NULL } -+}; -+ -+static const struct quota soft_quotas[] = { -+ { "memory", "a_memory_per_domain_soft, -+ "Total Xenstore memory per domain (warning level)" }, -+ { NULL, NULL, NULL } -+}; -+ -+static int quota_show_current(const void *ctx, struct connection *conn, -+ const struct quota *quotas) -+{ -+ char *resp; -+ unsigned int i; -+ -+ resp = talloc_strdup(ctx, "Quota settings:\n"); -+ if (!resp) -+ return ENOMEM; -+ -+ for (i = 0; quotas[i].quota; i++) { -+ resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n", -+ quotas[i].name, *quotas[i].quota, -+ quotas[i].descr); -+ if (!resp) -+ return ENOMEM; -+ } -+ -+ send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1); -+ -+ return 0; -+} -+ -+static int quota_set(const void *ctx, struct connection *conn, -+ char **vec, int num, const struct quota *quotas) -+{ -+ unsigned int i; -+ int val; -+ -+ if (num != 2) -+ return EINVAL; -+ -+ val = atoi(vec[1]); -+ if (val < 1) -+ return EINVAL; -+ -+ for (i = 0; quotas[i].quota; i++) { -+ if (!strcmp(vec[0], quotas[i].name)) { -+ *quotas[i].quota = val; -+ send_ack(conn, XS_CONTROL); -+ return 0; -+ } -+ } -+ -+ return EINVAL; -+} -+ -+static int quota_get(const void *ctx, struct connection *conn, -+ char **vec, int num) -+{ -+ if (num != 1) -+ return EINVAL; -+ -+ return domain_get_quota(ctx, conn, atoi(vec[0])); -+} -+ -+static int do_control_quota(void *ctx, struct connection *conn, -+ char **vec, int num) -+{ -+ if (num == 0) -+ return quota_show_current(ctx, conn, hard_quotas); -+ -+ if (!strcmp(vec[0], "set")) -+ return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas); -+ -+ return quota_get(ctx, conn, vec, num); -+} -+ -+static int do_control_quota_s(void *ctx, struct connection *conn, -+ char **vec, int num) -+{ -+ if (num == 0) -+ return quota_show_current(ctx, conn, soft_quotas); -+ -+ if (!strcmp(vec[0], "set")) -+ return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas); -+ -+ return EINVAL; -+} -+ - #ifdef __MINIOS__ - static int do_control_memreport(void *ctx, struct connection *conn, - char **vec, int num) -@@ -847,6 +956,8 @@ static struct cmd_s cmds[] = { - { "memreport", do_control_memreport, "[]" }, - #endif - { "print", do_control_print, "" }, -+ { "quota", do_control_quota, "[set |]" }, -+ { "quota-soft", do_control_quota_s, "[set ]" }, - { "help", do_control_help, "" }, - }; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 94fd561e9de4..e7c6886ccf47 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -31,6 +31,7 @@ - #include "xenstored_domain.h" - #include "xenstored_transaction.h" - #include "xenstored_watch.h" -+#include "xenstored_control.h" - - #include - #include -@@ -345,6 +346,38 @@ static struct domain *find_domain_struct(unsigned int domid) - return NULL; - } - -+int domain_get_quota(const void *ctx, struct connection *conn, -+ unsigned int domid) -+{ -+ struct domain *d = find_domain_struct(domid); -+ char *resp; -+ int ta; -+ -+ if (!d) -+ return ENOENT; -+ -+ ta = d->conn ? d->conn->transaction_started : 0; -+ resp = talloc_asprintf(ctx, "Domain %u:\n", domid); -+ if (!resp) -+ return ENOMEM; -+ -+#define ent(t, e) \ -+ resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \ -+ if (!resp) return ENOMEM -+ -+ ent(nodes, d->nbentry); -+ ent(watches, d->nbwatch); -+ ent(transactions, ta); -+ ent(outstanding, d->nboutstanding); -+ ent(memory, d->memory); -+ -+#undef ent -+ -+ send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1); -+ -+ return 0; -+} -+ - static struct domain *alloc_domain(const void *context, unsigned int domid) - { - struct domain *domain; -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 633c9a0a0a1f..904faa923afb 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -87,6 +87,8 @@ int domain_watch(struct connection *conn); - void domain_outstanding_inc(struct connection *conn); - void domain_outstanding_dec(struct connection *conn); - void domain_outstanding_domid_dec(unsigned int domid); -+int domain_get_quota(const void *ctx, struct connection *conn, -+ unsigned int domid); - - /* Special node permission handling. */ - int set_perms_special(struct connection *conn, const char *name, diff --git a/xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch b/xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch deleted file mode 100644 index 9aca0a7..0000000 --- a/xsa409-4.13-0001-libxl-docs-Use-arch-specific-default-paging-memory.patch +++ /dev/null @@ -1,147 +0,0 @@ -From bd4a7db4001364fd03a80a2e73b81c46aaa44e9c Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 22 Aug 2022 01:35:09 +0000 -Subject: [PATCH 1/4] libxl, docs: Use arch-specific default paging memory - -The default paging memory (descibed in `shadow_memory` entry in xl -config) in libxl is used to determine the memory pool size for xl -guests. Currently this size is only used for x86, and contains a part -of RAM to shadow the resident processes. Since on Arm there is no -shadow mode guests, so the part of RAM to shadow the resident processes -is not necessary. Therefore, this commit splits the function -`libxl_get_required_shadow_memory()` to arch specific helpers and -renamed the helper to `libxl__arch_get_required_paging_memory()`. - -On x86, this helper calls the original value from -`libxl_get_required_shadow_memory()` so no functional change intended. - -On Arm, this helper returns 1MB per vcpu plus 4KB per MiB of RAM -for the P2M map and additional 512KB. - -Also update the xl.cfg documentation to add Arm documentation -according to code changes and correct the comment style following Xen -coding style. - -This is part of CVE-2022-33747 / XSA-409. - -Suggested-by: Julien Grall -Signed-off-by: Henry Wang -Reviewed-by: Anthony PERARD ---- - docs/man/xl.cfg.5.pod.in | 5 +++++ - tools/libs/light/libxl_arch.h | 4 ++++ - tools/libs/light/libxl_arm.c | 14 ++++++++++++++ - tools/libs/light/libxl_utils.c | 9 ++------- - tools/libs/light/libxl_x86.c | 13 +++++++++++++ - 5 files changed, 38 insertions(+), 7 deletions(-) - -diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in -index b98d1613987e..eda1e77ebd06 100644 ---- a/docs/man/xl.cfg.5.pod.in -+++ b/docs/man/xl.cfg.5.pod.in -@@ -1768,6 +1768,11 @@ are not using hardware assisted paging (i.e. you are using shadow - mode) and your guest workload consists of a very large number of - similar processes then increasing this value may improve performance. - -+On Arm, this field is used to determine the size of the guest P2M pages -+pool, and the default value is 1MB per vCPU plus 4KB per MB of RAM for -+the P2M map and additional 512KB for extended regions. Users should -+adjust this value if bigger P2M pool size is needed. -+ - =back - - =head3 Processor and Platform Features -diff --git a/tools/libs/light/libxl_arch.h b/tools/libs/light/libxl_arch.h -index 1522ecb97f72..5a060c2c3033 100644 ---- a/tools/libs/light/libxl_arch.h -+++ b/tools/libs/light/libxl_arch.h -@@ -90,6 +90,10 @@ void libxl__arch_update_domain_config(libxl__gc *gc, - libxl_domain_config *dst, - const libxl_domain_config *src); - -+_hidden -+unsigned long libxl__arch_get_required_paging_memory(unsigned long maxmem_kb, -+ unsigned int smp_cpus); -+ - #if defined(__i386__) || defined(__x86_64__) - - #define LAPIC_BASE_ADDRESS 0xfee00000 -diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c -index eef1de093914..73a95e83af24 100644 ---- a/tools/libs/light/libxl_arm.c -+++ b/tools/libs/light/libxl_arm.c -@@ -154,6 +154,20 @@ out: - return rc; - } - -+unsigned long libxl__arch_get_required_paging_memory(unsigned long maxmem_kb, -+ unsigned int smp_cpus) -+{ -+ /* -+ * 256 pages (1MB) per vcpu, -+ * plus 1 page per MiB of RAM for the P2M map, -+ * plus 1 page per MiB of extended region. This default value is 128 MiB -+ * which should be enough for domains that are not running backend. -+ * This is higher than the minimum that Xen would allocate if no value -+ * were given (but the Xen minimum is for safety, not performance). -+ */ -+ return 4 * (256 * smp_cpus + maxmem_kb / 1024 + 128); -+} -+ - static struct arch_info { - const char *guest_type; - const char *timer_compat; -diff --git a/tools/libs/light/libxl_utils.c b/tools/libs/light/libxl_utils.c -index 4699c4a0a36f..e276c0ee9cc3 100644 ---- a/tools/libs/light/libxl_utils.c -+++ b/tools/libs/light/libxl_utils.c -@@ -18,6 +18,7 @@ - #include - - #include "libxl_internal.h" -+#include "libxl_arch.h" - #include "_paths.h" - - #ifndef LIBXL_HAVE_NONCONST_LIBXL_BASENAME_RETURN_VALUE -@@ -39,13 +40,7 @@ char *libxl_basename(const char *name) - - unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus) - { -- /* 256 pages (1MB) per vcpu, -- plus 1 page per MiB of RAM for the P2M map, -- plus 1 page per MiB of RAM to shadow the resident processes. -- This is higher than the minimum that Xen would allocate if no value -- were given (but the Xen minimum is for safety, not performance). -- */ -- return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024)); -+ return libxl__arch_get_required_paging_memory(maxmem_kb, smp_cpus); - } - - char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid) -diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c -index 1feadebb1852..51362893cf98 100644 ---- a/tools/libs/light/libxl_x86.c -+++ b/tools/libs/light/libxl_x86.c -@@ -882,6 +882,19 @@ void libxl__arch_update_domain_config(libxl__gc *gc, - libxl_defbool_val(src->b_info.arch_x86.msr_relaxed)); - } - -+unsigned long libxl__arch_get_required_paging_memory(unsigned long maxmem_kb, -+ unsigned int smp_cpus) -+{ -+ /* -+ * 256 pages (1MB) per vcpu, -+ * plus 1 page per MiB of RAM for the P2M map, -+ * plus 1 page per MiB of RAM to shadow the resident processes. -+ * This is higher than the minimum that Xen would allocate if no value -+ * were given (but the Xen minimum is for safety, not performance). -+ */ -+ return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024)); -+} -+ - /* - * Local variables: - * mode: C --- -2.37.1 - diff --git a/xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch b/xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch deleted file mode 100644 index 8c03657..0000000 --- a/xsa409-4.13-0002-xen-arm-Construct-the-P2M-pages-pool-for-guests.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 419a4bbc20cf7c5d7d9dedae59fb8049922e6a2c Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 6 Jun 2022 06:17:28 +0000 -Subject: [PATCH 2/4] xen/arm: Construct the P2M pages pool for guests - -This commit constructs the p2m pages pool for guests from the -data structure and helper perspective. - -This is implemented by: - -- Adding a `struct paging_domain` which contains a freelist, a -counter variable and a spinlock to `struct arch_domain` to -indicate the free p2m pages and the number of p2m total pages in -the p2m pages pool. - -- Adding a helper `p2m_get_allocation` to get the p2m pool size. - -- Adding a helper `p2m_set_allocation` to set the p2m pages pool -size. This helper should be called before allocating memory for -a guest. - -- Adding a helper `p2m_teardown_allocation` to free the p2m pages -pool. This helper should be called during the xl domain destory. - -This is part of CVE-2022-33747 / XSA-409. - -Signed-off-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - xen/arch/arm/p2m.c | 88 ++++++++++++++++++++++++++++++++++++ - xen/include/asm-arm/domain.h | 10 ++++ - xen/include/asm-arm/p2m.h | 4 ++ - 3 files changed, 102 insertions(+) - -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index 3bcd1e897e88..79f3d37f5230 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -50,6 +50,92 @@ static uint64_t generate_vttbr(uint16_t vmid, mfn_t root_mfn) - return (mfn_to_maddr(root_mfn) | ((uint64_t)vmid << 48)); - } - -+/* Return the size of the pool, rounded up to the nearest MB */ -+unsigned int p2m_get_allocation(struct domain *d) -+{ -+ unsigned long nr_pages = ACCESS_ONCE(d->arch.paging.p2m_total_pages); -+ -+ return ROUNDUP(nr_pages, 1 << (20 - PAGE_SHIFT)) >> (20 - PAGE_SHIFT); -+} -+ -+/* -+ * Set the pool of pages to the required number of pages. -+ * Returns 0 for success, non-zero for failure. -+ * Call with d->arch.paging.lock held. -+ */ -+int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted) -+{ -+ struct page_info *pg; -+ -+ ASSERT(spin_is_locked(&d->arch.paging.lock)); -+ -+ for ( ; ; ) -+ { -+ if ( d->arch.paging.p2m_total_pages < pages ) -+ { -+ /* Need to allocate more memory from domheap */ -+ pg = alloc_domheap_page(NULL, 0); -+ if ( pg == NULL ) -+ { -+ printk(XENLOG_ERR "Failed to allocate P2M pages.\n"); -+ return -ENOMEM; -+ } -+ ACCESS_ONCE(d->arch.paging.p2m_total_pages) = -+ d->arch.paging.p2m_total_pages + 1; -+ page_list_add_tail(pg, &d->arch.paging.p2m_freelist); -+ } -+ else if ( d->arch.paging.p2m_total_pages > pages ) -+ { -+ /* Need to return memory to domheap */ -+ pg = page_list_remove_head(&d->arch.paging.p2m_freelist); -+ if( pg ) -+ { -+ ACCESS_ONCE(d->arch.paging.p2m_total_pages) = -+ d->arch.paging.p2m_total_pages - 1; -+ free_domheap_page(pg); -+ } -+ else -+ { -+ printk(XENLOG_ERR -+ "Failed to free P2M pages, P2M freelist is empty.\n"); -+ return -ENOMEM; -+ } -+ } -+ else -+ break; -+ -+ /* Check to see if we need to yield and try again */ -+ if ( preempted && general_preempt_check() ) -+ { -+ *preempted = true; -+ return -ERESTART; -+ } -+ } -+ -+ return 0; -+} -+ -+int p2m_teardown_allocation(struct domain *d) -+{ -+ int ret = 0; -+ bool preempted = false; -+ -+ spin_lock(&d->arch.paging.lock); -+ if ( d->arch.paging.p2m_total_pages != 0 ) -+ { -+ ret = p2m_set_allocation(d, 0, &preempted); -+ if ( preempted ) -+ { -+ spin_unlock(&d->arch.paging.lock); -+ return -ERESTART; -+ } -+ ASSERT(d->arch.paging.p2m_total_pages == 0); -+ } -+ spin_unlock(&d->arch.paging.lock); -+ -+ return ret; -+} -+ - /* Unlock the flush and do a P2M TLB flush if necessary */ - void p2m_write_unlock(struct p2m_domain *p2m) - { -@@ -1599,7 +1685,9 @@ int p2m_init(struct domain *d) - unsigned int cpu; - - rwlock_init(&p2m->lock); -+ spin_lock_init(&d->arch.paging.lock); - INIT_PAGE_LIST_HEAD(&p2m->pages); -+ INIT_PAGE_LIST_HEAD(&d->arch.paging.p2m_freelist); - - p2m->vmid = INVALID_VMID; - -diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h -index 9b3647587a04..c90daa65afa7 100644 ---- a/xen/include/asm-arm/domain.h -+++ b/xen/include/asm-arm/domain.h -@@ -40,6 +40,14 @@ struct vtimer { - uint64_t cval; - }; - -+struct paging_domain { -+ spinlock_t lock; -+ /* Free P2M pages from the pre-allocated P2M pool */ -+ struct page_list_head p2m_freelist; -+ /* Number of pages from the pre-allocated P2M pool */ -+ unsigned long p2m_total_pages; -+}; -+ - struct arch_domain - { - #ifdef CONFIG_ARM_64 -@@ -51,6 +59,8 @@ struct arch_domain - - struct hvm_domain hvm; - -+ struct paging_domain paging; -+ - struct vmmio vmmio; - - /* Continuable domain_relinquish_resources(). */ -diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h -index b3ba83283e11..c9598740bd02 100644 ---- a/xen/include/asm-arm/p2m.h -+++ b/xen/include/asm-arm/p2m.h -@@ -218,6 +218,10 @@ void p2m_restore_state(struct vcpu *n); - /* Print debugging/statistial info about a domain's p2m */ - void p2m_dump_info(struct domain *d); - -+unsigned int p2m_get_allocation(struct domain *d); -+int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted); -+int p2m_teardown_allocation(struct domain *d); -+ - static inline void p2m_write_lock(struct p2m_domain *p2m) - { - write_lock(&p2m->lock); --- -2.37.1 - diff --git a/xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch b/xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch deleted file mode 100644 index bb638e1..0000000 --- a/xsa409-4.13-0003-xen-arm-libxl-Implement-XEN_DOMCTL_shadow_op-for-Arm.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 332a9979d4dd0b047aa16db201c50fcedbd56743 Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 6 Jun 2022 06:17:29 +0000 -Subject: [PATCH 3/4] xen/arm, libxl: Implement XEN_DOMCTL_shadow_op for Arm - -This commit implements the `XEN_DOMCTL_shadow_op` support in Xen -for Arm. The p2m pages pool size for xl guests is supposed to be -determined by `XEN_DOMCTL_shadow_op`. Hence, this commit: - -- Introduces a function `p2m_domctl` and implements the subops -`XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION` and -`XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION` of `XEN_DOMCTL_shadow_op`. - -- Adds the `XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION` support in libxl. - -Therefore enabling the setting of shadow memory pool size -when creating a guest from xl and getting shadow memory pool size -from Xen. - -Note that the `XEN_DOMCTL_shadow_op` added in this commit is only -a dummy op, and the functionality of setting/getting p2m memory pool -size for xl guests will be added in following commits. - -This is part of CVE-2022-33747 / XSA-409. - -Signed-off-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - tools/libs/light/libxl_arm.c | 12 ++++++++++++ - xen/arch/arm/domctl.c | 32 ++++++++++++++++++++++++++++++++ - 2 files changed, 44 insertions(+) - -diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c -index 73a95e83af24..22a0c561bbc6 100644 ---- a/tools/libs/light/libxl_arm.c -+++ b/tools/libs/light/libxl_arm.c -@@ -131,6 +131,18 @@ int libxl__arch_domain_create(libxl__gc *gc, - libxl__domain_build_state *state, - uint32_t domid) - { -+ libxl_ctx *ctx = libxl__gc_owner(gc); -+ unsigned int shadow_mb = DIV_ROUNDUP(d_config->b_info.shadow_memkb, 1024); -+ -+ int r = xc_shadow_control(ctx->xch, domid, -+ XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, -+ &shadow_mb, 0); -+ if (r) { -+ LOGED(ERROR, domid, -+ "Failed to set %u MiB shadow allocation", shadow_mb); -+ return ERROR_FAIL; -+ } -+ - return 0; - } - -diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c -index 1baf25c3d98b..9bf72e693019 100644 ---- a/xen/arch/arm/domctl.c -+++ b/xen/arch/arm/domctl.c -@@ -47,11 +47,43 @@ static int handle_vuart_init(struct domain *d, - return rc; - } - -+static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc, -+ XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) -+{ -+ if ( unlikely(d == current->domain) ) -+ { -+ printk(XENLOG_ERR "Tried to do a p2m domctl op on itself.\n"); -+ return -EINVAL; -+ } -+ -+ if ( unlikely(d->is_dying) ) -+ { -+ printk(XENLOG_ERR "Tried to do a p2m domctl op on dying domain %u\n", -+ d->domain_id); -+ return -EINVAL; -+ } -+ -+ switch ( sc->op ) -+ { -+ case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION: -+ return 0; -+ case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION: -+ return 0; -+ default: -+ { -+ printk(XENLOG_ERR "Bad p2m domctl op %u\n", sc->op); -+ return -EINVAL; -+ } -+ } -+} -+ - long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, - XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) - { - switch ( domctl->cmd ) - { -+ case XEN_DOMCTL_shadow_op: -+ return p2m_domctl(d, &domctl->u.shadow_op, u_domctl); - case XEN_DOMCTL_cacheflush: - { - gfn_t s = _gfn(domctl->u.cacheflush.start_pfn); --- -2.37.1 - diff --git a/xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch b/xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch deleted file mode 100644 index 5366c8f..0000000 --- a/xsa409-4.13-0004-xen-arm-Allocate-and-free-P2M-pages-from-the-P2M-poo.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 39664d9ee041f96e9c7ee131ed8ef72a4d19c9f8 Mon Sep 17 00:00:00 2001 -From: Henry Wang -Date: Mon, 6 Jun 2022 06:17:30 +0000 -Subject: [PATCH 4/4] xen/arm: Allocate and free P2M pages from the P2M pool - -This commit sets/tearsdown of p2m pages pool for non-privileged Arm -guests by calling `p2m_set_allocation` and `p2m_teardown_allocation`. - -- For dom0, P2M pages should come from heap directly instead of p2m -pool, so that the kernel may take advantage of the extended regions. - -- For xl guests, the setting of the p2m pool is called in -`XEN_DOMCTL_shadow_op` and the p2m pool is destroyed in -`domain_relinquish_resources`. Note that domctl->u.shadow_op.mb is -updated with the new size when setting the p2m pool. - -- For dom0less domUs, the setting of the p2m pool is called before -allocating memory during domain creation. Users can specify the p2m -pool size by `xen,domain-p2m-mem-mb` dts property. - -To actually allocate/free pages from the p2m pool, this commit adds -two helper functions namely `p2m_alloc_page` and `p2m_free_page` to -`struct p2m_domain`. By replacing the `alloc_domheap_page` and -`free_domheap_page` with these two helper functions, p2m pages can -be added/removed from the list of p2m pool rather than from the heap. - -Since page from `p2m_alloc_page` is cleaned, take the opportunity -to remove the redundant `clean_page` in `p2m_create_table`. - -This is part of CVE-2022-33747 / XSA-409. - -Signed-off-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - docs/misc/arm/device-tree/booting.txt | 8 ++++ - xen/arch/arm/domain.c | 6 +++ - xen/arch/arm/domain_build.c | 29 ++++++++++++++ - xen/arch/arm/domctl.c | 23 ++++++++++- - xen/arch/arm/p2m.c | 57 +++++++++++++++++++++++++-- - 5 files changed, 118 insertions(+), 5 deletions(-) - -diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt -index 71895663a4de..d92ccc56ffe0 100644 ---- a/docs/misc/arm/device-tree/booting.txt -+++ b/docs/misc/arm/device-tree/booting.txt -@@ -182,6 +182,14 @@ with the following properties: - Both #address-cells and #size-cells need to be specified because - both sub-nodes (described shortly) have reg properties. - -+- xen,domain-p2m-mem-mb -+ -+ Optional. A 32-bit integer specifying the amount of megabytes of RAM -+ used for the domain P2M pool. This is in-sync with the shadow_memory -+ option in xl.cfg. Leaving this field empty in device tree will lead to -+ the default size of domain P2M pool, i.e. 1MB per guest vCPU plus 4KB -+ per MB of guest RAM plus 512KB for guest extended regions. -+ - Under the "xen,domain" compatible node, one or more sub-nodes are present - for the DomU kernel and ramdisk. - -diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c -index 2694c39127c5..a818f33a1afa 100644 ---- a/xen/arch/arm/domain.c -+++ b/xen/arch/arm/domain.c -@@ -997,6 +997,7 @@ enum { - PROG_page, - PROG_mapping, - PROG_p2m, -+ PROG_p2m_pool, - PROG_done, - }; - -@@ -1062,6 +1063,11 @@ int domain_relinquish_resources(struct domain *d) - if ( ret ) - return ret; - -+ PROGRESS(p2m_pool): -+ ret = p2m_teardown_allocation(d); -+ if( ret ) -+ return ret; -+ - PROGRESS(done): - break; - -diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c -index d02bacbcd1ed..8aec3755ca5d 100644 ---- a/xen/arch/arm/domain_build.c -+++ b/xen/arch/arm/domain_build.c -@@ -2833,6 +2833,21 @@ static void __init find_gnttab_region(struct domain *d, - kinfo->gnttab_start, kinfo->gnttab_start + kinfo->gnttab_size); - } - -+static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb, -+ unsigned int smp_cpus) -+{ -+ /* -+ * Keep in sync with libxl__get_required_paging_memory(). -+ * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map, -+ * plus 128 pages to cover extended regions. -+ */ -+ unsigned long memkb = 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128); -+ -+ BUILD_BUG_ON(PAGE_SIZE != SZ_4K); -+ -+ return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); -+} -+ - static int __init construct_domain(struct domain *d, struct kernel_info *kinfo) - { - unsigned int i; -@@ -2924,6 +2939,8 @@ static int __init construct_domU(struct domain *d, - struct kernel_info kinfo = {}; - int rc; - u64 mem; -+ u32 p2m_mem_mb; -+ unsigned long p2m_pages; - - rc = dt_property_read_u64(node, "memory", &mem); - if ( !rc ) -@@ -2933,6 +2950,18 @@ static int __init construct_domU(struct domain *d, - } - kinfo.unassigned_mem = (paddr_t)mem * SZ_1K; - -+ rc = dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb); -+ /* If xen,domain-p2m-mem-mb is not specified, use the default value. */ -+ p2m_pages = rc ? -+ p2m_mem_mb << (20 - PAGE_SHIFT) : -+ domain_p2m_pages(mem, d->max_vcpus); -+ -+ spin_lock(&d->arch.paging.lock); -+ rc = p2m_set_allocation(d, p2m_pages, NULL); -+ spin_unlock(&d->arch.paging.lock); -+ if ( rc != 0 ) -+ return rc; -+ - printk("*** LOADING DOMU cpus=%u memory=%"PRIx64"KB ***\n", d->max_vcpus, mem); - - kinfo.vpl011 = dt_property_read_bool(node, "vpl011"); -diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c -index 9bf72e693019..c8fdeb124084 100644 ---- a/xen/arch/arm/domctl.c -+++ b/xen/arch/arm/domctl.c -@@ -50,6 +50,9 @@ static int handle_vuart_init(struct domain *d, - static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc, - XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) - { -+ long rc; -+ bool preempted = false; -+ - if ( unlikely(d == current->domain) ) - { - printk(XENLOG_ERR "Tried to do a p2m domctl op on itself.\n"); -@@ -66,9 +69,27 @@ static long p2m_domctl(struct domain *d, struct xen_domctl_shadow_op *sc, - switch ( sc->op ) - { - case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION: -- return 0; -+ { -+ /* Allow and handle preemption */ -+ spin_lock(&d->arch.paging.lock); -+ rc = p2m_set_allocation(d, sc->mb << (20 - PAGE_SHIFT), &preempted); -+ spin_unlock(&d->arch.paging.lock); -+ -+ if ( preempted ) -+ /* Not finished. Set up to re-run the call. */ -+ rc = hypercall_create_continuation(__HYPERVISOR_domctl, "h", -+ u_domctl); -+ else -+ /* Finished. Return the new allocation. */ -+ sc->mb = p2m_get_allocation(d); -+ -+ return rc; -+ } - case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION: -+ { -+ sc->mb = p2m_get_allocation(d); - return 0; -+ } - default: - { - printk(XENLOG_ERR "Bad p2m domctl op %u\n", sc->op); -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index 79f3d37f5230..1bf9cbeb53cf 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -50,6 +50,54 @@ static uint64_t generate_vttbr(uint16_t vmid, mfn_t root_mfn) - return (mfn_to_maddr(root_mfn) | ((uint64_t)vmid << 48)); - } - -+static struct page_info *p2m_alloc_page(struct domain *d) -+{ -+ struct page_info *pg; -+ -+ spin_lock(&d->arch.paging.lock); -+ /* -+ * For hardware domain, there should be no limit in the number of pages that -+ * can be allocated, so that the kernel may take advantage of the extended -+ * regions. Hence, allocate p2m pages for hardware domains from heap. -+ */ -+ if ( is_hardware_domain(d) ) -+ { -+ pg = alloc_domheap_page(NULL, 0); -+ if ( pg == NULL ) -+ { -+ printk(XENLOG_G_ERR "Failed to allocate P2M pages for hwdom.\n"); -+ spin_unlock(&d->arch.paging.lock); -+ return NULL; -+ } -+ } -+ else -+ { -+ pg = page_list_remove_head(&d->arch.paging.p2m_freelist); -+ if ( unlikely(!pg) ) -+ { -+ spin_unlock(&d->arch.paging.lock); -+ return NULL; -+ } -+ d->arch.paging.p2m_total_pages--; -+ } -+ spin_unlock(&d->arch.paging.lock); -+ -+ return pg; -+} -+ -+static void p2m_free_page(struct domain *d, struct page_info *pg) -+{ -+ spin_lock(&d->arch.paging.lock); -+ if ( is_hardware_domain(d) ) -+ free_domheap_page(pg); -+ else -+ { -+ d->arch.paging.p2m_total_pages++; -+ page_list_add_tail(pg, &d->arch.paging.p2m_freelist); -+ } -+ spin_unlock(&d->arch.paging.lock); -+} -+ - /* Return the size of the pool, rounded up to the nearest MB */ - unsigned int p2m_get_allocation(struct domain *d) - { -@@ -751,7 +799,7 @@ static int p2m_create_table(struct p2m_domain *p2m, lpae_t *entry) - - ASSERT(!p2m_is_valid(*entry)); - -- page = alloc_domheap_page(NULL, 0); -+ page = p2m_alloc_page(p2m->domain); - if ( page == NULL ) - return -ENOMEM; - -@@ -878,7 +926,7 @@ static void p2m_free_entry(struct p2m_domain *p2m, - pg = mfn_to_page(mfn); - - page_list_del(pg, &p2m->pages); -- free_domheap_page(pg); -+ p2m_free_page(p2m->domain, pg); - } - - static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry, -@@ -902,7 +950,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry, - ASSERT(level < target); - ASSERT(p2m_is_superpage(*entry, level)); - -- page = alloc_domheap_page(NULL, 0); -+ page = p2m_alloc_page(p2m->domain); - if ( !page ) - return false; - -@@ -1641,7 +1689,7 @@ int p2m_teardown(struct domain *d) - - while ( (pg = page_list_remove_head(&p2m->pages)) ) - { -- free_domheap_page(pg); -+ p2m_free_page(p2m->domain, pg); - count++; - /* Arbitrarily preempt every 512 iterations */ - if ( !(count % 512) && hypercall_preempt_check() ) -@@ -1665,6 +1713,7 @@ void p2m_final_teardown(struct domain *d) - return; - - ASSERT(page_list_empty(&p2m->pages)); -+ ASSERT(page_list_empty(&d->arch.paging.p2m_freelist)); - - if ( p2m->root ) - free_domheap_pages(p2m->root, P2M_ROOT_ORDER); --- -2.37.1 - diff --git a/xsa410-4.16-01.patch b/xsa410-4.16-01.patch deleted file mode 100644 index 8f352ee..0000000 --- a/xsa410-4.16-01.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 4b4359122a414cc15156e13e3805988b71ff9da0 Mon Sep 17 00:00:00 2001 -From: Julien Grall -Date: Mon, 6 Jun 2022 06:17:25 +0000 -Subject: [PATCH 1/2] xen/arm: p2m: Prevent adding mapping when domain is dying - -During the domain destroy process, the domain will still be accessible -until it is fully destroyed. So does the P2M because we don't bail -out early if is_dying is non-zero. If a domain has permission to -modify the other domain's P2M (i.e. dom0, or a stubdomain), then -foreign mapping can be added past relinquish_p2m_mapping(). - -Therefore, we need to prevent mapping to be added when the domain -is dying. This commit prevents such adding of mapping by adding the -d->is_dying check to p2m_set_entry(). Also this commit enhances the -check in relinquish_p2m_mapping() to make sure that no mappings can -be added in the P2M after the P2M lock is released. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Julien Grall -Signed-off-by: Henry Wang -Tested-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - xen/arch/arm/p2m.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index fb71fa4c1c90..cbeff90f4371 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -1093,6 +1093,15 @@ int p2m_set_entry(struct p2m_domain *p2m, - { - int rc = 0; - -+ /* -+ * Any reference taken by the P2M mappings (e.g. foreign mapping) will -+ * be dropped in relinquish_p2m_mapping(). As the P2M will still -+ * be accessible after, we need to prevent mapping to be added when the -+ * domain is dying. -+ */ -+ if ( unlikely(p2m->domain->is_dying) ) -+ return -ENOMEM; -+ - while ( nr ) - { - unsigned long mask; -@@ -1610,6 +1619,8 @@ int relinquish_p2m_mapping(struct domain *d) - unsigned int order; - gfn_t start, end; - -+ BUG_ON(!d->is_dying); -+ /* No mappings can be added in the P2M after the P2M lock is released. */ - p2m_write_lock(p2m); - - start = p2m->lowest_mapped_gfn; --- -2.37.1 - diff --git a/xsa410-4.16-02.patch b/xsa410-4.16-02.patch deleted file mode 100644 index 7599a47..0000000 --- a/xsa410-4.16-02.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 0d5846490348fa09a0d0915d7c795685a016ce10 Mon Sep 17 00:00:00 2001 -From: Julien Grall -Date: Mon, 6 Jun 2022 06:17:26 +0000 -Subject: [PATCH 2/2] xen/arm: p2m: Handle preemption when freeing intermediate - page tables - -At the moment the P2M page tables will be freed when the domain structure -is freed without any preemption. As the P2M is quite large, iterating -through this may take more time than it is reasonable without intermediate -preemption (to run softirqs and perhaps scheduler). - -Split p2m_teardown() in two parts: one preemptible and called when -relinquishing the resources, the other one non-preemptible and called -when freeing the domain structure. - -As we are now freeing the P2M pages early, we also need to prevent -further allocation if someone call p2m_set_entry() past p2m_teardown() -(I wasn't able to prove this will never happen). This is done by -the checking domain->is_dying from previous patch in p2m_set_entry(). - -Similarly, we want to make sure that no-one can accessed the free -pages. Therefore the root is cleared before freeing pages. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Julien Grall -Signed-off-by: Henry Wang -Tested-by: Henry Wang -Reviewed-by: Stefano Stabellini ---- - xen/arch/arm/domain.c | 10 +++++++-- - xen/arch/arm/p2m.c | 47 ++++++++++++++++++++++++++++++++++++--- - xen/include/asm-arm/p2m.h | 13 +++++++++-- - 3 files changed, 63 insertions(+), 7 deletions(-) - -diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c -index 96e1b235501d..2694c39127c5 100644 ---- a/xen/arch/arm/domain.c -+++ b/xen/arch/arm/domain.c -@@ -789,10 +789,10 @@ fail: - void arch_domain_destroy(struct domain *d) - { - /* IOMMU page table is shared with P2M, always call -- * iommu_domain_destroy() before p2m_teardown(). -+ * iommu_domain_destroy() before p2m_final_teardown(). - */ - iommu_domain_destroy(d); -- p2m_teardown(d); -+ p2m_final_teardown(d); - domain_vgic_free(d); - domain_vuart_free(d); - free_xenheap_page(d->shared_info); -@@ -996,6 +996,7 @@ enum { - PROG_xen, - PROG_page, - PROG_mapping, -+ PROG_p2m, - PROG_done, - }; - -@@ -1056,6 +1057,11 @@ int domain_relinquish_resources(struct domain *d) - if ( ret ) - return ret; - -+ PROGRESS(p2m): -+ ret = p2m_teardown(d); -+ if ( ret ) -+ return ret; -+ - PROGRESS(done): - break; - -diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c -index cbeff90f4371..3bcd1e897e88 100644 ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -1527,17 +1527,58 @@ static void p2m_free_vmid(struct domain *d) - spin_unlock(&vmid_alloc_lock); - } - --void p2m_teardown(struct domain *d) -+int p2m_teardown(struct domain *d) - { - struct p2m_domain *p2m = p2m_get_hostp2m(d); -+ unsigned long count = 0; - struct page_info *pg; -+ unsigned int i; -+ int rc = 0; -+ -+ p2m_write_lock(p2m); -+ -+ /* -+ * We are about to free the intermediate page-tables, so clear the -+ * root to prevent any walk to use them. -+ */ -+ for ( i = 0; i < P2M_ROOT_PAGES; i++ ) -+ clear_and_clean_page(p2m->root + i); -+ -+ /* -+ * The domain will not be scheduled anymore, so in theory we should -+ * not need to flush the TLBs. Do it for safety purpose. -+ * -+ * Note that all the devices have already been de-assigned. So we don't -+ * need to flush the IOMMU TLB here. -+ */ -+ p2m_force_tlb_flush_sync(p2m); -+ -+ while ( (pg = page_list_remove_head(&p2m->pages)) ) -+ { -+ free_domheap_page(pg); -+ count++; -+ /* Arbitrarily preempt every 512 iterations */ -+ if ( !(count % 512) && hypercall_preempt_check() ) -+ { -+ rc = -ERESTART; -+ break; -+ } -+ } -+ -+ p2m_write_unlock(p2m); -+ -+ return rc; -+} -+ -+void p2m_final_teardown(struct domain *d) -+{ -+ struct p2m_domain *p2m = p2m_get_hostp2m(d); - - /* p2m not actually initialized */ - if ( !p2m->domain ) - return; - -- while ( (pg = page_list_remove_head(&p2m->pages)) ) -- free_domheap_page(pg); -+ ASSERT(page_list_empty(&p2m->pages)); - - if ( p2m->root ) - free_domheap_pages(p2m->root, P2M_ROOT_ORDER); -diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h -index 8f11d9c97b5d..b3ba83283e11 100644 ---- a/xen/include/asm-arm/p2m.h -+++ b/xen/include/asm-arm/p2m.h -@@ -192,8 +192,17 @@ void setup_virt_paging(void); - /* Init the datastructures for later use by the p2m code */ - int p2m_init(struct domain *d); - --/* Return all the p2m resources to Xen. */ --void p2m_teardown(struct domain *d); -+/* -+ * The P2M resources are freed in two parts: -+ * - p2m_teardown() will be called when relinquish the resources. It -+ * will free large resources (e.g. intermediate page-tables) that -+ * requires preemption. -+ * - p2m_final_teardown() will be called when domain struct is been -+ * freed. This *cannot* be preempted and therefore one small -+ * resources should be freed here. -+ */ -+int p2m_teardown(struct domain *d); -+void p2m_final_teardown(struct domain *d); - - /* - * Remove mapping refcount on each mapping page in the p2m --- -2.37.1 - diff --git a/xsa410-4.16-03.patch b/xsa410-4.16-03.patch deleted file mode 100644 index 7411d90..0000000 --- a/xsa410-4.16-03.patch +++ /dev/null @@ -1,113 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: add option to skip root pagetable removal in p2m_teardown() - -Add a new parameter to p2m_teardown() in order to select whether the -root page table should also be freed. Note that all users are -adjusted to pass the parameter to remove the root page tables, so -behavior is not modified. - -No functional change intended. - -This is part of CVE-2022-33746 / XSA-410. - -Suggested-by: Julien Grall -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/include/asm-x86/p2m.h -+++ b/xen/include/asm-x86/p2m.h -@@ -574,7 +574,7 @@ int p2m_init(struct domain *d); - int p2m_alloc_table(struct p2m_domain *p2m); - - /* Return all the p2m resources to Xen. */ --void p2m_teardown(struct p2m_domain *p2m); -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root); - void p2m_final_teardown(struct domain *d); - - /* Add a page to a domain's p2m table */ ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -541,18 +541,18 @@ void hap_final_teardown(struct domain *d - } - - for ( i = 0; i < MAX_ALTP2M; i++ ) -- p2m_teardown(d->arch.altp2m_p2m[i]); -+ p2m_teardown(d->arch.altp2m_p2m[i], true); - } - - /* Destroy nestedp2m's first */ - for (i = 0; i < MAX_NESTEDP2M; i++) { -- p2m_teardown(d->arch.nested_p2m[i]); -+ p2m_teardown(d->arch.nested_p2m[i], true); - } - - if ( d->arch.paging.hap.total_pages != 0 ) - hap_teardown(d, NULL); - -- p2m_teardown(p2m_get_hostp2m(d)); -+ p2m_teardown(p2m_get_hostp2m(d), true); - /* Free any memory that the p2m teardown released */ - paging_lock(d); - hap_set_allocation(d, 0, NULL); ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -749,11 +749,11 @@ int p2m_alloc_table(struct p2m_domain *p - * hvm fixme: when adding support for pvh non-hardware domains, this path must - * cleanup any foreign p2m types (release refcnts on them). - */ --void p2m_teardown(struct p2m_domain *p2m) -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root) - /* Return all the p2m pages to Xen. - * We know we don't have any extra mappings to these pages */ - { -- struct page_info *pg; -+ struct page_info *pg, *root_pg = NULL; - struct domain *d; - - if (p2m == NULL) -@@ -763,10 +763,22 @@ void p2m_teardown(struct p2m_domain *p2m - - p2m_lock(p2m); - ASSERT(atomic_read(&d->shr_pages) == 0); -- p2m->phys_table = pagetable_null(); -+ -+ if ( remove_root ) -+ p2m->phys_table = pagetable_null(); -+ else if ( !pagetable_is_null(p2m->phys_table) ) -+ { -+ root_pg = pagetable_get_page(p2m->phys_table); -+ clear_domain_page(pagetable_get_mfn(p2m->phys_table)); -+ } - - while ( (pg = page_list_remove_head(&p2m->pages)) ) -- d->arch.paging.free_page(d, pg); -+ if ( pg != root_pg ) -+ d->arch.paging.free_page(d, pg); -+ -+ if ( root_pg ) -+ page_list_add(root_pg, &p2m->pages); -+ - p2m_unlock(p2m); - } - ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2701,7 +2701,7 @@ int shadow_enable(struct domain *d, u32 - paging_unlock(d); - out_unlocked: - if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) ) -- p2m_teardown(p2m); -+ p2m_teardown(p2m, true); - if ( rv != 0 && pg != NULL ) - { - pg->count_info &= ~PGC_count_mask; -@@ -2866,7 +2866,7 @@ void shadow_final_teardown(struct domain - shadow_teardown(d, NULL); - - /* It is now safe to pull down the p2m map. */ -- p2m_teardown(p2m_get_hostp2m(d)); -+ p2m_teardown(p2m_get_hostp2m(d), true); - /* Free any shadow memory that the p2m teardown released */ - paging_lock(d); - shadow_set_allocation(d, 0, NULL); diff --git a/xsa410-4.16-04.patch b/xsa410-4.16-04.patch deleted file mode 100644 index 2170b8e..0000000 --- a/xsa410-4.16-04.patch +++ /dev/null @@ -1,62 +0,0 @@ -From: Jan Beulich -Subject: x86/HAP: adjust monitor table related error handling - -hap_make_monitor_table() will return INVALID_MFN if it encounters an -error condition, but hap_update_paging_modes() wasn’t handling this -value, resulting in an inappropriate value being stored in -monitor_table. This would subsequently misguide at least -hap_vcpu_teardown(). Avoid this by bailing early. - -Further, when a domain has/was already crashed or (perhaps less -important as there's no such path known to lead here) is already dying, -avoid calling domain_crash() on it again - that's at best confusing. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Jan Beulich -Reviewed-by: Roger Pau Monné - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - - #include "private.h" - -@@ -405,8 +406,13 @@ static mfn_t hap_make_monitor_table(stru - return m4mfn; - - oom: -- printk(XENLOG_G_ERR "out of memory building monitor pagetable\n"); -- domain_crash(d); -+ if ( !d->is_dying && -+ (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) -+ { -+ printk(XENLOG_G_ERR "%pd: out of memory building monitor pagetable\n", -+ d); -+ domain_crash(d); -+ } - return INVALID_MFN; - } - -@@ -766,6 +772,9 @@ static void hap_update_paging_modes(stru - if ( pagetable_is_null(v->arch.hvm.monitor_table) ) - { - mfn_t mmfn = hap_make_monitor_table(v); -+ -+ if ( mfn_eq(mmfn, INVALID_MFN) ) -+ goto unlock; - v->arch.hvm.monitor_table = pagetable_from_mfn(mmfn); - make_cr3(v, mmfn); - hvm_update_host_cr3(v); -@@ -774,6 +783,7 @@ static void hap_update_paging_modes(stru - /* CR3 is effectively updated by a mode change. Flush ASIDs, etc. */ - hap_update_cr3(v, 0, false); - -+ unlock: - paging_unlock(d); - put_gfn(d, cr3_gfn); - } diff --git a/xsa410-4.16-05.patch b/xsa410-4.16-05.patch deleted file mode 100644 index dc626c7..0000000 --- a/xsa410-4.16-05.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: tolerate failure of sh_set_toplevel_shadow() - -Subsequently sh_set_toplevel_shadow() will be adjusted to install a -blank entry in case prealloc fails. There are, in fact, pre-existing -error paths which would put in place a blank entry. The 4- and 2-level -code in sh_update_cr3(), however, assume the top level entry to be -valid. - -Hence bail from the function in the unlikely event that it's not. Note -that 3-level logic works differently: In particular a guest is free to -supply a PDPTR pointing at 4 non-present (or otherwise deemed invalid) -entries. The guest will crash, but we already cope with that. - -Really mfn_valid() is likely wrong to use in sh_set_toplevel_shadow(), -and it should instead be !mfn_eq(gmfn, INVALID_MFN). Avoid such a change -in security context, but add a respective assertion. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2516,6 +2516,7 @@ void sh_set_toplevel_shadow(struct vcpu - /* Now figure out the new contents: is this a valid guest MFN? */ - if ( !mfn_valid(gmfn) ) - { -+ ASSERT(mfn_eq(gmfn, INVALID_MFN)); - new_entry = pagetable_null(); - goto install_new_entry; - } ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -3312,6 +3312,11 @@ sh_update_cr3(struct vcpu *v, int do_loc - if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 ) - guest_flush_tlb_mask(d, d->dirty_cpumask); - sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, sh_make_shadow); -+ if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) -+ { -+ ASSERT(d->is_dying || d->is_shutting_down); -+ return; -+ } - if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) ) - { - mfn_t smfn = pagetable_get_mfn(v->arch.paging.shadow.shadow_table[0]); -@@ -3370,6 +3375,11 @@ sh_update_cr3(struct vcpu *v, int do_loc - if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 ) - guest_flush_tlb_mask(d, d->dirty_cpumask); - sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, sh_make_shadow); -+ if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) -+ { -+ ASSERT(d->is_dying || d->is_shutting_down); -+ return; -+ } - #else - #error This should never happen - #endif diff --git a/xsa410-4.16-06.patch b/xsa410-4.16-06.patch deleted file mode 100644 index 8c89eb3..0000000 --- a/xsa410-4.16-06.patch +++ /dev/null @@ -1,255 +0,0 @@ -From: Roger Pau Monné -Subject: x86/shadow: tolerate failure in shadow_prealloc() - -Prevent _shadow_prealloc() from calling BUG() when unable to fulfill -the pre-allocation and instead return true/false. Modify -shadow_prealloc() to crash the domain on allocation failure (if the -domain is not already dying), as shadow cannot operate normally after -that. Modify callers to also gracefully handle {_,}shadow_prealloc() -failing to fulfill the request. - -Note this in turn requires adjusting the callers of -sh_make_monitor_table() also to handle it returning INVALID_MFN. -sh_update_paging_modes() is also modified to add additional error -paths in case of allocation failure, some of those will return with -null monitor page tables (and the domain likely crashed). This is no -different that current error paths, but the newly introduced ones are -more likely to trigger. - -The now added failure points in sh_update_paging_modes() also require -that on some error return paths the previous structures are cleared, -and thus monitor table is null. - -While there adjust the 'type' parameter type of shadow_prealloc() to -unsigned int rather than u32. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - #include "private.h" - - DEFINE_PER_CPU(uint32_t,trace_shadow_path_flags); -@@ -928,14 +929,15 @@ static inline void trace_shadow_prealloc - - /* Make sure there are at least count order-sized pages - * available in the shadow page pool. */ --static void _shadow_prealloc(struct domain *d, unsigned int pages) -+static bool __must_check _shadow_prealloc(struct domain *d, unsigned int pages) - { - struct vcpu *v; - struct page_info *sp, *t; - mfn_t smfn; - int i; - -- if ( d->arch.paging.shadow.free_pages >= pages ) return; -+ if ( d->arch.paging.shadow.free_pages >= pages ) -+ return true; - - /* Shouldn't have enabled shadows if we've no vcpus. */ - ASSERT(d->vcpu && d->vcpu[0]); -@@ -951,7 +953,8 @@ static void _shadow_prealloc(struct doma - sh_unpin(d, smfn); - - /* See if that freed up enough space */ -- if ( d->arch.paging.shadow.free_pages >= pages ) return; -+ if ( d->arch.paging.shadow.free_pages >= pages ) -+ return true; - } - - /* Stage two: all shadow pages are in use in hierarchies that are -@@ -974,7 +977,7 @@ static void _shadow_prealloc(struct doma - if ( d->arch.paging.shadow.free_pages >= pages ) - { - guest_flush_tlb_mask(d, d->dirty_cpumask); -- return; -+ return true; - } - } - } -@@ -987,7 +990,12 @@ static void _shadow_prealloc(struct doma - d->arch.paging.shadow.total_pages, - d->arch.paging.shadow.free_pages, - d->arch.paging.shadow.p2m_pages); -- BUG(); -+ -+ ASSERT(d->is_dying); -+ -+ guest_flush_tlb_mask(d, d->dirty_cpumask); -+ -+ return false; - } - - /* Make sure there are at least count pages of the order according to -@@ -995,9 +1003,19 @@ static void _shadow_prealloc(struct doma - * This must be called before any calls to shadow_alloc(). Since this - * will free existing shadows to make room, it must be called early enough - * to avoid freeing shadows that the caller is currently working on. */ --void shadow_prealloc(struct domain *d, u32 type, unsigned int count) -+bool shadow_prealloc(struct domain *d, unsigned int type, unsigned int count) - { -- return _shadow_prealloc(d, shadow_size(type) * count); -+ bool ret = _shadow_prealloc(d, shadow_size(type) * count); -+ -+ if ( !ret && !d->is_dying && -+ (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) -+ /* -+ * Failing to allocate memory required for shadow usage can only result in -+ * a domain crash, do it here rather that relying on every caller to do it. -+ */ -+ domain_crash(d); -+ -+ return ret; - } - - /* Deliberately free all the memory we can: this will tear down all of -@@ -1218,7 +1236,7 @@ void shadow_free(struct domain *d, mfn_t - static struct page_info * - shadow_alloc_p2m_page(struct domain *d) - { -- struct page_info *pg; -+ struct page_info *pg = NULL; - - /* This is called both from the p2m code (which never holds the - * paging lock) and the log-dirty code (which always does). */ -@@ -1236,16 +1254,18 @@ shadow_alloc_p2m_page(struct domain *d) - d->arch.paging.shadow.p2m_pages, - shadow_min_acceptable_pages(d)); - } -- paging_unlock(d); -- return NULL; -+ goto out; - } - -- shadow_prealloc(d, SH_type_p2m_table, 1); -+ if ( !shadow_prealloc(d, SH_type_p2m_table, 1) ) -+ goto out; -+ - pg = mfn_to_page(shadow_alloc(d, SH_type_p2m_table, 0)); - d->arch.paging.shadow.p2m_pages++; - d->arch.paging.shadow.total_pages--; - ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask)); - -+ out: - paging_unlock(d); - - return pg; -@@ -1336,7 +1356,9 @@ int shadow_set_allocation(struct domain - else if ( d->arch.paging.shadow.total_pages > pages ) - { - /* Need to return memory to domheap */ -- _shadow_prealloc(d, 1); -+ if ( !_shadow_prealloc(d, 1) ) -+ return -ENOMEM; -+ - sp = page_list_remove_head(&d->arch.paging.shadow.freelist); - ASSERT(sp); - /* -@@ -2334,12 +2356,13 @@ static void sh_update_paging_modes(struc - if ( mfn_eq(v->arch.paging.shadow.oos_snapshot[0], INVALID_MFN) ) - { - int i; -+ -+ if ( !shadow_prealloc(d, SH_type_oos_snapshot, SHADOW_OOS_PAGES) ) -+ return; -+ - for(i = 0; i < SHADOW_OOS_PAGES; i++) -- { -- shadow_prealloc(d, SH_type_oos_snapshot, 1); - v->arch.paging.shadow.oos_snapshot[i] = - shadow_alloc(d, SH_type_oos_snapshot, 0); -- } - } - #endif /* OOS */ - -@@ -2403,6 +2426,9 @@ static void sh_update_paging_modes(struc - mfn_t mmfn = sh_make_monitor_table( - v, v->arch.paging.mode->shadow.shadow_levels); - -+ if ( mfn_eq(mmfn, INVALID_MFN) ) -+ return; -+ - v->arch.hvm.monitor_table = pagetable_from_mfn(mmfn); - make_cr3(v, mmfn); - hvm_update_host_cr3(v); -@@ -2441,6 +2467,12 @@ static void sh_update_paging_modes(struc - v->arch.hvm.monitor_table = pagetable_null(); - new_mfn = sh_make_monitor_table( - v, v->arch.paging.mode->shadow.shadow_levels); -+ if ( mfn_eq(new_mfn, INVALID_MFN) ) -+ { -+ sh_destroy_monitor_table(v, old_mfn, -+ old_mode->shadow.shadow_levels); -+ return; -+ } - v->arch.hvm.monitor_table = pagetable_from_mfn(new_mfn); - SHADOW_PRINTK("new monitor table %"PRI_mfn "\n", - mfn_x(new_mfn)); -@@ -2526,7 +2558,12 @@ void sh_set_toplevel_shadow(struct vcpu - if ( !mfn_valid(smfn) ) - { - /* Make sure there's enough free shadow memory. */ -- shadow_prealloc(d, root_type, 1); -+ if ( !shadow_prealloc(d, root_type, 1) ) -+ { -+ new_entry = pagetable_null(); -+ goto install_new_entry; -+ } -+ - /* Shadow the page. */ - smfn = make_shadow(v, gmfn, root_type); - } ---- a/xen/arch/x86/mm/shadow/hvm.c -+++ b/xen/arch/x86/mm/shadow/hvm.c -@@ -700,7 +700,9 @@ mfn_t sh_make_monitor_table(const struct - ASSERT(!pagetable_get_pfn(v->arch.hvm.monitor_table)); - - /* Guarantee we can get the memory we need */ -- shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS); -+ if ( !shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS) ) -+ return INVALID_MFN; -+ - m4mfn = shadow_alloc(d, SH_type_monitor_table, 0); - mfn_to_page(m4mfn)->shadow_flags = 4; - ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -2440,9 +2440,14 @@ static int sh_page_fault(struct vcpu *v, - * Preallocate shadow pages *before* removing writable accesses - * otherwhise an OOS L1 might be demoted and promoted again with - * writable mappings. */ -- shadow_prealloc(d, -- SH_type_l1_shadow, -- GUEST_PAGING_LEVELS < 4 ? 1 : GUEST_PAGING_LEVELS - 1); -+ if ( !shadow_prealloc(d, SH_type_l1_shadow, -+ GUEST_PAGING_LEVELS < 4 -+ ? 1 : GUEST_PAGING_LEVELS - 1) ) -+ { -+ paging_unlock(d); -+ put_gfn(d, gfn_x(gfn)); -+ return 0; -+ } - - rc = gw_remove_write_accesses(v, va, &gw); - ---- a/xen/arch/x86/mm/shadow/private.h -+++ b/xen/arch/x86/mm/shadow/private.h -@@ -383,7 +383,8 @@ void shadow_promote(struct domain *d, mf - void shadow_demote(struct domain *d, mfn_t gmfn, u32 type); - - /* Shadow page allocation functions */ --void shadow_prealloc(struct domain *d, u32 shadow_type, unsigned int count); -+bool __must_check shadow_prealloc(struct domain *d, unsigned int shadow_type, -+ unsigned int count); - mfn_t shadow_alloc(struct domain *d, - u32 shadow_type, - unsigned long backpointer); diff --git a/xsa410-4.16-07.patch b/xsa410-4.16-07.patch deleted file mode 100644 index 9eea91c..0000000 --- a/xsa410-4.16-07.patch +++ /dev/null @@ -1,82 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: refuse new allocations for dying domains - -This will in particular prevent any attempts to add entries to the p2m, -once - in a subsequent change - non-root entries have been removed. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -245,6 +245,9 @@ static struct page_info *hap_alloc(struc - - ASSERT(paging_locked_by_me(d)); - -+ if ( unlikely(d->is_dying) ) -+ return NULL; -+ - pg = page_list_remove_head(&d->arch.paging.hap.freelist); - if ( unlikely(!pg) ) - return NULL; -@@ -281,7 +284,7 @@ static struct page_info *hap_alloc_p2m_p - d->arch.paging.hap.p2m_pages++; - ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask)); - } -- else if ( !d->arch.paging.p2m_alloc_failed ) -+ else if ( !d->arch.paging.p2m_alloc_failed && !d->is_dying ) - { - d->arch.paging.p2m_alloc_failed = 1; - dprintk(XENLOG_ERR, "d%i failed to allocate from HAP pool\n", ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -939,6 +939,10 @@ static bool __must_check _shadow_preallo - if ( d->arch.paging.shadow.free_pages >= pages ) - return true; - -+ if ( unlikely(d->is_dying) ) -+ /* No reclaim when the domain is dying, teardown will take care of it. */ -+ return false; -+ - /* Shouldn't have enabled shadows if we've no vcpus. */ - ASSERT(d->vcpu && d->vcpu[0]); - -@@ -991,7 +995,7 @@ static bool __must_check _shadow_preallo - d->arch.paging.shadow.free_pages, - d->arch.paging.shadow.p2m_pages); - -- ASSERT(d->is_dying); -+ ASSERT_UNREACHABLE(); - - guest_flush_tlb_mask(d, d->dirty_cpumask); - -@@ -1005,10 +1009,13 @@ static bool __must_check _shadow_preallo - * to avoid freeing shadows that the caller is currently working on. */ - bool shadow_prealloc(struct domain *d, unsigned int type, unsigned int count) - { -- bool ret = _shadow_prealloc(d, shadow_size(type) * count); -+ bool ret; -+ -+ if ( unlikely(d->is_dying) ) -+ return false; - -- if ( !ret && !d->is_dying && -- (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) -+ ret = _shadow_prealloc(d, shadow_size(type) * count); -+ if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) - /* - * Failing to allocate memory required for shadow usage can only result in - * a domain crash, do it here rather that relying on every caller to do it. -@@ -1238,6 +1245,9 @@ shadow_alloc_p2m_page(struct domain *d) - { - struct page_info *pg = NULL; - -+ if ( unlikely(d->is_dying) ) -+ return NULL; -+ - /* This is called both from the p2m code (which never holds the - * paging lock) and the log-dirty code (which always does). */ - paging_lock_recursive(d); diff --git a/xsa410-4.16-08.patch b/xsa410-4.16-08.patch deleted file mode 100644 index 92cdb49..0000000 --- a/xsa410-4.16-08.patch +++ /dev/null @@ -1,96 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: truly free paging pool memory for dying domains - -Modify {hap,shadow}_free to free the page immediately if the domain is -dying, so that pages don't accumulate in the pool when -{shadow,hap}_final_teardown() get called. This is to limit the amount of -work which needs to be done there (in a non-preemptable manner). - -Note the call to shadow_free() in shadow_free_p2m_page() is moved after -increasing total_pages, so that the decrease done in shadow_free() in -case the domain is dying doesn't underflow the counter, even if just for -a short interval. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -265,6 +265,18 @@ static void hap_free(struct domain *d, m - - ASSERT(paging_locked_by_me(d)); - -+ /* -+ * For dying domains, actually free the memory here. This way less work is -+ * left to hap_final_teardown(), which cannot easily have preemption checks -+ * added. -+ */ -+ if ( unlikely(d->is_dying) ) -+ { -+ free_domheap_page(pg); -+ d->arch.paging.hap.total_pages--; -+ return; -+ } -+ - d->arch.paging.hap.free_pages++; - page_list_add_tail(pg, &d->arch.paging.hap.freelist); - } ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -1187,6 +1187,7 @@ mfn_t shadow_alloc(struct domain *d, - void shadow_free(struct domain *d, mfn_t smfn) - { - struct page_info *next = NULL, *sp = mfn_to_page(smfn); -+ bool dying = ACCESS_ONCE(d->is_dying); - struct page_list_head *pin_list; - unsigned int pages; - u32 shadow_type; -@@ -1229,11 +1230,32 @@ void shadow_free(struct domain *d, mfn_t - * just before the allocator hands the page out again. */ - page_set_tlbflush_timestamp(sp); - perfc_decr(shadow_alloc_count); -- page_list_add_tail(sp, &d->arch.paging.shadow.freelist); -+ -+ /* -+ * For dying domains, actually free the memory here. This way less -+ * work is left to shadow_final_teardown(), which cannot easily have -+ * preemption checks added. -+ */ -+ if ( unlikely(dying) ) -+ { -+ /* -+ * The backpointer field (sh.back) used by shadow code aliases the -+ * domain owner field, unconditionally clear it here to avoid -+ * free_domheap_page() attempting to parse it. -+ */ -+ page_set_owner(sp, NULL); -+ free_domheap_page(sp); -+ } -+ else -+ page_list_add_tail(sp, &d->arch.paging.shadow.freelist); -+ - sp = next; - } - -- d->arch.paging.shadow.free_pages += pages; -+ if ( unlikely(dying) ) -+ d->arch.paging.shadow.total_pages -= pages; -+ else -+ d->arch.paging.shadow.free_pages += pages; - } - - /* Divert a page from the pool to be used by the p2m mapping. -@@ -1303,9 +1325,9 @@ shadow_free_p2m_page(struct domain *d, s - * paging lock) and the log-dirty code (which always does). */ - paging_lock_recursive(d); - -- shadow_free(d, page_to_mfn(pg)); - d->arch.paging.shadow.p2m_pages--; - d->arch.paging.shadow.total_pages++; -+ shadow_free(d, page_to_mfn(pg)); - - paging_unlock(d); - } diff --git a/xsa410-4.16-09.patch b/xsa410-4.16-09.patch deleted file mode 100644 index 60259e1..0000000 --- a/xsa410-4.16-09.patch +++ /dev/null @@ -1,159 +0,0 @@ -From: Roger Pau Monné -Subject: x86/p2m: free the paging memory pool preemptively - -The paging memory pool is currently freed in two different places: -from {shadow,hap}_teardown() via domain_relinquish_resources() and -from {shadow,hap}_final_teardown() via complete_domain_destroy(). -While the former does handle preemption, the later doesn't. - -Attempt to move as much p2m related freeing as possible to happen -before the call to {shadow,hap}_teardown(), so that most memory can be -freed in a preemptive way. In order to avoid causing issues to -existing callers leave the root p2m page tables set and free them in -{hap,shadow}_final_teardown(). Also modify {hap,shadow}_free to free -the page immediately if the domain is dying, so that pages don't -accumulate in the pool when {shadow,hap}_final_teardown() get called. - -Move altp2m_vcpu_disable_ve() to be done in hap_teardown(), as that's -the place where altp2m_active gets disabled now. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Roger Pau Monné -Signed-off-by: Jan Beulich -Acked-by: Tim Deegan - ---- a/xen/arch/x86/domain.c -+++ b/xen/arch/x86/domain.c -@@ -38,7 +38,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -2381,12 +2380,6 @@ int domain_relinquish_resources(struct d - vpmu_destroy(v); - } - -- if ( altp2m_active(d) ) -- { -- for_each_vcpu ( d, v ) -- altp2m_vcpu_disable_ve(v); -- } -- - if ( is_pv_domain(d) ) - { - for_each_vcpu ( d, v ) ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -546,24 +547,8 @@ void hap_final_teardown(struct domain *d - unsigned int i; - - if ( hvm_altp2m_supported() ) -- { -- d->arch.altp2m_active = 0; -- -- if ( d->arch.altp2m_eptp ) -- { -- free_xenheap_page(d->arch.altp2m_eptp); -- d->arch.altp2m_eptp = NULL; -- } -- -- if ( d->arch.altp2m_visible_eptp ) -- { -- free_xenheap_page(d->arch.altp2m_visible_eptp); -- d->arch.altp2m_visible_eptp = NULL; -- } -- - for ( i = 0; i < MAX_ALTP2M; i++ ) - p2m_teardown(d->arch.altp2m_p2m[i], true); -- } - - /* Destroy nestedp2m's first */ - for (i = 0; i < MAX_NESTEDP2M; i++) { -@@ -578,6 +563,8 @@ void hap_final_teardown(struct domain *d - paging_lock(d); - hap_set_allocation(d, 0, NULL); - ASSERT(d->arch.paging.hap.p2m_pages == 0); -+ ASSERT(d->arch.paging.hap.free_pages == 0); -+ ASSERT(d->arch.paging.hap.total_pages == 0); - paging_unlock(d); - } - -@@ -603,6 +590,7 @@ void hap_vcpu_teardown(struct vcpu *v) - void hap_teardown(struct domain *d, bool *preempted) - { - struct vcpu *v; -+ unsigned int i; - - ASSERT(d->is_dying); - ASSERT(d != current->domain); -@@ -611,6 +599,28 @@ void hap_teardown(struct domain *d, bool - for_each_vcpu ( d, v ) - hap_vcpu_teardown(v); - -+ /* Leave the root pt in case we get further attempts to modify the p2m. */ -+ if ( hvm_altp2m_supported() ) -+ { -+ if ( altp2m_active(d) ) -+ for_each_vcpu ( d, v ) -+ altp2m_vcpu_disable_ve(v); -+ -+ d->arch.altp2m_active = 0; -+ -+ FREE_XENHEAP_PAGE(d->arch.altp2m_eptp); -+ FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); -+ -+ for ( i = 0; i < MAX_ALTP2M; i++ ) -+ p2m_teardown(d->arch.altp2m_p2m[i], false); -+ } -+ -+ /* Destroy nestedp2m's after altp2m. */ -+ for ( i = 0; i < MAX_NESTEDP2M; i++ ) -+ p2m_teardown(d->arch.nested_p2m[i], false); -+ -+ p2m_teardown(p2m_get_hostp2m(d), false); -+ - paging_lock(d); /* Keep various asserts happy */ - - if ( d->arch.paging.hap.total_pages != 0 ) ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2824,8 +2824,17 @@ void shadow_teardown(struct domain *d, b - for_each_vcpu ( d, v ) - shadow_vcpu_teardown(v); - -+ p2m_teardown(p2m_get_hostp2m(d), false); -+ - paging_lock(d); - -+ /* -+ * Reclaim all shadow memory so that shadow_set_allocation() doesn't find -+ * in-use pages, as _shadow_prealloc() will no longer try to reclaim pages -+ * because the domain is dying. -+ */ -+ shadow_blow_tables(d); -+ - #if (SHADOW_OPTIMIZATIONS & (SHOPT_VIRTUAL_TLB|SHOPT_OUT_OF_SYNC)) - /* Free the virtual-TLB array attached to each vcpu */ - for_each_vcpu(d, v) -@@ -2946,6 +2955,9 @@ void shadow_final_teardown(struct domain - d->arch.paging.shadow.total_pages, - d->arch.paging.shadow.free_pages, - d->arch.paging.shadow.p2m_pages); -+ ASSERT(!d->arch.paging.shadow.total_pages); -+ ASSERT(!d->arch.paging.shadow.free_pages); -+ ASSERT(!d->arch.paging.shadow.p2m_pages); - paging_unlock(d); - } - diff --git a/xsa410-4.16-10.patch b/xsa410-4.16-10.patch deleted file mode 100644 index 258b7ff..0000000 --- a/xsa410-4.16-10.patch +++ /dev/null @@ -1,171 +0,0 @@ -From: Julien Grall -Subject: xen/x86: p2m: Add preemption in p2m_teardown() - -The list p2m->pages contain all the pages used by the P2M. On large -instance this can be quite large and the time spent to call -d->arch.paging.free_page() will take more than 1ms for a 80GB guest -on a Xen running in nested environment on a c5.metal. - -By extrapolation, it would take > 100ms for a 8TB guest (what we -current security support). So add some preemption in p2m_teardown() -and propagate to the callers. Note there are 3 places where -the preemption is not enabled: - - hap_final_teardown()/shadow_final_teardown(): We are - preventing update the P2M once the domain is dying (so - no more pages could be allocated) and most of the P2M pages - will be freed in preemptive manneer when relinquishing the - resources. So this is fine to disable preemption. - - shadow_enable(): This is fine because it will undo the allocation - that may have been made by p2m_alloc_table() (so only the root - page table). - -The preemption is arbitrarily checked every 1024 iterations. - -Note that with the current approach, Xen doesn't keep track on whether -the alt/nested P2Ms have been cleared. So there are some redundant work. -However, this is not expected to incurr too much overhead (the P2M lock -shouldn't be contended during teardown). So this is optimization is -left outside of the security event. - -This is part of CVE-2022-33746 / XSA-410. - -Signed-off-by: Julien Grall -Signed-off-by: Jan Beulich - ---- a/xen/include/asm-x86/p2m.h -+++ b/xen/include/asm-x86/p2m.h -@@ -574,7 +574,7 @@ int p2m_init(struct domain *d); - int p2m_alloc_table(struct p2m_domain *p2m); - - /* Return all the p2m resources to Xen. */ --void p2m_teardown(struct p2m_domain *p2m, bool remove_root); -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted); - void p2m_final_teardown(struct domain *d); - - /* Add a page to a domain's p2m table */ ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -548,17 +548,17 @@ void hap_final_teardown(struct domain *d - - if ( hvm_altp2m_supported() ) - for ( i = 0; i < MAX_ALTP2M; i++ ) -- p2m_teardown(d->arch.altp2m_p2m[i], true); -+ p2m_teardown(d->arch.altp2m_p2m[i], true, NULL); - - /* Destroy nestedp2m's first */ - for (i = 0; i < MAX_NESTEDP2M; i++) { -- p2m_teardown(d->arch.nested_p2m[i], true); -+ p2m_teardown(d->arch.nested_p2m[i], true, NULL); - } - - if ( d->arch.paging.hap.total_pages != 0 ) - hap_teardown(d, NULL); - -- p2m_teardown(p2m_get_hostp2m(d), true); -+ p2m_teardown(p2m_get_hostp2m(d), true, NULL); - /* Free any memory that the p2m teardown released */ - paging_lock(d); - hap_set_allocation(d, 0, NULL); -@@ -612,14 +612,24 @@ void hap_teardown(struct domain *d, bool - FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); - - for ( i = 0; i < MAX_ALTP2M; i++ ) -- p2m_teardown(d->arch.altp2m_p2m[i], false); -+ { -+ p2m_teardown(d->arch.altp2m_p2m[i], false, preempted); -+ if ( preempted && *preempted ) -+ return; -+ } - } - - /* Destroy nestedp2m's after altp2m. */ - for ( i = 0; i < MAX_NESTEDP2M; i++ ) -- p2m_teardown(d->arch.nested_p2m[i], false); -+ { -+ p2m_teardown(d->arch.nested_p2m[i], false, preempted); -+ if ( preempted && *preempted ) -+ return; -+ } - -- p2m_teardown(p2m_get_hostp2m(d), false); -+ p2m_teardown(p2m_get_hostp2m(d), false, preempted); -+ if ( preempted && *preempted ) -+ return; - - paging_lock(d); /* Keep various asserts happy */ - ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -749,12 +749,13 @@ int p2m_alloc_table(struct p2m_domain *p - * hvm fixme: when adding support for pvh non-hardware domains, this path must - * cleanup any foreign p2m types (release refcnts on them). - */ --void p2m_teardown(struct p2m_domain *p2m, bool remove_root) -+void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted) - /* Return all the p2m pages to Xen. - * We know we don't have any extra mappings to these pages */ - { - struct page_info *pg, *root_pg = NULL; - struct domain *d; -+ unsigned int i = 0; - - if (p2m == NULL) - return; -@@ -773,8 +774,19 @@ void p2m_teardown(struct p2m_domain *p2m - } - - while ( (pg = page_list_remove_head(&p2m->pages)) ) -- if ( pg != root_pg ) -- d->arch.paging.free_page(d, pg); -+ { -+ if ( pg == root_pg ) -+ continue; -+ -+ d->arch.paging.free_page(d, pg); -+ -+ /* Arbitrarily check preemption every 1024 iterations */ -+ if ( preempted && !(++i % 1024) && general_preempt_check() ) -+ { -+ *preempted = true; -+ break; -+ } -+ } - - if ( root_pg ) - page_list_add(root_pg, &p2m->pages); ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2770,8 +2770,12 @@ int shadow_enable(struct domain *d, u32 - out_locked: - paging_unlock(d); - out_unlocked: -+ /* -+ * This is fine to ignore the preemption here because only the root -+ * will be allocated by p2m_alloc_table(). -+ */ - if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) ) -- p2m_teardown(p2m, true); -+ p2m_teardown(p2m, true, NULL); - if ( rv != 0 && pg != NULL ) - { - pg->count_info &= ~PGC_count_mask; -@@ -2824,7 +2828,9 @@ void shadow_teardown(struct domain *d, b - for_each_vcpu ( d, v ) - shadow_vcpu_teardown(v); - -- p2m_teardown(p2m_get_hostp2m(d), false); -+ p2m_teardown(p2m_get_hostp2m(d), false, preempted); -+ if ( preempted && *preempted ) -+ return; - - paging_lock(d); - -@@ -2945,7 +2951,7 @@ void shadow_final_teardown(struct domain - shadow_teardown(d, NULL); - - /* It is now safe to pull down the p2m map. */ -- p2m_teardown(p2m_get_hostp2m(d), true); -+ p2m_teardown(p2m_get_hostp2m(d), true, NULL); - /* Free any shadow memory that the p2m teardown released */ - paging_lock(d); - shadow_set_allocation(d, 0, NULL); diff --git a/xsa411.patch b/xsa411.patch deleted file mode 100644 index 50dcae4..0000000 --- a/xsa411.patch +++ /dev/null @@ -1,55 +0,0 @@ -From: Jan Beulich -Subject: gnttab: correct locking on transitive grant copy error path - -While the comment next to the lock dropping in preparation of -recursively calling acquire_grant_for_copy() mistakenly talks about the -rd == td case (excluded a few lines further up), the same concerns apply -to the calling of release_grant_for_copy() on a subsequent error path. - -This is CVE-2022-33748 / XSA-411. - -Fixes: ad48fb963dbf ("gnttab: fix transitive grant handling") -Signed-off-by: Jan Beulich ---- -v2: Extend code comment. - ---- a/xen/common/grant_table.c -+++ b/xen/common/grant_table.c -@@ -2622,9 +2622,8 @@ acquire_grant_for_copy( - trans_domid); - - /* -- * acquire_grant_for_copy() could take the lock on the -- * remote table (if rd == td), so we have to drop the lock -- * here and reacquire. -+ * acquire_grant_for_copy() will take the lock on the remote table, -+ * so we have to drop the lock here and reacquire. - */ - active_entry_release(act); - grant_read_unlock(rgt); -@@ -2661,11 +2660,25 @@ acquire_grant_for_copy( - act->trans_gref != trans_gref || - !act->is_sub_page)) ) - { -+ /* -+ * Like above for acquire_grant_for_copy() we need to drop and then -+ * re-acquire the locks here to prevent lock order inversion issues. -+ * Unlike for acquire_grant_for_copy() we don't need to re-check -+ * anything, as release_grant_for_copy() doesn't depend on the grant -+ * table entry: It only updates internal state and the status flags. -+ */ -+ active_entry_release(act); -+ grant_read_unlock(rgt); -+ - release_grant_for_copy(td, trans_gref, readonly); - rcu_unlock_domain(td); -+ -+ grant_read_lock(rgt); -+ act = active_entry_acquire(rgt, gref); - reduce_status_for_pin(rd, act, status, readonly); - active_entry_release(act); - grant_read_unlock(rgt); -+ - put_page(*page); - *page = NULL; - return ERESTART; diff --git a/xsa412-4.16.patch b/xsa412-4.16.patch deleted file mode 100644 index f37fc21..0000000 --- a/xsa412-4.16.patch +++ /dev/null @@ -1,245 +0,0 @@ -From: Andrew Cooper -Subject: x86/vmx: Revert "VMX: use a single, global APIC access page" - -The claim "No accesses would ever go to this page." is false. A consequence -of how Intel's APIC Acceleration works, and Xen's choice to have per-domain -P2Ms (rather than per-vCPU P2Ms) means that the APIC page is fully read-write -to any vCPU which is not in xAPIC mode. - -This reverts commit 58850b9074d3e7affdf3bc94c84e417ecfa4d165. - -This is XSA-412 / CVE-2022-42327. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c -index d429d76c18c9..3f4276531322 100644 ---- a/xen/arch/x86/hvm/vmx/vmx.c -+++ b/xen/arch/x86/hvm/vmx/vmx.c -@@ -66,7 +66,8 @@ boolean_param("force-ept", opt_force_ept); - static void vmx_ctxt_switch_from(struct vcpu *v); - static void vmx_ctxt_switch_to(struct vcpu *v); - --static int alloc_vlapic_mapping(void); -+static int vmx_alloc_vlapic_mapping(struct domain *d); -+static void vmx_free_vlapic_mapping(struct domain *d); - static void vmx_install_vlapic_mapping(struct vcpu *v); - static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr, - unsigned int flags); -@@ -77,8 +78,6 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content); - static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content); - static void vmx_invlpg(struct vcpu *v, unsigned long linear); - --static mfn_t __read_mostly apic_access_mfn = INVALID_MFN_INITIALIZER; -- - /* Values for domain's ->arch.hvm_domain.pi_ops.flags. */ - #define PI_CSW_FROM (1u << 0) - #define PI_CSW_TO (1u << 1) -@@ -402,6 +401,7 @@ static int vmx_domain_initialise(struct domain *d) - .to = vmx_ctxt_switch_to, - .tail = vmx_do_resume, - }; -+ int rc; - - d->arch.ctxt_switch = &csw; - -@@ -411,15 +411,24 @@ static int vmx_domain_initialise(struct domain *d) - */ - d->arch.hvm.vmx.exec_sp = is_hardware_domain(d) || opt_ept_exec_sp; - -+ if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 ) -+ return rc; -+ - return 0; - } - -+static void vmx_domain_relinquish_resources(struct domain *d) -+{ -+ vmx_free_vlapic_mapping(d); -+} -+ - static void domain_creation_finished(struct domain *d) - { - gfn_t gfn = gaddr_to_gfn(APIC_DEFAULT_PHYS_BASE); -+ mfn_t apic_access_mfn = d->arch.hvm.vmx.apic_access_mfn; - bool ipat; - -- if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) ) -+ if ( mfn_eq(apic_access_mfn, _mfn(0)) ) - return; - - ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat, -@@ -2481,6 +2490,7 @@ static struct hvm_function_table __initdata vmx_function_table = { - .cpu_up_prepare = vmx_cpu_up_prepare, - .cpu_dead = vmx_cpu_dead, - .domain_initialise = vmx_domain_initialise, -+ .domain_relinquish_resources = vmx_domain_relinquish_resources, - .domain_creation_finished = domain_creation_finished, - .vcpu_initialise = vmx_vcpu_initialise, - .vcpu_destroy = vmx_vcpu_destroy, -@@ -2731,7 +2741,7 @@ const struct hvm_function_table * __init start_vmx(void) - { - set_in_cr4(X86_CR4_VMXE); - -- if ( vmx_vmcs_init() || alloc_vlapic_mapping() ) -+ if ( vmx_vmcs_init() ) - { - printk("VMX: failed to initialise.\n"); - return NULL; -@@ -3305,36 +3315,55 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content) - return X86EMUL_EXCEPTION; - } - --static int __init alloc_vlapic_mapping(void) -+static int vmx_alloc_vlapic_mapping(struct domain *d) - { - struct page_info *pg; - mfn_t mfn; - -- if ( !cpu_has_vmx_virtualize_apic_accesses ) -+ if ( !has_vlapic(d) || !cpu_has_vmx_virtualize_apic_accesses ) - return 0; - -- pg = alloc_domheap_page(NULL, 0); -+ pg = alloc_domheap_page(d, MEMF_no_refcount); - if ( !pg ) - return -ENOMEM; - -- /* -- * Signal to shadow code that this page cannot be refcounted. This also -- * makes epte_get_entry_emt() recognize this page as "special". -- */ -- page_suppress_refcounting(pg); -+ if ( !get_page_and_type(pg, d, PGT_writable_page) ) -+ { -+ /* -+ * The domain can't possibly know about this page yet, so failure -+ * here is a clear indication of something fishy going on. -+ */ -+ domain_crash(d); -+ return -ENODATA; -+ } - - mfn = page_to_mfn(pg); - clear_domain_page(mfn); -- apic_access_mfn = mfn; -+ d->arch.hvm.vmx.apic_access_mfn = mfn; - - return 0; - } - -+static void vmx_free_vlapic_mapping(struct domain *d) -+{ -+ mfn_t mfn = d->arch.hvm.vmx.apic_access_mfn; -+ -+ d->arch.hvm.vmx.apic_access_mfn = _mfn(0); -+ if ( !mfn_eq(mfn, _mfn(0)) ) -+ { -+ struct page_info *pg = mfn_to_page(mfn); -+ -+ put_page_alloc_ref(pg); -+ put_page_and_type(pg); -+ } -+} -+ - static void vmx_install_vlapic_mapping(struct vcpu *v) - { -+ mfn_t apic_access_mfn = v->domain->arch.hvm.vmx.apic_access_mfn; - paddr_t virt_page_ma, apic_page_ma; - -- if ( !has_vlapic(v->domain) || mfn_eq(apic_access_mfn, INVALID_MFN) ) -+ if ( mfn_eq(apic_access_mfn, _mfn(0)) ) - return; - - ASSERT(cpu_has_vmx_virtualize_apic_accesses); -diff --git a/xen/arch/x86/mm/shadow/set.c b/xen/arch/x86/mm/shadow/set.c -index 87e9c6eeb219..bd6c68b547c9 100644 ---- a/xen/arch/x86/mm/shadow/set.c -+++ b/xen/arch/x86/mm/shadow/set.c -@@ -101,14 +101,6 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type) - owner = page_get_owner(pg); - } - -- /* -- * Check whether refcounting is suppressed on this page. For example, -- * VMX'es APIC access MFN is just a surrogate page. It doesn't actually -- * get accessed, and hence there's no need to refcount it. -- */ -- if ( pg && page_refcounting_suppressed(pg) ) -- return 0; -- - if ( owner == dom_io ) - owner = NULL; - -diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h -index 6970e7d6ea4a..814a4018535a 100644 ---- a/xen/arch/x86/mm/shadow/types.h -+++ b/xen/arch/x86/mm/shadow/types.h -@@ -276,16 +276,9 @@ int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e, - static void inline - shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d) - { -- mfn_t mfn = shadow_l1e_get_mfn(sl1e); -- - if ( !shadow_mode_refcounts(d) ) - return; - -- if ( mfn_valid(mfn) && -- /* See the respective comment in shadow_get_page_from_l1e(). */ -- page_refcounting_suppressed(mfn_to_page(mfn)) ) -- return; -- - put_page_from_l1e(sl1e, d); - } - -diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h -index 03c9ccf627ab..8073af323b96 100644 ---- a/xen/include/asm-x86/hvm/vmx/vmcs.h -+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h -@@ -58,6 +58,7 @@ struct ept_data { - #define _VMX_DOMAIN_PML_ENABLED 0 - #define VMX_DOMAIN_PML_ENABLED (1ul << _VMX_DOMAIN_PML_ENABLED) - struct vmx_domain { -+ mfn_t apic_access_mfn; - /* VMX_DOMAIN_* */ - unsigned int status; - -diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h -index 7bdf9c2290d8..e1bcea57a8f5 100644 ---- a/xen/include/asm-x86/mm.h -+++ b/xen/include/asm-x86/mm.h -@@ -83,7 +83,7 @@ - #define PGC_state_offlined PG_mask(2, 6) - #define PGC_state_free PG_mask(3, 6) - #define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st) --/* Page is not reference counted (see below for caveats) */ -+/* Page is not reference counted */ - #define _PGC_extra PG_shift(7) - #define PGC_extra PG_mask(1, 7) - -@@ -375,24 +375,6 @@ void zap_ro_mpt(mfn_t mfn); - - bool is_iomem_page(mfn_t mfn); - --/* -- * Pages with no owner which may get passed to functions wanting to -- * refcount them can be marked PGC_extra to bypass this refcounting (which -- * would fail due to the lack of an owner). -- * -- * (For pages with owner PGC_extra has different meaning.) -- */ --static inline void page_suppress_refcounting(struct page_info *pg) --{ -- ASSERT(!page_get_owner(pg)); -- pg->count_info |= PGC_extra; --} -- --static inline bool page_refcounting_suppressed(const struct page_info *pg) --{ -- return !page_get_owner(pg) && (pg->count_info & PGC_extra); --} -- - struct platform_bad_page { - unsigned long mfn; - unsigned int order; diff --git a/xsa414.patch b/xsa414.patch deleted file mode 100644 index 27ab0c2..0000000 --- a/xsa414.patch +++ /dev/null @@ -1,112 +0,0 @@ -From: Julien Grall -Subject: tools/xenstore: create_node: Don't defer work to undo any changes on - failure - -XSA-115 extended destroy_node() to update the node accounting for the -connection. The implementation is assuming the connection is the parent -of the node, however all the nodes are allocated using a separate context -(see process_message()). This will result to crash (or corrupt) xenstored -as the pointer is wrongly used. - -In case of an error, any changes to the database or update to the -accounting will now be reverted in create_node() by calling directly -destroy_node(). This has the nice advantage to remove the loop to unset -the destructors in case of success. - -Take the opportunity to free the nodes right now as they are not -going to be reachable (the function returns NULL) and are just wasting -resources. - -This is XSA-414 / CVE-2022-42309. - -Reported-by: Julien Grall -Fixes: 0bfb2101f243 ("tools/xenstore: fix node accounting after failed node creation") -Signed-off-by: Julien Grall -Reviewed-by: Juergen Gross - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 8867f93431d4..c30d14cbf2ab 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1084,9 +1084,8 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - return NULL; - } - --static int destroy_node(void *_node) -+static int destroy_node(struct connection *conn, struct node *node) - { -- struct node *node = _node; - TDB_DATA key; - - if (streq(node->name, "/")) -@@ -1095,7 +1094,7 @@ static int destroy_node(void *_node) - set_tdb_key(node->name, &key); - tdb_delete(tdb_ctx, key); - -- domain_entry_dec(talloc_parent(node), node); -+ domain_entry_dec(conn, node); - - return 0; - } -@@ -1104,7 +1103,8 @@ static struct node *create_node(struct connection *conn, const void *ctx, - const char *name, - void *data, unsigned int datalen) - { -- struct node *node, *i; -+ struct node *node, *i, *j; -+ int ret; - - node = construct_node(conn, ctx, name); - if (!node) -@@ -1126,23 +1126,40 @@ static struct node *create_node(struct connection *conn, const void *ctx, - /* i->parent is set for each new node, so check quota. */ - if (i->parent && - domain_entry(conn) >= quota_nb_entry_per_domain) { -- errno = ENOSPC; -- return NULL; -+ ret = ENOSPC; -+ goto err; - } -- if (write_node(conn, i, false)) -- return NULL; - -- /* Account for new node, set destructor for error case. */ -- if (i->parent) { -+ ret = write_node(conn, i, false); -+ if (ret) -+ goto err; -+ -+ /* Account for new node */ -+ if (i->parent) - domain_entry_inc(conn, i); -- talloc_set_destructor(i, destroy_node); -- } - } - -- /* OK, now remove destructors so they stay around */ -- for (i = node; i->parent; i = i->parent) -- talloc_set_destructor(i, NULL); - return node; -+ -+err: -+ /* -+ * We failed to update TDB for some of the nodes. Undo any work that -+ * have already been done. -+ */ -+ for (j = node; j != i; j = j->parent) -+ destroy_node(conn, j); -+ -+ /* We don't need to keep the nodes around, so free them. */ -+ i = node; -+ while (i) { -+ j = i; -+ i = i->parent; -+ talloc_free(j); -+ } -+ -+ errno = ret; -+ -+ return NULL; - } - - /* path, data... */ diff --git a/xsa415.patch b/xsa415.patch deleted file mode 100644 index b6f6971..0000000 --- a/xsa415.patch +++ /dev/null @@ -1,134 +0,0 @@ -From: Julien Grall -Subject: tools/xenstore: Fail a transaction if it is not possible to create a - node - -Commit f2bebf72c4d5 "xenstore: rework of transaction handling" moved -out from copying the entire database everytime a new transaction is -opened to track the list of nodes changed. - -The content of all the nodes accessed during a transaction will be -temporarily stored in TDB using a different key. - -The function create_node() may write/update multiple nodes if the child -doesn't exist. In case of a failure, the function will revert any -changes (this include any update to TDB). Unfortunately, the function -which reverts the changes (i.e. destroy_node()) will not use the correct -key to delete any update or even request the transaction to fail. - -This means that if a client decide to go ahead with committing the -transaction, orphan nodes will be created because they were not linked -to an existing node (create_node() will write the nodes backwards). - -Once some nodes have been partially updated in a transaction, it is not -easily possible to undo any changes. So rather than continuing and hit -weird issue while committing, it is much saner to fail the transaction. - -This will have an impact on any client that decides to commit even if it -can't write a node. Although, it is not clear why a normal client would -want to do that... - -Lastly, update destroy_node() to use the correct key for deleting the -node. Rather than recreating it (this will allocate memory and -therefore fail), stash the key in the structure node. - -This is XSA-415 / CVE-2022-42310. - -Reported-by: Julien Grall -Signed-off-by: Julien Grall -Reviewed-by: Juergen Gross - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index c30d14cbf2ab..55b79e4c032e 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -562,15 +562,17 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - return 0; - } - -+/* -+ * Write the node. If the node is written, caller can find the key used in -+ * node->key. This can later be used if the change needs to be reverted. -+ */ - static int write_node(struct connection *conn, struct node *node, - bool no_quota_check) - { -- TDB_DATA key; -- -- if (access_node(conn, node, NODE_ACCESS_WRITE, &key)) -+ if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key)) - return errno; - -- return write_node_raw(conn, &key, node, no_quota_check); -+ return write_node_raw(conn, &node->key, node, no_quota_check); - } - - unsigned int perm_for_conn(struct connection *conn, -@@ -1086,16 +1088,21 @@ static struct node *construct_node(struct connection *conn, const void *ctx, - - static int destroy_node(struct connection *conn, struct node *node) - { -- TDB_DATA key; -- - if (streq(node->name, "/")) - corrupt(NULL, "Destroying root node!"); - -- set_tdb_key(node->name, &key); -- tdb_delete(tdb_ctx, key); -+ tdb_delete(tdb_ctx, node->key); - - domain_entry_dec(conn, node); - -+ /* -+ * It is not possible to easily revert the changes in a transaction. -+ * So if the failure happens in a transaction, mark it as fail to -+ * prevent any commit. -+ */ -+ if ( conn->transaction ) -+ fail_transaction(conn->transaction); -+ - return 0; - } - -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index 742812a97469..7d0fe77e7989 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -155,6 +155,8 @@ struct node_perms { - - struct node { - const char *name; -+ /* Key used to update TDB */ -+ TDB_DATA key; - - /* Parent (optional) */ - struct node *parent; -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index cd07fb0f218b..faf6c930e42a 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -580,6 +580,11 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid) - list_add_tail(&d->list, &trans->changed_domains); - } - -+void fail_transaction(struct transaction *trans) -+{ -+ trans->fail = true; -+} -+ - void conn_delete_all_transactions(struct connection *conn) - { - struct transaction *trans; -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 43a162bea3f3..14062730e3c9 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -46,6 +46,9 @@ int access_node(struct connection *conn, struct node *node, - int transaction_prepend(struct connection *conn, const char *name, - TDB_DATA *key); - -+/* Mark the transaction as failed. This will prevent it to be committed. */ -+void fail_transaction(struct transaction *trans); -+ - void conn_delete_all_transactions(struct connection *conn); - int check_transactions(struct hashtable *hash); - diff --git a/xsa416-4.16.patch b/xsa416-4.16.patch deleted file mode 100644 index 0df409a..0000000 --- a/xsa416-4.16.patch +++ /dev/null @@ -1,704 +0,0 @@ -From 80d128b14482d2e9342184d2d9949367851c4d14 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: don't use conn->in as context for temporary - allocations - -Using the struct buffered data pointer of the current processed request -for temporary data allocations has a major drawback: the used area (and -with that the temporary data) is freed only after the response of the -request has been written to the ring page or has been read via the -socket. This can happen much later in case a guest isn't reading its -responses fast enough. - -As the temporary data can be safely freed after creating the response, -add a temporary context for that purpose and use that for allocating -the temporary memory, as it was already the case before commit -cc0612464896 ("xenstore: add small default data buffer to internal -struct"). - -Some sub-functions need to gain the "const" attribute for the talloc -context. - -This is XSA-416 / CVE-2022-42319. - -Reported-by: Julien Grall -Fixes: cc0612464896 ("xenstore: add small default data buffer to internal struct") -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c -index 1031a81c3874..d0350c6ad861 100644 ---- a/tools/xenstore/xenstored_control.c -+++ b/tools/xenstore/xenstored_control.c -@@ -155,7 +155,7 @@ bool lu_is_pending(void) - - struct cmd_s { - char *cmd; -- int (*func)(void *, struct connection *, char **, int); -+ int (*func)(const void *, struct connection *, char **, int); - char *pars; - /* - * max_pars can be used to limit the size of the parameter vector, -@@ -167,7 +167,7 @@ struct cmd_s { - unsigned int max_pars; - }; - --static int do_control_check(void *ctx, struct connection *conn, -+static int do_control_check(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num) -@@ -179,7 +179,7 @@ static int do_control_check(void *ctx, struct connection *conn, - return 0; - } - --static int do_control_log(void *ctx, struct connection *conn, -+static int do_control_log(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num != 1) -@@ -281,7 +281,7 @@ static int quota_get(const void *ctx, struct connection *conn, - return domain_get_quota(ctx, conn, atoi(vec[0])); - } - --static int do_control_quota(void *ctx, struct connection *conn, -+static int do_control_quota(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num == 0) -@@ -293,7 +293,7 @@ static int do_control_quota(void *ctx, struct connection *conn, - return quota_get(ctx, conn, vec, num); - } - --static int do_control_quota_s(void *ctx, struct connection *conn, -+static int do_control_quota_s(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num == 0) -@@ -306,7 +306,7 @@ static int do_control_quota_s(void *ctx, struct connection *conn, - } - - #ifdef __MINIOS__ --static int do_control_memreport(void *ctx, struct connection *conn, -+static int do_control_memreport(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num) -@@ -318,7 +318,7 @@ static int do_control_memreport(void *ctx, struct connection *conn, - return 0; - } - #else --static int do_control_logfile(void *ctx, struct connection *conn, -+static int do_control_logfile(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num != 1) -@@ -333,7 +333,7 @@ static int do_control_logfile(void *ctx, struct connection *conn, - return 0; - } - --static int do_control_memreport(void *ctx, struct connection *conn, -+static int do_control_memreport(const void *ctx, struct connection *conn, - char **vec, int num) - { - FILE *fp; -@@ -373,7 +373,7 @@ static int do_control_memreport(void *ctx, struct connection *conn, - } - #endif - --static int do_control_print(void *ctx, struct connection *conn, -+static int do_control_print(const void *ctx, struct connection *conn, - char **vec, int num) - { - if (num != 1) -@@ -875,7 +875,7 @@ static const char *lu_start(const void *ctx, struct connection *conn, - return NULL; - } - --static int do_control_lu(void *ctx, struct connection *conn, -+static int do_control_lu(const void *ctx, struct connection *conn, - char **vec, int num) - { - const char *ret = NULL; -@@ -922,7 +922,7 @@ static int do_control_lu(void *ctx, struct connection *conn, - } - #endif - --static int do_control_help(void *, struct connection *, char **, int); -+static int do_control_help(const void *, struct connection *, char **, int); - - static struct cmd_s cmds[] = { - { "check", do_control_check, "" }, -@@ -961,7 +961,7 @@ static struct cmd_s cmds[] = { - { "help", do_control_help, "" }, - }; - --static int do_control_help(void *ctx, struct connection *conn, -+static int do_control_help(const void *ctx, struct connection *conn, - char **vec, int num) - { - int cmd, len = 0; -@@ -997,7 +997,8 @@ static int do_control_help(void *ctx, struct connection *conn, - return 0; - } - --int do_control(struct connection *conn, struct buffered_data *in) -+int do_control(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - unsigned int cmd, num, off; - char **vec = NULL; -@@ -1017,11 +1018,11 @@ int do_control(struct connection *conn, struct buffered_data *in) - num = xs_count_strings(in->buffer, in->used); - if (cmds[cmd].max_pars) - num = min(num, cmds[cmd].max_pars); -- vec = talloc_array(in, char *, num); -+ vec = talloc_array(ctx, char *, num); - if (!vec) - return ENOMEM; - if (get_strings(in, vec, num) < num) - return EIO; - -- return cmds[cmd].func(in, conn, vec + 1, num - 1); -+ return cmds[cmd].func(ctx, conn, vec + 1, num - 1); - } -diff --git a/tools/xenstore/xenstored_control.h b/tools/xenstore/xenstored_control.h -index 98b6fbcea2b1..a8cb76559ba1 100644 ---- a/tools/xenstore/xenstored_control.h -+++ b/tools/xenstore/xenstored_control.h -@@ -16,7 +16,8 @@ - along with this program; If not, see . - */ - --int do_control(struct connection *conn, struct buffered_data *in); -+int do_control(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - void lu_read_state(void); - - struct connection *lu_get_connection(void); -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 16504de42017..411cc0e44714 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1248,11 +1248,13 @@ static struct node *get_node_canonicalized(struct connection *conn, - return get_node(conn, ctx, *canonical_name, perm); - } - --static int send_directory(struct connection *conn, struct buffered_data *in) -+static int send_directory(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - -- node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, onearg(in), NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1261,7 +1263,7 @@ static int send_directory(struct connection *conn, struct buffered_data *in) - return 0; - } - --static int send_directory_part(struct connection *conn, -+static int send_directory_part(const void *ctx, struct connection *conn, - struct buffered_data *in) - { - unsigned int off, len, maxlen, genlen; -@@ -1273,7 +1275,8 @@ static int send_directory_part(struct connection *conn, - return EINVAL; - - /* First arg is node name. */ -- node = get_node_canonicalized(conn, in, in->buffer, NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, in->buffer, NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1300,7 +1303,7 @@ static int send_directory_part(struct connection *conn, - break; - } - -- data = talloc_array(in, char, genlen + len + 1); -+ data = talloc_array(ctx, char, genlen + len + 1); - if (!data) - return ENOMEM; - -@@ -1316,11 +1319,13 @@ static int send_directory_part(struct connection *conn, - return 0; - } - --static int do_read(struct connection *conn, struct buffered_data *in) -+static int do_read(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - -- node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, onearg(in), NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1510,7 +1515,8 @@ static struct node *create_node(struct connection *conn, const void *ctx, - } - - /* path, data... */ --static int do_write(struct connection *conn, struct buffered_data *in) -+static int do_write(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - unsigned int offset, datalen; - struct node *node; -@@ -1524,12 +1530,12 @@ static int do_write(struct connection *conn, struct buffered_data *in) - offset = strlen(vec[0]) + 1; - datalen = in->used - offset; - -- node = get_node_canonicalized(conn, in, vec[0], &name, XS_PERM_WRITE); -+ node = get_node_canonicalized(conn, ctx, vec[0], &name, XS_PERM_WRITE); - if (!node) { - /* No permissions, invalid input? */ - if (errno != ENOENT) - return errno; -- node = create_node(conn, in, name, in->buffer + offset, -+ node = create_node(conn, ctx, name, in->buffer + offset, - datalen); - if (!node) - return errno; -@@ -1540,18 +1546,19 @@ static int do_write(struct connection *conn, struct buffered_data *in) - return errno; - } - -- fire_watches(conn, in, name, node, false, NULL); -+ fire_watches(conn, ctx, name, node, false, NULL); - send_ack(conn, XS_WRITE); - - return 0; - } - --static int do_mkdir(struct connection *conn, struct buffered_data *in) -+static int do_mkdir(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - char *name; - -- node = get_node_canonicalized(conn, in, onearg(in), &name, -+ node = get_node_canonicalized(conn, ctx, onearg(in), &name, - XS_PERM_WRITE); - - /* If it already exists, fine. */ -@@ -1561,10 +1568,10 @@ static int do_mkdir(struct connection *conn, struct buffered_data *in) - return errno; - if (!name) - return ENOMEM; -- node = create_node(conn, in, name, NULL, 0); -+ node = create_node(conn, ctx, name, NULL, 0); - if (!node) - return errno; -- fire_watches(conn, in, name, node, false, NULL); -+ fire_watches(conn, ctx, name, node, false, NULL); - } - send_ack(conn, XS_MKDIR); - -@@ -1662,24 +1669,25 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - } - - --static int do_rm(struct connection *conn, struct buffered_data *in) -+static int do_rm(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - int ret; - char *name; - char *parentname; - -- node = get_node_canonicalized(conn, in, onearg(in), &name, -+ node = get_node_canonicalized(conn, ctx, onearg(in), &name, - XS_PERM_WRITE); - if (!node) { - /* Didn't exist already? Fine, if parent exists. */ - if (errno == ENOENT) { - if (!name) - return ENOMEM; -- parentname = get_parent(in, name); -+ parentname = get_parent(ctx, name); - if (!parentname) - return errno; -- node = read_node(conn, in, parentname); -+ node = read_node(conn, ctx, parentname); - if (node) { - send_ack(conn, XS_RM); - return 0; -@@ -1694,7 +1702,7 @@ static int do_rm(struct connection *conn, struct buffered_data *in) - if (streq(name, "/")) - return EINVAL; - -- ret = _rm(conn, in, node, name); -+ ret = _rm(conn, ctx, node, name); - if (ret) - return ret; - -@@ -1704,13 +1712,15 @@ static int do_rm(struct connection *conn, struct buffered_data *in) - } - - --static int do_get_perms(struct connection *conn, struct buffered_data *in) -+static int do_get_perms(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node *node; - char *strings; - unsigned int len; - -- node = get_node_canonicalized(conn, in, onearg(in), NULL, XS_PERM_READ); -+ node = get_node_canonicalized(conn, ctx, onearg(in), NULL, -+ XS_PERM_READ); - if (!node) - return errno; - -@@ -1723,7 +1733,8 @@ static int do_get_perms(struct connection *conn, struct buffered_data *in) - return 0; - } - --static int do_set_perms(struct connection *conn, struct buffered_data *in) -+static int do_set_perms(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct node_perms perms, old_perms; - char *name, *permstr; -@@ -1740,7 +1751,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - - permstr = in->buffer + strlen(in->buffer) + 1; - -- perms.p = talloc_array(in, struct xs_permissions, perms.num); -+ perms.p = talloc_array(ctx, struct xs_permissions, perms.num); - if (!perms.p) - return ENOMEM; - if (!xs_strings_to_perms(perms.p, perms.num, permstr)) -@@ -1755,7 +1766,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - } - - /* We must own node to do this (tools can do this too). */ -- node = get_node_canonicalized(conn, in, in->buffer, &name, -+ node = get_node_canonicalized(conn, ctx, in->buffer, &name, - XS_PERM_WRITE | XS_PERM_OWNER); - if (!node) - return errno; -@@ -1790,7 +1801,7 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - return errno; - } - -- fire_watches(conn, in, name, node, false, &old_perms); -+ fire_watches(conn, ctx, name, node, false, &old_perms); - send_ack(conn, XS_SET_PERMS); - - return 0; -@@ -1798,7 +1809,8 @@ static int do_set_perms(struct connection *conn, struct buffered_data *in) - - static struct { - const char *str; -- int (*func)(struct connection *conn, struct buffered_data *in); -+ int (*func)(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - unsigned int flags; - #define XS_FLAG_NOTID (1U << 0) /* Ignore transaction id. */ - #define XS_FLAG_PRIV (1U << 1) /* Privileged domain only. */ -@@ -1874,6 +1886,7 @@ static void process_message(struct connection *conn, struct buffered_data *in) - struct transaction *trans; - enum xsd_sockmsg_type type = in->hdr.msg.type; - int ret; -+ void *ctx; - - /* At least send_error() and send_reply() expects conn->in == in */ - assert(conn->in == in); -@@ -1898,10 +1911,17 @@ static void process_message(struct connection *conn, struct buffered_data *in) - return; - } - -+ ctx = talloc_new(NULL); -+ if (!ctx) { -+ send_error(conn, ENOMEM); -+ return; -+ } -+ - assert(conn->transaction == NULL); - conn->transaction = trans; - -- ret = wire_funcs[type].func(conn, in); -+ ret = wire_funcs[type].func(ctx, conn, in); -+ talloc_free(ctx); - if (ret) - send_error(conn, ret); - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index e7c6886ccf47..fb732d0a14c3 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -330,7 +330,7 @@ bool domain_is_unprivileged(struct connection *conn) - domid_is_unprivileged(conn->domain->domid); - } - --static char *talloc_domain_path(void *context, unsigned int domid) -+static char *talloc_domain_path(const void *context, unsigned int domid) - { - return talloc_asprintf(context, "/local/domain/%u", domid); - } -@@ -534,7 +534,8 @@ static struct domain *introduce_domain(const void *ctx, - } - - /* domid, gfn, evtchn, path */ --int do_introduce(struct connection *conn, struct buffered_data *in) -+int do_introduce(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct domain *domain; - char *vec[3]; -@@ -552,7 +553,7 @@ int do_introduce(struct connection *conn, struct buffered_data *in) - if (port <= 0) - return EINVAL; - -- domain = introduce_domain(in, domid, port, false); -+ domain = introduce_domain(ctx, domid, port, false); - if (!domain) - return errno; - -@@ -575,7 +576,8 @@ static struct domain *find_connected_domain(unsigned int domid) - return domain; - } - --int do_set_target(struct connection *conn, struct buffered_data *in) -+int do_set_target(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - char *vec[2]; - unsigned int domid, tdomid; -@@ -619,7 +621,8 @@ static struct domain *onearg_domain(struct connection *conn, - } - - /* domid */ --int do_release(struct connection *conn, struct buffered_data *in) -+int do_release(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct domain *domain; - -@@ -634,7 +637,8 @@ int do_release(struct connection *conn, struct buffered_data *in) - return 0; - } - --int do_resume(struct connection *conn, struct buffered_data *in) -+int do_resume(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct domain *domain; - -@@ -649,7 +653,8 @@ int do_resume(struct connection *conn, struct buffered_data *in) - return 0; - } - --int do_get_domain_path(struct connection *conn, struct buffered_data *in) -+int do_get_domain_path(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - char *path; - const char *domid_str = onearg(in); -@@ -657,18 +662,17 @@ int do_get_domain_path(struct connection *conn, struct buffered_data *in) - if (!domid_str) - return EINVAL; - -- path = talloc_domain_path(conn, atoi(domid_str)); -+ path = talloc_domain_path(ctx, atoi(domid_str)); - if (!path) - return errno; - - send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1); - -- talloc_free(path); -- - return 0; - } - --int do_is_domain_introduced(struct connection *conn, struct buffered_data *in) -+int do_is_domain_introduced(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - int result; - unsigned int domid; -@@ -689,7 +693,8 @@ int do_is_domain_introduced(struct connection *conn, struct buffered_data *in) - } - - /* Allow guest to reset all watches */ --int do_reset_watches(struct connection *conn, struct buffered_data *in) -+int do_reset_watches(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - conn_delete_all_watches(conn); - conn_delete_all_transactions(conn); -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 904faa923afb..b9e152890149 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -24,25 +24,32 @@ void handle_event(void); - void check_domains(void); - - /* domid, mfn, eventchn, path */ --int do_introduce(struct connection *conn, struct buffered_data *in); -+int do_introduce(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_is_domain_introduced(struct connection *conn, struct buffered_data *in); -+int do_is_domain_introduced(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_release(struct connection *conn, struct buffered_data *in); -+int do_release(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_resume(struct connection *conn, struct buffered_data *in); -+int do_resume(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid, target */ --int do_set_target(struct connection *conn, struct buffered_data *in); -+int do_set_target(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* domid */ --int do_get_domain_path(struct connection *conn, struct buffered_data *in); -+int do_get_domain_path(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* Allow guest to reset all watches */ --int do_reset_watches(struct connection *conn, struct buffered_data *in); -+int do_reset_watches(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - void domain_init(int evtfd); - void dom0_init(void); -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 28774813de83..3e3eb47326cc 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -481,7 +481,8 @@ struct transaction *transaction_lookup(struct connection *conn, uint32_t id) - return ERR_PTR(-ENOENT); - } - --int do_transaction_start(struct connection *conn, struct buffered_data *in) -+int do_transaction_start(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct transaction *trans, *exists; - char id_str[20]; -@@ -494,8 +495,8 @@ int do_transaction_start(struct connection *conn, struct buffered_data *in) - conn->transaction_started > quota_max_transaction) - return ENOSPC; - -- /* Attach transaction to input for autofree until it's complete */ -- trans = talloc_zero(in, struct transaction); -+ /* Attach transaction to ctx for autofree until it's complete */ -+ trans = talloc_zero(ctx, struct transaction); - if (!trans) - return ENOMEM; - -@@ -544,7 +545,8 @@ static int transaction_fix_domains(struct transaction *trans, bool update) - return 0; - } - --int do_transaction_end(struct connection *conn, struct buffered_data *in) -+int do_transaction_end(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - const char *arg = onearg(in); - struct transaction *trans; -@@ -562,8 +564,8 @@ int do_transaction_end(struct connection *conn, struct buffered_data *in) - if (!conn->transaction_started) - conn->ta_start_time = 0; - -- /* Attach transaction to in for auto-cleanup */ -- talloc_steal(in, trans); -+ /* Attach transaction to ctx for auto-cleanup */ -+ talloc_steal(ctx, trans); - - if (streq(arg, "T")) { - if (trans->fail) -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index e3cbd6b23095..39d7f81c5127 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -29,8 +29,10 @@ struct transaction; - - extern uint64_t generation; - --int do_transaction_start(struct connection *conn, struct buffered_data *node); --int do_transaction_end(struct connection *conn, struct buffered_data *in); -+int do_transaction_start(const void *ctx, struct connection *conn, -+ struct buffered_data *node); -+int do_transaction_end(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - struct transaction *transaction_lookup(struct connection *conn, uint32_t id); - -diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c -index 85362bcce314..316c08b7f754 100644 ---- a/tools/xenstore/xenstored_watch.c -+++ b/tools/xenstore/xenstored_watch.c -@@ -243,7 +243,7 @@ static struct watch *add_watch(struct connection *conn, char *path, char *token, - return NULL; - } - --int do_watch(struct connection *conn, struct buffered_data *in) -+int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in) - { - struct watch *watch; - char *vec[2]; -@@ -252,7 +252,7 @@ int do_watch(struct connection *conn, struct buffered_data *in) - if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) - return EINVAL; - -- errno = check_watch_path(conn, in, &(vec[0]), &relative); -+ errno = check_watch_path(conn, ctx, &(vec[0]), &relative); - if (errno) - return errno; - -@@ -283,7 +283,8 @@ int do_watch(struct connection *conn, struct buffered_data *in) - return 0; - } - --int do_unwatch(struct connection *conn, struct buffered_data *in) -+int do_unwatch(const void *ctx, struct connection *conn, -+ struct buffered_data *in) - { - struct watch *watch; - char *node, *vec[2]; -@@ -291,7 +292,7 @@ int do_unwatch(struct connection *conn, struct buffered_data *in) - if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) - return EINVAL; - -- node = xenstore_canonicalize(conn, in, vec[0]); -+ node = xenstore_canonicalize(conn, ctx, vec[0]); - if (!node) - return ENOMEM; - list_for_each_entry(watch, &conn->watches, list) { -diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h -index 0e693f0839cd..091890edca96 100644 ---- a/tools/xenstore/xenstored_watch.h -+++ b/tools/xenstore/xenstored_watch.h -@@ -21,8 +21,10 @@ - - #include "xenstored_core.h" - --int do_watch(struct connection *conn, struct buffered_data *in); --int do_unwatch(struct connection *conn, struct buffered_data *in); -+int do_watch(const void *ctx, struct connection *conn, -+ struct buffered_data *in); -+int do_unwatch(const void *ctx, struct connection *conn, -+ struct buffered_data *in); - - /* Fire all watches: !exact means all the children are affected (ie. rm). */ - void fire_watches(struct connection *conn, const void *tmp, const char *name, diff --git a/xsa417.patch b/xsa417.patch deleted file mode 100644 index 3f10bf7..0000000 --- a/xsa417.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 67d5ecd609b8f12346eadb40e547cd7e01d825dc Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:10 +0200 -Subject: tools/xenstore: fix checking node permissions - -Today chk_domain_generation() is being used to check whether a node -permission entry is still valid or whether it is referring to a domain -no longer existing. This is done by comparing the node's and the -domain's generation count. - -In case no struct domain is existing for a checked domain, but the -domain itself is valid, chk_domain_generation() assumes it is being -called due to the first node created for a new domain and it will -return success. - -This might be wrong in case the checked permission is related to an -old domain, which has just been replaced with a new domain using the -same domid. - -Fix that by letting chk_domain_generation() fail in case a struct -domain isn't found. In order to cover the case of the first node for -a new domain try to allocate the needed struct domain explicitly when -processing the related SET_PERMS command. In case a referenced domain -isn't existing, flag the related permission to be ignored right away. - -This is XSA-417 / CVE-2022-42320. - -Reported-by: Juergen Gross -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 66bbeaf6bfb0..a0c176fa203e 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1753,6 +1753,11 @@ static int do_set_perms(const void *ctx, struct connection *conn, - if (!xs_strings_to_perms(perms.p, perms.num, permstr)) - return errno; - -+ if (domain_alloc_permrefs(&perms) < 0) -+ return ENOMEM; -+ if (perms.p[0].perms & XS_PERM_IGNORE) -+ return ENOENT; -+ - /* First arg is node name. */ - if (strstarts(in->buffer, "@")) { - if (set_perms_special(conn, in->buffer, &perms)) -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index b9ff4ded8360..98b401fdec30 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -907,7 +907,6 @@ int domain_entry_inc(struct connection *conn, struct node *node) - * count (used for testing whether a node permission is older than a domain). - * - * Return values: -- * -1: error - * 0: domain has higher generation count (it is younger than a node with the - * given count), or domain isn't existing any longer - * 1: domain is older than the node -@@ -915,20 +914,38 @@ int domain_entry_inc(struct connection *conn, struct node *node) - static int chk_domain_generation(unsigned int domid, uint64_t gen) - { - struct domain *d; -- xc_dominfo_t dominfo; - - if (!xc_handle && domid == 0) - return 1; - - d = find_domain_struct(domid); -- if (d) -- return (d->generation <= gen) ? 1 : 0; - -- if (!get_domain_info(domid, &dominfo)) -- return 0; -+ return (d && d->generation <= gen) ? 1 : 0; -+} - -- d = alloc_domain(NULL, domid); -- return d ? 1 : -1; -+/* -+ * Allocate all missing struct domain referenced by a permission set. -+ * Any permission entries for not existing domains will be marked to be -+ * ignored. -+ */ -+int domain_alloc_permrefs(struct node_perms *perms) -+{ -+ unsigned int i, domid; -+ struct domain *d; -+ xc_dominfo_t dominfo; -+ -+ for (i = 0; i < perms->num; i++) { -+ domid = perms->p[i].id; -+ d = find_domain_struct(domid); -+ if (!d) { -+ if (!get_domain_info(domid, &dominfo)) -+ perms->p[i].perms |= XS_PERM_IGNORE; -+ else if (!alloc_domain(NULL, domid)) -+ return ENOMEM; -+ } -+ } -+ -+ return 0; - } - - /* -@@ -941,8 +958,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node) - int ret; - - ret = chk_domain_generation(node->perms.p[0].id, node->generation); -- if (ret < 0) -- return errno; - - /* If the owner doesn't exist any longer give it to priv domain. */ - if (!ret) { -@@ -959,8 +974,6 @@ int domain_adjust_node_perms(struct connection *conn, struct node *node) - continue; - ret = chk_domain_generation(node->perms.p[i].id, - node->generation); -- if (ret < 0) -- return errno; - if (!ret) - node->perms.p[i].perms |= XS_PERM_IGNORE; - } -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 209442190911..7fe0a21d9e45 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -63,6 +63,7 @@ bool domain_is_unprivileged(struct connection *conn); - - /* Remove node permissions for no longer existing domains. */ - int domain_adjust_node_perms(struct connection *conn, struct node *node); -+int domain_alloc_permrefs(struct node_perms *perms); - - /* Quota manipulation */ - int domain_entry_inc(struct connection *conn, struct node *); diff --git a/xsa418-4.16-01.patch b/xsa418-4.16-01.patch deleted file mode 100644 index c4a17b4..0000000 --- a/xsa418-4.16-01.patch +++ /dev/null @@ -1,119 +0,0 @@ -From d1e6dca486599ab914af7b38b3782b237d3d603b Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:11 +0200 -Subject: tools/xenstore: remove recursion from construct_node() - -In order to reduce stack usage due to recursion, switch -construct_node() to use a loop instead. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index c676ee4e4e4f..3907c35643e9 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1377,45 +1377,69 @@ static int add_child(const void *ctx, struct node *parent, const char *name) - static struct node *construct_node(struct connection *conn, const void *ctx, - const char *name) - { -- struct node *parent, *node; -- char *parentname = get_parent(ctx, name); -+ const char **names = NULL; -+ unsigned int levels = 0; -+ struct node *node = NULL; -+ struct node *parent = NULL; -+ const char *parentname = talloc_strdup(ctx, name); - - if (!parentname) - return NULL; - -- /* If parent doesn't exist, create it. */ -- parent = read_node(conn, parentname, parentname); -- if (!parent && errno == ENOENT) -- parent = construct_node(conn, ctx, parentname); -- if (!parent) -- return NULL; -+ /* Walk the path up until an existing node is found. */ -+ while (!parent) { -+ names = talloc_realloc(ctx, names, const char *, levels + 1); -+ if (!names) -+ goto nomem; - -- /* Add child to parent. */ -- if (add_child(ctx, parent, name)) -- goto nomem; -+ /* -+ * names[0] is the name of the node to construct initially, -+ * names[1] is its parent, and so on. -+ */ -+ names[levels] = parentname; -+ parentname = get_parent(ctx, parentname); -+ if (!parentname) -+ return NULL; - -- /* Allocate node */ -- node = talloc(ctx, struct node); -- if (!node) -- goto nomem; -- node->name = talloc_strdup(node, name); -- if (!node->name) -- goto nomem; -+ /* Try to read parent node until we found an existing one. */ -+ parent = read_node(conn, ctx, parentname); -+ if (!parent && (errno != ENOENT || !strcmp(parentname, "/"))) -+ return NULL; - -- /* Inherit permissions, except unprivileged domains own what they create */ -- node->perms.num = parent->perms.num; -- node->perms.p = talloc_memdup(node, parent->perms.p, -- node->perms.num * sizeof(*node->perms.p)); -- if (!node->perms.p) -- goto nomem; -- if (domain_is_unprivileged(conn)) -- node->perms.p[0].id = conn->id; -+ levels++; -+ } -+ -+ /* Walk the path down again constructing the missing nodes. */ -+ for (; levels > 0; levels--) { -+ /* Add child to parent. */ -+ if (add_child(ctx, parent, names[levels - 1])) -+ goto nomem; -+ -+ /* Allocate node */ -+ node = talloc(ctx, struct node); -+ if (!node) -+ goto nomem; -+ node->name = talloc_steal(node, names[levels - 1]); -+ -+ /* Inherit permissions, unpriv domains own what they create. */ -+ node->perms.num = parent->perms.num; -+ node->perms.p = talloc_memdup(node, parent->perms.p, -+ node->perms.num * -+ sizeof(*node->perms.p)); -+ if (!node->perms.p) -+ goto nomem; -+ if (domain_is_unprivileged(conn)) -+ node->perms.p[0].id = conn->id; -+ -+ /* No children, no data */ -+ node->children = node->data = NULL; -+ node->childlen = node->datalen = 0; -+ node->acc.memory = 0; -+ node->parent = parent; -+ -+ parent = node; -+ } - -- /* No children, no data */ -- node->children = node->data = NULL; -- node->childlen = node->datalen = 0; -- node->acc.memory = 0; -- node->parent = parent; - return node; - - nomem: diff --git a/xsa418-4.16-02.patch b/xsa418-4.16-02.patch deleted file mode 100644 index 874bab2..0000000 --- a/xsa418-4.16-02.patch +++ /dev/null @@ -1,103 +0,0 @@ -From c13d85a2fe94bbf3cb8186b89324c5d1b4f9a61f Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:11 +0200 -Subject: tools/xenstore: don't let remove_child_entry() call corrupt() - -In case of write_node() returning an error, remove_child_entry() will -call corrupt() today. This could result in an endless recursion, as -remove_child_entry() is called by corrupt(), too: - -corrupt() - check_store() - check_store_() - remove_child_entry() - -Fix that by letting remove_child_entry() return an error instead and -let the caller decide what to do. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 3907c35643e9..f433a45dc217 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1608,15 +1608,15 @@ static void memdel(void *mem, unsigned off, unsigned len, unsigned total) - memmove(mem + off, mem + off + len, total - off - len); - } - --static void remove_child_entry(struct connection *conn, struct node *node, -- size_t offset) -+static int remove_child_entry(struct connection *conn, struct node *node, -+ size_t offset) - { - size_t childlen = strlen(node->children + offset); - - memdel(node->children, offset, childlen + 1, node->childlen); - node->childlen -= childlen + 1; -- if (write_node(conn, node, true)) -- corrupt(conn, "Can't update parent node '%s'", node->name); -+ -+ return write_node(conn, node, true); - } - - static void delete_child(struct connection *conn, -@@ -1626,7 +1626,9 @@ static void delete_child(struct connection *conn, - - for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) { - if (streq(node->children+i, childname)) { -- remove_child_entry(conn, node, i); -+ if (remove_child_entry(conn, node, i)) -+ corrupt(conn, "Can't update parent node '%s'", -+ node->name); - return; - } - } -@@ -2325,6 +2327,17 @@ int remember_string(struct hashtable *hash, const char *str) - return hashtable_insert(hash, k, (void *)1); - } - -+static int rm_child_entry(struct node *node, size_t off, size_t len) -+{ -+ if (!recovery) -+ return off; -+ -+ if (remove_child_entry(NULL, node, off)) -+ log("check_store: child entry could not be removed from '%s'", -+ node->name); -+ -+ return off - len - 1; -+} - - /** - * A node has a children field that names the children of the node, separated -@@ -2377,12 +2390,7 @@ static int check_store_(const char *name, struct hashtable *reachable) - if (hashtable_search(children, childname)) { - log("check_store: '%s' is duplicated!", - childname); -- -- if (recovery) { -- remove_child_entry(NULL, node, -- i); -- i -= childlen + 1; -- } -+ i = rm_child_entry(node, i, childlen); - } - else { - if (!remember_string(children, -@@ -2399,11 +2407,7 @@ static int check_store_(const char *name, struct hashtable *reachable) - } else if (errno != ENOMEM) { - log("check_store: No child '%s' found!\n", - childname); -- -- if (recovery) { -- remove_child_entry(NULL, node, i); -- i -= childlen + 1; -- } -+ i = rm_child_entry(node, i, childlen); - } else { - log("check_store: ENOMEM"); - ret = ENOMEM; diff --git a/xsa418-4.16-03.patch b/xsa418-4.16-03.patch deleted file mode 100644 index 321ccf0..0000000 --- a/xsa418-4.16-03.patch +++ /dev/null @@ -1,243 +0,0 @@ -From aac9b51b6fbbbd16c910f69365345528c5bec106 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:11 +0200 -Subject: tools/xenstore: add generic treewalk function - -Add a generic function to walk the complete node tree. It will start -at "/" and descend recursively into each child, calling a function -specified by the caller. Depending on the return value of the user -specified function the walk will be aborted, continued, or the current -child will be skipped by not descending into its children. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index f433a45dc217..2cda3ee375ab 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1838,6 +1838,135 @@ static int do_set_perms(const void *ctx, struct connection *conn, - return 0; - } - -+static char *child_name(const void *ctx, const char *s1, const char *s2) -+{ -+ if (strcmp(s1, "/")) -+ return talloc_asprintf(ctx, "%s/%s", s1, s2); -+ return talloc_asprintf(ctx, "/%s", s2); -+} -+ -+static int rm_from_parent(struct connection *conn, struct node *parent, -+ const char *name) -+{ -+ size_t off; -+ -+ if (!parent) -+ return WALK_TREE_ERROR_STOP; -+ -+ for (off = parent->childoff - 1; off && parent->children[off - 1]; -+ off--); -+ if (remove_child_entry(conn, parent, off)) { -+ log("treewalk: child entry could not be removed from '%s'", -+ parent->name); -+ return WALK_TREE_ERROR_STOP; -+ } -+ parent->childoff = off; -+ -+ return WALK_TREE_OK; -+} -+ -+static int walk_call_func(const void *ctx, struct connection *conn, -+ struct node *node, struct node *parent, void *arg, -+ int (*func)(const void *ctx, struct connection *conn, -+ struct node *node, void *arg)) -+{ -+ int ret; -+ -+ if (!func) -+ return WALK_TREE_OK; -+ -+ ret = func(ctx, conn, node, arg); -+ if (ret == WALK_TREE_RM_CHILDENTRY && parent) -+ ret = rm_from_parent(conn, parent, node->name); -+ -+ return ret; -+} -+ -+int walk_node_tree(const void *ctx, struct connection *conn, const char *root, -+ struct walk_funcs *funcs, void *arg) -+{ -+ int ret = 0; -+ void *tmpctx; -+ char *name; -+ struct node *node = NULL; -+ struct node *parent = NULL; -+ -+ tmpctx = talloc_new(ctx); -+ if (!tmpctx) { -+ errno = ENOMEM; -+ return WALK_TREE_ERROR_STOP; -+ } -+ name = talloc_strdup(tmpctx, root); -+ if (!name) { -+ errno = ENOMEM; -+ talloc_free(tmpctx); -+ return WALK_TREE_ERROR_STOP; -+ } -+ -+ /* Continue the walk until an error is returned. */ -+ while (ret >= 0) { -+ /* node == NULL possible only for the initial loop iteration. */ -+ if (node) { -+ /* Go one step up if ret or if last child finished. */ -+ if (ret || node->childoff >= node->childlen) { -+ parent = node->parent; -+ /* Call function AFTER processing a node. */ -+ ret = walk_call_func(ctx, conn, node, parent, -+ arg, funcs->exit); -+ /* Last node, so exit loop. */ -+ if (!parent) -+ break; -+ talloc_free(node); -+ /* Continue with parent. */ -+ node = parent; -+ continue; -+ } -+ /* Get next child of current node. */ -+ name = child_name(tmpctx, node->name, -+ node->children + node->childoff); -+ if (!name) { -+ ret = WALK_TREE_ERROR_STOP; -+ break; -+ } -+ /* Point to next child. */ -+ node->childoff += strlen(node->children + -+ node->childoff) + 1; -+ /* Descent into children. */ -+ parent = node; -+ } -+ /* Read next node (root node or next child). */ -+ node = read_node(conn, tmpctx, name); -+ if (!node) { -+ /* Child not found - should not happen! */ -+ /* ENOENT case can be handled by supplied function. */ -+ if (errno == ENOENT && funcs->enoent) -+ ret = funcs->enoent(ctx, conn, parent, name, -+ arg); -+ else -+ ret = WALK_TREE_ERROR_STOP; -+ if (!parent) -+ break; -+ if (ret == WALK_TREE_RM_CHILDENTRY) -+ ret = rm_from_parent(conn, parent, name); -+ if (ret < 0) -+ break; -+ talloc_free(name); -+ node = parent; -+ continue; -+ } -+ talloc_free(name); -+ node->parent = parent; -+ node->childoff = 0; -+ /* Call function BEFORE processing a node. */ -+ ret = walk_call_func(ctx, conn, node, parent, arg, -+ funcs->enter); -+ } -+ -+ talloc_free(tmpctx); -+ -+ return ret < 0 ? ret : WALK_TREE_OK; -+} -+ - static struct { - const char *str; - int (*func)(const void *ctx, struct connection *conn, -@@ -2305,18 +2434,6 @@ static int keys_equal_fn(void *key1, void *key2) - return 0 == strcmp((char *)key1, (char *)key2); - } - -- --static char *child_name(const char *s1, const char *s2) --{ -- if (strcmp(s1, "/")) { -- return talloc_asprintf(NULL, "%s/%s", s1, s2); -- } -- else { -- return talloc_asprintf(NULL, "/%s", s2); -- } --} -- -- - int remember_string(struct hashtable *hash, const char *str) - { - char *k = malloc(strlen(str) + 1); -@@ -2376,7 +2493,7 @@ static int check_store_(const char *name, struct hashtable *reachable) - while (i < node->childlen && !ret) { - struct node *childnode; - size_t childlen = strlen(node->children + i); -- char * childname = child_name(node->name, -+ char * childname = child_name(NULL, node->name, - node->children + i); - - if (!childname) { -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index bfd3fc1e9df3..2d9942171d92 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -202,6 +202,7 @@ struct node { - - /* Children, each nul-terminated. */ - unsigned int childlen; -+ unsigned int childoff; /* Used by walk_node_tree() internally. */ - char *children; - - /* Allocation information for node currently in store. */ -@@ -338,6 +339,45 @@ void read_state_buffered_data(const void *ctx, struct connection *conn, - const struct xs_state_connection *sc); - void read_state_node(const void *ctx, const void *state); - -+/* -+ * Walk the node tree below root calling funcs->enter() and funcs->exit() for -+ * each node. funcs->enter() is being called when entering a node, so before -+ * any of the children of the node is processed. funcs->exit() is being -+ * called when leaving the node, so after all children have been processed. -+ * funcs->enoent() is being called when a node isn't existing. -+ * funcs->*() return values: -+ * < 0: tree walk is stopped, walk_node_tree() returns funcs->*() return value -+ * in case WALK_TREE_ERROR_STOP is returned, errno should be set -+ * WALK_TREE_OK: tree walk is continuing -+ * WALK_TREE_SKIP_CHILDREN: tree walk won't descend below current node, but -+ * walk continues -+ * WALK_TREE_RM_CHILDENTRY: Remove the child entry from its parent and write -+ * the modified parent node back to the data base, implies to not descend -+ * below the current node, but to continue the walk -+ * funcs->*() is allowed to modify the node it is called for in the data base. -+ * In case funcs->enter() is deleting the node, it must not return WALK_TREE_OK -+ * in order to avoid descending into no longer existing children. -+ */ -+/* Return values for funcs->*() and walk_node_tree(). */ -+#define WALK_TREE_SUCCESS_STOP -100 /* Stop walk early, no error. */ -+#define WALK_TREE_ERROR_STOP -1 /* Stop walk due to error. */ -+#define WALK_TREE_OK 0 /* No error. */ -+/* Return value for funcs->*() only. */ -+#define WALK_TREE_SKIP_CHILDREN 1 /* Don't recurse below current node. */ -+#define WALK_TREE_RM_CHILDENTRY 2 /* Remove child entry from parent. */ -+ -+struct walk_funcs { -+ int (*enter)(const void *ctx, struct connection *conn, -+ struct node *node, void *arg); -+ int (*exit)(const void *ctx, struct connection *conn, -+ struct node *node, void *arg); -+ int (*enoent)(const void *ctx, struct connection *conn, -+ struct node *parent, char *name, void *arg); -+}; -+ -+int walk_node_tree(const void *ctx, struct connection *conn, const char *root, -+ struct walk_funcs *funcs, void *arg); -+ - #endif /* _XENSTORED_CORE_H */ - - /* diff --git a/xsa418-4.16-04.patch b/xsa418-4.16-04.patch deleted file mode 100644 index 95de88f..0000000 --- a/xsa418-4.16-04.patch +++ /dev/null @@ -1,108 +0,0 @@ -From bdc931fb5dcebbd8d0e44b5d8bd3fb9106ee8596 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: simplify check_store() - -check_store() is using a hash table for storing all node names it has -found via walking the tree. Additionally it using another hash table -for all children of a node to detect duplicate child names. - -Simplify that by dropping the second hash table as the first one is -already holding all the needed information. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 2cda3ee375ab..760f3c16c794 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2477,50 +2477,34 @@ static int check_store_(const char *name, struct hashtable *reachable) - if (node) { - size_t i = 0; - -- struct hashtable * children = -- create_hashtable(16, hash_from_key_fn, keys_equal_fn); -- if (!children) { -- log("check_store create table: ENOMEM"); -- return ENOMEM; -- } -- - if (!remember_string(reachable, name)) { -- hashtable_destroy(children, 0); - log("check_store: ENOMEM"); - return ENOMEM; - } - - while (i < node->childlen && !ret) { -- struct node *childnode; -+ struct node *childnode = NULL; - size_t childlen = strlen(node->children + i); -- char * childname = child_name(NULL, node->name, -- node->children + i); -+ char *childname = child_name(NULL, node->name, -+ node->children + i); - - if (!childname) { - log("check_store: ENOMEM"); - ret = ENOMEM; - break; - } -+ -+ if (hashtable_search(reachable, childname)) { -+ log("check_store: '%s' is duplicated!", -+ childname); -+ i = rm_child_entry(node, i, childlen); -+ goto next; -+ } -+ - childnode = read_node(NULL, childname, childname); -- -+ - if (childnode) { -- if (hashtable_search(children, childname)) { -- log("check_store: '%s' is duplicated!", -- childname); -- i = rm_child_entry(node, i, childlen); -- } -- else { -- if (!remember_string(children, -- childname)) { -- log("check_store: ENOMEM"); -- talloc_free(childnode); -- talloc_free(childname); -- ret = ENOMEM; -- break; -- } -- ret = check_store_(childname, -- reachable); -- } -+ ret = check_store_(childname, reachable); - } else if (errno != ENOMEM) { - log("check_store: No child '%s' found!\n", - childname); -@@ -2530,19 +2514,18 @@ static int check_store_(const char *name, struct hashtable *reachable) - ret = ENOMEM; - } - -+ next: - talloc_free(childnode); - talloc_free(childname); - i += childlen + 1; - } - -- hashtable_destroy(children, 0 /* Don't free values (they are -- all (void *)1) */); - talloc_free(node); - } else if (errno != ENOMEM) { - /* Impossible, because no database should ever be without the - root, and otherwise, we've just checked in our caller - (which made a recursive call to get here). */ -- -+ - log("check_store: No child '%s' found: impossible!", name); - } else { - log("check_store: ENOMEM"); diff --git a/xsa418-4.16-05.patch b/xsa418-4.16-05.patch deleted file mode 100644 index fca551e..0000000 --- a/xsa418-4.16-05.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 27817f0a7d6802be04e8f43a0900b02f881b28b2 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: use treewalk for check_store() - -Instead of doing an open tree walk using call recursion, use -walk_node_tree() when checking the store for inconsistencies. - -This will reduce code size and avoid many nesting levels of function -calls which could potentially exhaust the stack. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 760f3c16c794..efdd1888fd78 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2444,18 +2444,6 @@ int remember_string(struct hashtable *hash, const char *str) - return hashtable_insert(hash, k, (void *)1); - } - --static int rm_child_entry(struct node *node, size_t off, size_t len) --{ -- if (!recovery) -- return off; -- -- if (remove_child_entry(NULL, node, off)) -- log("check_store: child entry could not be removed from '%s'", -- node->name); -- -- return off - len - 1; --} -- - /** - * A node has a children field that names the children of the node, separated - * by NULs. We check whether there are entries in there that are duplicated -@@ -2469,70 +2457,29 @@ static int rm_child_entry(struct node *node, size_t off, size_t len) - * As we go, we record each node in the given reachable hashtable. These - * entries will be used later in clean_store. - */ --static int check_store_(const char *name, struct hashtable *reachable) -+static int check_store_step(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) - { -- struct node *node = read_node(NULL, name, name); -- int ret = 0; -- -- if (node) { -- size_t i = 0; -- -- if (!remember_string(reachable, name)) { -- log("check_store: ENOMEM"); -- return ENOMEM; -- } -- -- while (i < node->childlen && !ret) { -- struct node *childnode = NULL; -- size_t childlen = strlen(node->children + i); -- char *childname = child_name(NULL, node->name, -- node->children + i); -- -- if (!childname) { -- log("check_store: ENOMEM"); -- ret = ENOMEM; -- break; -- } -+ struct hashtable *reachable = arg; - -- if (hashtable_search(reachable, childname)) { -- log("check_store: '%s' is duplicated!", -- childname); -- i = rm_child_entry(node, i, childlen); -- goto next; -- } -- -- childnode = read_node(NULL, childname, childname); -- -- if (childnode) { -- ret = check_store_(childname, reachable); -- } else if (errno != ENOMEM) { -- log("check_store: No child '%s' found!\n", -- childname); -- i = rm_child_entry(node, i, childlen); -- } else { -- log("check_store: ENOMEM"); -- ret = ENOMEM; -- } -+ if (hashtable_search(reachable, (void *)node->name)) { -+ log("check_store: '%s' is duplicated!", node->name); -+ return recovery ? WALK_TREE_RM_CHILDENTRY -+ : WALK_TREE_SKIP_CHILDREN; -+ } - -- next: -- talloc_free(childnode); -- talloc_free(childname); -- i += childlen + 1; -- } -+ if (!remember_string(reachable, node->name)) -+ return WALK_TREE_ERROR_STOP; - -- talloc_free(node); -- } else if (errno != ENOMEM) { -- /* Impossible, because no database should ever be without the -- root, and otherwise, we've just checked in our caller -- (which made a recursive call to get here). */ -+ return WALK_TREE_OK; -+} - -- log("check_store: No child '%s' found: impossible!", name); -- } else { -- log("check_store: ENOMEM"); -- ret = ENOMEM; -- } -+static int check_store_enoent(const void *ctx, struct connection *conn, -+ struct node *parent, char *name, void *arg) -+{ -+ log("check_store: node '%s' not found", name); - -- return ret; -+ return recovery ? WALK_TREE_RM_CHILDENTRY : WALK_TREE_OK; - } - - -@@ -2581,24 +2528,28 @@ static void clean_store(struct hashtable *reachable) - - void check_store(void) - { -- char * root = talloc_strdup(NULL, "/"); -- struct hashtable * reachable = -- create_hashtable(16, hash_from_key_fn, keys_equal_fn); -- -+ struct hashtable *reachable; -+ struct walk_funcs walkfuncs = { -+ .enter = check_store_step, -+ .enoent = check_store_enoent, -+ }; -+ -+ reachable = create_hashtable(16, hash_from_key_fn, keys_equal_fn); - if (!reachable) { - log("check_store: ENOMEM"); - return; - } - - log("Checking store ..."); -- if (!check_store_(root, reachable) && -- !check_transactions(reachable)) -+ if (walk_node_tree(NULL, NULL, "/", &walkfuncs, reachable)) { -+ if (errno == ENOMEM) -+ log("check_store: ENOMEM"); -+ } else if (!check_transactions(reachable)) - clean_store(reachable); - log("Checking store complete."); - - hashtable_destroy(reachable, 0 /* Don't free values (they are all - (void *)1) */); -- talloc_free(root); - } - - diff --git a/xsa418-4.16-06.patch b/xsa418-4.16-06.patch deleted file mode 100644 index d46c057..0000000 --- a/xsa418-4.16-06.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 6ea0ffbd88b11f23779d763501ec1370b590bb2a Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: use treewalk for deleting nodes - -Instead of doing an open tree walk using call recursion, use -walk_node_tree() when deleting a sub-tree of nodes. - -This will reduce code size and avoid many nesting levels of function -calls which could potentially exhaust the stack. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Acked-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index efdd1888fd78..58fb651542ec 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -1334,21 +1334,6 @@ static int do_read(const void *ctx, struct connection *conn, - return 0; - } - --static void delete_node_single(struct connection *conn, struct node *node) --{ -- TDB_DATA key; -- -- if (access_node(conn, node, NODE_ACCESS_DELETE, &key)) -- return; -- -- if (do_tdb_delete(conn, &key, &node->acc) != 0) { -- corrupt(conn, "Could not delete '%s'", node->name); -- return; -- } -- -- domain_entry_dec(conn, node); --} -- - /* Must not be / */ - static char *basename(const char *name) - { -@@ -1619,69 +1604,59 @@ static int remove_child_entry(struct connection *conn, struct node *node, - return write_node(conn, node, true); - } - --static void delete_child(struct connection *conn, -- struct node *node, const char *childname) -+static int delete_child(struct connection *conn, -+ struct node *node, const char *childname) - { - unsigned int i; - - for (i = 0; i < node->childlen; i += strlen(node->children+i) + 1) { - if (streq(node->children+i, childname)) { -- if (remove_child_entry(conn, node, i)) -- corrupt(conn, "Can't update parent node '%s'", -- node->name); -- return; -+ errno = remove_child_entry(conn, node, i) ? EIO : 0; -+ return errno; - } - } - corrupt(conn, "Can't find child '%s' in %s", childname, node->name); -+ -+ errno = EIO; -+ return errno; - } - --static int delete_node(struct connection *conn, const void *ctx, -- struct node *parent, struct node *node, bool watch_exact) -+static int delnode_sub(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) - { -- char *name; -+ const char *root = arg; -+ bool watch_exact; -+ int ret; -+ TDB_DATA key; - -- /* Delete children. */ -- while (node->childlen) { -- struct node *child; -+ /* Any error here will probably be repeated for all following calls. */ -+ ret = access_node(conn, node, NODE_ACCESS_DELETE, &key); -+ if (ret > 0) -+ return WALK_TREE_SUCCESS_STOP; - -- name = talloc_asprintf(node, "%s/%s", node->name, -- node->children); -- child = name ? read_node(conn, node, name) : NULL; -- if (child) { -- if (delete_node(conn, ctx, node, child, true)) -- return errno; -- } else { -- trace("delete_node: Error deleting child '%s/%s'!\n", -- node->name, node->children); -- /* Quit deleting. */ -- errno = ENOMEM; -- return errno; -- } -- talloc_free(name); -- } -+ /* In case of error stop the walk. */ -+ if (!ret && do_tdb_delete(conn, &key, &node->acc)) -+ return WALK_TREE_SUCCESS_STOP; - - /* - * Fire the watches now, when we can still see the node permissions. - * This fine as we are single threaded and the next possible read will - * be handled only after the node has been really removed. -- */ -+ */ -+ watch_exact = strcmp(root, node->name); - fire_watches(conn, ctx, node->name, node, watch_exact, NULL); -- delete_node_single(conn, node); -- delete_child(conn, parent, basename(node->name)); -- talloc_free(node); - -- return 0; -+ domain_entry_dec(conn, node); -+ -+ return WALK_TREE_RM_CHILDENTRY; - } - --static int _rm(struct connection *conn, const void *ctx, struct node *node, -- const char *name) -+static int _rm(struct connection *conn, const void *ctx, const char *name) - { -- /* -- * Deleting node by node, so the result is always consistent even in -- * case of a failure. -- */ - struct node *parent; - char *parentname = get_parent(ctx, name); -+ struct walk_funcs walkfuncs = { .exit = delnode_sub }; -+ int ret; - - if (!parentname) - return errno; -@@ -1689,9 +1664,21 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, - parent = read_node(conn, ctx, parentname); - if (!parent) - return read_node_can_propagate_errno() ? errno : EINVAL; -- node->parent = parent; - -- return delete_node(conn, ctx, parent, node, false); -+ ret = walk_node_tree(ctx, conn, name, &walkfuncs, (void *)name); -+ if (ret < 0) { -+ if (ret == WALK_TREE_ERROR_STOP) { -+ corrupt(conn, "error when deleting sub-nodes of %s\n", -+ name); -+ errno = EIO; -+ } -+ return errno; -+ } -+ -+ if (delete_child(conn, parent, basename(name))) -+ return errno; -+ -+ return 0; - } - - -@@ -1728,7 +1715,7 @@ static int do_rm(const void *ctx, struct connection *conn, - if (streq(name, "/")) - return EINVAL; - -- ret = _rm(conn, ctx, node, name); -+ ret = _rm(conn, ctx, name); - if (ret) - return ret; - diff --git a/xsa418-4.16-07.patch b/xsa418-4.16-07.patch deleted file mode 100644 index 9600d8c..0000000 --- a/xsa418-4.16-07.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 1ee281b18b52bec87335ea64ee74cc159e63d036 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: use treewalk for creating node records - -Instead of doing an open tree walk using call recursion, use -walk_node_tree() when creating the node records during a live update. - -This will reduce code size and avoid many nesting levels of function -calls which could potentially exhaust the stack. - -This is part of XSA-418 / CVE-2022-42321. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 58fb651542ec..05d349778bb4 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -3120,101 +3120,76 @@ const char *dump_state_node_perms(FILE *fp, const struct xs_permissions *perms, - return NULL; - } - --static const char *dump_state_node_tree(FILE *fp, char *path, -- unsigned int path_max_len) -+struct dump_node_data { -+ FILE *fp; -+ const char *err; -+}; -+ -+static int dump_state_node_err(struct dump_node_data *data, const char *err) - { -- unsigned int pathlen, childlen, p = 0; -+ data->err = err; -+ return WALK_TREE_ERROR_STOP; -+} -+ -+static int dump_state_node(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) -+{ -+ struct dump_node_data *data = arg; -+ FILE *fp = data->fp; -+ unsigned int pathlen; - struct xs_state_record_header head; - struct xs_state_node sn; -- TDB_DATA key, data; -- const struct xs_tdb_record_hdr *hdr; -- const char *child; - const char *ret; - -- pathlen = strlen(path) + 1; -- -- set_tdb_key(path, &key); -- data = tdb_fetch(tdb_ctx, key); -- if (data.dptr == NULL) -- return "Error reading node"; -- -- /* Clean up in case of failure. */ -- talloc_steal(path, data.dptr); -- -- hdr = (void *)data.dptr; -+ pathlen = strlen(node->name) + 1; - - head.type = XS_STATE_TYPE_NODE; - head.length = sizeof(sn); - sn.conn_id = 0; - sn.ta_id = 0; - sn.ta_access = 0; -- sn.perm_n = hdr->num_perms; -+ sn.perm_n = node->perms.num; - sn.path_len = pathlen; -- sn.data_len = hdr->datalen; -- head.length += hdr->num_perms * sizeof(*sn.perms); -+ sn.data_len = node->datalen; -+ head.length += node->perms.num * sizeof(*sn.perms); - head.length += pathlen; -- head.length += hdr->datalen; -+ head.length += node->datalen; - head.length = ROUNDUP(head.length, 3); - - if (fwrite(&head, sizeof(head), 1, fp) != 1) -- return "Dump node state error"; -+ return dump_state_node_err(data, "Dump node head error"); - if (fwrite(&sn, sizeof(sn), 1, fp) != 1) -- return "Dump node state error"; -+ return dump_state_node_err(data, "Dump node state error"); - -- ret = dump_state_node_perms(fp, hdr->perms, hdr->num_perms); -+ ret = dump_state_node_perms(fp, node->perms.p, node->perms.num); - if (ret) -- return ret; -+ return dump_state_node_err(data, ret); -+ -+ if (fwrite(node->name, pathlen, 1, fp) != 1) -+ return dump_state_node_err(data, "Dump node path error"); - -- if (fwrite(path, pathlen, 1, fp) != 1) -- return "Dump node path error"; -- if (hdr->datalen && -- fwrite(hdr->perms + hdr->num_perms, hdr->datalen, 1, fp) != 1) -- return "Dump node data error"; -+ if (node->datalen && fwrite(node->data, node->datalen, 1, fp) != 1) -+ return dump_state_node_err(data, "Dump node data error"); - - ret = dump_state_align(fp); - if (ret) -- return ret; -+ return dump_state_node_err(data, ret); - -- child = (char *)(hdr->perms + hdr->num_perms) + hdr->datalen; -- -- /* -- * Use path for constructing children paths. -- * As we don't write out nodes without having written their parent -- * already we will never clobber a part of the path we'll need later. -- */ -- pathlen--; -- if (path[pathlen - 1] != '/') { -- path[pathlen] = '/'; -- pathlen++; -- } -- while (p < hdr->childlen) { -- childlen = strlen(child) + 1; -- if (pathlen + childlen > path_max_len) -- return "Dump node path length error"; -- strcpy(path + pathlen, child); -- ret = dump_state_node_tree(fp, path, path_max_len); -- if (ret) -- return ret; -- p += childlen; -- child += childlen; -- } -- -- talloc_free(data.dptr); -- -- return NULL; -+ return WALK_TREE_OK; - } - - const char *dump_state_nodes(FILE *fp, const void *ctx) - { -- char *path; -- -- path = talloc_size(ctx, XENSTORE_ABS_PATH_MAX + 1); -- if (!path) -- return "Path buffer allocation error"; -+ struct dump_node_data data = { -+ .fp = fp, -+ .err = "Dump node walk error" -+ }; -+ struct walk_funcs walkfuncs = { .enter = dump_state_node }; - -- strcpy(path, "/"); -+ if (walk_node_tree(ctx, NULL, "/", &walkfuncs, &data)) -+ return data.err; - -- return dump_state_node_tree(fp, path, XENSTORE_ABS_PATH_MAX + 1); -+ return NULL; - } - - void read_state_global(const void *ctx, const void *state) diff --git a/xsa419-oxenstored.patch b/xsa419-oxenstored.patch deleted file mode 100644 index 0ac365d..0000000 --- a/xsa419-oxenstored.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 09228369a549427294febe351372d7227e624da1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:06 +0100 -Subject: tools/ocaml/xenstored: Fix quota bypass on domain shutdown -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -XSA-322 fixed a domid reuse vulnerability by assigning Dom0 as the owner of -any nodes left after a domain is shutdown (e.g. outside its /local/domain/N -tree). - -However Dom0 has no quota on purpose, so this opened up another potential -attack vector. Avoid it by deleting these nodes instead of assigning them to -Dom0. - -This is part of XSA-419 / CVE-2022-42323. - -Reported-by: Juergen Gross -Fixes: c46eff921209 ("tools/ocaml/xenstored: clean up permissions for dead domains") -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml -index e8a16221f8fa..84f2503e8e29 100644 ---- a/tools/ocaml/xenstored/perms.ml -+++ b/tools/ocaml/xenstored/perms.ml -@@ -64,8 +64,7 @@ let get_owner perm = perm.owner - * *) - let remove_domid ~domid perm = - let acl = List.filter (fun (acl_domid, _) -> acl_domid <> domid) perm.acl in -- let owner = if perm.owner = domid then 0 else perm.owner in -- { perm with acl; owner } -+ if perm.owner = domid then None else Some { perm with acl; owner = perm.owner } - - let default0 = create 0 NONE [] - -diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml -index 20e67b142746..70f0c83de404 100644 ---- a/tools/ocaml/xenstored/store.ml -+++ b/tools/ocaml/xenstored/store.ml -@@ -87,10 +87,21 @@ let check_owner node connection = - - let rec recurse fct node = fct node; SymbolMap.iter (fun _ -> recurse fct) node.children - --(** [recurse_map f tree] applies [f] on each node in the tree recursively *) --let recurse_map f = -+(** [recurse_filter_map f tree] applies [f] on each node in the tree recursively, -+ possibly removing some nodes. -+ Note that the nodes removed this way won't generate watch events. -+*) -+let recurse_filter_map f = -+ let invalid = -1 in -+ let is_valid _ node = node.perms.owner <> invalid in - let rec walk node = -- f { node with children = SymbolMap.map walk node.children } -+ (* Map.filter_map is Ocaml 4.11+ only *) -+ let node = -+ { node with children = -+ SymbolMap.map walk node.children |> SymbolMap.filter is_valid } in -+ match f node with -+ | Some keep -> keep -+ | None -> { node with perms = {node.perms with owner = invalid } } - in - walk - -@@ -444,11 +455,13 @@ let setperms store perm path nperms = - - let reset_permissions store domid = - Logging.info "store|node" "Cleaning up xenstore ACLs for domid %d" domid; -- store.root <- Node.recurse_map (fun node -> -- let perms = Perms.Node.remove_domid ~domid node.perms in -- if perms <> node.perms then -- Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); -- { node with perms } -+ store.root <- Node.recurse_filter_map (fun node -> -+ match Perms.Node.remove_domid ~domid node.perms with -+ | None -> None -+ | Some perms -> -+ if perms <> node.perms then -+ Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); -+ Some { node with perms } - ) store.root - - type ops = { diff --git a/xsa419-xenstored-01.patch b/xsa419-xenstored-01.patch deleted file mode 100644 index 3409790..0000000 --- a/xsa419-xenstored-01.patch +++ /dev/null @@ -1,289 +0,0 @@ -From e4250bf8b39ed73623c75b0f1436ac7c1d45aba7 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:12 +0200 -Subject: tools/xenstore: remove nodes owned by destroyed domain - -In case a domain is removed from Xenstore, remove all nodes owned by -it per default. - -This tackles the problem that nodes might be created by a domain -outside its home path in Xenstore, leading to Xenstore hogging more -and more memory. Domain quota don't work in this case if the guest is -rebooting in between. - -Since XSA-322 ownership of such stale nodes is transferred to dom0, -which is helping against unintended access, but not against OOM of -Xenstore. - -As a fallback for weird cases add a Xenstore start parameter for -keeping today's way to handle stale nodes, adding the risk of Xenstore -hitting an OOM situation. - -This is part of XSA-419 / CVE-2022-42322. - -Reported-by: Juergen Gross -Fixes: 496306324d8d ("tools/xenstore: revoke access rights for removed domains") -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index bdc14679adf5..13e48aaa731c 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -80,6 +80,7 @@ static bool verbose = false; - LIST_HEAD(connections); - int tracefd = -1; - static bool recovery = true; -+bool keep_orphans = false; - static int reopen_log_pipe[2]; - static int reopen_log_pipe0_pollfd_idx = -1; - char *tracefile = NULL; -@@ -753,7 +754,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - node->perms.p = hdr->perms; - node->acc.domid = node->perms.p[0].id; - node->acc.memory = data.dsize; -- if (domain_adjust_node_perms(conn, node)) -+ if (domain_adjust_node_perms(node)) - goto error; - - /* If owner is gone reset currently accounted memory size. */ -@@ -796,7 +797,7 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - void *p; - struct xs_tdb_record_hdr *hdr; - -- if (domain_adjust_node_perms(conn, node)) -+ if (domain_adjust_node_perms(node)) - return errno; - - data.dsize = sizeof(*hdr) -@@ -1647,7 +1648,7 @@ static int delnode_sub(const void *ctx, struct connection *conn, - return WALK_TREE_RM_CHILDENTRY; - } - --static int _rm(struct connection *conn, const void *ctx, const char *name) -+int rm_node(struct connection *conn, const void *ctx, const char *name) - { - struct node *parent; - char *parentname = get_parent(ctx, name); -@@ -1711,7 +1712,7 @@ static int do_rm(const void *ctx, struct connection *conn, - if (streq(name, "/")) - return EINVAL; - -- ret = _rm(conn, ctx, name); -+ ret = rm_node(conn, ctx, name); - if (ret) - return ret; - -@@ -2618,6 +2619,8 @@ static void usage(void) - " -R, --no-recovery to request that no recovery should be attempted when\n" - " the store is corrupted (debug only),\n" - " -I, --internal-db store database in memory, not on disk\n" -+" -K, --keep-orphans don't delete nodes owned by a domain when the\n" -+" domain is deleted (this is a security risk!)\n" - " -V, --verbose to request verbose execution.\n"); - } - -@@ -2642,6 +2645,7 @@ static struct option options[] = { - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, - { "internal-db", 0, NULL, 'I' }, -+ { "keep-orphans", 0, NULL, 'K' }, - { "verbose", 0, NULL, 'V' }, - { "watch-nb", 1, NULL, 'W' }, - #ifndef NO_LIVE_UPDATE -@@ -2721,7 +2725,7 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:A:M:Q:q:T:RVW:w:U", -+ while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U", - options, NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2757,6 +2761,9 @@ int main(int argc, char *argv[]) - case 'I': - tdb_flags = TDB_INTERNAL|TDB_NOLOCK; - break; -+ case 'K': -+ keep_orphans = true; -+ break; - case 'V': - verbose = true; - break; -diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h -index acb00ad96914..37006d508dbf 100644 ---- a/tools/xenstore/xenstored_core.h -+++ b/tools/xenstore/xenstored_core.h -@@ -240,6 +240,9 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - struct node *read_node(struct connection *conn, const void *ctx, - const char *name); - -+/* Remove a node and its children. */ -+int rm_node(struct connection *conn, const void *ctx, const char *name); -+ - void setup_structure(bool live_update); - struct connection *new_connection(const struct interface_funcs *funcs); - struct connection *get_connection_by_id(unsigned int conn_id); -@@ -284,6 +287,7 @@ extern int quota_req_outstanding; - extern int quota_trans_nodes; - extern int quota_memory_per_domain_soft; - extern int quota_memory_per_domain_hard; -+extern bool keep_orphans; - - extern unsigned int timeout_watch_event_msec; - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index 98b401fdec30..84b7817cd5e6 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -227,10 +227,64 @@ static void unmap_interface(void *interface) - xengnttab_unmap(*xgt_handle, interface, 1); - } - -+static int domain_tree_remove_sub(const void *ctx, struct connection *conn, -+ struct node *node, void *arg) -+{ -+ struct domain *domain = arg; -+ TDB_DATA key; -+ int ret = WALK_TREE_OK; -+ -+ if (node->perms.p[0].id != domain->domid) -+ return WALK_TREE_OK; -+ -+ if (keep_orphans) { -+ set_tdb_key(node->name, &key); -+ domain->nbentry--; -+ node->perms.p[0].id = priv_domid; -+ node->acc.memory = 0; -+ domain_entry_inc(NULL, node); -+ if (write_node_raw(NULL, &key, node, true)) { -+ /* That's unfortunate. We only can try to continue. */ -+ syslog(LOG_ERR, -+ "error when moving orphaned node %s to dom0\n", -+ node->name); -+ } else -+ trace("orphaned node %s moved to dom0\n", node->name); -+ } else { -+ if (rm_node(NULL, ctx, node->name)) { -+ /* That's unfortunate. We only can try to continue. */ -+ syslog(LOG_ERR, -+ "error when deleting orphaned node %s\n", -+ node->name); -+ } else -+ trace("orphaned node %s deleted\n", node->name); -+ -+ /* Skip children in all cases in order to avoid more errors. */ -+ ret = WALK_TREE_SKIP_CHILDREN; -+ } -+ -+ return domain->nbentry > 0 ? ret : WALK_TREE_SUCCESS_STOP; -+} -+ -+static void domain_tree_remove(struct domain *domain) -+{ -+ int ret; -+ struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub }; -+ -+ if (domain->nbentry > 0) { -+ ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain); -+ if (ret == WALK_TREE_ERROR_STOP) -+ syslog(LOG_ERR, -+ "error when looking for orphaned nodes\n"); -+ } -+} -+ - static int destroy_domain(void *_domain) - { - struct domain *domain = _domain; - -+ domain_tree_remove(domain); -+ - list_del(&domain->list); - - if (!domain->introduced) -@@ -883,15 +937,15 @@ int domain_entry_inc(struct connection *conn, struct node *node) - struct domain *d; - unsigned int domid; - -- if (!conn) -+ if (!node->perms.p) - return 0; - -- domid = node->perms.p ? node->perms.p[0].id : conn->id; -+ domid = node->perms.p[0].id; - -- if (conn->transaction) { -+ if (conn && conn->transaction) { - transaction_entry_inc(conn->transaction, domid); - } else { -- d = (domid == conn->id && conn->domain) ? conn->domain -+ d = (conn && domid == conn->id && conn->domain) ? conn->domain - : find_or_alloc_existing_domain(domid); - if (d) - d->nbentry++; -@@ -952,23 +1006,11 @@ int domain_alloc_permrefs(struct node_perms *perms) - * Remove permissions for no longer existing domains in order to avoid a new - * domain with the same domid inheriting the permissions. - */ --int domain_adjust_node_perms(struct connection *conn, struct node *node) -+int domain_adjust_node_perms(struct node *node) - { - unsigned int i; - int ret; - -- ret = chk_domain_generation(node->perms.p[0].id, node->generation); -- -- /* If the owner doesn't exist any longer give it to priv domain. */ -- if (!ret) { -- /* -- * In theory we'd need to update the number of dom0 nodes here, -- * but we could be called for a read of the node. So better -- * avoid the risk to overflow the node count of dom0. -- */ -- node->perms.p[0].id = priv_domid; -- } -- - for (i = 1; i < node->perms.num; i++) { - if (node->perms.p[i].perms & XS_PERM_IGNORE) - continue; -@@ -986,15 +1028,15 @@ void domain_entry_dec(struct connection *conn, struct node *node) - struct domain *d; - unsigned int domid; - -- if (!conn) -+ if (!node->perms.p) - return; - - domid = node->perms.p ? node->perms.p[0].id : conn->id; - -- if (conn->transaction) { -+ if (conn && conn->transaction) { - transaction_entry_dec(conn->transaction, domid); - } else { -- d = (domid == conn->id && conn->domain) ? conn->domain -+ d = (conn && domid == conn->id && conn->domain) ? conn->domain - : find_domain_struct(domid); - if (d) { - d->nbentry--; -@@ -1113,7 +1155,7 @@ int domain_memory_add(unsigned int domid, int mem, bool no_quota_check) - * exist, as accounting is done either for a domain related to - * the current connection, or for the domain owning a node - * (which is always existing, as the owner of the node is -- * tested to exist and replaced by domid 0 if not). -+ * tested to exist and deleted or replaced by domid 0 if not). - * So not finding the related domain MUST be an error in the - * data base. - */ -diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h -index 7fe0a21d9e45..b38c82991dc6 100644 ---- a/tools/xenstore/xenstored_domain.h -+++ b/tools/xenstore/xenstored_domain.h -@@ -62,7 +62,7 @@ const char *get_implicit_path(const struct connection *conn); - bool domain_is_unprivileged(struct connection *conn); - - /* Remove node permissions for no longer existing domains. */ --int domain_adjust_node_perms(struct connection *conn, struct node *node); -+int domain_adjust_node_perms(struct node *node); - int domain_alloc_permrefs(struct node_perms *perms); - - /* Quota manipulation */ diff --git a/xsa419-xenstored-02.patch b/xsa419-xenstored-02.patch deleted file mode 100644 index e5d46a2..0000000 --- a/xsa419-xenstored-02.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 929da557efea6c7d2340467d9a7fdae7fda6d2b1 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:13 +0200 -Subject: tools/xenstore: make the internal memory data base the default - -Having a file backed data base has the only advantage of being capable -to dump the contents of it while Xenstore is running, and potentially -using less swap space in case the data base can't be kept in memory. - -It has the major disadvantage of a huge performance overhead: switching -to keep the data base in memory only speeds up live update of xenstored -with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk -of this configuration will be reduced from 7 seconds to 280 msecs -(measured by "xenstore-control check"). - -So make the internal memory data base the default and enhance the -"--internal-db" command line parameter to take an optional parameter -allowing to switch the internal data base back to the file based one. - -This is part of XSA-419. - -Reported-by: Juergen Gross -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall - -diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c -index 2d9ab6f1c583..04e351ca29a8 100644 ---- a/tools/helpers/init-xenstore-domain.c -+++ b/tools/helpers/init-xenstore-domain.c -@@ -222,9 +222,9 @@ static int build(xc_interface *xch) - } - - if ( param ) -- snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param); -+ snprintf(cmdline, 512, "--event %d %s", rv, param); - else -- snprintf(cmdline, 512, "--event %d --internal-db", rv); -+ snprintf(cmdline, 512, "--event %d", rv); - - dom->guest_domid = domid; - dom->cmdline = xc_dom_strdup(dom, cmdline); -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 13e48aaa731c..36fb4a832834 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2308,7 +2308,7 @@ static void accept_connection(int sock) - } - #endif - --static int tdb_flags; -+static int tdb_flags = TDB_INTERNAL | TDB_NOLOCK; - - /* We create initial nodes manually. */ - static void manual_node(const char *name, const char *child) -@@ -2618,7 +2618,8 @@ static void usage(void) - " watch-event: time a watch-event is kept pending\n" - " -R, --no-recovery to request that no recovery should be attempted when\n" - " the store is corrupted (debug only),\n" --" -I, --internal-db store database in memory, not on disk\n" -+" -I, --internal-db [on|off] store database in memory, not on disk, default is\n" -+" memory, with \"--internal-db off\" it is on disk\n" - " -K, --keep-orphans don't delete nodes owned by a domain when the\n" - " domain is deleted (this is a security risk!)\n" - " -V, --verbose to request verbose execution.\n"); -@@ -2644,7 +2645,7 @@ static struct option options[] = { - { "quota-soft", 1, NULL, 'q' }, - { "timeout", 1, NULL, 'w' }, - { "no-recovery", 0, NULL, 'R' }, -- { "internal-db", 0, NULL, 'I' }, -+ { "internal-db", 2, NULL, 'I' }, - { "keep-orphans", 0, NULL, 'K' }, - { "verbose", 0, NULL, 'V' }, - { "watch-nb", 1, NULL, 'W' }, -@@ -2725,7 +2726,8 @@ int main(int argc, char *argv[]) - orig_argc = argc; - orig_argv = argv; - -- while ((opt = getopt_long(argc, argv, "DE:F:HKNPS:t:A:M:Q:q:T:RVW:w:U", -+ while ((opt = getopt_long(argc, argv, -+ "DE:F:HI::KNPS:t:A:M:Q:q:T:RVW:w:U", - options, NULL)) != -1) { - switch (opt) { - case 'D': -@@ -2759,7 +2761,8 @@ int main(int argc, char *argv[]) - tracefile = optarg; - break; - case 'I': -- tdb_flags = TDB_INTERNAL|TDB_NOLOCK; -+ if (optarg && !strcmp(optarg, "off")) -+ tdb_flags = 0; - break; - case 'K': - keep_orphans = true; diff --git a/xsa419-xenstored-03.patch b/xsa419-xenstored-03.patch deleted file mode 100644 index 38130c0..0000000 --- a/xsa419-xenstored-03.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 54e63b7e7c42e4f975163809a01574e78552a6ab Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:13 +0200 -Subject: docs: enhance xenstore.txt with permissions description -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The permission scheme of Xenstore nodes is not really covered by -docs/misc/xenstore.txt, other than referring to the Xen wiki. - -Add a paragraph explaining the permissions of nodes, and especially -mentioning removal of nodes when a domain has been removed from -Xenstore. - -This is part of XSA-419. - -Reported-by: Juergen Gross -Signed-off-by: Juergen Gross -Reviewed-by: Edwin Török -Acked-by: Julien Grall - -diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt -index 988ef89cba2d..44428ae3a755 100644 ---- a/docs/misc/xenstore.txt -+++ b/docs/misc/xenstore.txt -@@ -43,6 +43,17 @@ bytes are forbidden; clients specifying relative paths should keep - them to within 2048 bytes. (See XENSTORE_*_PATH_MAX in xs_wire.h.) - - -+Each node has one or multiple permission entries. Permissions are -+granted by domain-id, the first permission entry of each node specifies -+the owner of the node. Permissions of a node can be changed by the -+owner of the node, the owner can only be modified by the control -+domain (usually domain id 0). The owner always has the right to read -+and write the node, while other permissions can be setup to allow -+read and/or write access. When a domain is being removed from Xenstore -+nodes owned by that domain will be removed together with all of those -+nodes' children. -+ -+ - Communication with xenstore is via either sockets, or event channel - and shared memory, as specified in io/xs_wire.h: each message in - either direction is a header formatted as a struct xsd_sockmsg diff --git a/xsa420.patch b/xsa420.patch deleted file mode 100644 index 5d00dc2..0000000 --- a/xsa420.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 210879456769ca211c6630f47399ca7a61a37f35 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= -Date: Wed, 12 Oct 2022 19:13:05 +0100 -Subject: tools/ocaml: Ensure packet size is never negative -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Integers in Ocaml have 63 or 31 bits of signed precision. - -On 64-bit builds of Ocaml, this is fine because a C uint32_t always fits -within a 63-bit signed integer. - -In 32-bit builds of Ocaml, this goes wrong. The C uint32_t is truncated -first (loses the top bit), then has a unsigned/signed mismatch. - -A "negative" value (i.e. a packet on the ring of between 1G and 2G in size) -will trigger an exception later in Bytes.make in xb.ml, and because the packet -is not removed from the ring, the exception re-triggers on every subsequent -query, creating a livelock. - -Fix both the source of the exception in Xb, and as defence in depth, mark the -domain as bad for any Invalid_argument exceptions to avoid the risk of -livelock. - -This is XSA-420 / CVE-2022-42324. - -Reported-by: Juergen Gross -Signed-off-by: Edwin Török -Acked-by: Christian Lindig - -diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml -index b6e2a716e263..3aa8927eb7f0 100644 ---- a/tools/ocaml/libs/xb/partial.ml -+++ b/tools/ocaml/libs/xb/partial.ml -@@ -36,7 +36,7 @@ let of_string s = - This will leave the guest connection is a bad state and will - be hard to recover from without restarting the connection - (ie rebooting the guest) *) -- let dlen = min xenstore_payload_max dlen in -+ let dlen = max 0 (min xenstore_payload_max dlen) in - { - tid = tid; - rid = rid; -@@ -46,8 +46,8 @@ let of_string s = - } - - let append pkt s sz = -- if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer"; -- Buffer.add_string pkt.buf (String.sub s 0 sz) -+ if Buffer.length pkt.buf + sz > xenstore_payload_max then failwith "Buffer.add: cannot grow buffer"; -+ Buffer.add_substring pkt.buf s 0 sz - - let to_complete pkt = - pkt.len - (Buffer.length pkt.buf) -diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml -index 5f439fe59f47..f3a71b24ad94 100644 ---- a/tools/ocaml/xenstored/process.ml -+++ b/tools/ocaml/xenstored/process.ml -@@ -722,7 +722,7 @@ let do_input store cons doms con = - History.reconnect con; - info "%s reconnection complete" (Connection.get_domstr con); - None -- | Failure exp -> -+ | Invalid_argument exp | Failure exp -> - error "caught exception %s" exp; - error "got a bad client %s" (sprintf "%-8s" (Connection.get_domstr con)); - Connection.mark_as_bad con; diff --git a/xsa421-01.patch b/xsa421-01.patch deleted file mode 100644 index 10960ba..0000000 --- a/xsa421-01.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 9166869e7e6530befddfd8bb46ff37436a38efc1 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:13 +0200 -Subject: tools/xenstore: fix deleting node in transaction - -In case a node has been created in a transaction and it is later -deleted in the same transaction, the transaction will be terminated -with an error. - -As this error is encountered only when handling the deleted node at -transaction finalization, the transaction will have been performed -partially and without updating the accounting information. This will -enable a malicious guest to create arbitrary number of nodes. - -This is part of XSA-421 / CVE-2022-42325. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Tested-by: Julien Grall -Reviewed-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 3e3eb47326cc..7ffe21bb5285 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -418,7 +418,13 @@ static int finalize_transaction(struct connection *conn, - true); - talloc_free(data.dptr); - } else { -- ret = do_tdb_delete(conn, &key, NULL); -+ /* -+ * A node having been created and later deleted -+ * in this transaction will have no generation -+ * information stored. -+ */ -+ ret = (i->generation == NO_GENERATION) -+ ? 0 : do_tdb_delete(conn, &key, NULL); - } - if (ret) - goto err; diff --git a/xsa421-02.patch b/xsa421-02.patch deleted file mode 100644 index 1a0b5cd..0000000 --- a/xsa421-02.patch +++ /dev/null @@ -1,401 +0,0 @@ -From 09fc22fea8a4689c5e563ba4a2fa959282071792 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Tue, 13 Sep 2022 07:35:14 +0200 -Subject: tools/xenstore: harden transaction finalization against errors - -When finalizing a transaction, any error occurring after checking for -conflicts will result in the transaction being performed only -partially today. Additionally accounting data will not be updated at -the end of the transaction, which might result in further problems -later. - -Avoid those problems by multiple modifications: - -- free any transaction specific nodes which don't need to be committed - as they haven't been written during the transaction as soon as their - generation count has been verified, this will reduce the risk of - out-of-memory situations - -- store the transaction specific node name in struct accessed_node in - order to avoid the need to allocate additional memory for it when - finalizing the transaction - -- don't stop the transaction finalization when hitting an error - condition, but try to continue to handle all modified nodes - -- in case of a detected error do the accounting update as needed and - call the data base checking only after that - -- if writing a node in a transaction is failing (e.g. due to a failed - quota check), fail the transaction, as prior changes to struct - accessed_node can't easily be undone in that case - -This is part of XSA-421 / CVE-2022-42326. - -Reported-by: Julien Grall -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall -Tested-by: Julien Grall - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 36fb4a832834..476d5c6d51bd 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -723,8 +723,7 @@ struct node *read_node(struct connection *conn, const void *ctx, - return NULL; - } - -- if (transaction_prepend(conn, name, &key)) -- return NULL; -+ transaction_prepend(conn, name, &key); - - data = tdb_fetch(tdb_ctx, key); - -@@ -842,10 +841,21 @@ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node, - static int write_node(struct connection *conn, struct node *node, - bool no_quota_check) - { -+ int ret; -+ - if (access_node(conn, node, NODE_ACCESS_WRITE, &node->key)) - return errno; - -- return write_node_raw(conn, &node->key, node, no_quota_check); -+ ret = write_node_raw(conn, &node->key, node, no_quota_check); -+ if (ret && conn && conn->transaction) { -+ /* -+ * Reverting access_node() is hard, so just fail the -+ * transaction. -+ */ -+ fail_transaction(conn->transaction); -+ } -+ -+ return ret; - } - - unsigned int perm_for_conn(struct connection *conn, -diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c -index 7ffe21bb5285..ac854197cadb 100644 ---- a/tools/xenstore/xenstored_transaction.c -+++ b/tools/xenstore/xenstored_transaction.c -@@ -114,7 +114,8 @@ struct accessed_node - struct list_head list; - - /* The name of the node. */ -- char *node; -+ char *trans_name; /* Transaction specific name. */ -+ char *node; /* Main data base name. */ - - /* Generation count (or NO_GENERATION) for conflict checking. */ - uint64_t generation; -@@ -199,25 +200,20 @@ static char *transaction_get_node_name(void *ctx, struct transaction *trans, - * Prepend the transaction to name if node has been modified in the current - * transaction. - */ --int transaction_prepend(struct connection *conn, const char *name, -- TDB_DATA *key) -+void transaction_prepend(struct connection *conn, const char *name, -+ TDB_DATA *key) - { -- char *tdb_name; -+ struct accessed_node *i; - -- if (!conn || !conn->transaction || -- !find_accessed_node(conn->transaction, name)) { -- set_tdb_key(name, key); -- return 0; -+ if (conn && conn->transaction) { -+ i = find_accessed_node(conn->transaction, name); -+ if (i) { -+ set_tdb_key(i->trans_name, key); -+ return; -+ } - } - -- tdb_name = transaction_get_node_name(conn->transaction, -- conn->transaction, name); -- if (!tdb_name) -- return errno; -- -- set_tdb_key(tdb_name, key); -- -- return 0; -+ set_tdb_key(name, key); - } - - /* -@@ -240,7 +236,6 @@ int access_node(struct connection *conn, struct node *node, - struct accessed_node *i = NULL; - struct transaction *trans; - TDB_DATA local_key; -- const char *trans_name = NULL; - int ret; - bool introduce = false; - -@@ -259,10 +254,6 @@ int access_node(struct connection *conn, struct node *node, - - trans = conn->transaction; - -- trans_name = transaction_get_node_name(node, trans, node->name); -- if (!trans_name) -- goto nomem; -- - i = find_accessed_node(trans, node->name); - if (!i) { - if (trans->nodes >= quota_trans_nodes && -@@ -273,9 +264,10 @@ int access_node(struct connection *conn, struct node *node, - i = talloc_zero(trans, struct accessed_node); - if (!i) - goto nomem; -- i->node = talloc_strdup(i, node->name); -- if (!i->node) -+ i->trans_name = transaction_get_node_name(i, trans, node->name); -+ if (!i->trans_name) - goto nomem; -+ i->node = strchr(i->trans_name, '/') + 1; - if (node->generation != NO_GENERATION && node->perms.num) { - i->perms.p = talloc_array(i, struct xs_permissions, - node->perms.num); -@@ -302,7 +294,7 @@ int access_node(struct connection *conn, struct node *node, - i->generation = node->generation; - i->check_gen = true; - if (node->generation != NO_GENERATION) { -- set_tdb_key(trans_name, &local_key); -+ set_tdb_key(i->trans_name, &local_key); - ret = write_node_raw(conn, &local_key, node, true); - if (ret) - goto err; -@@ -321,7 +313,7 @@ int access_node(struct connection *conn, struct node *node, - return -1; - - if (key) { -- set_tdb_key(trans_name, key); -+ set_tdb_key(i->trans_name, key); - if (type == NODE_ACCESS_WRITE) - i->ta_node = true; - if (type == NODE_ACCESS_DELETE) -@@ -333,7 +325,6 @@ int access_node(struct connection *conn, struct node *node, - nomem: - ret = ENOMEM; - err: -- talloc_free((void *)trans_name); - talloc_free(i); - trans->fail = true; - errno = ret; -@@ -371,100 +362,90 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact) - * base. - */ - static int finalize_transaction(struct connection *conn, -- struct transaction *trans) -+ struct transaction *trans, bool *is_corrupt) - { -- struct accessed_node *i; -+ struct accessed_node *i, *n; - TDB_DATA key, ta_key, data; - struct xs_tdb_record_hdr *hdr; - uint64_t gen; -- char *trans_name; -- int ret; - -- list_for_each_entry(i, &trans->accessed, list) { -- if (!i->check_gen) -- continue; -+ list_for_each_entry_safe(i, n, &trans->accessed, list) { -+ if (i->check_gen) { -+ set_tdb_key(i->node, &key); -+ data = tdb_fetch(tdb_ctx, key); -+ hdr = (void *)data.dptr; -+ if (!data.dptr) { -+ if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST) -+ return EIO; -+ gen = NO_GENERATION; -+ } else -+ gen = hdr->generation; -+ talloc_free(data.dptr); -+ if (i->generation != gen) -+ return EAGAIN; -+ } - -- set_tdb_key(i->node, &key); -- data = tdb_fetch(tdb_ctx, key); -- hdr = (void *)data.dptr; -- if (!data.dptr) { -- if (tdb_error(tdb_ctx) != TDB_ERR_NOEXIST) -- return EIO; -- gen = NO_GENERATION; -- } else -- gen = hdr->generation; -- talloc_free(data.dptr); -- if (i->generation != gen) -- return EAGAIN; -+ /* Entries for unmodified nodes can be removed early. */ -+ if (!i->modified) { -+ if (i->ta_node) { -+ set_tdb_key(i->trans_name, &ta_key); -+ if (do_tdb_delete(conn, &ta_key, NULL)) -+ return EIO; -+ } -+ list_del(&i->list); -+ talloc_free(i); -+ } - } - - while ((i = list_top(&trans->accessed, struct accessed_node, list))) { -- trans_name = transaction_get_node_name(i, trans, i->node); -- if (!trans_name) -- /* We are doomed: the transaction is only partial. */ -- goto err; -- -- set_tdb_key(trans_name, &ta_key); -- -- if (i->modified) { -- set_tdb_key(i->node, &key); -- if (i->ta_node) { -- data = tdb_fetch(tdb_ctx, ta_key); -- if (!data.dptr) -- goto err; -+ set_tdb_key(i->node, &key); -+ if (i->ta_node) { -+ set_tdb_key(i->trans_name, &ta_key); -+ data = tdb_fetch(tdb_ctx, ta_key); -+ if (data.dptr) { - hdr = (void *)data.dptr; - hdr->generation = ++generation; -- ret = do_tdb_write(conn, &key, &data, NULL, -- true); -+ *is_corrupt |= do_tdb_write(conn, &key, &data, -+ NULL, true); - talloc_free(data.dptr); -+ if (do_tdb_delete(conn, &ta_key, NULL)) -+ *is_corrupt = true; - } else { -- /* -- * A node having been created and later deleted -- * in this transaction will have no generation -- * information stored. -- */ -- ret = (i->generation == NO_GENERATION) -- ? 0 : do_tdb_delete(conn, &key, NULL); -- } -- if (ret) -- goto err; -- if (i->fire_watch) { -- fire_watches(conn, trans, i->node, NULL, -- i->watch_exact, -- i->perms.p ? &i->perms : NULL); -+ *is_corrupt = true; - } -+ } else { -+ /* -+ * A node having been created and later deleted -+ * in this transaction will have no generation -+ * information stored. -+ */ -+ *is_corrupt |= (i->generation == NO_GENERATION) -+ ? false -+ : do_tdb_delete(conn, &key, NULL); - } -+ if (i->fire_watch) -+ fire_watches(conn, trans, i->node, NULL, i->watch_exact, -+ i->perms.p ? &i->perms : NULL); - -- if (i->ta_node && do_tdb_delete(conn, &ta_key, NULL)) -- goto err; - list_del(&i->list); - talloc_free(i); - } - - return 0; -- --err: -- corrupt(conn, "Partial transaction"); -- return EIO; - } - - static int destroy_transaction(void *_transaction) - { - struct transaction *trans = _transaction; - struct accessed_node *i; -- char *trans_name; - TDB_DATA key; - - wrl_ntransactions--; - trace_destroy(trans, "transaction"); - while ((i = list_top(&trans->accessed, struct accessed_node, list))) { - if (i->ta_node) { -- trans_name = transaction_get_node_name(i, trans, -- i->node); -- if (trans_name) { -- set_tdb_key(trans_name, &key); -- do_tdb_delete(trans->conn, &key, NULL); -- } -+ set_tdb_key(i->trans_name, &key); -+ do_tdb_delete(trans->conn, &key, NULL); - } - list_del(&i->list); - talloc_free(i); -@@ -556,6 +537,7 @@ int do_transaction_end(const void *ctx, struct connection *conn, - { - const char *arg = onearg(in); - struct transaction *trans; -+ bool is_corrupt = false; - int ret; - - if (!arg || (!streq(arg, "T") && !streq(arg, "F"))) -@@ -579,13 +561,17 @@ int do_transaction_end(const void *ctx, struct connection *conn, - ret = transaction_fix_domains(trans, false); - if (ret) - return ret; -- if (finalize_transaction(conn, trans)) -- return EAGAIN; -+ ret = finalize_transaction(conn, trans, &is_corrupt); -+ if (ret) -+ return ret; - - wrl_apply_debit_trans_commit(conn); - - /* fix domain entry for each changed domain */ - transaction_fix_domains(trans, true); -+ -+ if (is_corrupt) -+ corrupt(conn, "transaction inconsistency"); - } - send_ack(conn, XS_TRANSACTION_END); - -@@ -660,7 +646,7 @@ int check_transactions(struct hashtable *hash) - struct connection *conn; - struct transaction *trans; - struct accessed_node *i; -- char *tname, *tnode; -+ char *tname; - - list_for_each_entry(conn, &connections, list) { - list_for_each_entry(trans, &conn->transaction_list, list) { -@@ -672,11 +658,8 @@ int check_transactions(struct hashtable *hash) - list_for_each_entry(i, &trans->accessed, list) { - if (!i->ta_node) - continue; -- tnode = transaction_get_node_name(tname, trans, -- i->node); -- if (!tnode || !remember_string(hash, tnode)) -+ if (!remember_string(hash, i->trans_name)) - goto nomem; -- talloc_free(tnode); - } - - talloc_free(tname); -diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h -index 39d7f81c5127..3417303f9427 100644 ---- a/tools/xenstore/xenstored_transaction.h -+++ b/tools/xenstore/xenstored_transaction.h -@@ -48,8 +48,8 @@ int __must_check access_node(struct connection *conn, struct node *node, - void queue_watches(struct connection *conn, const char *name, bool watch_exact); - - /* Prepend the transaction to name if appropriate. */ --int transaction_prepend(struct connection *conn, const char *name, -- TDB_DATA *key); -+void transaction_prepend(struct connection *conn, const char *name, -+ TDB_DATA *key); - - /* Mark the transaction as failed. This will prevent it to be committed. */ - void fail_transaction(struct transaction *trans); diff --git a/xsa422-4.16-1.patch b/xsa422-4.16-1.patch deleted file mode 100644 index 1d36873..0000000 --- a/xsa422-4.16-1.patch +++ /dev/null @@ -1,70 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Enumeration for IBPB_RET - -The IBPB_RET bit indicates that the CPU's implementation of MSR_PRED_CMD.IBPB -does flush the RSB/RAS too. - -This is part of XSA-422 / CVE-2022-23824. - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich - -diff --git a/tools/libs/light/libxl_cpuid.c b/tools/libs/light/libxl_cpuid.c -index bf6fdee360a9..691d5c6b2a68 100644 ---- a/tools/libs/light/libxl_cpuid.c -+++ b/tools/libs/light/libxl_cpuid.c -@@ -289,6 +289,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str) - {"ssb-no", 0x80000008, NA, CPUID_REG_EBX, 26, 1}, - {"psfd", 0x80000008, NA, CPUID_REG_EBX, 28, 1}, - {"btc-no", 0x80000008, NA, CPUID_REG_EBX, 29, 1}, -+ {"ibpb-ret", 0x80000008, NA, CPUID_REG_EBX, 30, 1}, - - {"nc", 0x80000008, NA, CPUID_REG_ECX, 0, 8}, - {"apicidsize", 0x80000008, NA, CPUID_REG_ECX, 12, 4}, -diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c -index fe22f5f5b68b..cd094427dd4c 100644 ---- a/tools/misc/xen-cpuid.c -+++ b/tools/misc/xen-cpuid.c -@@ -159,6 +159,7 @@ static const char *const str_e8b[32] = - [24] = "amd-ssbd", [25] = "virt-ssbd", - [26] = "ssb-no", - [28] = "psfd", [29] = "btc-no", -+ [30] = "ibpb-ret", - }; - - static const char *const str_7d0[32] = -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 0f4bad3d3abb..16a562d3a172 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -419,7 +419,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps) - * Hardware read-only information, stating immunity to certain issues, or - * suggestions of which mitigation to use. - */ -- printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", -+ printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (caps & ARCH_CAPS_RDCL_NO) ? " RDCL_NO" : "", - (caps & ARCH_CAPS_IBRS_ALL) ? " IBRS_ALL" : "", - (caps & ARCH_CAPS_RSBA) ? " RSBA" : "", -@@ -436,7 +436,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps) - (e8b & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS)) ? " STIBP_ALWAYS" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS_FAST)) ? " IBRS_FAST" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS_SAME_MODE)) ? " IBRS_SAME_MODE" : "", -- (e8b & cpufeat_mask(X86_FEATURE_BTC_NO)) ? " BTC_NO" : ""); -+ (e8b & cpufeat_mask(X86_FEATURE_BTC_NO)) ? " BTC_NO" : "", -+ (e8b & cpufeat_mask(X86_FEATURE_IBPB_RET)) ? " IBPB_RET" : ""); - - /* Hardware features which need driving to mitigate issues. */ - printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s\n", -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index e7b8167800a2..e0731221404c 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -267,6 +267,7 @@ XEN_CPUFEATURE(VIRT_SSBD, 8*32+25) /* MSR_VIRT_SPEC_CTRL.SSBD */ - XEN_CPUFEATURE(SSB_NO, 8*32+26) /*A Hardware not vulnerable to SSB */ - XEN_CPUFEATURE(PSFD, 8*32+28) /*S MSR_SPEC_CTRL.PSFD */ - XEN_CPUFEATURE(BTC_NO, 8*32+29) /*A Hardware not vulnerable to Branch Type Confusion */ -+XEN_CPUFEATURE(IBPB_RET, 8*32+30) /*A IBPB clears RSB/RAS too. */ - - /* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */ - XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A AVX512 Neural Network Instructions */ diff --git a/xsa422-4.16-2.patch b/xsa422-4.16-2.patch deleted file mode 100644 index a1a2f8d..0000000 --- a/xsa422-4.16-2.patch +++ /dev/null @@ -1,100 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Mitigate IBPB not flushing the RSB/RAS - -Introduce spec_ctrl_new_guest_context() to encapsulate all logic pertaining to -using MSR_PRED_CMD for a new guest context, even if it only has one user -presently. - -Introduce X86_BUG_IBPB_NO_RET, and use it extend spec_ctrl_new_guest_context() -with a manual fixup for hardware which mis-implements IBPB. - -This is part of XSA-422 / CVE-2022-23824. - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich - -diff --git a/xen/arch/x86/asm-macros.c b/xen/arch/x86/asm-macros.c -index 7e536b0d82f5..891d86c7655c 100644 ---- a/xen/arch/x86/asm-macros.c -+++ b/xen/arch/x86/asm-macros.c -@@ -1,2 +1,3 @@ - #include - #include -+#include -diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c -index 3fab2364be8d..3080cde62b5b 100644 ---- a/xen/arch/x86/domain.c -+++ b/xen/arch/x86/domain.c -@@ -2092,7 +2092,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next) - */ - if ( *last_id != next_id ) - { -- wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB); -+ spec_ctrl_new_guest_context(); - *last_id = next_id; - } - } -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 16a562d3a172..90d86fe5cb47 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -805,6 +805,14 @@ static void __init ibpb_calculations(void) - } - - /* -+ * AMD/Hygon CPUs to date (June 2022) don't flush the the RAS. Future -+ * CPUs are expected to enumerate IBPB_RET when this has been fixed. -+ * Until then, cover the difference with the software sequence. -+ */ -+ if ( boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_IBPB_RET) ) -+ setup_force_cpu_cap(X86_BUG_IBPB_NO_RET); -+ -+ /* - * IBPB-on-entry mitigations for Branch Type Confusion. - * - * IBPB && !BTC_NO selects all AMD/Hygon hardware, not known to be safe, -diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h -index 672c9ee22ba2..ecc1bb09505a 100644 ---- a/xen/include/asm-x86/cpufeatures.h -+++ b/xen/include/asm-x86/cpufeatures.h -@@ -49,6 +49,7 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM, X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for - #define X86_BUG_FPU_PTRS X86_BUG( 0) /* (F)X{SAVE,RSTOR} doesn't save/restore FOP/FIP/FDP. */ - #define X86_BUG_NULL_SEG X86_BUG( 1) /* NULL-ing a selector preserves the base and limit. */ - #define X86_BUG_CLFLUSH_MFENCE X86_BUG( 2) /* MFENCE needed to serialise CLFLUSH */ -+#define X86_BUG_IBPB_NO_RET X86_BUG( 3) /* IBPB doesn't flush the RSB/RAS */ - - /* Total number of capability words, inc synth and bug words. */ - #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */ -diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h -index 9403b81dc7af..6a77c3937844 100644 ---- a/xen/include/asm-x86/spec_ctrl.h -+++ b/xen/include/asm-x86/spec_ctrl.h -@@ -65,6 +65,28 @@ - void init_speculation_mitigations(void); - void spec_ctrl_init_domain(struct domain *d); - -+/* -+ * Switch to a new guest prediction context. -+ * -+ * This flushes all indirect branch predictors (BTB, RSB/RAS), so guest code -+ * which has previously run on this CPU can't attack subsequent guest code. -+ * -+ * As this flushes the RSB/RAS, it destroys the predictions of the calling -+ * context. For best performace, arrange for this to be used when we're going -+ * to jump out of the current context, e.g. with reset_stack_and_jump(). -+ * -+ * For hardware which mis-implements IBPB, fix up by flushing the RSB/RAS -+ * manually. -+ */ -+static always_inline void spec_ctrl_new_guest_context(void) -+{ -+ wrmsrl(MSR_PRED_CMD, PRED_CMD_IBPB); -+ -+ /* (ab)use alternative_input() to specify clobbers. */ -+ alternative_input("", "DO_OVERWRITE_RSB", X86_BUG_IBPB_NO_RET, -+ : "rax", "rcx"); -+} -+ - extern int8_t opt_ibpb_ctxt_switch; - extern bool opt_ssbd; - extern int8_t opt_eager_fpu; From 766c47c1cba8bfbb4561927005f40fa5aeb77825 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 20 Dec 2022 19:55:18 +0000 Subject: [PATCH 03/99] python3-setuptools BuildRequires is needed for python 3.12 --- xen.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xen.spec b/xen.spec index 989eaba..1571164 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -121,7 +121,7 @@ BuildRequires: seabios-bin ipxe-roms-qemu # for the VMX "bios" BuildRequires: dev86 %endif -BuildRequires: python3-devel ncurses-devel +BuildRequires: python3-devel ncurses-devel python3-setuptools BuildRequires: perl-interpreter perl-generators %ifarch %{ix86} x86_64 # so that x86_64 builds pick up glibc32 correctly @@ -931,6 +931,9 @@ fi %endif %changelog +* Tue Dec 20 2022 Michael Young - 4.17.0-2 +- python3-setuptools BuildRequires is needed for python 3.12 + * Tue Dec 13 2022 Michael Young - 4.17.0-1 - update to xen-4.17.0 rebase xen.fedora.systemd.patch and xen.canonicalize.patch From 8695caf85a84e6ec55e8782e754a8c86f8c14a48 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sun, 8 Jan 2023 09:35:06 +0000 Subject: [PATCH 04/99] fix clean up of init scripts if /etc/rc.d/init.d doesn't exist --- xen.spec | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/xen.spec b/xen.spec index 1571164..91a199a 100644 --- a/xen.spec +++ b/xen.spec @@ -515,10 +515,12 @@ mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d/ install -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/logrotate.d/%{name} # init scripts -rm %{buildroot}%{_sysconfdir}/rc.d/init.d/xen-watchdog -rm %{buildroot}%{_sysconfdir}/rc.d/init.d/xencommons -rm %{buildroot}%{_sysconfdir}/rc.d/init.d/xendomains -rm %{buildroot}%{_sysconfdir}/rc.d/init.d/xendriverdomain +%define initdloc %(test -d /etc/rc.d/init.d/ && echo rc.d/init.d || echo init.d ) + +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xen-watchdog +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xencommons +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xendomains +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xendriverdomain ############ create dirs in /var ############ @@ -931,7 +933,10 @@ fi %endif %changelog -* Tue Dec 20 2022 Michael Young - 4.17.0-2 +* Sun Jan 08 2023 Michael Young - 4.17.0-2 +- fix clean up of init scripts if /etc/rc.d/init.d doesn't exist + +* Tue Dec 20 2022 Michael Young - python3-setuptools BuildRequires is needed for python 3.12 * Tue Dec 13 2022 Michael Young - 4.17.0-1 From 0e3619e0576f6c78ba7dc9787b7f0678f9105625 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 17 Jan 2023 22:07:23 +0000 Subject: [PATCH 05/99] build fix for gcc13 --- xen.gcc13.fixes.patch | 10 ++++++++++ xen.spec | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 xen.gcc13.fixes.patch diff --git a/xen.gcc13.fixes.patch b/xen.gcc13.fixes.patch new file mode 100644 index 0000000..d9800e2 --- /dev/null +++ b/xen.gcc13.fixes.patch @@ -0,0 +1,10 @@ +--- xen-4.17.0/xen/common/bunzip2.c.orig 2022-12-08 18:03:08.000000000 +0000 ++++ xen-4.17.0/xen/common/bunzip2.c 2023-01-17 21:35:39.251292015 +0000 +@@ -223,6 +223,7 @@ + for (j = 0; j < groupCount; j++) { + unsigned char length[MAX_SYMBOLS], temp[MAX_HUFCODE_BITS+1]; + int minLen, maxLen, pp; ++ length[0]=0; + /* Read Huffman code lengths for each symbol. They're + stored in a way similar to mtf; record a starting + value for the first symbol, and an offset from the diff --git a/xen.spec b/xen.spec index 91a199a..bb50fcd 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -109,6 +109,7 @@ Patch41: xen.gcc9.fixes.patch Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch +Patch47: xen.gcc13.fixes.patch %if %build_qemutrad @@ -319,6 +320,7 @@ manage Xen virtual machines. %patch43 -p1 %patch45 -p1 %patch46 -p1 +%patch47 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -933,6 +935,9 @@ fi %endif %changelog +* Tue Jan 17 2023 Michael Young - 4.17.0-3 +- build fix for gcc13 + * Sun Jan 08 2023 Michael Young - 4.17.0-2 - fix clean up of init scripts if /etc/rc.d/init.d doesn't exist From e92b341446442f013d7adf749499ffd0810879b2 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 21 Jan 2023 07:19:34 +0000 Subject: [PATCH 06/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index bb50fcd..d4b1e62 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -935,6 +935,9 @@ fi %endif %changelog +* Sat Jan 21 2023 Fedora Release Engineering - 4.17.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + * Tue Jan 17 2023 Michael Young - 4.17.0-3 - build fix for gcc13 From eadd06a27e93113260ba79ab0bb67c6cac8e4703 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 24 Jan 2023 23:45:25 +0000 Subject: [PATCH 07/99] now need BuildRequires for hostname --- xen.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index d4b1e62..1e797c0 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -182,6 +182,7 @@ BuildRequires: edk2-ovmf %if %build_hyp BuildRequires: bison flex %endif +BuildRequires: hostname %description This package contains the XenD daemon and xm command line @@ -935,6 +936,9 @@ fi %endif %changelog +* Tue Jan 24 2023 Michael Young - 4.17.0-5 +- now need BuildRequires for hostname + * Sat Jan 21 2023 Fedora Release Engineering - 4.17.0-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild From d59e49c417c5589c6425dea926d226ec82a4e57b Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 25 Jan 2023 17:36:04 +0000 Subject: [PATCH 08/99] Guests can cause Xenstore crash via soft reset [XSA-425, CVE-2022-42330] --- xen.spec | 8 +++- xsa425.patch | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 xsa425.patch diff --git a/xen.spec b/xen.spec index 1e797c0..a260881 100644 --- a/xen.spec +++ b/xen.spec @@ -110,6 +110,7 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch +Patch48: xsa425.patch %if %build_qemutrad @@ -322,6 +323,7 @@ manage Xen virtual machines. %patch45 -p1 %patch46 -p1 %patch47 -p1 +%patch48 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -936,7 +938,11 @@ fi %endif %changelog -* Tue Jan 24 2023 Michael Young - 4.17.0-5 +* Wed Jan 25 2023 Michael Young - 4.17.0-5 +- Guests can cause Xenstore crash via soft reset [XSA-425, CVE-2022-42330] + (#2164520) + +* Tue Jan 24 2023 Michael Young - now need BuildRequires for hostname * Sat Jan 21 2023 Fedora Release Engineering - 4.17.0-4 diff --git a/xsa425.patch b/xsa425.patch new file mode 100644 index 0000000..b367320 --- /dev/null +++ b/xsa425.patch @@ -0,0 +1,132 @@ +From: Jason Andryuk +Subject: Revert "tools/xenstore: simplify loop handling connection I/O" + +I'm observing guest kexec trigger xenstored to abort on a double free. + +gdb output: +Program received signal SIGABRT, Aborted. +__pthread_kill_implementation (no_tid=0, signo=6, threadid=140645614258112) at ./nptl/pthread_kill.c:44 +44 ./nptl/pthread_kill.c: No such file or directory. +(gdb) bt + at ./nptl/pthread_kill.c:44 + at ./nptl/pthread_kill.c:78 + at ./nptl/pthread_kill.c:89 + at ../sysdeps/posix/raise.c:26 + at talloc.c:119 + ptr=ptr@entry=0x559fae724290) at talloc.c:232 + at xenstored_core.c:2945 +(gdb) frame 5 + at talloc.c:119 +119 TALLOC_ABORT("Bad talloc magic value - double free"); +(gdb) frame 7 + at xenstored_core.c:2945 +2945 talloc_increase_ref_count(conn); +(gdb) p conn +$1 = (struct connection *) 0x559fae724290 + +Looking at a xenstore trace, we have: +IN 0x559fae71f250 20230120 17:40:53 READ (/local/domain/3/image/device-model-dom +id ) +wrl: dom 0 1 msec 10000 credit 1000000 reserve 100 disc +ard +wrl: dom 3 1 msec 10000 credit 1000000 reserve 100 disc +ard +wrl: dom 0 0 msec 10000 credit 1000000 reserve 0 disc +ard +wrl: dom 3 0 msec 10000 credit 1000000 reserve 0 disc +ard +OUT 0x559fae71f250 20230120 17:40:53 ERROR (ENOENT ) +wrl: dom 0 1 msec 10000 credit 1000000 reserve 100 disc +ard +wrl: dom 3 1 msec 10000 credit 1000000 reserve 100 disc +ard +IN 0x559fae71f250 20230120 17:40:53 RELEASE (3 ) +DESTROY watch 0x559fae73f630 +DESTROY watch 0x559fae75ddf0 +DESTROY watch 0x559fae75ec30 +DESTROY watch 0x559fae75ea60 +DESTROY watch 0x559fae732c00 +DESTROY watch 0x559fae72cea0 +DESTROY watch 0x559fae728fc0 +DESTROY watch 0x559fae729570 +DESTROY connection 0x559fae724290 +orphaned node /local/domain/3/device/suspend/event-channel deleted +orphaned node /local/domain/3/device/vbd/51712 deleted +orphaned node /local/domain/3/device/vkbd/0 deleted +orphaned node /local/domain/3/device/vif/0 deleted +orphaned node /local/domain/3/control/shutdown deleted +orphaned node /local/domain/3/control/feature-poweroff deleted +orphaned node /local/domain/3/control/feature-reboot deleted +orphaned node /local/domain/3/control/feature-suspend deleted +orphaned node /local/domain/3/control/feature-s3 deleted +orphaned node /local/domain/3/control/feature-s4 deleted +orphaned node /local/domain/3/control/sysrq deleted +orphaned node /local/domain/3/data deleted +orphaned node /local/domain/3/drivers deleted +orphaned node /local/domain/3/feature deleted +orphaned node /local/domain/3/attr deleted +orphaned node /local/domain/3/error deleted +orphaned node /local/domain/3/console/backend-id deleted + +and no further output. + +The trace shows that DESTROY was called for connection 0x559fae724290, +but that is the same pointer (conn) main() was looping through from +connections. So it wasn't actually removed from the connections list? + +Reverting commit e8e6e42279a5 "tools/xenstore: simplify loop handling +connection I/O" fixes the abort/double free. I think the use of +list_for_each_entry_safe is incorrect. list_for_each_entry_safe makes +traversal safe for deleting the current iterator, but RELEASE/do_release +will delete some other entry in the connections list. I think the +observed abort is because list_for_each_entry has next pointing to the +deleted connection, and it is used in the subsequent iteration. + +Add a comment explaining the unsuitability of list_for_each_entry_safe. +Also notice that the old code takes a reference on next which would +prevents a use-after-free. + +This reverts commit e8e6e42279a5723239c5c40ba4c7f579a979465d. + +This is XSA-425/CVE-2022-42330. + +Fixes: e8e6e42279a5 ("tools/xenstore: simplify loop handling connection I/O") +Signed-off-by: Jason Andryuk +Reviewed-by: Juergen Gross +Reviewed-by: Julien Grall +--- + tools/xenstore/xenstored_core.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c +index 78a3edaa4e..029e3852fc 100644 +--- a/tools/xenstore/xenstored_core.c ++++ b/tools/xenstore/xenstored_core.c +@@ -2941,8 +2941,23 @@ int main(int argc, char *argv[]) + } + } + +- list_for_each_entry_safe(conn, next, &connections, list) { +- talloc_increase_ref_count(conn); ++ /* ++ * list_for_each_entry_safe is not suitable here because ++ * handle_input may delete entries besides the current one, but ++ * those may be in the temporary next which would trigger a ++ * use-after-free. list_for_each_entry_safe is only safe for ++ * deleting the current entry. ++ */ ++ next = list_entry(connections.next, typeof(*conn), list); ++ if (&next->list != &connections) ++ talloc_increase_ref_count(next); ++ while (&next->list != &connections) { ++ conn = next; ++ ++ next = list_entry(conn->list.next, ++ typeof(*conn), list); ++ if (&next->list != &connections) ++ talloc_increase_ref_count(next); + + if (conn_can_read(conn)) + handle_input(conn); +-- +2.34.1 From cef4bbf95956f16679a79e2ceb6a9f9bdfcf2153 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 14 Feb 2023 21:19:26 +0000 Subject: [PATCH 09/99] x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] --- xen.spec | 7 +++- xsa426.patch | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 xsa426.patch diff --git a/xen.spec b/xen.spec index a260881..6918277 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,6 +111,7 @@ Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch48: xsa425.patch +Patch49: xsa426.patch %if %build_qemutrad @@ -324,6 +325,7 @@ manage Xen virtual machines. %patch46 -p1 %patch47 -p1 %patch48 -p1 +%patch49 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -938,6 +940,9 @@ fi %endif %changelog +* Tue Feb 14 2023 Michael Young - 4.17.0-6 +- x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] + * Wed Jan 25 2023 Michael Young - 4.17.0-5 - Guests can cause Xenstore crash via soft reset [XSA-425, CVE-2022-42330] (#2164520) diff --git a/xsa426.patch b/xsa426.patch new file mode 100644 index 0000000..3f5f952 --- /dev/null +++ b/xsa426.patch @@ -0,0 +1,107 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Mitigate Cross-Thread Return Address Predictions + +This is XSA-426 / CVE-2022-27672 + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc +index 923910f553c5..a2ff38cdebf2 100644 +--- a/docs/misc/xen-command-line.pandoc ++++ b/docs/misc/xen-command-line.pandoc +@@ -2355,7 +2355,7 @@ guests to use. + on entry and exit. These blocks are necessary to virtualise support for + guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. + * `rsb=` offers control over whether to overwrite the Return Stack Buffer / +- Return Address Stack on entry to Xen. ++ Return Address Stack on entry to Xen and on idle. + * `md-clear=` offers control over whether to use VERW to flush + microarchitectural buffers on idle and exit from Xen. *Note: For + compatibility with development versions of this fix, `mds=` is also accepted +diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h +index 865f1109866d..da0593de8542 100644 +--- a/xen/arch/x86/include/asm/cpufeatures.h ++++ b/xen/arch/x86/include/asm/cpufeatures.h +@@ -35,7 +35,8 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM + XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ + XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ + XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ +-/* Bits 23,24 unused. */ ++/* Bits 23 unused. */ ++XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ + XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ + XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ + XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ +diff --git a/xen/arch/x86/include/asm/spec_ctrl.h b/xen/arch/x86/include/asm/spec_ctrl.h +index 6a77c3937844..391973ef6a28 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl.h ++++ b/xen/arch/x86/include/asm/spec_ctrl.h +@@ -159,6 +159,21 @@ static always_inline void spec_ctrl_enter_idle(struct cpu_info *info) + */ + alternative_input("", "verw %[sel]", X86_FEATURE_SC_VERW_IDLE, + [sel] "m" (info->verw_sel)); ++ ++ /* ++ * Cross-Thread Return Address Predictions: ++ * ++ * On vulnerable systems, the return predictions (RSB/RAS) are statically ++ * partitioned between active threads. When entering idle, our entries ++ * are re-partitioned to allow the other threads to use them. ++ * ++ * In some cases, we might still have guest entries in the RAS, so flush ++ * them before injecting them sideways to our sibling thread. ++ * ++ * (ab)use alternative_input() to specify clobbers. ++ */ ++ alternative_input("", "DO_OVERWRITE_RSB", X86_FEATURE_SC_RSB_IDLE, ++ : "rax", "rcx"); + } + + /* WARNING! `ret`, `call *`, `jmp *` not safe before this call. */ +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index a320b81947c8..e80e2a5ed1a9 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -1327,13 +1327,38 @@ void __init init_speculation_mitigations(void) + * 3) Some CPUs have RSBs which are not full width, which allow the + * attacker's entries to alias Xen addresses. + * ++ * 4) Some CPUs have RSBs which are re-partitioned based on thread ++ * idleness, which allows an attacker to inject entries into the other ++ * thread. We still active the optimisation in this case, and mitigate ++ * in the idle path which has lower overhead. ++ * + * It is safe to turn off RSB stuffing when Xen is using SMEP itself, and + * 32bit PV guests are disabled, and when the RSB is full width. + */ + BUILD_BUG_ON(RO_MPT_VIRT_START != PML4_ADDR(256)); +- if ( opt_rsb_pv == -1 && boot_cpu_has(X86_FEATURE_XEN_SMEP) && +- !opt_pv32 && rsb_is_full_width() ) +- opt_rsb_pv = 0; ++ if ( opt_rsb_pv == -1 ) ++ { ++ opt_rsb_pv = (opt_pv32 || !boot_cpu_has(X86_FEATURE_XEN_SMEP) || ++ !rsb_is_full_width()); ++ ++ /* ++ * Cross-Thread Return Address Predictions. ++ * ++ * Vulnerable systems are Zen1/Zen2 uarch, which is AMD Fam17 / Hygon ++ * Fam18, when SMT is active. ++ * ++ * To mitigate, we must flush the RSB/RAS/RAP once between entering ++ * Xen and going idle. ++ * ++ * Most cases flush on entry to Xen anyway. The one case where we ++ * don't is when using the SMEP optimisation for PV guests. Flushing ++ * before going idle is less overhead than flushing on PV entry. ++ */ ++ if ( !opt_rsb_pv && hw_smt_enabled && ++ (boot_cpu_data.x86_vendor & (X86_VENDOR_AMD|X86_VENDOR_HYGON)) && ++ (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) ) ++ setup_force_cpu_cap(X86_FEATURE_SC_RSB_IDLE); ++ } + + if ( opt_rsb_pv ) + { From 06e1d41034b24e4279b51d9f792c049ce0b13404 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 15 Feb 2023 20:11:24 +0000 Subject: [PATCH 10/99] x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] --- xen.spec | 8 +++- xsa426.patch | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 xsa426.patch diff --git a/xen.spec b/xen.spec index f2f311e..926a5d8 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.3 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,6 +111,7 @@ Patch43: xen.gcc11.fixes.patch Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch +Patch47: xsa426.patch %if %build_qemutrad @@ -323,6 +324,7 @@ manage Xen virtual machines. %patch44 -p1 %patch45 -p1 %patch46 -p1 +%patch47 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -938,6 +940,10 @@ fi %endif %changelog +* Wed Feb 15 2023 Michael Young - 4.16.3-2 +- x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] + (backported to xen-4.16) + * Mon Dec 19 2022 Michael Young - 4.16.3-1 - update to xen-4.16.3 remove or adjust patches now included or superceded upstream diff --git a/xsa426.patch b/xsa426.patch new file mode 100644 index 0000000..6df680c --- /dev/null +++ b/xsa426.patch @@ -0,0 +1,107 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Mitigate Cross-Thread Return Address Predictions + +This is XSA-426 / CVE-2022-27672 + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc +index 923910f553c5..a2ff38cdebf2 100644 +--- a/docs/misc/xen-command-line.pandoc ++++ b/docs/misc/xen-command-line.pandoc +@@ -2355,7 +2355,7 @@ guests to use. + on entry and exit. These blocks are necessary to virtualise support for + guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. + * `rsb=` offers control over whether to overwrite the Return Stack Buffer / +- Return Address Stack on entry to Xen. ++ Return Address Stack on entry to Xen and on idle. + * `md-clear=` offers control over whether to use VERW to flush + microarchitectural buffers on idle and exit from Xen. *Note: For + compatibility with development versions of this fix, `mds=` is also accepted +diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h +index 865f1109866d..da0593de8542 100644 +--- a/xen/include/asm-x86/cpufeatures.h ++++ b/xen/include/asm-x86/cpufeatures.h +@@ -35,7 +35,8 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM + XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ + XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ + XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ +-/* Bits 23,24 unused. */ ++/* Bits 23 unused. */ ++XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ + XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ + XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ + XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ +diff --git a/xen/arch/x86/include/asm/spec_ctrl.h b/xen/arch/x86/include/asm/spec_ctrl.h +index 6a77c3937844..391973ef6a28 100644 +--- a/xen/include/asm-x86/spec_ctrl.h ++++ b/xen/include/asm-x86/spec_ctrl.h +@@ -159,6 +159,21 @@ static always_inline void spec_ctrl_enter_idle(struct cpu_info *info) + */ + alternative_input("", "verw %[sel]", X86_FEATURE_SC_VERW_IDLE, + [sel] "m" (info->verw_sel)); ++ ++ /* ++ * Cross-Thread Return Address Predictions: ++ * ++ * On vulnerable systems, the return predictions (RSB/RAS) are statically ++ * partitioned between active threads. When entering idle, our entries ++ * are re-partitioned to allow the other threads to use them. ++ * ++ * In some cases, we might still have guest entries in the RAS, so flush ++ * them before injecting them sideways to our sibling thread. ++ * ++ * (ab)use alternative_input() to specify clobbers. ++ */ ++ alternative_input("", "DO_OVERWRITE_RSB", X86_FEATURE_SC_RSB_IDLE, ++ : "rax", "rcx"); + } + + /* WARNING! `ret`, `call *`, `jmp *` not safe before this call. */ +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index a320b81947c8..e80e2a5ed1a9 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -1327,13 +1327,38 @@ void __init init_speculation_mitigations(void) + * 3) Some CPUs have RSBs which are not full width, which allow the + * attacker's entries to alias Xen addresses. + * ++ * 4) Some CPUs have RSBs which are re-partitioned based on thread ++ * idleness, which allows an attacker to inject entries into the other ++ * thread. We still active the optimisation in this case, and mitigate ++ * in the idle path which has lower overhead. ++ * + * It is safe to turn off RSB stuffing when Xen is using SMEP itself, and + * 32bit PV guests are disabled, and when the RSB is full width. + */ + BUILD_BUG_ON(RO_MPT_VIRT_START != PML4_ADDR(256)); +- if ( opt_rsb_pv == -1 && boot_cpu_has(X86_FEATURE_XEN_SMEP) && +- !opt_pv32 && rsb_is_full_width() ) +- opt_rsb_pv = 0; ++ if ( opt_rsb_pv == -1 ) ++ { ++ opt_rsb_pv = (opt_pv32 || !boot_cpu_has(X86_FEATURE_XEN_SMEP) || ++ !rsb_is_full_width()); ++ ++ /* ++ * Cross-Thread Return Address Predictions. ++ * ++ * Vulnerable systems are Zen1/Zen2 uarch, which is AMD Fam17 / Hygon ++ * Fam18, when SMT is active. ++ * ++ * To mitigate, we must flush the RSB/RAS/RAP once between entering ++ * Xen and going idle. ++ * ++ * Most cases flush on entry to Xen anyway. The one case where we ++ * don't is when using the SMEP optimisation for PV guests. Flushing ++ * before going idle is less overhead than flushing on PV entry. ++ */ ++ if ( !opt_rsb_pv && hw_smt_enabled && ++ (boot_cpu_data.x86_vendor & (X86_VENDOR_AMD|X86_VENDOR_HYGON)) && ++ (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) ) ++ setup_force_cpu_cap(X86_FEATURE_SC_RSB_IDLE); ++ } + + if ( opt_rsb_pv ) + { From 04f2270c6eab29274039e79b6b268a8a09b95e95 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sat, 18 Feb 2023 08:18:51 +0000 Subject: [PATCH 11/99] use OVMF.fd from new edk2-ovmf-xen package ovmf.bin file built from edk2-ovmf package no longer supports xen (#2170930) --- xen.spec | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/xen.spec b/xen.spec index 6918277..60e5db9 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 6%{?dist} +Release: 7%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -178,9 +178,6 @@ BuildRequires: systemd-devel %ifarch armv7hl aarch64 BuildRequires: libfdt-devel %endif -%if %build_ovmf -BuildRequires: edk2-ovmf -%endif %if %build_hyp BuildRequires: bison flex %endif @@ -216,6 +213,9 @@ Recommends: qemu-system-x86-core # rom file for qemu-xen-traditional Recommends: ipxe-roms-qemu %endif +%if %build_ovmf +Recommends: edk2-ovmf-xen +%endif %description runtime This package contains the runtime programs and daemons which @@ -377,7 +377,7 @@ CONFIG_EXTRA="--enable-qemu-traditional" CONFIG_EXTRA="" %endif %if %build_ovmf -CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ovmf=%{_libexecdir}/%{name}/boot/ovmf.bin" +CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ovmf=/usr/share/edk2/xen/OVMF.fd" %endif %ifnarch armv7hl aarch64 CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ipxe=/usr/share/ipxe/10ec8139.rom" @@ -511,10 +511,6 @@ strip -s %{buildroot}/%{_libdir}/efi/xen-%{version}.efi rm -rf %{buildroot}/%{_unitdir}/oxenstored.service %endif -%if %build_ovmf -cat /usr/share/OVMF/OVMF_{VARS,CODE}.fd >%{buildroot}%{_libexecdir}/%{name}/boot/ovmf.bin -%endif - ############ fixup files in /etc ############ # logrotate @@ -794,9 +790,6 @@ fi %{_libexecdir}/%{name}/boot/xen-shim /usr/lib/debug%{_libexecdir}/xen/boot/xen-shim-syms %endif -%if %build_ovmf -%{_libexecdir}/xen/boot/ovmf.bin -%endif %if %build_stubdom %if %build_qemutrad %{_libexecdir}/xen/boot/ioemu-stubdom.gz @@ -940,6 +933,10 @@ fi %endif %changelog +* Sat Feb 18 2023 Michael Young - 4.17.0-7 +- use OVMF.fd from new edk2-ovmf-xen package as ovmf.bin file + built from edk2-ovmf package no longer supports xen (#2170930) + * Tue Feb 14 2023 Michael Young - 4.17.0-6 - x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] From 0b14ad1009fe1f04032d24f87174f1e94d5021a5 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sat, 18 Feb 2023 11:40:29 +0000 Subject: [PATCH 12/99] use OVMF.fd from new edk2-ovmf-xen package ovmf.bin file built from edk2-ovmf package no longer supports xen (#2170930) --- xen.spec | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/xen.spec b/xen.spec index 926a5d8..12671b1 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.3 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -178,9 +178,6 @@ BuildRequires: systemd-devel %ifarch armv7hl aarch64 BuildRequires: libfdt-devel %endif -%if %build_ovmf -BuildRequires: edk2-ovmf -%endif %if %build_hyp BuildRequires: bison flex %endif @@ -215,6 +212,9 @@ Recommends: qemu-system-x86-core # rom file for qemu-xen-traditional Recommends: ipxe-roms-qemu %endif +%if %build_ovmf +Recommends: edk2-ovmf-xen +%endif %description runtime This package contains the runtime programs and daemons which @@ -376,7 +376,7 @@ CONFIG_EXTRA="--enable-qemu-traditional" CONFIG_EXTRA="" %endif %if %build_ovmf -CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ovmf=%{_libexecdir}/%{name}/boot/ovmf.bin" +CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ovmf=/usr/share/edk2/xen/OVMF.fd" %endif %ifnarch armv7hl aarch64 CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ipxe=/usr/share/ipxe/10ec8139.rom" @@ -510,10 +510,6 @@ strip -s %{buildroot}/%{_libdir}/efi/xen-%{version}.efi rm -rf %{buildroot}/%{_unitdir}/oxenstored.service %endif -%if %build_ovmf -cat /usr/share/OVMF/OVMF_{VARS,CODE}.fd >%{buildroot}%{_libexecdir}/%{name}/boot/ovmf.bin -%endif - ############ fixup files in /etc ############ # logrotate @@ -792,9 +788,6 @@ fi %{_libexecdir}/%{name}/boot/xen-shim /usr/lib/debug%{_libexecdir}/xen/boot/xen-shim-syms %endif -%if %build_ovmf -%{_libexecdir}/xen/boot/ovmf.bin -%endif %if %build_stubdom %if %build_qemutrad %{_libexecdir}/xen/boot/ioemu-stubdom.gz @@ -940,6 +933,10 @@ fi %endif %changelog +* Sat Feb 18 2023 Michael Young - 4.16.3-3 +- use OVMF.fd from new edk2-ovmf-xen package as ovmf.bin file + built from edk2-ovmf package no longer supports xen (#2170930) + * Wed Feb 15 2023 Michael Young - 4.16.3-2 - x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] (backported to xen-4.16) From bf947f8f9369e91f4cc0a1f3bef036338e2eecd2 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 21 Mar 2023 17:20:08 +0000 Subject: [PATCH 13/99] 3 security issues (#2180425) x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332] x86/HVM pinned cache attributes mis-handling [XSA-428, CVE-2022-42333, CVE-2022-42334] x86: speculative vulnerability in 32bit SYSCALL path [XSA-429, CVE-2022-42331] --- xen.spec | 18 ++++++- xsa427.patch | 76 +++++++++++++++++++++++++++++ xsa428-4.17-1.patch | 40 ++++++++++++++++ xsa428-4.17-2.patch | 114 ++++++++++++++++++++++++++++++++++++++++++++ xsa429.patch | 46 ++++++++++++++++++ 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 xsa427.patch create mode 100644 xsa428-4.17-1.patch create mode 100644 xsa428-4.17-2.patch create mode 100644 xsa429.patch diff --git a/xen.spec b/xen.spec index 60e5db9..8ae2d41 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 7%{?dist} +Release: 8%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,10 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch48: xsa425.patch Patch49: xsa426.patch +Patch50: xsa427.patch +Patch51: xsa428-4.17-1.patch +Patch52: xsa428-4.17-2.patch +Patch53: xsa429.patch %if %build_qemutrad @@ -326,6 +330,10 @@ manage Xen virtual machines. %patch47 -p1 %patch48 -p1 %patch49 -p1 +%patch50 -p1 +%patch51 -p1 +%patch52 -p1 +%patch53 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -933,6 +941,14 @@ fi %endif %changelog +* Tue Mar 21 2023 Michael Young - 4.17.0-8 +- 3 security issues (#2180425) + x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332] + x86/HVM pinned cache attributes mis-handling [XSA-428, CVE-2022-42333, + CVE-2022-42334] + x86: speculative vulnerability in 32bit SYSCALL path [XSA-429, + CVE-2022-42331] + * Sat Feb 18 2023 Michael Young - 4.17.0-7 - use OVMF.fd from new edk2-ovmf-xen package as ovmf.bin file built from edk2-ovmf package no longer supports xen (#2170930) diff --git a/xsa427.patch b/xsa427.patch new file mode 100644 index 0000000..861f81d --- /dev/null +++ b/xsa427.patch @@ -0,0 +1,76 @@ +From: Jan Beulich +Subject: x86/shadow: account for log-dirty mode when pre-allocating + +Pre-allocation is intended to ensure that in the course of constructing +or updating shadows there won't be any risk of just made shadows or +shadows being acted upon can disappear under our feet. The amount of +pages pre-allocated then, however, needs to account for all possible +subsequent allocations. While the use in sh_page_fault() accounts for +all shadows which may need making, so far it didn't account for +allocations coming from log-dirty tracking (which piggybacks onto the +P2M allocation functions). + +Since shadow_prealloc() takes a count of shadows (or other data +structures) rather than a count of pages, putting the adjustment at the +call site of this function won't work very well: We simply can't express +the correct count that way in all cases. Instead take care of this in +the function itself, by "snooping" for L1 type requests. (While not +applicable right now, future new request sites of L1 tables would then +also be covered right away.) + +It is relevant to note here that pre-allocations like the one done from +shadow_alloc_p2m_page() are benign when they fall in the "scope" of an +earlier pre-alloc which already included that count: The inner call will +simply find enough pages available then; it'll bail right away. + +This is CVE-2022-42332 / XSA-427. + +Signed-off-by: Jan Beulich +Reviewed-by: Tim Deegan +--- +v2: Entirely different approach. + +--- a/xen/arch/x86/include/asm/paging.h ++++ b/xen/arch/x86/include/asm/paging.h +@@ -189,6 +189,10 @@ bool paging_mfn_is_dirty(const struct do + #define L4_LOGDIRTY_IDX(pfn) ((pfn_x(pfn) >> (PAGE_SHIFT + 3 + PAGETABLE_ORDER * 2)) & \ + (LOGDIRTY_NODE_ENTRIES-1)) + ++#define paging_logdirty_levels() \ ++ (DIV_ROUND_UP(PADDR_BITS - PAGE_SHIFT - (PAGE_SHIFT + 3), \ ++ PAGE_SHIFT - ilog2(sizeof(mfn_t))) + 1) ++ + #ifdef CONFIG_HVM + /* VRAM dirty tracking support */ + struct sh_dirty_vram { +--- a/xen/arch/x86/mm/paging.c ++++ b/xen/arch/x86/mm/paging.c +@@ -282,6 +282,7 @@ void paging_mark_pfn_dirty(struct domain + if ( unlikely(!VALID_M2P(pfn_x(pfn))) ) + return; + ++ BUILD_BUG_ON(paging_logdirty_levels() != 4); + i1 = L1_LOGDIRTY_IDX(pfn); + i2 = L2_LOGDIRTY_IDX(pfn); + i3 = L3_LOGDIRTY_IDX(pfn); +--- a/xen/arch/x86/mm/shadow/common.c ++++ b/xen/arch/x86/mm/shadow/common.c +@@ -1011,7 +1011,17 @@ bool shadow_prealloc(struct domain *d, u + if ( unlikely(d->is_dying) ) + return false; + +- ret = _shadow_prealloc(d, shadow_size(type) * count); ++ count *= shadow_size(type); ++ /* ++ * Log-dirty handling may result in allocations when populating its ++ * tracking structures. Tie this to the caller requesting space for L1 ++ * shadows. ++ */ ++ if ( paging_mode_log_dirty(d) && ++ ((SHF_L1_ANY | SHF_FL1_ANY) & (1u << type)) ) ++ count += paging_logdirty_levels(); ++ ++ ret = _shadow_prealloc(d, count); + if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) + /* + * Failing to allocate memory required for shadow usage can only result in diff --git a/xsa428-4.17-1.patch b/xsa428-4.17-1.patch new file mode 100644 index 0000000..3852f08 --- /dev/null +++ b/xsa428-4.17-1.patch @@ -0,0 +1,40 @@ +From: Jan Beulich +Subject: x86/HVM: bound number of pinned cache attribute regions + +This is exposed via DMOP, i.e. to potentially not fully privileged +device models. With that we may not permit registration of an (almost) +unbounded amount of such regions. + +This is CVE-2022-42333 / part of XSA-428. + +Reported-by: Andrew Cooper +Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/xen/arch/x86/hvm/mtrr.c ++++ b/xen/arch/x86/hvm/mtrr.c +@@ -595,6 +595,7 @@ int hvm_set_mem_pinned_cacheattr(struct + uint64_t gfn_end, uint32_t type) + { + struct hvm_mem_pinned_cacheattr_range *range; ++ unsigned int nr = 0; + int rc = 1; + + if ( !is_hvm_domain(d) ) +@@ -666,11 +667,15 @@ int hvm_set_mem_pinned_cacheattr(struct + rc = -EBUSY; + break; + } ++ ++nr; + } + rcu_read_unlock(&pinned_cacheattr_rcu_lock); + if ( rc <= 0 ) + return rc; + ++ if ( nr >= 64 /* The limit is arbitrary. */ ) ++ return -ENOSPC; ++ + range = xzalloc(struct hvm_mem_pinned_cacheattr_range); + if ( range == NULL ) + return -ENOMEM; diff --git a/xsa428-4.17-2.patch b/xsa428-4.17-2.patch new file mode 100644 index 0000000..087230a --- /dev/null +++ b/xsa428-4.17-2.patch @@ -0,0 +1,114 @@ +From: Jan Beulich +Subject: x86/HVM: serialize pinned cache attribute list manipulation + +While the RCU variants of list insertion and removal allow lockless list +traversal (with RCU just read-locked), insertions and removals still +need serializing amongst themselves. To keep things simple, use the +domain lock for this purpose. + +This is CVE-2022-42334 / part of XSA-428. + +Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") +Signed-off-by: Jan Beulich +Reviewed-by: Julien Grall + +--- a/xen/arch/x86/hvm/mtrr.c ++++ b/xen/arch/x86/hvm/mtrr.c +@@ -594,7 +594,7 @@ static void cf_check free_pinned_cacheat + int hvm_set_mem_pinned_cacheattr(struct domain *d, uint64_t gfn_start, + uint64_t gfn_end, uint32_t type) + { +- struct hvm_mem_pinned_cacheattr_range *range; ++ struct hvm_mem_pinned_cacheattr_range *range, *newr; + unsigned int nr = 0; + int rc = 1; + +@@ -608,14 +608,15 @@ int hvm_set_mem_pinned_cacheattr(struct + { + case XEN_DOMCTL_DELETE_MEM_CACHEATTR: + /* Remove the requested range. */ +- rcu_read_lock(&pinned_cacheattr_rcu_lock); +- list_for_each_entry_rcu ( range, +- &d->arch.hvm.pinned_cacheattr_ranges, +- list ) ++ domain_lock(d); ++ list_for_each_entry ( range, ++ &d->arch.hvm.pinned_cacheattr_ranges, ++ list ) + if ( range->start == gfn_start && range->end == gfn_end ) + { +- rcu_read_unlock(&pinned_cacheattr_rcu_lock); + list_del_rcu(&range->list); ++ domain_unlock(d); ++ + type = range->type; + call_rcu(&range->rcu, free_pinned_cacheattr_entry); + p2m_memory_type_changed(d); +@@ -636,7 +637,7 @@ int hvm_set_mem_pinned_cacheattr(struct + } + return 0; + } +- rcu_read_unlock(&pinned_cacheattr_rcu_lock); ++ domain_unlock(d); + return -ENOENT; + + case PAT_TYPE_UC_MINUS: +@@ -651,7 +652,10 @@ int hvm_set_mem_pinned_cacheattr(struct + return -EINVAL; + } + +- rcu_read_lock(&pinned_cacheattr_rcu_lock); ++ newr = xzalloc(struct hvm_mem_pinned_cacheattr_range); ++ ++ domain_lock(d); ++ + list_for_each_entry_rcu ( range, + &d->arch.hvm.pinned_cacheattr_ranges, + list ) +@@ -669,27 +673,34 @@ int hvm_set_mem_pinned_cacheattr(struct + } + ++nr; + } +- rcu_read_unlock(&pinned_cacheattr_rcu_lock); ++ + if ( rc <= 0 ) +- return rc; ++ /* nothing */; ++ else if ( nr >= 64 /* The limit is arbitrary. */ ) ++ rc = -ENOSPC; ++ else if ( !newr ) ++ rc = -ENOMEM; ++ else ++ { ++ newr->start = gfn_start; ++ newr->end = gfn_end; ++ newr->type = type; + +- if ( nr >= 64 /* The limit is arbitrary. */ ) +- return -ENOSPC; ++ list_add_rcu(&newr->list, &d->arch.hvm.pinned_cacheattr_ranges); ++ ++ newr = NULL; ++ rc = 0; ++ } + +- range = xzalloc(struct hvm_mem_pinned_cacheattr_range); +- if ( range == NULL ) +- return -ENOMEM; ++ domain_unlock(d); + +- range->start = gfn_start; +- range->end = gfn_end; +- range->type = type; ++ xfree(newr); + +- list_add_rcu(&range->list, &d->arch.hvm.pinned_cacheattr_ranges); + p2m_memory_type_changed(d); + if ( type != PAT_TYPE_WRBACK ) + flush_all(FLUSH_CACHE); + +- return 0; ++ return rc; + } + + static int cf_check hvm_save_mtrr_msr(struct vcpu *v, hvm_domain_context_t *h) diff --git a/xsa429.patch b/xsa429.patch new file mode 100644 index 0000000..443869f --- /dev/null +++ b/xsa429.patch @@ -0,0 +1,46 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Defer CR4_PV32_RESTORE on the cstar_enter path + +As stated (correctly) by the comment next to SPEC_CTRL_ENTRY_FROM_PV, between +the two hunks visible in the patch, RET's are not safe prior to this point. + +CR4_PV32_RESTORE hides a CALL/RET pair in certain configurations (PV32 +compiled in, SMEP or SMAP active), and the RET can be attacked with one of +several known speculative issues. + +Furthermore, CR4_PV32_RESTORE also hides a reference to the cr4_pv32_mask +global variable, which is not safe when XPTI is active before restoring Xen's +full pagetables. + +This crash has gone unnoticed because it is only AMD CPUs which permit the +SYSCALL instruction in compatibility mode, and these are not vulnerable to +Meltdown so don't activate XPTI by default. + +This is XSA-429 / CVE-2022-42331 + +Fixes: 5e7962901131 ("x86/entry: Organise the use of MSR_SPEC_CTRL at each entry/exit point") +Fixes: 5784de3e2067 ("x86: Meltdown band-aid against malicious 64-bit PV guests") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index ae012851819a..7675a59ff057 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -288,7 +288,6 @@ ENTRY(cstar_enter) + ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK + #endif + push %rax /* Guest %rsp */ +- CR4_PV32_RESTORE + movq 8(%rsp), %rax /* Restore guest %rax. */ + movq $FLAT_USER_SS32, 8(%rsp) /* Assume a 64bit domain. Compat handled lower. */ + pushq %r11 +@@ -312,6 +311,8 @@ ENTRY(cstar_enter) + .Lcstar_cr3_okay: + sti + ++ CR4_PV32_RESTORE ++ + movq STACK_CPUINFO_FIELD(current_vcpu)(%rbx), %rbx + + #ifdef CONFIG_PV32 From 85b6cafcb8d3d4e0678855a86665516d8762d971 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 21 Mar 2023 23:50:32 +0000 Subject: [PATCH 14/99] 3 security issues (#2180425) x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332] x86/HVM pinned cache attributes mis-handling [XSA-428, CVE-2022-42333, CVE-2022-42334] x86: speculative vulnerability in 32bit SYSCALL path [XSA-429, CVE-2022-42331] --- xen.spec | 18 ++++++- xsa427-4.16.patch | 74 ++++++++++++++++++++++++++++ xsa428-4.16-1.patch | 40 ++++++++++++++++ xsa428-4.16-2.patch | 114 ++++++++++++++++++++++++++++++++++++++++++++ xsa429.patch | 46 ++++++++++++++++++ 5 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 xsa427-4.16.patch create mode 100644 xsa428-4.16-1.patch create mode 100644 xsa428-4.16-2.patch create mode 100644 xsa429.patch diff --git a/xen.spec b/xen.spec index 12671b1..fcd0c28 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.3 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,10 @@ Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xsa426.patch +Patch48: xsa427-4.16.patch +Patch49: xsa428-4.16-1.patch +Patch50: xsa428-4.16-2.patch +Patch51: xsa429.patch %if %build_qemutrad @@ -325,6 +329,10 @@ manage Xen virtual machines. %patch45 -p1 %patch46 -p1 %patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 +%patch51 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -933,6 +941,14 @@ fi %endif %changelog +* Tue Mar 21 2023 Michael Young - 4.16.3-4 +- 3 security issues (#2180425) + x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332] + x86/HVM pinned cache attributes mis-handling [XSA-428, CVE-2022-42333, + CVE-2022-42334] + x86: speculative vulnerability in 32bit SYSCALL path [XSA-429, + CVE-2022-42331] + * Sat Feb 18 2023 Michael Young - 4.16.3-3 - use OVMF.fd from new edk2-ovmf-xen package as ovmf.bin file built from edk2-ovmf package no longer supports xen (#2170930) diff --git a/xsa427-4.16.patch b/xsa427-4.16.patch new file mode 100644 index 0000000..4b11fd0 --- /dev/null +++ b/xsa427-4.16.patch @@ -0,0 +1,74 @@ +From: Jan Beulich +Subject: x86/shadow: account for log-dirty mode when pre-allocating + +Pre-allocation is intended to ensure that in the course of constructing +or updating shadows there won't be any risk of just made shadows or +shadows being acted upon can disappear under our feet. The amount of +pages pre-allocated then, however, needs to account for all possible +subsequent allocations. While the use in sh_page_fault() accounts for +all shadows which may need making, so far it didn't account for +allocations coming from log-dirty tracking (which piggybacks onto the +P2M allocation functions). + +Since shadow_prealloc() takes a count of shadows (or other data +structures) rather than a count of pages, putting the adjustment at the +call site of this function won't work very well: We simply can't express +the correct count that way in all cases. Instead take care of this in +the function itself, by "snooping" for L1 type requests. (While not +applicable right now, future new request sites of L1 tables would then +also be covered right away.) + +It is relevant to note here that pre-allocations like the one done from +shadow_alloc_p2m_page() are benign when they fall in the "scope" of an +earlier pre-alloc which already included that count: The inner call will +simply find enough pages available then; it'll bail right away. + +This is CVE-2022-42332 / XSA-427. + +Signed-off-by: Jan Beulich +Reviewed-by: Tim Deegan + +--- a/xen/include/asm-x86/paging.h ++++ b/xen/include/asm-x86/paging.h +@@ -192,6 +192,10 @@ int paging_mfn_is_dirty(struct domain *d + #define L4_LOGDIRTY_IDX(pfn) ((pfn_x(pfn) >> (PAGE_SHIFT + 3 + PAGETABLE_ORDER * 2)) & \ + (LOGDIRTY_NODE_ENTRIES-1)) + ++#define paging_logdirty_levels() \ ++ (DIV_ROUND_UP(PADDR_BITS - PAGE_SHIFT - (PAGE_SHIFT + 3), \ ++ PAGE_SHIFT - ilog2(sizeof(mfn_t))) + 1) ++ + #ifdef CONFIG_HVM + /* VRAM dirty tracking support */ + struct sh_dirty_vram { +--- a/xen/arch/x86/mm/paging.c ++++ b/xen/arch/x86/mm/paging.c +@@ -280,6 +280,7 @@ void paging_mark_pfn_dirty(struct domain + if ( unlikely(!VALID_M2P(pfn_x(pfn))) ) + return; + ++ BUILD_BUG_ON(paging_logdirty_levels() != 4); + i1 = L1_LOGDIRTY_IDX(pfn); + i2 = L2_LOGDIRTY_IDX(pfn); + i3 = L3_LOGDIRTY_IDX(pfn); +--- a/xen/arch/x86/mm/shadow/common.c ++++ b/xen/arch/x86/mm/shadow/common.c +@@ -1015,7 +1015,17 @@ bool shadow_prealloc(struct domain *d, u + if ( unlikely(d->is_dying) ) + return false; + +- ret = _shadow_prealloc(d, shadow_size(type) * count); ++ count *= shadow_size(type); ++ /* ++ * Log-dirty handling may result in allocations when populating its ++ * tracking structures. Tie this to the caller requesting space for L1 ++ * shadows. ++ */ ++ if ( paging_mode_log_dirty(d) && ++ ((SHF_L1_ANY | SHF_FL1_ANY) & (1u << type)) ) ++ count += paging_logdirty_levels(); ++ ++ ret = _shadow_prealloc(d, count); + if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) + /* + * Failing to allocate memory required for shadow usage can only result in diff --git a/xsa428-4.16-1.patch b/xsa428-4.16-1.patch new file mode 100644 index 0000000..3852f08 --- /dev/null +++ b/xsa428-4.16-1.patch @@ -0,0 +1,40 @@ +From: Jan Beulich +Subject: x86/HVM: bound number of pinned cache attribute regions + +This is exposed via DMOP, i.e. to potentially not fully privileged +device models. With that we may not permit registration of an (almost) +unbounded amount of such regions. + +This is CVE-2022-42333 / part of XSA-428. + +Reported-by: Andrew Cooper +Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/xen/arch/x86/hvm/mtrr.c ++++ b/xen/arch/x86/hvm/mtrr.c +@@ -595,6 +595,7 @@ int hvm_set_mem_pinned_cacheattr(struct + uint64_t gfn_end, uint32_t type) + { + struct hvm_mem_pinned_cacheattr_range *range; ++ unsigned int nr = 0; + int rc = 1; + + if ( !is_hvm_domain(d) ) +@@ -666,11 +667,15 @@ int hvm_set_mem_pinned_cacheattr(struct + rc = -EBUSY; + break; + } ++ ++nr; + } + rcu_read_unlock(&pinned_cacheattr_rcu_lock); + if ( rc <= 0 ) + return rc; + ++ if ( nr >= 64 /* The limit is arbitrary. */ ) ++ return -ENOSPC; ++ + range = xzalloc(struct hvm_mem_pinned_cacheattr_range); + if ( range == NULL ) + return -ENOMEM; diff --git a/xsa428-4.16-2.patch b/xsa428-4.16-2.patch new file mode 100644 index 0000000..4b3f331 --- /dev/null +++ b/xsa428-4.16-2.patch @@ -0,0 +1,114 @@ +From: Jan Beulich +Subject: x86/HVM: serialize pinned cache attribute list manipulation + +While the RCU variants of list insertion and removal allow lockless list +traversal (with RCU just read-locked), insertions and removals still +need serializing amongst themselves. To keep things simple, use the +domain lock for this purpose. + +This is CVE-2022-42334 / part of XSA-428. + +Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") +Signed-off-by: Jan Beulich +Reviewed-by: Julien Grall + +--- a/xen/arch/x86/hvm/mtrr.c ++++ b/xen/arch/x86/hvm/mtrr.c +@@ -594,7 +594,7 @@ static void free_pinned_cacheattr_entry( + int hvm_set_mem_pinned_cacheattr(struct domain *d, uint64_t gfn_start, + uint64_t gfn_end, uint32_t type) + { +- struct hvm_mem_pinned_cacheattr_range *range; ++ struct hvm_mem_pinned_cacheattr_range *range, *newr; + unsigned int nr = 0; + int rc = 1; + +@@ -608,14 +608,15 @@ int hvm_set_mem_pinned_cacheattr(struct + { + case XEN_DOMCTL_DELETE_MEM_CACHEATTR: + /* Remove the requested range. */ +- rcu_read_lock(&pinned_cacheattr_rcu_lock); +- list_for_each_entry_rcu ( range, +- &d->arch.hvm.pinned_cacheattr_ranges, +- list ) ++ domain_lock(d); ++ list_for_each_entry ( range, ++ &d->arch.hvm.pinned_cacheattr_ranges, ++ list ) + if ( range->start == gfn_start && range->end == gfn_end ) + { +- rcu_read_unlock(&pinned_cacheattr_rcu_lock); + list_del_rcu(&range->list); ++ domain_unlock(d); ++ + type = range->type; + call_rcu(&range->rcu, free_pinned_cacheattr_entry); + p2m_memory_type_changed(d); +@@ -636,7 +637,7 @@ int hvm_set_mem_pinned_cacheattr(struct + } + return 0; + } +- rcu_read_unlock(&pinned_cacheattr_rcu_lock); ++ domain_unlock(d); + return -ENOENT; + + case PAT_TYPE_UC_MINUS: +@@ -651,7 +652,10 @@ int hvm_set_mem_pinned_cacheattr(struct + return -EINVAL; + } + +- rcu_read_lock(&pinned_cacheattr_rcu_lock); ++ newr = xzalloc(struct hvm_mem_pinned_cacheattr_range); ++ ++ domain_lock(d); ++ + list_for_each_entry_rcu ( range, + &d->arch.hvm.pinned_cacheattr_ranges, + list ) +@@ -669,27 +673,34 @@ int hvm_set_mem_pinned_cacheattr(struct + } + ++nr; + } +- rcu_read_unlock(&pinned_cacheattr_rcu_lock); ++ + if ( rc <= 0 ) +- return rc; ++ /* nothing */; ++ else if ( nr >= 64 /* The limit is arbitrary. */ ) ++ rc = -ENOSPC; ++ else if ( !newr ) ++ rc = -ENOMEM; ++ else ++ { ++ newr->start = gfn_start; ++ newr->end = gfn_end; ++ newr->type = type; + +- if ( nr >= 64 /* The limit is arbitrary. */ ) +- return -ENOSPC; ++ list_add_rcu(&newr->list, &d->arch.hvm.pinned_cacheattr_ranges); ++ ++ newr = NULL; ++ rc = 0; ++ } + +- range = xzalloc(struct hvm_mem_pinned_cacheattr_range); +- if ( range == NULL ) +- return -ENOMEM; ++ domain_unlock(d); + +- range->start = gfn_start; +- range->end = gfn_end; +- range->type = type; ++ xfree(newr); + +- list_add_rcu(&range->list, &d->arch.hvm.pinned_cacheattr_ranges); + p2m_memory_type_changed(d); + if ( type != PAT_TYPE_WRBACK ) + flush_all(FLUSH_CACHE); + +- return 0; ++ return rc; + } + + static int hvm_save_mtrr_msr(struct vcpu *v, hvm_domain_context_t *h) diff --git a/xsa429.patch b/xsa429.patch new file mode 100644 index 0000000..443869f --- /dev/null +++ b/xsa429.patch @@ -0,0 +1,46 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Defer CR4_PV32_RESTORE on the cstar_enter path + +As stated (correctly) by the comment next to SPEC_CTRL_ENTRY_FROM_PV, between +the two hunks visible in the patch, RET's are not safe prior to this point. + +CR4_PV32_RESTORE hides a CALL/RET pair in certain configurations (PV32 +compiled in, SMEP or SMAP active), and the RET can be attacked with one of +several known speculative issues. + +Furthermore, CR4_PV32_RESTORE also hides a reference to the cr4_pv32_mask +global variable, which is not safe when XPTI is active before restoring Xen's +full pagetables. + +This crash has gone unnoticed because it is only AMD CPUs which permit the +SYSCALL instruction in compatibility mode, and these are not vulnerable to +Meltdown so don't activate XPTI by default. + +This is XSA-429 / CVE-2022-42331 + +Fixes: 5e7962901131 ("x86/entry: Organise the use of MSR_SPEC_CTRL at each entry/exit point") +Fixes: 5784de3e2067 ("x86: Meltdown band-aid against malicious 64-bit PV guests") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index ae012851819a..7675a59ff057 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -288,7 +288,6 @@ ENTRY(cstar_enter) + ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK + #endif + push %rax /* Guest %rsp */ +- CR4_PV32_RESTORE + movq 8(%rsp), %rax /* Restore guest %rax. */ + movq $FLAT_USER_SS32, 8(%rsp) /* Assume a 64bit domain. Compat handled lower. */ + pushq %r11 +@@ -312,6 +311,8 @@ ENTRY(cstar_enter) + .Lcstar_cr3_okay: + sti + ++ CR4_PV32_RESTORE ++ + movq STACK_CPUINFO_FIELD(current_vcpu)(%rbx), %rbx + + #ifdef CONFIG_PV32 From e44f0d9ede09a9851d8f2987d5ec365df5dc7b36 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 25 Apr 2023 21:24:14 +0100 Subject: [PATCH 15/99] x86 shadow paging arbitrary pointer dereference [XSA-430, CVE-2022-42335] --- xen.spec | 7 +++++- xsa430.patch | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 xsa430.patch diff --git a/xen.spec b/xen.spec index 8ae2d41..9467ab7 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.0 -Release: 8%{?dist} +Release: 9%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -116,6 +116,7 @@ Patch50: xsa427.patch Patch51: xsa428-4.17-1.patch Patch52: xsa428-4.17-2.patch Patch53: xsa429.patch +Patch54: xsa430.patch %if %build_qemutrad @@ -334,6 +335,7 @@ manage Xen virtual machines. %patch51 -p1 %patch52 -p1 %patch53 -p1 +%patch54 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -941,6 +943,9 @@ fi %endif %changelog +* Tue Apr 25 2023 Michael Young - 4.17.0-9 +- x86 shadow paging arbitrary pointer dereference [XSA-430, CVE-2022-42335] + * Tue Mar 21 2023 Michael Young - 4.17.0-8 - 3 security issues (#2180425) x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332] diff --git a/xsa430.patch b/xsa430.patch new file mode 100644 index 0000000..4472e41 --- /dev/null +++ b/xsa430.patch @@ -0,0 +1,65 @@ +From 57b3a2ace5c4a78118b372c95f69af4f0585b48d Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Mon, 20 Mar 2023 12:08:52 +0100 +Subject: [PATCH] x86/shadow: restore dropped check in + sh_unshadow_for_p2m_change() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As a result of 241702e064604dbb3e0d9b731aa8f45be448243b the +mfn_valid() check in sh_unshadow_for_p2m_change() was lost. That +allows sh_remove_shadows() to be called with gfns that have no backing +page, causing an ASSERT to trigger in debug builds or dereferencing an +arbitrary pointer partially under guest control in non-debug builds: + +RIP: e008:[] sh_remove_shadows+0x19f/0x722 +RFLAGS: 0000000000010246 CONTEXT: hypervisor (d0v2) +[...] +Xen call trace: + [] R sh_remove_shadows+0x19f/0x722 + [] F arch/x86/mm/shadow/hvm.c#sh_unshadow_for_p2m_change+0xab/0x2b7 + [] F arch/x86/mm/p2m-pt.c#write_p2m_entry+0x19b/0x4d3 + [] F arch/x86/mm/p2m-pt.c#p2m_pt_set_entry+0x67b/0xa8e + [] F p2m_set_entry+0xcc/0x149 + [] F unmap_mmio_regions+0x17b/0x2c9 + [] F do_domctl+0x11f3/0x195e + [] F hvm_hypercall+0x5b1/0xa2d + [] F vmx_vmexit_handler+0x130f/0x1cd5 + [] F vmx_asm_vmexit_handler+0xf2/0x210 + +**************************************** +Panic on CPU 1: +Assertion 'mfn_valid(gmfn)' failed at arch/x86/mm/shadow/common.c:2203 +**************************************** + +Fix this by restoring the mfn_valid() check in +sh_unshadow_for_p2m_change(), unifying it with the rest of the checks +that are done at the start of the function. + +This is XSA-430 / CVE-2022-42335 + +Fixes: 241702e064 ('x86/shadow: slightly consolidate sh_unshadow_for_p2m_change() (part II)') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/mm/shadow/hvm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xen/arch/x86/mm/shadow/hvm.c b/xen/arch/x86/mm/shadow/hvm.c +index 88c3c16322..6de479c008 100644 +--- a/xen/arch/x86/mm/shadow/hvm.c ++++ b/xen/arch/x86/mm/shadow/hvm.c +@@ -814,7 +814,8 @@ static void cf_check sh_unshadow_for_p2m_change( + + /* Only previously present / valid entries need processing. */ + if ( !(oflags & _PAGE_PRESENT) || +- (!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) ) ++ (!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) || ++ !mfn_valid(omfn) ) + return; + + switch ( level ) +-- +2.40.0 + From d6d8d8a3933fa5df15c2511afeb7862d72e8cb22 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 2 May 2023 21:53:01 +0100 Subject: [PATCH 16/99] update to xen-4.17.1 remove patches now included upstream switch from patchN to patch N format for applying patches --- .gitignore | 2 +- sources | 2 +- xen.spec | 103 ++++++++++++++++------------------ xsa425.patch | 132 -------------------------------------------- xsa426.patch | 107 ----------------------------------- xsa427.patch | 76 ------------------------- xsa428-4.17-1.patch | 40 -------------- xsa428-4.17-2.patch | 114 -------------------------------------- xsa429.patch | 46 --------------- xsa430.patch | 65 ---------------------- 10 files changed, 49 insertions(+), 638 deletions(-) delete mode 100644 xsa425.patch delete mode 100644 xsa426.patch delete mode 100644 xsa427.patch delete mode 100644 xsa428-4.17-1.patch delete mode 100644 xsa428-4.17-2.patch delete mode 100644 xsa429.patch delete mode 100644 xsa430.patch diff --git a/.gitignore b/.gitignore index 139f059..a3ba858 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.17.0.tar.gz +/xen-4.17.1.tar.gz diff --git a/sources b/sources index 435fdc0..c81c5e2 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.17.0.tar.gz) = 8aa7c3025c81127a4f653411bc1cbe8fc27b767a2f96a2a454329a6773cb74d714ecc1ff011a8e7169c6b83b2cc5cb39c39798bd6b1178df75ce9ff00f5a1011 +SHA512 (xen-4.17.1.tar.gz) = bd98c5a2d75a0368ef312274b8e47f27db7f6b79302fd0c8b4975185e63640f98d9302e2834344acc1e97133e19f3993359dfab85aea5928008debada78c5f7a diff --git a/xen.spec b/xen.spec index 9467ab7..0c8c5de 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.17.0 -Release: 9%{?dist} +Version: 4.17.1 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -110,13 +110,6 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch -Patch48: xsa425.patch -Patch49: xsa426.patch -Patch50: xsa427.patch -Patch51: xsa428-4.17-1.patch -Patch52: xsa428-4.17-2.patch -Patch53: xsa429.patch -Patch54: xsa430.patch %if %build_qemutrad @@ -298,56 +291,49 @@ manage Xen virtual machines. %prep %setup -q -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch24 -p1 -%patch25 -p1 -%patch33 -p1 -%patch34 -p1 -%patch37 -p1 -%patch40 -p1 -%patch41 -p1 -%patch43 -p1 -%patch45 -p1 -%patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 -%patch54 -p1 +%patch 4 -p1 +%patch 5 -p1 +%patch 6 -p1 +%patch 7 -p1 +%patch 8 -p1 +%patch 9 -p1 +%patch 10 -p1 +%patch 11 -p1 +%patch 12 -p1 +%patch 13 -p1 +%patch 14 -p1 +%patch 15 -p1 +%patch 16 -p1 +%patch 17 -p1 +%patch 18 -p1 +%patch 19 -p1 +%patch 20 -p1 +%patch 21 -p1 +%patch 22 -p1 +%patch 23 -p1 +%patch 24 -p1 +%patch 25 -p1 +%patch 33 -p1 +%patch 34 -p1 +%patch 37 -p1 +%patch 40 -p1 +%patch 41 -p1 +%patch 43 -p1 +%patch 45 -p1 +%patch 46 -p1 +%patch 47 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional -%patch27 -p1 -%patch29 -p1 -%patch30 -p1 -%patch31 -p1 -%patch32 -p1 -%patch35 -p1 -%patch36 -p1 -%patch38 -p1 -%patch39 -p1 +%patch 27 -p1 +%patch 29 -p1 +%patch 30 -p1 +%patch 31 -p1 +%patch 32 -p1 +%patch 35 -p1 +%patch 36 -p1 +%patch 38 -p1 +%patch 39 -p1 popd # qemu-xen patches @@ -943,6 +929,11 @@ fi %endif %changelog +* Tue May 02 2023 Michael Young - 4.17.1-1 +- update to xen-4.17.1 + remove patches now included upstream + switch from patchN to patch N format for applying patches + * Tue Apr 25 2023 Michael Young - 4.17.0-9 - x86 shadow paging arbitrary pointer dereference [XSA-430, CVE-2022-42335] diff --git a/xsa425.patch b/xsa425.patch deleted file mode 100644 index b367320..0000000 --- a/xsa425.patch +++ /dev/null @@ -1,132 +0,0 @@ -From: Jason Andryuk -Subject: Revert "tools/xenstore: simplify loop handling connection I/O" - -I'm observing guest kexec trigger xenstored to abort on a double free. - -gdb output: -Program received signal SIGABRT, Aborted. -__pthread_kill_implementation (no_tid=0, signo=6, threadid=140645614258112) at ./nptl/pthread_kill.c:44 -44 ./nptl/pthread_kill.c: No such file or directory. -(gdb) bt - at ./nptl/pthread_kill.c:44 - at ./nptl/pthread_kill.c:78 - at ./nptl/pthread_kill.c:89 - at ../sysdeps/posix/raise.c:26 - at talloc.c:119 - ptr=ptr@entry=0x559fae724290) at talloc.c:232 - at xenstored_core.c:2945 -(gdb) frame 5 - at talloc.c:119 -119 TALLOC_ABORT("Bad talloc magic value - double free"); -(gdb) frame 7 - at xenstored_core.c:2945 -2945 talloc_increase_ref_count(conn); -(gdb) p conn -$1 = (struct connection *) 0x559fae724290 - -Looking at a xenstore trace, we have: -IN 0x559fae71f250 20230120 17:40:53 READ (/local/domain/3/image/device-model-dom -id ) -wrl: dom 0 1 msec 10000 credit 1000000 reserve 100 disc -ard -wrl: dom 3 1 msec 10000 credit 1000000 reserve 100 disc -ard -wrl: dom 0 0 msec 10000 credit 1000000 reserve 0 disc -ard -wrl: dom 3 0 msec 10000 credit 1000000 reserve 0 disc -ard -OUT 0x559fae71f250 20230120 17:40:53 ERROR (ENOENT ) -wrl: dom 0 1 msec 10000 credit 1000000 reserve 100 disc -ard -wrl: dom 3 1 msec 10000 credit 1000000 reserve 100 disc -ard -IN 0x559fae71f250 20230120 17:40:53 RELEASE (3 ) -DESTROY watch 0x559fae73f630 -DESTROY watch 0x559fae75ddf0 -DESTROY watch 0x559fae75ec30 -DESTROY watch 0x559fae75ea60 -DESTROY watch 0x559fae732c00 -DESTROY watch 0x559fae72cea0 -DESTROY watch 0x559fae728fc0 -DESTROY watch 0x559fae729570 -DESTROY connection 0x559fae724290 -orphaned node /local/domain/3/device/suspend/event-channel deleted -orphaned node /local/domain/3/device/vbd/51712 deleted -orphaned node /local/domain/3/device/vkbd/0 deleted -orphaned node /local/domain/3/device/vif/0 deleted -orphaned node /local/domain/3/control/shutdown deleted -orphaned node /local/domain/3/control/feature-poweroff deleted -orphaned node /local/domain/3/control/feature-reboot deleted -orphaned node /local/domain/3/control/feature-suspend deleted -orphaned node /local/domain/3/control/feature-s3 deleted -orphaned node /local/domain/3/control/feature-s4 deleted -orphaned node /local/domain/3/control/sysrq deleted -orphaned node /local/domain/3/data deleted -orphaned node /local/domain/3/drivers deleted -orphaned node /local/domain/3/feature deleted -orphaned node /local/domain/3/attr deleted -orphaned node /local/domain/3/error deleted -orphaned node /local/domain/3/console/backend-id deleted - -and no further output. - -The trace shows that DESTROY was called for connection 0x559fae724290, -but that is the same pointer (conn) main() was looping through from -connections. So it wasn't actually removed from the connections list? - -Reverting commit e8e6e42279a5 "tools/xenstore: simplify loop handling -connection I/O" fixes the abort/double free. I think the use of -list_for_each_entry_safe is incorrect. list_for_each_entry_safe makes -traversal safe for deleting the current iterator, but RELEASE/do_release -will delete some other entry in the connections list. I think the -observed abort is because list_for_each_entry has next pointing to the -deleted connection, and it is used in the subsequent iteration. - -Add a comment explaining the unsuitability of list_for_each_entry_safe. -Also notice that the old code takes a reference on next which would -prevents a use-after-free. - -This reverts commit e8e6e42279a5723239c5c40ba4c7f579a979465d. - -This is XSA-425/CVE-2022-42330. - -Fixes: e8e6e42279a5 ("tools/xenstore: simplify loop handling connection I/O") -Signed-off-by: Jason Andryuk -Reviewed-by: Juergen Gross -Reviewed-by: Julien Grall ---- - tools/xenstore/xenstored_core.c | 19 +++++++++++++++++-- - 1 file changed, 17 insertions(+), 2 deletions(-) - -diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c -index 78a3edaa4e..029e3852fc 100644 ---- a/tools/xenstore/xenstored_core.c -+++ b/tools/xenstore/xenstored_core.c -@@ -2941,8 +2941,23 @@ int main(int argc, char *argv[]) - } - } - -- list_for_each_entry_safe(conn, next, &connections, list) { -- talloc_increase_ref_count(conn); -+ /* -+ * list_for_each_entry_safe is not suitable here because -+ * handle_input may delete entries besides the current one, but -+ * those may be in the temporary next which would trigger a -+ * use-after-free. list_for_each_entry_safe is only safe for -+ * deleting the current entry. -+ */ -+ next = list_entry(connections.next, typeof(*conn), list); -+ if (&next->list != &connections) -+ talloc_increase_ref_count(next); -+ while (&next->list != &connections) { -+ conn = next; -+ -+ next = list_entry(conn->list.next, -+ typeof(*conn), list); -+ if (&next->list != &connections) -+ talloc_increase_ref_count(next); - - if (conn_can_read(conn)) - handle_input(conn); --- -2.34.1 diff --git a/xsa426.patch b/xsa426.patch deleted file mode 100644 index 3f5f952..0000000 --- a/xsa426.patch +++ /dev/null @@ -1,107 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Mitigate Cross-Thread Return Address Predictions - -This is XSA-426 / CVE-2022-27672 - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc -index 923910f553c5..a2ff38cdebf2 100644 ---- a/docs/misc/xen-command-line.pandoc -+++ b/docs/misc/xen-command-line.pandoc -@@ -2355,7 +2355,7 @@ guests to use. - on entry and exit. These blocks are necessary to virtualise support for - guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. - * `rsb=` offers control over whether to overwrite the Return Stack Buffer / -- Return Address Stack on entry to Xen. -+ Return Address Stack on entry to Xen and on idle. - * `md-clear=` offers control over whether to use VERW to flush - microarchitectural buffers on idle and exit from Xen. *Note: For - compatibility with development versions of this fix, `mds=` is also accepted -diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h -index 865f1109866d..da0593de8542 100644 ---- a/xen/arch/x86/include/asm/cpufeatures.h -+++ b/xen/arch/x86/include/asm/cpufeatures.h -@@ -35,7 +35,8 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM - XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ - XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ - XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ --/* Bits 23,24 unused. */ -+/* Bits 23 unused. */ -+XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ - XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ - XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ - XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ -diff --git a/xen/arch/x86/include/asm/spec_ctrl.h b/xen/arch/x86/include/asm/spec_ctrl.h -index 6a77c3937844..391973ef6a28 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl.h -+++ b/xen/arch/x86/include/asm/spec_ctrl.h -@@ -159,6 +159,21 @@ static always_inline void spec_ctrl_enter_idle(struct cpu_info *info) - */ - alternative_input("", "verw %[sel]", X86_FEATURE_SC_VERW_IDLE, - [sel] "m" (info->verw_sel)); -+ -+ /* -+ * Cross-Thread Return Address Predictions: -+ * -+ * On vulnerable systems, the return predictions (RSB/RAS) are statically -+ * partitioned between active threads. When entering idle, our entries -+ * are re-partitioned to allow the other threads to use them. -+ * -+ * In some cases, we might still have guest entries in the RAS, so flush -+ * them before injecting them sideways to our sibling thread. -+ * -+ * (ab)use alternative_input() to specify clobbers. -+ */ -+ alternative_input("", "DO_OVERWRITE_RSB", X86_FEATURE_SC_RSB_IDLE, -+ : "rax", "rcx"); - } - - /* WARNING! `ret`, `call *`, `jmp *` not safe before this call. */ -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index a320b81947c8..e80e2a5ed1a9 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -1327,13 +1327,38 @@ void __init init_speculation_mitigations(void) - * 3) Some CPUs have RSBs which are not full width, which allow the - * attacker's entries to alias Xen addresses. - * -+ * 4) Some CPUs have RSBs which are re-partitioned based on thread -+ * idleness, which allows an attacker to inject entries into the other -+ * thread. We still active the optimisation in this case, and mitigate -+ * in the idle path which has lower overhead. -+ * - * It is safe to turn off RSB stuffing when Xen is using SMEP itself, and - * 32bit PV guests are disabled, and when the RSB is full width. - */ - BUILD_BUG_ON(RO_MPT_VIRT_START != PML4_ADDR(256)); -- if ( opt_rsb_pv == -1 && boot_cpu_has(X86_FEATURE_XEN_SMEP) && -- !opt_pv32 && rsb_is_full_width() ) -- opt_rsb_pv = 0; -+ if ( opt_rsb_pv == -1 ) -+ { -+ opt_rsb_pv = (opt_pv32 || !boot_cpu_has(X86_FEATURE_XEN_SMEP) || -+ !rsb_is_full_width()); -+ -+ /* -+ * Cross-Thread Return Address Predictions. -+ * -+ * Vulnerable systems are Zen1/Zen2 uarch, which is AMD Fam17 / Hygon -+ * Fam18, when SMT is active. -+ * -+ * To mitigate, we must flush the RSB/RAS/RAP once between entering -+ * Xen and going idle. -+ * -+ * Most cases flush on entry to Xen anyway. The one case where we -+ * don't is when using the SMEP optimisation for PV guests. Flushing -+ * before going idle is less overhead than flushing on PV entry. -+ */ -+ if ( !opt_rsb_pv && hw_smt_enabled && -+ (boot_cpu_data.x86_vendor & (X86_VENDOR_AMD|X86_VENDOR_HYGON)) && -+ (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) ) -+ setup_force_cpu_cap(X86_FEATURE_SC_RSB_IDLE); -+ } - - if ( opt_rsb_pv ) - { diff --git a/xsa427.patch b/xsa427.patch deleted file mode 100644 index 861f81d..0000000 --- a/xsa427.patch +++ /dev/null @@ -1,76 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: account for log-dirty mode when pre-allocating - -Pre-allocation is intended to ensure that in the course of constructing -or updating shadows there won't be any risk of just made shadows or -shadows being acted upon can disappear under our feet. The amount of -pages pre-allocated then, however, needs to account for all possible -subsequent allocations. While the use in sh_page_fault() accounts for -all shadows which may need making, so far it didn't account for -allocations coming from log-dirty tracking (which piggybacks onto the -P2M allocation functions). - -Since shadow_prealloc() takes a count of shadows (or other data -structures) rather than a count of pages, putting the adjustment at the -call site of this function won't work very well: We simply can't express -the correct count that way in all cases. Instead take care of this in -the function itself, by "snooping" for L1 type requests. (While not -applicable right now, future new request sites of L1 tables would then -also be covered right away.) - -It is relevant to note here that pre-allocations like the one done from -shadow_alloc_p2m_page() are benign when they fall in the "scope" of an -earlier pre-alloc which already included that count: The inner call will -simply find enough pages available then; it'll bail right away. - -This is CVE-2022-42332 / XSA-427. - -Signed-off-by: Jan Beulich -Reviewed-by: Tim Deegan ---- -v2: Entirely different approach. - ---- a/xen/arch/x86/include/asm/paging.h -+++ b/xen/arch/x86/include/asm/paging.h -@@ -189,6 +189,10 @@ bool paging_mfn_is_dirty(const struct do - #define L4_LOGDIRTY_IDX(pfn) ((pfn_x(pfn) >> (PAGE_SHIFT + 3 + PAGETABLE_ORDER * 2)) & \ - (LOGDIRTY_NODE_ENTRIES-1)) - -+#define paging_logdirty_levels() \ -+ (DIV_ROUND_UP(PADDR_BITS - PAGE_SHIFT - (PAGE_SHIFT + 3), \ -+ PAGE_SHIFT - ilog2(sizeof(mfn_t))) + 1) -+ - #ifdef CONFIG_HVM - /* VRAM dirty tracking support */ - struct sh_dirty_vram { ---- a/xen/arch/x86/mm/paging.c -+++ b/xen/arch/x86/mm/paging.c -@@ -282,6 +282,7 @@ void paging_mark_pfn_dirty(struct domain - if ( unlikely(!VALID_M2P(pfn_x(pfn))) ) - return; - -+ BUILD_BUG_ON(paging_logdirty_levels() != 4); - i1 = L1_LOGDIRTY_IDX(pfn); - i2 = L2_LOGDIRTY_IDX(pfn); - i3 = L3_LOGDIRTY_IDX(pfn); ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -1011,7 +1011,17 @@ bool shadow_prealloc(struct domain *d, u - if ( unlikely(d->is_dying) ) - return false; - -- ret = _shadow_prealloc(d, shadow_size(type) * count); -+ count *= shadow_size(type); -+ /* -+ * Log-dirty handling may result in allocations when populating its -+ * tracking structures. Tie this to the caller requesting space for L1 -+ * shadows. -+ */ -+ if ( paging_mode_log_dirty(d) && -+ ((SHF_L1_ANY | SHF_FL1_ANY) & (1u << type)) ) -+ count += paging_logdirty_levels(); -+ -+ ret = _shadow_prealloc(d, count); - if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) - /* - * Failing to allocate memory required for shadow usage can only result in diff --git a/xsa428-4.17-1.patch b/xsa428-4.17-1.patch deleted file mode 100644 index 3852f08..0000000 --- a/xsa428-4.17-1.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Jan Beulich -Subject: x86/HVM: bound number of pinned cache attribute regions - -This is exposed via DMOP, i.e. to potentially not fully privileged -device models. With that we may not permit registration of an (almost) -unbounded amount of such regions. - -This is CVE-2022-42333 / part of XSA-428. - -Reported-by: Andrew Cooper -Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") -Signed-off-by: Jan Beulich -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/hvm/mtrr.c -+++ b/xen/arch/x86/hvm/mtrr.c -@@ -595,6 +595,7 @@ int hvm_set_mem_pinned_cacheattr(struct - uint64_t gfn_end, uint32_t type) - { - struct hvm_mem_pinned_cacheattr_range *range; -+ unsigned int nr = 0; - int rc = 1; - - if ( !is_hvm_domain(d) ) -@@ -666,11 +667,15 @@ int hvm_set_mem_pinned_cacheattr(struct - rc = -EBUSY; - break; - } -+ ++nr; - } - rcu_read_unlock(&pinned_cacheattr_rcu_lock); - if ( rc <= 0 ) - return rc; - -+ if ( nr >= 64 /* The limit is arbitrary. */ ) -+ return -ENOSPC; -+ - range = xzalloc(struct hvm_mem_pinned_cacheattr_range); - if ( range == NULL ) - return -ENOMEM; diff --git a/xsa428-4.17-2.patch b/xsa428-4.17-2.patch deleted file mode 100644 index 087230a..0000000 --- a/xsa428-4.17-2.patch +++ /dev/null @@ -1,114 +0,0 @@ -From: Jan Beulich -Subject: x86/HVM: serialize pinned cache attribute list manipulation - -While the RCU variants of list insertion and removal allow lockless list -traversal (with RCU just read-locked), insertions and removals still -need serializing amongst themselves. To keep things simple, use the -domain lock for this purpose. - -This is CVE-2022-42334 / part of XSA-428. - -Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") -Signed-off-by: Jan Beulich -Reviewed-by: Julien Grall - ---- a/xen/arch/x86/hvm/mtrr.c -+++ b/xen/arch/x86/hvm/mtrr.c -@@ -594,7 +594,7 @@ static void cf_check free_pinned_cacheat - int hvm_set_mem_pinned_cacheattr(struct domain *d, uint64_t gfn_start, - uint64_t gfn_end, uint32_t type) - { -- struct hvm_mem_pinned_cacheattr_range *range; -+ struct hvm_mem_pinned_cacheattr_range *range, *newr; - unsigned int nr = 0; - int rc = 1; - -@@ -608,14 +608,15 @@ int hvm_set_mem_pinned_cacheattr(struct - { - case XEN_DOMCTL_DELETE_MEM_CACHEATTR: - /* Remove the requested range. */ -- rcu_read_lock(&pinned_cacheattr_rcu_lock); -- list_for_each_entry_rcu ( range, -- &d->arch.hvm.pinned_cacheattr_ranges, -- list ) -+ domain_lock(d); -+ list_for_each_entry ( range, -+ &d->arch.hvm.pinned_cacheattr_ranges, -+ list ) - if ( range->start == gfn_start && range->end == gfn_end ) - { -- rcu_read_unlock(&pinned_cacheattr_rcu_lock); - list_del_rcu(&range->list); -+ domain_unlock(d); -+ - type = range->type; - call_rcu(&range->rcu, free_pinned_cacheattr_entry); - p2m_memory_type_changed(d); -@@ -636,7 +637,7 @@ int hvm_set_mem_pinned_cacheattr(struct - } - return 0; - } -- rcu_read_unlock(&pinned_cacheattr_rcu_lock); -+ domain_unlock(d); - return -ENOENT; - - case PAT_TYPE_UC_MINUS: -@@ -651,7 +652,10 @@ int hvm_set_mem_pinned_cacheattr(struct - return -EINVAL; - } - -- rcu_read_lock(&pinned_cacheattr_rcu_lock); -+ newr = xzalloc(struct hvm_mem_pinned_cacheattr_range); -+ -+ domain_lock(d); -+ - list_for_each_entry_rcu ( range, - &d->arch.hvm.pinned_cacheattr_ranges, - list ) -@@ -669,27 +673,34 @@ int hvm_set_mem_pinned_cacheattr(struct - } - ++nr; - } -- rcu_read_unlock(&pinned_cacheattr_rcu_lock); -+ - if ( rc <= 0 ) -- return rc; -+ /* nothing */; -+ else if ( nr >= 64 /* The limit is arbitrary. */ ) -+ rc = -ENOSPC; -+ else if ( !newr ) -+ rc = -ENOMEM; -+ else -+ { -+ newr->start = gfn_start; -+ newr->end = gfn_end; -+ newr->type = type; - -- if ( nr >= 64 /* The limit is arbitrary. */ ) -- return -ENOSPC; -+ list_add_rcu(&newr->list, &d->arch.hvm.pinned_cacheattr_ranges); -+ -+ newr = NULL; -+ rc = 0; -+ } - -- range = xzalloc(struct hvm_mem_pinned_cacheattr_range); -- if ( range == NULL ) -- return -ENOMEM; -+ domain_unlock(d); - -- range->start = gfn_start; -- range->end = gfn_end; -- range->type = type; -+ xfree(newr); - -- list_add_rcu(&range->list, &d->arch.hvm.pinned_cacheattr_ranges); - p2m_memory_type_changed(d); - if ( type != PAT_TYPE_WRBACK ) - flush_all(FLUSH_CACHE); - -- return 0; -+ return rc; - } - - static int cf_check hvm_save_mtrr_msr(struct vcpu *v, hvm_domain_context_t *h) diff --git a/xsa429.patch b/xsa429.patch deleted file mode 100644 index 443869f..0000000 --- a/xsa429.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Defer CR4_PV32_RESTORE on the cstar_enter path - -As stated (correctly) by the comment next to SPEC_CTRL_ENTRY_FROM_PV, between -the two hunks visible in the patch, RET's are not safe prior to this point. - -CR4_PV32_RESTORE hides a CALL/RET pair in certain configurations (PV32 -compiled in, SMEP or SMAP active), and the RET can be attacked with one of -several known speculative issues. - -Furthermore, CR4_PV32_RESTORE also hides a reference to the cr4_pv32_mask -global variable, which is not safe when XPTI is active before restoring Xen's -full pagetables. - -This crash has gone unnoticed because it is only AMD CPUs which permit the -SYSCALL instruction in compatibility mode, and these are not vulnerable to -Meltdown so don't activate XPTI by default. - -This is XSA-429 / CVE-2022-42331 - -Fixes: 5e7962901131 ("x86/entry: Organise the use of MSR_SPEC_CTRL at each entry/exit point") -Fixes: 5784de3e2067 ("x86: Meltdown band-aid against malicious 64-bit PV guests") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index ae012851819a..7675a59ff057 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -288,7 +288,6 @@ ENTRY(cstar_enter) - ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK - #endif - push %rax /* Guest %rsp */ -- CR4_PV32_RESTORE - movq 8(%rsp), %rax /* Restore guest %rax. */ - movq $FLAT_USER_SS32, 8(%rsp) /* Assume a 64bit domain. Compat handled lower. */ - pushq %r11 -@@ -312,6 +311,8 @@ ENTRY(cstar_enter) - .Lcstar_cr3_okay: - sti - -+ CR4_PV32_RESTORE -+ - movq STACK_CPUINFO_FIELD(current_vcpu)(%rbx), %rbx - - #ifdef CONFIG_PV32 diff --git a/xsa430.patch b/xsa430.patch deleted file mode 100644 index 4472e41..0000000 --- a/xsa430.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 57b3a2ace5c4a78118b372c95f69af4f0585b48d Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Mon, 20 Mar 2023 12:08:52 +0100 -Subject: [PATCH] x86/shadow: restore dropped check in - sh_unshadow_for_p2m_change() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As a result of 241702e064604dbb3e0d9b731aa8f45be448243b the -mfn_valid() check in sh_unshadow_for_p2m_change() was lost. That -allows sh_remove_shadows() to be called with gfns that have no backing -page, causing an ASSERT to trigger in debug builds or dereferencing an -arbitrary pointer partially under guest control in non-debug builds: - -RIP: e008:[] sh_remove_shadows+0x19f/0x722 -RFLAGS: 0000000000010246 CONTEXT: hypervisor (d0v2) -[...] -Xen call trace: - [] R sh_remove_shadows+0x19f/0x722 - [] F arch/x86/mm/shadow/hvm.c#sh_unshadow_for_p2m_change+0xab/0x2b7 - [] F arch/x86/mm/p2m-pt.c#write_p2m_entry+0x19b/0x4d3 - [] F arch/x86/mm/p2m-pt.c#p2m_pt_set_entry+0x67b/0xa8e - [] F p2m_set_entry+0xcc/0x149 - [] F unmap_mmio_regions+0x17b/0x2c9 - [] F do_domctl+0x11f3/0x195e - [] F hvm_hypercall+0x5b1/0xa2d - [] F vmx_vmexit_handler+0x130f/0x1cd5 - [] F vmx_asm_vmexit_handler+0xf2/0x210 - -**************************************** -Panic on CPU 1: -Assertion 'mfn_valid(gmfn)' failed at arch/x86/mm/shadow/common.c:2203 -**************************************** - -Fix this by restoring the mfn_valid() check in -sh_unshadow_for_p2m_change(), unifying it with the rest of the checks -that are done at the start of the function. - -This is XSA-430 / CVE-2022-42335 - -Fixes: 241702e064 ('x86/shadow: slightly consolidate sh_unshadow_for_p2m_change() (part II)') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/mm/shadow/hvm.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/xen/arch/x86/mm/shadow/hvm.c b/xen/arch/x86/mm/shadow/hvm.c -index 88c3c16322..6de479c008 100644 ---- a/xen/arch/x86/mm/shadow/hvm.c -+++ b/xen/arch/x86/mm/shadow/hvm.c -@@ -814,7 +814,8 @@ static void cf_check sh_unshadow_for_p2m_change( - - /* Only previously present / valid entries need processing. */ - if ( !(oflags & _PAGE_PRESENT) || -- (!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) ) -+ (!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) || -+ !mfn_valid(omfn) ) - return; - - switch ( level ) --- -2.40.0 - From 01f64a0113e2a6d60c52fa92778ce0eff6b0e62c Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 2 May 2023 22:54:41 +0100 Subject: [PATCH 17/99] update to xen-4.16.4 remove patches now included upstream --- .gitignore | 2 +- sources | 2 +- xen.spec | 18 +++---- xsa426.patch | 107 ----------------------------------------- xsa427-4.16.patch | 74 ---------------------------- xsa428-4.16-1.patch | 40 ---------------- xsa428-4.16-2.patch | 114 -------------------------------------------- xsa429.patch | 46 ------------------ 8 files changed, 8 insertions(+), 395 deletions(-) delete mode 100644 xsa426.patch delete mode 100644 xsa427-4.16.patch delete mode 100644 xsa428-4.16-1.patch delete mode 100644 xsa428-4.16-2.patch delete mode 100644 xsa429.patch diff --git a/.gitignore b/.gitignore index 3d1112b..d252877 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.16.3.tar.gz +/xen-4.16.4.tar.gz diff --git a/sources b/sources index b3ba74d..55e15c7 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.16.3.tar.gz) = b8cbd6f95681de5f824ada2d3cbe0653a38514a18df0dafcf811fb255219c7abec96f46217bdb0c83e1119f685da9a6af7194eeaa94f1cc3c892702782133b4f +SHA512 (xen-4.16.4.tar.gz) = 1b5a167a9f5537b5311ef1cb56e0e6ffda0e4e569ef0534e47b4f4a528067bda46fb58b2a01abc02e8c38b2b70207fb201a5d4d10274fba70135eaa8e318e055 diff --git a/xen.spec b/xen.spec index fcd0c28..aba2fce 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.16.3 -Release: 4%{?dist} +Version: 4.16.4 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,11 +111,6 @@ Patch43: xen.gcc11.fixes.patch Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch -Patch47: xsa426.patch -Patch48: xsa427-4.16.patch -Patch49: xsa428-4.16-1.patch -Patch50: xsa428-4.16-2.patch -Patch51: xsa429.patch %if %build_qemutrad @@ -328,11 +323,6 @@ manage Xen virtual machines. %patch44 -p1 %patch45 -p1 %patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -941,6 +931,10 @@ fi %endif %changelog +* Tue May 02 2023 Michael Young - 4.16.4-1 +- update to xen-4.16.4 + remove patches now included upstream + * Tue Mar 21 2023 Michael Young - 4.16.3-4 - 3 security issues (#2180425) x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332] diff --git a/xsa426.patch b/xsa426.patch deleted file mode 100644 index 6df680c..0000000 --- a/xsa426.patch +++ /dev/null @@ -1,107 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Mitigate Cross-Thread Return Address Predictions - -This is XSA-426 / CVE-2022-27672 - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc -index 923910f553c5..a2ff38cdebf2 100644 ---- a/docs/misc/xen-command-line.pandoc -+++ b/docs/misc/xen-command-line.pandoc -@@ -2355,7 +2355,7 @@ guests to use. - on entry and exit. These blocks are necessary to virtualise support for - guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. - * `rsb=` offers control over whether to overwrite the Return Stack Buffer / -- Return Address Stack on entry to Xen. -+ Return Address Stack on entry to Xen and on idle. - * `md-clear=` offers control over whether to use VERW to flush - microarchitectural buffers on idle and exit from Xen. *Note: For - compatibility with development versions of this fix, `mds=` is also accepted -diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h -index 865f1109866d..da0593de8542 100644 ---- a/xen/include/asm-x86/cpufeatures.h -+++ b/xen/include/asm-x86/cpufeatures.h -@@ -35,7 +35,8 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM - XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ - XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ - XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ --/* Bits 23,24 unused. */ -+/* Bits 23 unused. */ -+XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ - XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ - XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ - XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ -diff --git a/xen/arch/x86/include/asm/spec_ctrl.h b/xen/arch/x86/include/asm/spec_ctrl.h -index 6a77c3937844..391973ef6a28 100644 ---- a/xen/include/asm-x86/spec_ctrl.h -+++ b/xen/include/asm-x86/spec_ctrl.h -@@ -159,6 +159,21 @@ static always_inline void spec_ctrl_enter_idle(struct cpu_info *info) - */ - alternative_input("", "verw %[sel]", X86_FEATURE_SC_VERW_IDLE, - [sel] "m" (info->verw_sel)); -+ -+ /* -+ * Cross-Thread Return Address Predictions: -+ * -+ * On vulnerable systems, the return predictions (RSB/RAS) are statically -+ * partitioned between active threads. When entering idle, our entries -+ * are re-partitioned to allow the other threads to use them. -+ * -+ * In some cases, we might still have guest entries in the RAS, so flush -+ * them before injecting them sideways to our sibling thread. -+ * -+ * (ab)use alternative_input() to specify clobbers. -+ */ -+ alternative_input("", "DO_OVERWRITE_RSB", X86_FEATURE_SC_RSB_IDLE, -+ : "rax", "rcx"); - } - - /* WARNING! `ret`, `call *`, `jmp *` not safe before this call. */ -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index a320b81947c8..e80e2a5ed1a9 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -1327,13 +1327,38 @@ void __init init_speculation_mitigations(void) - * 3) Some CPUs have RSBs which are not full width, which allow the - * attacker's entries to alias Xen addresses. - * -+ * 4) Some CPUs have RSBs which are re-partitioned based on thread -+ * idleness, which allows an attacker to inject entries into the other -+ * thread. We still active the optimisation in this case, and mitigate -+ * in the idle path which has lower overhead. -+ * - * It is safe to turn off RSB stuffing when Xen is using SMEP itself, and - * 32bit PV guests are disabled, and when the RSB is full width. - */ - BUILD_BUG_ON(RO_MPT_VIRT_START != PML4_ADDR(256)); -- if ( opt_rsb_pv == -1 && boot_cpu_has(X86_FEATURE_XEN_SMEP) && -- !opt_pv32 && rsb_is_full_width() ) -- opt_rsb_pv = 0; -+ if ( opt_rsb_pv == -1 ) -+ { -+ opt_rsb_pv = (opt_pv32 || !boot_cpu_has(X86_FEATURE_XEN_SMEP) || -+ !rsb_is_full_width()); -+ -+ /* -+ * Cross-Thread Return Address Predictions. -+ * -+ * Vulnerable systems are Zen1/Zen2 uarch, which is AMD Fam17 / Hygon -+ * Fam18, when SMT is active. -+ * -+ * To mitigate, we must flush the RSB/RAS/RAP once between entering -+ * Xen and going idle. -+ * -+ * Most cases flush on entry to Xen anyway. The one case where we -+ * don't is when using the SMEP optimisation for PV guests. Flushing -+ * before going idle is less overhead than flushing on PV entry. -+ */ -+ if ( !opt_rsb_pv && hw_smt_enabled && -+ (boot_cpu_data.x86_vendor & (X86_VENDOR_AMD|X86_VENDOR_HYGON)) && -+ (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) ) -+ setup_force_cpu_cap(X86_FEATURE_SC_RSB_IDLE); -+ } - - if ( opt_rsb_pv ) - { diff --git a/xsa427-4.16.patch b/xsa427-4.16.patch deleted file mode 100644 index 4b11fd0..0000000 --- a/xsa427-4.16.patch +++ /dev/null @@ -1,74 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: account for log-dirty mode when pre-allocating - -Pre-allocation is intended to ensure that in the course of constructing -or updating shadows there won't be any risk of just made shadows or -shadows being acted upon can disappear under our feet. The amount of -pages pre-allocated then, however, needs to account for all possible -subsequent allocations. While the use in sh_page_fault() accounts for -all shadows which may need making, so far it didn't account for -allocations coming from log-dirty tracking (which piggybacks onto the -P2M allocation functions). - -Since shadow_prealloc() takes a count of shadows (or other data -structures) rather than a count of pages, putting the adjustment at the -call site of this function won't work very well: We simply can't express -the correct count that way in all cases. Instead take care of this in -the function itself, by "snooping" for L1 type requests. (While not -applicable right now, future new request sites of L1 tables would then -also be covered right away.) - -It is relevant to note here that pre-allocations like the one done from -shadow_alloc_p2m_page() are benign when they fall in the "scope" of an -earlier pre-alloc which already included that count: The inner call will -simply find enough pages available then; it'll bail right away. - -This is CVE-2022-42332 / XSA-427. - -Signed-off-by: Jan Beulich -Reviewed-by: Tim Deegan - ---- a/xen/include/asm-x86/paging.h -+++ b/xen/include/asm-x86/paging.h -@@ -192,6 +192,10 @@ int paging_mfn_is_dirty(struct domain *d - #define L4_LOGDIRTY_IDX(pfn) ((pfn_x(pfn) >> (PAGE_SHIFT + 3 + PAGETABLE_ORDER * 2)) & \ - (LOGDIRTY_NODE_ENTRIES-1)) - -+#define paging_logdirty_levels() \ -+ (DIV_ROUND_UP(PADDR_BITS - PAGE_SHIFT - (PAGE_SHIFT + 3), \ -+ PAGE_SHIFT - ilog2(sizeof(mfn_t))) + 1) -+ - #ifdef CONFIG_HVM - /* VRAM dirty tracking support */ - struct sh_dirty_vram { ---- a/xen/arch/x86/mm/paging.c -+++ b/xen/arch/x86/mm/paging.c -@@ -280,6 +280,7 @@ void paging_mark_pfn_dirty(struct domain - if ( unlikely(!VALID_M2P(pfn_x(pfn))) ) - return; - -+ BUILD_BUG_ON(paging_logdirty_levels() != 4); - i1 = L1_LOGDIRTY_IDX(pfn); - i2 = L2_LOGDIRTY_IDX(pfn); - i3 = L3_LOGDIRTY_IDX(pfn); ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -1015,7 +1015,17 @@ bool shadow_prealloc(struct domain *d, u - if ( unlikely(d->is_dying) ) - return false; - -- ret = _shadow_prealloc(d, shadow_size(type) * count); -+ count *= shadow_size(type); -+ /* -+ * Log-dirty handling may result in allocations when populating its -+ * tracking structures. Tie this to the caller requesting space for L1 -+ * shadows. -+ */ -+ if ( paging_mode_log_dirty(d) && -+ ((SHF_L1_ANY | SHF_FL1_ANY) & (1u << type)) ) -+ count += paging_logdirty_levels(); -+ -+ ret = _shadow_prealloc(d, count); - if ( !ret && (!d->is_shutting_down || d->shutdown_code != SHUTDOWN_crash) ) - /* - * Failing to allocate memory required for shadow usage can only result in diff --git a/xsa428-4.16-1.patch b/xsa428-4.16-1.patch deleted file mode 100644 index 3852f08..0000000 --- a/xsa428-4.16-1.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Jan Beulich -Subject: x86/HVM: bound number of pinned cache attribute regions - -This is exposed via DMOP, i.e. to potentially not fully privileged -device models. With that we may not permit registration of an (almost) -unbounded amount of such regions. - -This is CVE-2022-42333 / part of XSA-428. - -Reported-by: Andrew Cooper -Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") -Signed-off-by: Jan Beulich -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/hvm/mtrr.c -+++ b/xen/arch/x86/hvm/mtrr.c -@@ -595,6 +595,7 @@ int hvm_set_mem_pinned_cacheattr(struct - uint64_t gfn_end, uint32_t type) - { - struct hvm_mem_pinned_cacheattr_range *range; -+ unsigned int nr = 0; - int rc = 1; - - if ( !is_hvm_domain(d) ) -@@ -666,11 +667,15 @@ int hvm_set_mem_pinned_cacheattr(struct - rc = -EBUSY; - break; - } -+ ++nr; - } - rcu_read_unlock(&pinned_cacheattr_rcu_lock); - if ( rc <= 0 ) - return rc; - -+ if ( nr >= 64 /* The limit is arbitrary. */ ) -+ return -ENOSPC; -+ - range = xzalloc(struct hvm_mem_pinned_cacheattr_range); - if ( range == NULL ) - return -ENOMEM; diff --git a/xsa428-4.16-2.patch b/xsa428-4.16-2.patch deleted file mode 100644 index 4b3f331..0000000 --- a/xsa428-4.16-2.patch +++ /dev/null @@ -1,114 +0,0 @@ -From: Jan Beulich -Subject: x86/HVM: serialize pinned cache attribute list manipulation - -While the RCU variants of list insertion and removal allow lockless list -traversal (with RCU just read-locked), insertions and removals still -need serializing amongst themselves. To keep things simple, use the -domain lock for this purpose. - -This is CVE-2022-42334 / part of XSA-428. - -Fixes: 642123c5123f ("x86/hvm: provide XEN_DMOP_pin_memory_cacheattr") -Signed-off-by: Jan Beulich -Reviewed-by: Julien Grall - ---- a/xen/arch/x86/hvm/mtrr.c -+++ b/xen/arch/x86/hvm/mtrr.c -@@ -594,7 +594,7 @@ static void free_pinned_cacheattr_entry( - int hvm_set_mem_pinned_cacheattr(struct domain *d, uint64_t gfn_start, - uint64_t gfn_end, uint32_t type) - { -- struct hvm_mem_pinned_cacheattr_range *range; -+ struct hvm_mem_pinned_cacheattr_range *range, *newr; - unsigned int nr = 0; - int rc = 1; - -@@ -608,14 +608,15 @@ int hvm_set_mem_pinned_cacheattr(struct - { - case XEN_DOMCTL_DELETE_MEM_CACHEATTR: - /* Remove the requested range. */ -- rcu_read_lock(&pinned_cacheattr_rcu_lock); -- list_for_each_entry_rcu ( range, -- &d->arch.hvm.pinned_cacheattr_ranges, -- list ) -+ domain_lock(d); -+ list_for_each_entry ( range, -+ &d->arch.hvm.pinned_cacheattr_ranges, -+ list ) - if ( range->start == gfn_start && range->end == gfn_end ) - { -- rcu_read_unlock(&pinned_cacheattr_rcu_lock); - list_del_rcu(&range->list); -+ domain_unlock(d); -+ - type = range->type; - call_rcu(&range->rcu, free_pinned_cacheattr_entry); - p2m_memory_type_changed(d); -@@ -636,7 +637,7 @@ int hvm_set_mem_pinned_cacheattr(struct - } - return 0; - } -- rcu_read_unlock(&pinned_cacheattr_rcu_lock); -+ domain_unlock(d); - return -ENOENT; - - case PAT_TYPE_UC_MINUS: -@@ -651,7 +652,10 @@ int hvm_set_mem_pinned_cacheattr(struct - return -EINVAL; - } - -- rcu_read_lock(&pinned_cacheattr_rcu_lock); -+ newr = xzalloc(struct hvm_mem_pinned_cacheattr_range); -+ -+ domain_lock(d); -+ - list_for_each_entry_rcu ( range, - &d->arch.hvm.pinned_cacheattr_ranges, - list ) -@@ -669,27 +673,34 @@ int hvm_set_mem_pinned_cacheattr(struct - } - ++nr; - } -- rcu_read_unlock(&pinned_cacheattr_rcu_lock); -+ - if ( rc <= 0 ) -- return rc; -+ /* nothing */; -+ else if ( nr >= 64 /* The limit is arbitrary. */ ) -+ rc = -ENOSPC; -+ else if ( !newr ) -+ rc = -ENOMEM; -+ else -+ { -+ newr->start = gfn_start; -+ newr->end = gfn_end; -+ newr->type = type; - -- if ( nr >= 64 /* The limit is arbitrary. */ ) -- return -ENOSPC; -+ list_add_rcu(&newr->list, &d->arch.hvm.pinned_cacheattr_ranges); -+ -+ newr = NULL; -+ rc = 0; -+ } - -- range = xzalloc(struct hvm_mem_pinned_cacheattr_range); -- if ( range == NULL ) -- return -ENOMEM; -+ domain_unlock(d); - -- range->start = gfn_start; -- range->end = gfn_end; -- range->type = type; -+ xfree(newr); - -- list_add_rcu(&range->list, &d->arch.hvm.pinned_cacheattr_ranges); - p2m_memory_type_changed(d); - if ( type != PAT_TYPE_WRBACK ) - flush_all(FLUSH_CACHE); - -- return 0; -+ return rc; - } - - static int hvm_save_mtrr_msr(struct vcpu *v, hvm_domain_context_t *h) diff --git a/xsa429.patch b/xsa429.patch deleted file mode 100644 index 443869f..0000000 --- a/xsa429.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Defer CR4_PV32_RESTORE on the cstar_enter path - -As stated (correctly) by the comment next to SPEC_CTRL_ENTRY_FROM_PV, between -the two hunks visible in the patch, RET's are not safe prior to this point. - -CR4_PV32_RESTORE hides a CALL/RET pair in certain configurations (PV32 -compiled in, SMEP or SMAP active), and the RET can be attacked with one of -several known speculative issues. - -Furthermore, CR4_PV32_RESTORE also hides a reference to the cr4_pv32_mask -global variable, which is not safe when XPTI is active before restoring Xen's -full pagetables. - -This crash has gone unnoticed because it is only AMD CPUs which permit the -SYSCALL instruction in compatibility mode, and these are not vulnerable to -Meltdown so don't activate XPTI by default. - -This is XSA-429 / CVE-2022-42331 - -Fixes: 5e7962901131 ("x86/entry: Organise the use of MSR_SPEC_CTRL at each entry/exit point") -Fixes: 5784de3e2067 ("x86: Meltdown band-aid against malicious 64-bit PV guests") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index ae012851819a..7675a59ff057 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -288,7 +288,6 @@ ENTRY(cstar_enter) - ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK - #endif - push %rax /* Guest %rsp */ -- CR4_PV32_RESTORE - movq 8(%rsp), %rax /* Restore guest %rax. */ - movq $FLAT_USER_SS32, 8(%rsp) /* Assume a 64bit domain. Compat handled lower. */ - pushq %r11 -@@ -312,6 +311,8 @@ ENTRY(cstar_enter) - .Lcstar_cr3_okay: - sti - -+ CR4_PV32_RESTORE -+ - movq STACK_CPUINFO_FIELD(current_vcpu)(%rbx), %rbx - - #ifdef CONFIG_PV32 From f3cac52735cbd10e6bbd305401dd832bca994fd0 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 16 May 2023 19:21:37 +0100 Subject: [PATCH 18/99] Mishandling of guest SSBD selection on AMD hardware [XSA-431, CVE-2022-42336] --- xen.spec | 8 ++++- xsa431.patch | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 xsa431.patch diff --git a/xen.spec b/xen.spec index 0c8c5de..5f71cfc 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -110,6 +110,7 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch +Patch48: xsa431.patch %if %build_qemutrad @@ -322,6 +323,7 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 47 -p1 +%patch 48 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -929,6 +931,10 @@ fi %endif %changelog +* Tue May 16 2023 Michael Young - 4.17.1-2 +- Mishandling of guest SSBD selection on AMD hardware + [XSA-431, CVE-2022-42336] + * Tue May 02 2023 Michael Young - 4.17.1-1 - update to xen-4.17.1 remove patches now included upstream diff --git a/xsa431.patch b/xsa431.patch new file mode 100644 index 0000000..b804592 --- /dev/null +++ b/xsa431.patch @@ -0,0 +1,94 @@ +From 9c03380fc9e328f0ccba860cbe09ef58ea366f71 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Wed, 22 Mar 2023 11:52:07 +0100 +Subject: [PATCH] x86/amd: fix legacy setting of SSBD on AMD Family 17h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current logic to set SSBD on AMD Family 17h and Hygon Family 18h +processors requires that the setting of SSBD is coordinated at a core +level, as the setting is shared between threads. Logic was introduced +to keep track of how many threads require SSBD active in order to +coordinate it, such logic relies on using a per-core counter of +threads that have SSBD active. + +Given the current logic, it's possible for a guest to under or +overflow the thread counter, because each write to VIRT_SPEC_CTRL.SSBD +by the guest gets propagated to the helper that does the per-core +active accounting. Overflowing the counter is not so much of an +issue, as this would just make SSBD sticky. + +Underflowing however is more problematic: on non-debug Xen builds a +guest can perform empty writes to VIRT_SPEC_CTRL that would cause the +counter to underflow and thus the value gets saturated to the max +value of unsigned int. At which points attempts from any thread to +set VIRT_SPEC_CTRL.SSBD won't get propagated to the hardware anymore, +because the logic will see that the counter is greater than 1 and +assume that SSBD is already active, effectively loosing the setting +of SSBD and the protection it provides. + +Fix this by introducing a per-CPU variable that keeps track of whether +the current thread has legacy SSBD active or not, and thus only +attempt to propagate the value to the hardware once the thread +selected value changes. + +This is XSA-431 / CVE-2022-42336 + +Fixes: b2030e6730a2 ('amd/virt_ssbd: set SSBD at vCPU context switch') +Reported-by: Andrew Cooper +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/cpu/amd.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index caafe4474021..9a1a3858edd4 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -783,12 +783,23 @@ bool __init amd_setup_legacy_ssbd(void) + return true; + } + ++/* ++ * legacy_ssbd is always initialized to false because when SSBD is set ++ * from the command line guest attempts to change it are a no-op (see ++ * amd_set_legacy_ssbd()), whereas when SSBD is inactive hardware will ++ * be forced into that mode (see amd_init_ssbd()). ++ */ ++static DEFINE_PER_CPU(bool, legacy_ssbd); ++ ++/* Must be called only when the SSBD setting needs toggling. */ + static void core_set_legacy_ssbd(bool enable) + { + const struct cpuinfo_x86 *c = ¤t_cpu_data; + struct ssbd_ls_cfg *status; + unsigned long flags; + ++ BUG_ON(this_cpu(legacy_ssbd) == enable); ++ + if ((c->x86 != 0x17 && c->x86 != 0x18) || c->x86_num_siblings <= 1) { + BUG_ON(!set_legacy_ssbd(c, enable)); + return; +@@ -816,12 +827,17 @@ void amd_set_legacy_ssbd(bool enable) + */ + return; + ++ if (this_cpu(legacy_ssbd) == enable) ++ return; ++ + if (cpu_has_virt_ssbd) + wrmsr(MSR_VIRT_SPEC_CTRL, enable ? SPEC_CTRL_SSBD : 0, 0); + else if (amd_legacy_ssbd) + core_set_legacy_ssbd(enable); + else + ASSERT_UNREACHABLE(); ++ ++ this_cpu(legacy_ssbd) = enable; + } + + /* +-- +2.40.0 + From b65002c5bff594567e4a527ef5ee3e3a0912069e Mon Sep 17 00:00:00 2001 From: Python Maint Date: Tue, 13 Jun 2023 21:39:25 +0200 Subject: [PATCH 19/99] Rebuilt for Python 3.12 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 5f71cfc..527486d 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -931,6 +931,9 @@ fi %endif %changelog +* Tue Jun 13 2023 Python Maint - 4.17.1-3 +- Rebuilt for Python 3.12 + * Tue May 16 2023 Michael Young - 4.17.1-2 - Mishandling of guest SSBD selection on AMD hardware [XSA-431, CVE-2022-42336] From 19ebd639fc7411f3536ce607e11fa1c99dafda7f Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 27 Jun 2023 20:32:48 +0100 Subject: [PATCH 20/99] work around a build problem with python 3.12 --- xen.python3.12.patch | 22 ++++++++++++++++++++++ xen.spec | 7 ++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 xen.python3.12.patch diff --git a/xen.python3.12.patch b/xen.python3.12.patch new file mode 100644 index 0000000..a6539c2 --- /dev/null +++ b/xen.python3.12.patch @@ -0,0 +1,22 @@ +--- xen-4.17.1/tools/python/Makefile.orig 2023-04-27 13:53:19.000000000 +0100 ++++ xen-4.17.1/tools/python/Makefile 2023-06-22 22:21:25.287486906 +0100 +@@ -4,7 +4,7 @@ + .PHONY: all + all: build + +-PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS) ++PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS) -Wno-error=declaration-after-statement + PY_LDFLAGS = $(SHLIB_LDFLAGS) $(APPEND_LDFLAGS) + INSTALL_LOG = build/installed_files.txt + +--- xen-4.17.1/tools/pygrub/Makefile.orig 2023-04-27 13:53:19.000000000 +0100 ++++ xen-4.17.1/tools/pygrub/Makefile 2023-06-22 22:52:52.803047401 +0100 +@@ -2,7 +2,7 @@ + XEN_ROOT = $(CURDIR)/../.. + include $(XEN_ROOT)/tools/Rules.mk + +-PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS) ++PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS) -Wno-error=declaration-after-statement + PY_LDFLAGS = $(SHLIB_LDFLAGS) $(APPEND_LDFLAGS) + INSTALL_LOG = build/installed_files.txt + diff --git a/xen.spec b/xen.spec index 527486d..fe57b65 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,6 +111,7 @@ Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch48: xsa431.patch +Patch49: xen.python3.12.patch %if %build_qemutrad @@ -324,6 +325,7 @@ manage Xen virtual machines. %patch 46 -p1 %patch 47 -p1 %patch 48 -p1 +%patch 49 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -931,6 +933,9 @@ fi %endif %changelog +* Tue Jun 27 2023 Michael Young - 4.17.1-4 +- work around a build problem with python 3.12 + * Tue Jun 13 2023 Python Maint - 4.17.1-3 - Rebuilt for Python 3.12 From 70cfe51077bd939d93b6d28fe3d2fc65dbe070ff Mon Sep 17 00:00:00 2001 From: Jerry James Date: Mon, 10 Jul 2023 15:55:49 -0600 Subject: [PATCH 21/99] Add patch for OCaml 5.0.0 --- xen.ocaml5.fixes.patch | 70 ++++++++++++++++++++++++++++++++++++++++++ xen.spec | 7 ++++- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 xen.ocaml5.fixes.patch diff --git a/xen.ocaml5.fixes.patch b/xen.ocaml5.fixes.patch new file mode 100644 index 0000000..2191334 --- /dev/null +++ b/xen.ocaml5.fixes.patch @@ -0,0 +1,70 @@ +--- xen-4.17.1/tools/ocaml/common.make.orig 2023-04-27 06:53:19.000000000 -0600 ++++ xen-4.17.1/tools/ocaml/common.make 2023-06-20 09:47:25.250969763 -0600 +@@ -11,9 +11,9 @@ OCAMLFIND ?= ocamlfind + + CFLAGS += -fPIC -I$(shell ocamlc -where) + +-OCAMLOPTFLAG_G := $(shell $(OCAMLOPT) -h 2>&1 | sed -n 's/^ *\(-g\) .*/\1/p') +-OCAMLOPTFLAGS = $(OCAMLOPTFLAG_G) -ccopt "$(LDFLAGS)" -dtypes $(OCAMLINCLUDE) -cc $(CC) -w F -warn-error F +-OCAMLCFLAGS += -g $(OCAMLINCLUDE) -w F -warn-error F ++OCAMLOPTFLAG_G := -g ++OCAMLOPTFLAGS = $(OCAMLOPTFLAG_G) -ccopt "$(LDFLAGS)" -dtypes $(OCAMLINCLUDE) -cc $(CC) -w F -warn-error F -I +unix ++OCAMLCFLAGS += -g $(OCAMLINCLUDE) -w F -warn-error F -I +unix + + VERSION := 4.1 + +--- xen-4.17.1/tools/ocaml/libs/xentoollog/xentoollog_stubs.c.orig 2023-04-27 06:53:19.000000000 -0600 ++++ xen-4.17.1/tools/ocaml/libs/xentoollog/xentoollog_stubs.c 2023-06-20 09:04:30.375263358 -0600 +@@ -33,7 +33,7 @@ + + /* The following is equal to the CAMLreturn macro, but without the return */ + #define CAMLdone do{ \ +-caml_local_roots = caml__frame; \ ++CAML_LOCAL_ROOTS = caml__frame; \ + }while (0) + + #define XTL ((xentoollog_logger *) Xtl_val(handle)) +--- xen-4.17.1/tools/ocaml/libs/xl/xenlight_stubs.c.orig 2023-04-27 06:53:19.000000000 -0600 ++++ xen-4.17.1/tools/ocaml/libs/xl/xenlight_stubs.c 2023-06-20 09:34:09.550454354 -0600 +@@ -43,14 +43,14 @@ + #ifndef CAMLreturnT + #define CAMLreturnT(type, result) do { \ + type caml__temp_result = (result); \ +- caml_local_roots = caml__frame; \ ++ CAML_LOCAL_ROOTS = caml__frame; \ + return (caml__temp_result); \ + } while (0) + #endif + + /* The following is equal to the CAMLreturn macro, but without the return */ + #define CAMLdone do{ \ +-caml_local_roots = caml__frame; \ ++CAML_LOCAL_ROOTS = caml__frame; \ + }while (0) + + #define Ctx_val(x)(*((libxl_ctx **) Data_custom_val(x))) +--- xen-4.17.1/tools/ocaml/Makefile.rules.orig 2023-04-27 06:53:19.000000000 -0600 ++++ xen-4.17.1/tools/ocaml/Makefile.rules 2023-06-20 10:00:58.769235173 -0600 +@@ -59,9 +59,9 @@ quiet-command = $(if $(V),$1,@printf " % + mk-caml-lib-native = $(call quiet-command, $(OCAMLOPT) $(OCAMLOPTFLAGS) -a -o $1 $2 $3,MLA,$1) + mk-caml-lib-bytecode = $(call quiet-command, $(OCAMLC) $(OCAMLCFLAGS) -a -o $1 $2 $3,MLA,$1) + +-mk-caml-stubs = $(call quiet-command, $(OCAMLMKLIB) -o `basename $1 .a` $2,MKLIB,$1) ++mk-caml-stubs = $(call quiet-command, $(OCAMLMKLIB) -g -o `basename $1 .a` $2,MKLIB,$1) + mk-caml-lib-stubs = \ +- $(call quiet-command, $(AR) rcs $1 $2 && $(OCAMLMKLIB) -o `basename $1 .a | sed -e 's/^lib//'` $2,MKLIB,$1) ++ $(call quiet-command, $(AR) rcs $1 $2 && $(OCAMLMKLIB) -g -o `basename $1 .a | sed -e 's/^lib//'` $2,MKLIB,$1) + + # define a library target .cmxa and .cma + define OCAML_LIBRARY_template +--- xen-4.17.1/tools/ocaml/xenstored/disk.ml.orig 2023-04-27 06:53:19.000000000 -0600 ++++ xen-4.17.1/tools/ocaml/xenstored/disk.ml 2023-06-20 09:49:44.361963710 -0600 +@@ -30,7 +30,7 @@ let undec c = + | _ -> raise (Failure "undecify") + + let unhex c = +- let c = Char.lowercase c in ++ let c = Char.lowercase_ascii c in + match c with + | '0' .. '9' -> (Char.code c) - (Char.code '0') + | 'a' .. 'f' -> (Char.code c) - (Char.code 'a') + 10 diff --git a/xen.spec b/xen.spec index fe57b65..db8ddb6 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,7 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch48: xsa431.patch Patch49: xen.python3.12.patch +Patch50: xen.ocaml5.fixes.patch %if %build_qemutrad @@ -326,6 +327,7 @@ manage Xen virtual machines. %patch 47 -p1 %patch 48 -p1 %patch 49 -p1 +%patch 50 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -933,6 +935,9 @@ fi %endif %changelog +* Mon Jul 10 2023 Jerry James - 4.17.1-5 +- Add patch for OCaml 5.0.0 + * Tue Jun 27 2023 Michael Young - 4.17.1-4 - work around a build problem with python 3.12 From 7669a6105566bc9fc6a2f3fa3d27e0e90665c02c Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 22 Jul 2023 18:41:52 +0000 Subject: [PATCH 22/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index db8ddb6..5ae86a8 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -935,6 +935,9 @@ fi %endif %changelog +* Sat Jul 22 2023 Fedora Release Engineering - 4.17.1-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + * Mon Jul 10 2023 Jerry James - 4.17.1-5 - Add patch for OCaml 5.0.0 From 14c61e310509e7b9ceffadaf26722e201a1e2ace Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 24 Jul 2023 22:15:29 +0100 Subject: [PATCH 23/99] x86/AMD: Zenbleed [XSA-433] omit OCaml 5 patch on fc38 --- xen.spec | 10 +++- xsa433-4.17.patch | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 xsa433-4.17.patch diff --git a/xen.spec b/xen.spec index 5ae86a8..8e953f9 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 6%{?dist} +Release: 7%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -113,6 +113,7 @@ Patch47: xen.gcc13.fixes.patch Patch48: xsa431.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch +Patch51: xsa433-4.17.patch %if %build_qemutrad @@ -327,7 +328,10 @@ manage Xen virtual machines. %patch 47 -p1 %patch 48 -p1 %patch 49 -p1 +%if "%dist" >= ".fc39" %patch 50 -p1 +%endif +%patch 51 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -935,6 +939,10 @@ fi %endif %changelog +* Mon Jul 24 2023 Michael Young - 4.17.1-7 +- x86/AMD: Zenbleed [XSA-433] +- omit OCaml 5 patch on fc38 + * Sat Jul 22 2023 Fedora Release Engineering - 4.17.1-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild diff --git a/xsa433-4.17.patch b/xsa433-4.17.patch new file mode 100644 index 0000000..668f556 --- /dev/null +++ b/xsa433-4.17.patch @@ -0,0 +1,138 @@ +From: Andrew Cooper +Subject: x86/amd: Mitigations for Zenbleed + +Zenbleed is a malfunction on AMD Zen2 uarch parts which results in corruption +of the vector registers. An attacker can trigger this bug deliberately in +order to access stale data in the physical vector register file. This can +include data from sibling threads, or a higher-privilege context. + +Microcode is the preferred mitigation but in the case that's not available use +the chickenbit as instructed by AMD. Re-evaluate the mitigation on late +microcode load too. + +This is XSA-433 / CVE-2023-20593. + +Signed-off-by: Andrew Cooper +Acked-by: Roger Pau Monné + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index b6a20d375ad1..8d23a5be0c5f 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "cpu.h" + +@@ -878,6 +879,72 @@ void __init detect_zen2_null_seg_behaviour(void) + + } + ++void amd_check_zenbleed(void) ++{ ++ const struct cpu_signature *sig = &this_cpu(cpu_sig); ++ unsigned int good_rev, chickenbit = (1 << 9); ++ uint64_t val, old_val; ++ ++ /* ++ * If we're virtualised, we can't do family/model checks safely, and ++ * we likely wouldn't have access to DE_CFG even if we could see a ++ * microcode revision. ++ * ++ * A hypervisor may hide AVX as a stopgap mitigation. We're not in a ++ * position to care either way. An admin doesn't want to be disabling ++ * AVX as a mitigation on any build of Xen with this logic present. ++ */ ++ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17) ++ return; ++ ++ switch (boot_cpu_data.x86_model) { ++ case 0x30 ... 0x3f: good_rev = 0x0830107a; break; ++ case 0x60 ... 0x67: good_rev = 0x0860010b; break; ++ case 0x68 ... 0x6f: good_rev = 0x08608105; break; ++ case 0x70 ... 0x7f: good_rev = 0x08701032; break; ++ case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; ++ default: ++ /* ++ * With the Fam17h check above, parts getting here are Zen1. ++ * They're not affected. ++ */ ++ return; ++ } ++ ++ rdmsrl(MSR_AMD64_DE_CFG, val); ++ old_val = val; ++ ++ /* ++ * Microcode is the preferred mitigation, in terms of performance. ++ * However, without microcode, this chickenbit (specific to the Zen2 ++ * uarch) disables Floating Point Mov-Elimination to mitigate the ++ * issue. ++ */ ++ val &= ~chickenbit; ++ if (sig->rev < good_rev) ++ val |= chickenbit; ++ ++ if (val == old_val) ++ /* Nothing to change. */ ++ return; ++ ++ /* ++ * DE_CFG is a Core-scoped MSR, and this write is racy during late ++ * microcode load. However, both threads calculate the new value from ++ * state which is shared, and unrelated to the old value, so the ++ * result should be consistent. ++ */ ++ wrmsrl(MSR_AMD64_DE_CFG, val); ++ ++ /* ++ * Inform the admin that we changed something, but don't spam, ++ * especially during a late microcode load. ++ */ ++ if (smp_processor_id() == 0) ++ printk(XENLOG_INFO "Zenbleed mitigation - using %s\n", ++ val & chickenbit ? "chickenbit" : "microcode"); ++} ++ + static void cf_check init_amd(struct cpuinfo_x86 *c) + { + u32 l, h; +@@ -1150,6 +1217,8 @@ static void cf_check init_amd(struct cpuinfo_x86 *c) + if ((smp_processor_id() == 1) && !cpu_has(c, X86_FEATURE_ITSC)) + disable_c1_ramping(); + ++ amd_check_zenbleed(); ++ + check_syscfg_dram_mod_en(); + + amd_log_freq(c); +diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c +index ded8fe90e650..c6d13f3fb35f 100644 +--- a/xen/arch/x86/cpu/microcode/amd.c ++++ b/xen/arch/x86/cpu/microcode/amd.c +@@ -262,6 +262,8 @@ static int cf_check apply_microcode(const struct microcode_patch *patch) + "microcode: CPU%u updated from revision %#x to %#x, date = %04x-%02x-%02x\n", + cpu, old_rev, rev, patch->year, patch->month, patch->day); + ++ amd_check_zenbleed(); ++ + return 0; + } + +diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h +index 8e2816fae9b9..66611df6efc1 100644 +--- a/xen/arch/x86/include/asm/processor.h ++++ b/xen/arch/x86/include/asm/processor.h +@@ -637,6 +637,8 @@ enum ap_boot_method { + }; + extern enum ap_boot_method ap_boot_method; + ++void amd_check_zenbleed(void); ++ + #endif /* !__ASSEMBLY__ */ + + #endif /* __ASM_X86_PROCESSOR_H */ + From baa6ba2e5a0739576d01a71e01c25b7e0cacac07 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 26 Jul 2023 00:01:08 +0100 Subject: [PATCH 24/99] adjust OCaml patch condition so eln builds work --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 8e953f9..9883325 100644 --- a/xen.spec +++ b/xen.spec @@ -328,7 +328,7 @@ manage Xen virtual machines. %patch 47 -p1 %patch 48 -p1 %patch 49 -p1 -%if "%dist" >= ".fc39" +%if "%dist" != ".fc38" %patch 50 -p1 %endif %patch 51 -p1 @@ -939,6 +939,9 @@ fi %endif %changelog +* Tue Jul 25 2023 Michael Young +- adjust OCaml patch condition so eln builds work + * Mon Jul 24 2023 Michael Young - 4.17.1-7 - x86/AMD: Zenbleed [XSA-433] - omit OCaml 5 patch on fc38 From c09e550528d079432c9502ca08aeacdc2b2db5ab Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 26 Jul 2023 19:46:52 +0100 Subject: [PATCH 25/99] add CVE reference --- xen.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 9883325..3c8922b 100644 --- a/xen.spec +++ b/xen.spec @@ -943,7 +943,7 @@ fi - adjust OCaml patch condition so eln builds work * Mon Jul 24 2023 Michael Young - 4.17.1-7 -- x86/AMD: Zenbleed [XSA-433] +- x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] - omit OCaml 5 patch on fc38 * Sat Jul 22 2023 Fedora Release Engineering - 4.17.1-6 From 4a3496d719095a51b074423e22e43c0b99d259ad Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 26 Jul 2023 19:57:13 +0100 Subject: [PATCH 26/99] x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] --- xen.spec | 7 ++- xsa433-4.16.patch | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 xsa433-4.16.patch diff --git a/xen.spec b/xen.spec index aba2fce..28c409c 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.4 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,6 +111,7 @@ Patch43: xen.gcc11.fixes.patch Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch +Patch47: xsa433-4.16.patch %if %build_qemutrad @@ -323,6 +324,7 @@ manage Xen virtual machines. %patch44 -p1 %patch45 -p1 %patch46 -p1 +%patch47 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -931,6 +933,9 @@ fi %endif %changelog +* Wed Jul 26 2023 Michael Young - 4.16.4-2 +- x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] + * Tue May 02 2023 Michael Young - 4.16.4-1 - update to xen-4.16.4 remove patches now included upstream diff --git a/xsa433-4.16.patch b/xsa433-4.16.patch new file mode 100644 index 0000000..eab4204 --- /dev/null +++ b/xsa433-4.16.patch @@ -0,0 +1,138 @@ +From: Andrew Cooper +Subject: x86/amd: Mitigations for Zenbleed + +Zenbleed is a malfunction on AMD Zen2 uarch parts which results in corruption +of the vector registers. An attacker can trigger this bug deliberately in +order to access stale data in the physical vector register file. This can +include data from sibling threads, or a higher-privilege context. + +Microcode is the preferred mitigation but in the case that's not available use +the chickenbit as instructed by AMD. Re-evaluate the mitigation on late +microcode load too. + +This is XSA-433 / CVE-2023-20593. + +Signed-off-by: Andrew Cooper +Acked-by: Roger Pau Monné + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 08e3e1e8a2d8..4ed08df4a8ce 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "cpu.h" + +@@ -769,6 +770,72 @@ void __init detect_zen2_null_seg_behaviour(void) + + } + ++void amd_check_zenbleed(void) ++{ ++ const struct cpu_signature *sig = &this_cpu(cpu_sig); ++ unsigned int good_rev, chickenbit = (1 << 9); ++ uint64_t val, old_val; ++ ++ /* ++ * If we're virtualised, we can't do family/model checks safely, and ++ * we likely wouldn't have access to DE_CFG even if we could see a ++ * microcode revision. ++ * ++ * A hypervisor may hide AVX as a stopgap mitigation. We're not in a ++ * position to care either way. An admin doesn't want to be disabling ++ * AVX as a mitigation on any build of Xen with this logic present. ++ */ ++ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17) ++ return; ++ ++ switch (boot_cpu_data.x86_model) { ++ case 0x30 ... 0x3f: good_rev = 0x0830107a; break; ++ case 0x60 ... 0x67: good_rev = 0x0860010b; break; ++ case 0x68 ... 0x6f: good_rev = 0x08608105; break; ++ case 0x70 ... 0x7f: good_rev = 0x08701032; break; ++ case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; ++ default: ++ /* ++ * With the Fam17h check above, parts getting here are Zen1. ++ * They're not affected. ++ */ ++ return; ++ } ++ ++ rdmsrl(MSR_AMD64_DE_CFG, val); ++ old_val = val; ++ ++ /* ++ * Microcode is the preferred mitigation, in terms of performance. ++ * However, without microcode, this chickenbit (specific to the Zen2 ++ * uarch) disables Floating Point Mov-Elimination to mitigate the ++ * issue. ++ */ ++ val &= ~chickenbit; ++ if (sig->rev < good_rev) ++ val |= chickenbit; ++ ++ if (val == old_val) ++ /* Nothing to change. */ ++ return; ++ ++ /* ++ * DE_CFG is a Core-scoped MSR, and this write is racy during late ++ * microcode load. However, both threads calculate the new value from ++ * state which is shared, and unrelated to the old value, so the ++ * result should be consistent. ++ */ ++ wrmsrl(MSR_AMD64_DE_CFG, val); ++ ++ /* ++ * Inform the admin that we changed something, but don't spam, ++ * especially during a late microcode load. ++ */ ++ if (smp_processor_id() == 0) ++ printk(XENLOG_INFO "Zenbleed mitigation - using %s\n", ++ val & chickenbit ? "chickenbit" : "microcode"); ++} ++ + static void init_amd(struct cpuinfo_x86 *c) + { + u32 l, h; +@@ -1041,6 +1108,8 @@ static void init_amd(struct cpuinfo_x86 *c) + if ((smp_processor_id() == 1) && !cpu_has(c, X86_FEATURE_ITSC)) + disable_c1_ramping(); + ++ amd_check_zenbleed(); ++ + check_syscfg_dram_mod_en(); + + amd_log_freq(c); +diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c +index 52182c1a2383..483a9b547f80 100644 +--- a/xen/arch/x86/cpu/microcode/amd.c ++++ b/xen/arch/x86/cpu/microcode/amd.c +@@ -262,6 +262,8 @@ static int apply_microcode(const struct microcode_patch *patch) + "microcode: CPU%u updated from revision %#x to %#x, date = %04x-%02x-%02x\n", + cpu, old_rev, rev, patch->year, patch->month, patch->day); + ++ amd_check_zenbleed(); ++ + return 0; + } + +diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h +index 3d8aacd3aab2..96621ec39f8b 100644 +--- a/xen/include/asm-x86/processor.h ++++ b/xen/include/asm-x86/processor.h +@@ -639,6 +639,8 @@ enum ap_boot_method { + }; + extern enum ap_boot_method ap_boot_method; + ++void amd_check_zenbleed(void); ++ + #endif /* !__ASSEMBLY__ */ + + #endif /* __ASM_X86_PROCESSOR_H */ + From eb85956ccc59f95e1ff982c0a491b6dca8b9237a Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 31 Jul 2023 20:47:37 +0100 Subject: [PATCH 27/99] bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] --- xen.spec | 5 +++++ xsa433-bugfix.patch | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 xsa433-bugfix.patch diff --git a/xen.spec b/xen.spec index 3c8922b..844667f 100644 --- a/xen.spec +++ b/xen.spec @@ -114,6 +114,7 @@ Patch48: xsa431.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch51: xsa433-4.17.patch +Patch52: xsa433-bugfix.patch %if %build_qemutrad @@ -332,6 +333,7 @@ manage Xen virtual machines. %patch 50 -p1 %endif %patch 51 -p1 +%patch 52 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -939,6 +941,9 @@ fi %endif %changelog +* Mon Jul 31 2023 Michael Young - 4.17.1-8 +- bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] + * Tue Jul 25 2023 Michael Young - adjust OCaml patch condition so eln builds work diff --git a/xsa433-bugfix.patch b/xsa433-bugfix.patch new file mode 100644 index 0000000..8ad4eda --- /dev/null +++ b/xsa433-bugfix.patch @@ -0,0 +1,29 @@ +From: Andrew Cooper +Subject: x86/amd: Fix DE_CFG truncation in amd_check_zenbleed() + +This line: + + val &= ~chickenbit; + +ends up truncating val to 32 bits, and turning off various errata workarounds +in Zen2 systems. + +Fixes: f91c5ea97067 ("x86/amd: Mitigations for Zenbleed") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 3ed06f670491..df2681b7c455 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -909,8 +909,8 @@ void __init detect_zen2_null_seg_behaviour(void) + void amd_check_zenbleed(void) + { + const struct cpu_signature *sig = &this_cpu(cpu_sig); +- unsigned int good_rev, chickenbit = (1 << 9); +- uint64_t val, old_val; ++ unsigned int good_rev; ++ uint64_t val, old_val, chickenbit = (1 << 9); + + /* + * If we're virtualised, we can't do family/model checks safely, and From ca3f59d0e3666693e753bdb4fdb181338eae9f15 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 31 Jul 2023 20:53:11 +0100 Subject: [PATCH 28/99] increment Release --- xen.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 844667f..13c1487 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 7%{?dist} +Release: 8%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz From 8f43f4c45b933595a24b180896034fce0b91e8bf Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 31 Jul 2023 22:08:57 +0100 Subject: [PATCH 29/99] bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] --- xen.spec | 7 ++++++- xsa433-bugfix.patch | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 xsa433-bugfix.patch diff --git a/xen.spec b/xen.spec index 28c409c..96a43c7 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.4 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,7 @@ Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xsa433-4.16.patch +Patch48: xsa433-bugfix.patch %if %build_qemutrad @@ -325,6 +326,7 @@ manage Xen virtual machines. %patch45 -p1 %patch46 -p1 %patch47 -p1 +%patch48 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -933,6 +935,9 @@ fi %endif %changelog +* Mon Jul 31 2023 Michael Young - 4.16.4-3 +- bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] + * Wed Jul 26 2023 Michael Young - 4.16.4-2 - x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] diff --git a/xsa433-bugfix.patch b/xsa433-bugfix.patch new file mode 100644 index 0000000..8ad4eda --- /dev/null +++ b/xsa433-bugfix.patch @@ -0,0 +1,29 @@ +From: Andrew Cooper +Subject: x86/amd: Fix DE_CFG truncation in amd_check_zenbleed() + +This line: + + val &= ~chickenbit; + +ends up truncating val to 32 bits, and turning off various errata workarounds +in Zen2 systems. + +Fixes: f91c5ea97067 ("x86/amd: Mitigations for Zenbleed") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 3ed06f670491..df2681b7c455 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -909,8 +909,8 @@ void __init detect_zen2_null_seg_behaviour(void) + void amd_check_zenbleed(void) + { + const struct cpu_signature *sig = &this_cpu(cpu_sig); +- unsigned int good_rev, chickenbit = (1 << 9); +- uint64_t val, old_val; ++ unsigned int good_rev; ++ uint64_t val, old_val, chickenbit = (1 << 9); + + /* + * If we're virtualised, we can't do family/model checks safely, and From c0ff82bee4c64c2bbe125d5a9cad4b7dd5febc97 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 1 Aug 2023 21:16:33 +0100 Subject: [PATCH 30/99] arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] --- xen.spec | 8 +- xsa436.patch | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 xsa436.patch diff --git a/xen.spec b/xen.spec index 13c1487..dfe9536 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.1 -Release: 8%{?dist} +Release: 9%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -115,6 +115,7 @@ Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch51: xsa433-4.17.patch Patch52: xsa433-bugfix.patch +Patch53: xsa436.patch %if %build_qemutrad @@ -334,6 +335,7 @@ manage Xen virtual machines. %endif %patch 51 -p1 %patch 52 -p1 +%patch 53 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -941,6 +943,10 @@ fi %endif %changelog +* Tue Aug 01 2023 Michael Young - 4.17.1-9 +- arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] + (#2228238) + * Mon Jul 31 2023 Michael Young - 4.17.1-8 - bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] diff --git a/xsa436.patch b/xsa436.patch new file mode 100644 index 0000000..02c04f2 --- /dev/null +++ b/xsa436.patch @@ -0,0 +1,288 @@ +From b6c28b0a7fa91e9c92caf388ac875639c424abce Mon Sep 17 00:00:00 2001 +From: Luca Fancellu +Date: Mon, 17 Jul 2023 13:25:46 +0100 +Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling + +Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence of a +store-exclusive or read of PAR_EL1 and a load with device or non-cacheable +memory attributes. +A workaround is available, but it depends on a firmware counterpart. + +The proposed workaround from the errata document is to modify the software +running at EL1 and above to include a DMB SY before and after accessing +PAR_EL1. + +In conjunction to the above, the firmware needs to use a specific write +sequence to several IMPLEMENTATION DEFINED registers to have the hardware +insert a DMB SY after all load-exclusive and store-exclusive instructions. + +Apply the workaround to Xen where PAR_EL1 is read, implementing an helper +function to do that. +Since Xen can be interrupted by irqs in any moment, add a barrier on +entry/exit when we are running on the affected cores. + +A guest without the workaround can deadlock the system, so warn the users +of Xen with the above type of cores to use only trusted guests, by +printing a message on Xen startup. + +Signed-off-by: Luca Fancellu +Reviewed-by: Bertrand Marquis +Reviewed-by: Julien Grall +--- + SUPPORT.md | 2 ++ + docs/misc/arm/silicon-errata.txt | 1 + + xen/arch/arm/Kconfig | 21 +++++++++++++++++++++ + xen/arch/arm/arm64/entry.S | 19 +++++++++++++++++++ + xen/arch/arm/cpuerrata.c | 16 ++++++++++++---- + xen/arch/arm/domain.c | 2 +- + xen/arch/arm/include/asm/arm64/page.h | 12 ++++++------ + xen/arch/arm/include/asm/cpufeature.h | 3 ++- + xen/arch/arm/include/asm/sysregs.h | 24 ++++++++++++++++++++++++ + 9 files changed, 88 insertions(+), 12 deletions(-) + +diff --git a/SUPPORT.md b/SUPPORT.md +index 8e040d1c1ef5..b63376f4d8d2 100644 +--- a/SUPPORT.md ++++ b/SUPPORT.md +@@ -39,8 +39,10 @@ supported in this document. + + Status: Supported + Status, Cortex A57 r0p0-r1p1: Supported, not security supported ++ Status, Cortex A77 r0p0-r1p0: Supported, not security supported + + For the Cortex A57 r0p0 - r1p1, see Errata 832075. ++For the Cortex A77 r0p0 - r1p0, see Errata 1508412. + + ## Host hardware support + +diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt +index 1925d8fd4ee0..c4e82df53566 100644 +--- a/docs/misc/arm/silicon-errata.txt ++++ b/docs/misc/arm/silicon-errata.txt +@@ -58,4 +58,5 @@ stable hypervisors. + | ARM | Cortex-A76 | #1286807 | ARM64_ERRATUM_1286807 | + | ARM | Neoverse-N1 | #1165522 | N/A + | ARM | Neoverse-N1 | #1286807 | ARM64_ERRATUM_1286807 | ++| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 | + | ARM | MMU-500 | #842869 | N/A | +diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig +index 33e004d702bf..6ed1d51791e1 100644 +--- a/xen/arch/arm/Kconfig ++++ b/xen/arch/arm/Kconfig +@@ -312,6 +312,27 @@ config ARM64_ERRATUM_1286807 + + If unsure, say Y. + ++config ARM64_ERRATUM_1508412 ++ bool "Cortex-A77: 1508412: possible deadlock on sequence of NC/Device load and store exclusive or PAR read" ++ default y ++ depends on ARM_64 ++ help ++ This option adds a workaround for Arm Cortex-A77 erratum 1508412. ++ ++ Affected Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence ++ of a store-exclusive or read of PAR_EL1 and a load with device or ++ non-cacheable memory attributes. The workaround depends on a firmware ++ counterpart. ++ ++ Xen guests must also have the workaround implemented or they can ++ deadlock the system. ++ ++ Work around the issue by inserting DMB SY barriers around PAR_EL1 ++ register reads and warning Xen users. The DMB barrier is sufficient ++ to prevent a speculative PAR_EL1 read. ++ ++ If unsure, say Y. ++ + endmenu + + config ARM64_HARDEN_BRANCH_PREDICTOR +diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S +index 95f1a9268419..95ff4e3e0517 100644 +--- a/xen/arch/arm/arm64/entry.S ++++ b/xen/arch/arm/arm64/entry.S +@@ -134,6 +134,16 @@ + * position on the stack before. + */ + .macro entry, hyp, compat, save_x0_x1=1 ++ ++ /* ++ * Ensure any PAR_EL1 reads complete, in case we were interrupted ++ * between the PAR_EL1 read and the memory barrier for the erratum ++ * 1508412 workaround. ++ */ ++ alternative_if ARM64_WORKAROUND_1508412 ++ dmb sy ++ alternative_else_nop_endif ++ + sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ + + .if \hyp == 0 /* Guest mode */ +@@ -492,6 +502,15 @@ return_from_trap: + + ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ + ++ /* ++ * Ensure any device/NC reads complete, in case we were interrupted ++ * between the memory barrier for the erratum 1508412 workaround and ++ * any PAR_EL1 read. ++ */ ++ alternative_if ARM64_WORKAROUND_1508412 ++ dmb sy ++ alternative_else_nop_endif ++ + eret + sb + +diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c +index ae649d16ef02..ea680fac2e44 100644 +--- a/xen/arch/arm/cpuerrata.c ++++ b/xen/arch/arm/cpuerrata.c +@@ -668,6 +668,14 @@ static const struct arm_cpu_capabilities arm_errata[] = { + .capability = ARM64_WORKAROUND_AT_SPECULATE, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), + }, ++#ifdef CONFIG_ARM64_ERRATUM_1508412 ++ { ++ /* Cortex-A77 r0p0 - r1p0 */ ++ .desc = "ARM erratum 1508412 (hypervisor portion)", ++ .capability = ARM64_WORKAROUND_1508412, ++ MIDR_RANGE(MIDR_CORTEX_A77, 0, 1), ++ }, ++#endif + { + /* Cortex-A55 (All versions as erratum is open in SDEN v14) */ + .desc = "ARM erratum 1530923", +@@ -686,11 +694,11 @@ void __init enable_errata_workarounds(void) + { + enable_cpu_capabilities(arm_errata); + +-#ifdef CONFIG_ARM64_ERRATUM_832075 +- if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ) ++#if defined(CONFIG_ARM64_ERRATUM_832075) || defined(CONFIG_ARM64_ERRATUM_1508412) ++ if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) || ++ cpus_have_cap(ARM64_WORKAROUND_1508412) ) + { +- printk_once("**** This CPU is affected by the errata 832075. ****\n" +- "**** Guests without CPU erratum workarounds can deadlock the system! ****\n" ++ printk_once("**** Guests without CPU erratum workarounds can deadlock the system! ****\n" + "**** Only trusted guests should be used. ****\n"); + + /* Taint the machine has being insecure */ +diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c +index 2cd481979cf1..3e372fb70b99 100644 +--- a/xen/arch/arm/domain.c ++++ b/xen/arch/arm/domain.c +@@ -137,7 +137,7 @@ static void ctxt_switch_from(struct vcpu *p) + p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1); + if ( is_32bit_domain(p->domain) ) + p->arch.dacr = READ_SYSREG(DACR32_EL2); +- p->arch.par = READ_SYSREG64(PAR_EL1); ++ p->arch.par = read_sysreg_par(); + #if defined(CONFIG_ARM_32) + p->arch.mair0 = READ_CP32(MAIR0); + p->arch.mair1 = READ_CP32(MAIR1); +diff --git a/xen/arch/arm/include/asm/arm64/page.h b/xen/arch/arm/include/asm/arm64/page.h +index 0cba2663733b..fbfe67bf8951 100644 +--- a/xen/arch/arm/include/asm/arm64/page.h ++++ b/xen/arch/arm/include/asm/arm64/page.h +@@ -48,11 +48,11 @@ static inline void invalidate_icache_local(void) + /* Ask the MMU to translate a VA for us */ + static inline uint64_t __va_to_par(vaddr_t va) + { +- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); ++ uint64_t par, tmp = read_sysreg_par(); + + asm volatile ("at s1e2r, %0;" : : "r" (va)); + isb(); +- par = READ_SYSREG64(PAR_EL1); ++ par = read_sysreg_par(); + WRITE_SYSREG64(tmp, PAR_EL1); + return par; + } +@@ -60,28 +60,28 @@ static inline uint64_t __va_to_par(vaddr_t va) + /* Ask the MMU to translate a Guest VA for us */ + static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags) + { +- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); ++ uint64_t par, tmp = read_sysreg_par(); + + if ( (flags & GV2M_WRITE) == GV2M_WRITE ) + asm volatile ("at s12e1w, %0;" : : "r" (va)); + else + asm volatile ("at s12e1r, %0;" : : "r" (va)); + isb(); +- par = READ_SYSREG64(PAR_EL1); ++ par = read_sysreg_par(); + WRITE_SYSREG64(tmp, PAR_EL1); + return par; + } + + static inline uint64_t gva_to_ipa_par(vaddr_t va, unsigned int flags) + { +- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); ++ uint64_t par, tmp = read_sysreg_par(); + + if ( (flags & GV2M_WRITE) == GV2M_WRITE ) + asm volatile ("at s1e1w, %0;" : : "r" (va)); + else + asm volatile ("at s1e1r, %0;" : : "r" (va)); + isb(); +- par = READ_SYSREG64(PAR_EL1); ++ par = read_sysreg_par(); + WRITE_SYSREG64(tmp, PAR_EL1); + return par; + } +diff --git a/xen/arch/arm/include/asm/cpufeature.h b/xen/arch/arm/include/asm/cpufeature.h +index c86a2e7f291c..3a39fe4b5afe 100644 +--- a/xen/arch/arm/include/asm/cpufeature.h ++++ b/xen/arch/arm/include/asm/cpufeature.h +@@ -68,8 +68,9 @@ + #define ARM_WORKAROUND_BHB_LOOP_32 14 + #define ARM_WORKAROUND_BHB_SMCC_3 15 + #define ARM_HAS_SB 16 ++#define ARM64_WORKAROUND_1508412 17 + +-#define ARM_NCAPS 17 ++#define ARM_NCAPS 18 + + #ifndef __ASSEMBLY__ + +diff --git a/xen/arch/arm/include/asm/sysregs.h b/xen/arch/arm/include/asm/sysregs.h +index 5c5c51bbcdbf..61e30c9e517c 100644 +--- a/xen/arch/arm/include/asm/sysregs.h ++++ b/xen/arch/arm/include/asm/sysregs.h +@@ -9,6 +9,30 @@ + # error "unknown ARM variant" + #endif + ++#ifndef __ASSEMBLY__ ++ ++#include ++ ++static inline register_t read_sysreg_par(void) ++{ ++ register_t par_el1; ++ ++ /* ++ * On Cortex-A77 r0p0 and r1p0, read access to PAR_EL1 shall include a ++ * DMB SY before and after accessing it, as part of the workaround for the ++ * errata 1508412. ++ */ ++ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, ++ CONFIG_ARM64_ERRATUM_1508412)); ++ par_el1 = READ_SYSREG64(PAR_EL1); ++ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, ++ CONFIG_ARM64_ERRATUM_1508412)); ++ ++ return par_el1; ++} ++ ++#endif /* !__ASSEMBLY__ */ ++ + #endif /* __ASM_ARM_SYSREGS_H */ + /* + * Local variables: +-- +2.40.1 + From 5b38fd1c96f3839326b1ce546dc9c3d718ec99d6 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 1 Aug 2023 22:13:54 +0100 Subject: [PATCH 31/99] arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] --- xen.spec | 8 +- xsa436-4.16.patch | 288 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 xsa436-4.16.patch diff --git a/xen.spec b/xen.spec index 96a43c7..c692d17 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.4 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -113,6 +113,7 @@ Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xsa433-4.16.patch Patch48: xsa433-bugfix.patch +Patch49: xsa436-4.16.patch %if %build_qemutrad @@ -327,6 +328,7 @@ manage Xen virtual machines. %patch46 -p1 %patch47 -p1 %patch48 -p1 +%patch49 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -935,6 +937,10 @@ fi %endif %changelog +* Tue Aug 01 2023 Michael Young - 4.16.4-4 +- arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] + (#2228238) + * Mon Jul 31 2023 Michael Young - 4.16.4-3 - bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] diff --git a/xsa436-4.16.patch b/xsa436-4.16.patch new file mode 100644 index 0000000..43819b3 --- /dev/null +++ b/xsa436-4.16.patch @@ -0,0 +1,288 @@ +From 5083b8b4a425c64820ac106ce0f79cc5af195b5b Mon Sep 17 00:00:00 2001 +From: Luca Fancellu +Date: Mon, 17 Jul 2023 13:25:46 +0100 +Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling + +Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence of a +store-exclusive or read of PAR_EL1 and a load with device or non-cacheable +memory attributes. +A workaround is available, but it depends on a firmware counterpart. + +The proposed workaround from the errata document is to modify the software +running at EL1 and above to include a DMB SY before and after accessing +PAR_EL1. + +In conjunction to the above, the firmware needs to use a specific write +sequence to several IMPLEMENTATION DEFINED registers to have the hardware +insert a DMB SY after all load-exclusive and store-exclusive instructions. + +Apply the workaround to Xen where PAR_EL1 is read, implementing an helper +function to do that. +Since Xen can be interrupted by irqs in any moment, add a barrier on +entry/exit when we are running on the affected cores. + +A guest without the workaround can deadlock the system, so warn the users +of Xen with the above type of cores to use only trusted guests, by +printing a message on Xen startup. + +Signed-off-by: Luca Fancellu +Reviewed-by: Bertrand Marquis +Reviewed-by: Julien Grall +--- + SUPPORT.md | 2 ++ + docs/misc/arm/silicon-errata.txt | 1 + + xen/arch/arm/Kconfig | 21 +++++++++++++++++++++ + xen/arch/arm/arm64/entry.S | 19 +++++++++++++++++++ + xen/arch/arm/cpuerrata.c | 16 ++++++++++++---- + xen/arch/arm/domain.c | 2 +- + xen/include/asm-arm/arm64/page.h | 12 ++++++------ + xen/include/asm-arm/cpufeature.h | 3 ++- + xen/include/asm-arm/sysregs.h | 24 ++++++++++++++++++++++++ + 9 files changed, 88 insertions(+), 12 deletions(-) + +diff --git a/SUPPORT.md b/SUPPORT.md +index 85726102eab8..78a93159e3da 100644 +--- a/SUPPORT.md ++++ b/SUPPORT.md +@@ -39,8 +39,10 @@ supported in this document. + + Status: Supported + Status, Cortex A57 r0p0-r1p1: Supported, not security supported ++ Status, Cortex A77 r0p0-r1p0: Supported, not security supported + + For the Cortex A57 r0p0 - r1p1, see Errata 832075. ++For the Cortex A77 r0p0 - r1p0, see Errata 1508412. + + ## Host hardware support + +diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt +index 1925d8fd4ee0..c4e82df53566 100644 +--- a/docs/misc/arm/silicon-errata.txt ++++ b/docs/misc/arm/silicon-errata.txt +@@ -58,4 +58,5 @@ stable hypervisors. + | ARM | Cortex-A76 | #1286807 | ARM64_ERRATUM_1286807 | + | ARM | Neoverse-N1 | #1165522 | N/A + | ARM | Neoverse-N1 | #1286807 | ARM64_ERRATUM_1286807 | ++| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 | + | ARM | MMU-500 | #842869 | N/A | +diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig +index ecfa6822e4d3..c787a042a0a2 100644 +--- a/xen/arch/arm/Kconfig ++++ b/xen/arch/arm/Kconfig +@@ -278,6 +278,27 @@ config ARM64_ERRATUM_1286807 + + If unsure, say Y. + ++config ARM64_ERRATUM_1508412 ++ bool "Cortex-A77: 1508412: possible deadlock on sequence of NC/Device load and store exclusive or PAR read" ++ default y ++ depends on ARM_64 ++ help ++ This option adds a workaround for Arm Cortex-A77 erratum 1508412. ++ ++ Affected Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence ++ of a store-exclusive or read of PAR_EL1 and a load with device or ++ non-cacheable memory attributes. The workaround depends on a firmware ++ counterpart. ++ ++ Xen guests must also have the workaround implemented or they can ++ deadlock the system. ++ ++ Work around the issue by inserting DMB SY barriers around PAR_EL1 ++ register reads and warning Xen users. The DMB barrier is sufficient ++ to prevent a speculative PAR_EL1 read. ++ ++ If unsure, say Y. ++ + endmenu + + config ARM64_HARDEN_BRANCH_PREDICTOR +diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S +index 95f1a9268419..95ff4e3e0517 100644 +--- a/xen/arch/arm/arm64/entry.S ++++ b/xen/arch/arm/arm64/entry.S +@@ -134,6 +134,16 @@ + * position on the stack before. + */ + .macro entry, hyp, compat, save_x0_x1=1 ++ ++ /* ++ * Ensure any PAR_EL1 reads complete, in case we were interrupted ++ * between the PAR_EL1 read and the memory barrier for the erratum ++ * 1508412 workaround. ++ */ ++ alternative_if ARM64_WORKAROUND_1508412 ++ dmb sy ++ alternative_else_nop_endif ++ + sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ + + .if \hyp == 0 /* Guest mode */ +@@ -492,6 +502,15 @@ return_from_trap: + + ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ + ++ /* ++ * Ensure any device/NC reads complete, in case we were interrupted ++ * between the memory barrier for the erratum 1508412 workaround and ++ * any PAR_EL1 read. ++ */ ++ alternative_if ARM64_WORKAROUND_1508412 ++ dmb sy ++ alternative_else_nop_endif ++ + eret + sb + +diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c +index ae649d16ef02..ea680fac2e44 100644 +--- a/xen/arch/arm/cpuerrata.c ++++ b/xen/arch/arm/cpuerrata.c +@@ -668,6 +668,14 @@ static const struct arm_cpu_capabilities arm_errata[] = { + .capability = ARM64_WORKAROUND_AT_SPECULATE, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), + }, ++#ifdef CONFIG_ARM64_ERRATUM_1508412 ++ { ++ /* Cortex-A77 r0p0 - r1p0 */ ++ .desc = "ARM erratum 1508412 (hypervisor portion)", ++ .capability = ARM64_WORKAROUND_1508412, ++ MIDR_RANGE(MIDR_CORTEX_A77, 0, 1), ++ }, ++#endif + { + /* Cortex-A55 (All versions as erratum is open in SDEN v14) */ + .desc = "ARM erratum 1530923", +@@ -686,11 +694,11 @@ void __init enable_errata_workarounds(void) + { + enable_cpu_capabilities(arm_errata); + +-#ifdef CONFIG_ARM64_ERRATUM_832075 +- if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ) ++#if defined(CONFIG_ARM64_ERRATUM_832075) || defined(CONFIG_ARM64_ERRATUM_1508412) ++ if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) || ++ cpus_have_cap(ARM64_WORKAROUND_1508412) ) + { +- printk_once("**** This CPU is affected by the errata 832075. ****\n" +- "**** Guests without CPU erratum workarounds can deadlock the system! ****\n" ++ printk_once("**** Guests without CPU erratum workarounds can deadlock the system! ****\n" + "**** Only trusted guests should be used. ****\n"); + + /* Taint the machine has being insecure */ +diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c +index 96e1b235501d..cb1d54ba8549 100644 +--- a/xen/arch/arm/domain.c ++++ b/xen/arch/arm/domain.c +@@ -137,7 +137,7 @@ static void ctxt_switch_from(struct vcpu *p) + p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1); + if ( is_32bit_domain(p->domain) ) + p->arch.dacr = READ_SYSREG(DACR32_EL2); +- p->arch.par = READ_SYSREG64(PAR_EL1); ++ p->arch.par = read_sysreg_par(); + #if defined(CONFIG_ARM_32) + p->arch.mair0 = READ_CP32(MAIR0); + p->arch.mair1 = READ_CP32(MAIR1); +diff --git a/xen/include/asm-arm/arm64/page.h b/xen/include/asm-arm/arm64/page.h +index 0cba2663733b..fbfe67bf8951 100644 +--- a/xen/include/asm-arm/arm64/page.h ++++ b/xen/include/asm-arm/arm64/page.h +@@ -48,11 +48,11 @@ static inline void invalidate_icache_local(void) + /* Ask the MMU to translate a VA for us */ + static inline uint64_t __va_to_par(vaddr_t va) + { +- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); ++ uint64_t par, tmp = read_sysreg_par(); + + asm volatile ("at s1e2r, %0;" : : "r" (va)); + isb(); +- par = READ_SYSREG64(PAR_EL1); ++ par = read_sysreg_par(); + WRITE_SYSREG64(tmp, PAR_EL1); + return par; + } +@@ -60,28 +60,28 @@ static inline uint64_t __va_to_par(vaddr_t va) + /* Ask the MMU to translate a Guest VA for us */ + static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags) + { +- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); ++ uint64_t par, tmp = read_sysreg_par(); + + if ( (flags & GV2M_WRITE) == GV2M_WRITE ) + asm volatile ("at s12e1w, %0;" : : "r" (va)); + else + asm volatile ("at s12e1r, %0;" : : "r" (va)); + isb(); +- par = READ_SYSREG64(PAR_EL1); ++ par = read_sysreg_par(); + WRITE_SYSREG64(tmp, PAR_EL1); + return par; + } + + static inline uint64_t gva_to_ipa_par(vaddr_t va, unsigned int flags) + { +- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); ++ uint64_t par, tmp = read_sysreg_par(); + + if ( (flags & GV2M_WRITE) == GV2M_WRITE ) + asm volatile ("at s1e1w, %0;" : : "r" (va)); + else + asm volatile ("at s1e1r, %0;" : : "r" (va)); + isb(); +- par = READ_SYSREG64(PAR_EL1); ++ par = read_sysreg_par(); + WRITE_SYSREG64(tmp, PAR_EL1); + return par; + } +diff --git a/xen/include/asm-arm/cpufeature.h b/xen/include/asm-arm/cpufeature.h +index f7368766c07c..2f38137f39d5 100644 +--- a/xen/include/asm-arm/cpufeature.h ++++ b/xen/include/asm-arm/cpufeature.h +@@ -67,8 +67,9 @@ + #define ARM_WORKAROUND_BHB_LOOP_24 13 + #define ARM_WORKAROUND_BHB_LOOP_32 14 + #define ARM_WORKAROUND_BHB_SMCC_3 15 ++#define ARM64_WORKAROUND_1508412 16 + +-#define ARM_NCAPS 16 ++#define ARM_NCAPS 17 + + #ifndef __ASSEMBLY__ + +diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h +index 5c5c51bbcdbf..61e30c9e517c 100644 +--- a/xen/include/asm-arm/sysregs.h ++++ b/xen/include/asm-arm/sysregs.h +@@ -9,6 +9,30 @@ + # error "unknown ARM variant" + #endif + ++#ifndef __ASSEMBLY__ ++ ++#include ++ ++static inline register_t read_sysreg_par(void) ++{ ++ register_t par_el1; ++ ++ /* ++ * On Cortex-A77 r0p0 and r1p0, read access to PAR_EL1 shall include a ++ * DMB SY before and after accessing it, as part of the workaround for the ++ * errata 1508412. ++ */ ++ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, ++ CONFIG_ARM64_ERRATUM_1508412)); ++ par_el1 = READ_SYSREG64(PAR_EL1); ++ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, ++ CONFIG_ARM64_ERRATUM_1508412)); ++ ++ return par_el1; ++} ++ ++#endif /* !__ASSEMBLY__ */ ++ + #endif /* __ASM_ARM_SYSREGS_H */ + /* + * Local variables: +-- +2.40.1 + From 9f61265760472d58d2c71ca9a2770538144a4be5 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Thu, 10 Aug 2023 19:07:43 +0100 Subject: [PATCH 32/99] update to xen-4.17.2 which includes security updates x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569] x86/Intel: Gather Data Sampling [XSA-435, CVE-2022-40982] remove patches now included upstream --- .gitignore | 2 +- sources | 2 +- xen.spec | 18 ++- xsa431.patch | 94 --------------- xsa433-4.17.patch | 138 --------------------- xsa433-bugfix.patch | 29 ----- xsa436.patch | 288 -------------------------------------------- 7 files changed, 10 insertions(+), 561 deletions(-) delete mode 100644 xsa431.patch delete mode 100644 xsa433-4.17.patch delete mode 100644 xsa433-bugfix.patch delete mode 100644 xsa436.patch diff --git a/.gitignore b/.gitignore index a3ba858..e0e02a4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.17.1.tar.gz +/xen-4.17.2.tar.gz diff --git a/sources b/sources index c81c5e2..730c9d1 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.17.1.tar.gz) = bd98c5a2d75a0368ef312274b8e47f27db7f6b79302fd0c8b4975185e63640f98d9302e2834344acc1e97133e19f3993359dfab85aea5928008debada78c5f7a +SHA512 (xen-4.17.2.tar.gz) = 0bc475483676e4aa27735695f9a8d2821059e7a55984adb8a29badb5c09a4e7cf8ea29cbc9691be616cc0d7a5ee6b6dacc59ba29c2b16e0919ebdf7dfc54201a diff --git a/xen.spec b/xen.spec index dfe9536..dda5785 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.17.1 -Release: 9%{?dist} +Version: 4.17.2 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -110,12 +110,8 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch -Patch48: xsa431.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch -Patch51: xsa433-4.17.patch -Patch52: xsa433-bugfix.patch -Patch53: xsa436.patch %if %build_qemutrad @@ -328,14 +324,10 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 47 -p1 -%patch 48 -p1 %patch 49 -p1 %if "%dist" != ".fc38" %patch 50 -p1 %endif -%patch 51 -p1 -%patch 52 -p1 -%patch 53 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -943,6 +935,12 @@ fi %endif %changelog +* Thu Aug 10 2023 Michael Young - 4.17.2-1 +- update to xen-4.17.2 which includes + x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569] + x86/Intel: Gather Data Sampling [XSA-435, CVE-2022-40982] +- remove patches now included upstream + * Tue Aug 01 2023 Michael Young - 4.17.1-9 - arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] (#2228238) diff --git a/xsa431.patch b/xsa431.patch deleted file mode 100644 index b804592..0000000 --- a/xsa431.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 9c03380fc9e328f0ccba860cbe09ef58ea366f71 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Wed, 22 Mar 2023 11:52:07 +0100 -Subject: [PATCH] x86/amd: fix legacy setting of SSBD on AMD Family 17h -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The current logic to set SSBD on AMD Family 17h and Hygon Family 18h -processors requires that the setting of SSBD is coordinated at a core -level, as the setting is shared between threads. Logic was introduced -to keep track of how many threads require SSBD active in order to -coordinate it, such logic relies on using a per-core counter of -threads that have SSBD active. - -Given the current logic, it's possible for a guest to under or -overflow the thread counter, because each write to VIRT_SPEC_CTRL.SSBD -by the guest gets propagated to the helper that does the per-core -active accounting. Overflowing the counter is not so much of an -issue, as this would just make SSBD sticky. - -Underflowing however is more problematic: on non-debug Xen builds a -guest can perform empty writes to VIRT_SPEC_CTRL that would cause the -counter to underflow and thus the value gets saturated to the max -value of unsigned int. At which points attempts from any thread to -set VIRT_SPEC_CTRL.SSBD won't get propagated to the hardware anymore, -because the logic will see that the counter is greater than 1 and -assume that SSBD is already active, effectively loosing the setting -of SSBD and the protection it provides. - -Fix this by introducing a per-CPU variable that keeps track of whether -the current thread has legacy SSBD active or not, and thus only -attempt to propagate the value to the hardware once the thread -selected value changes. - -This is XSA-431 / CVE-2022-42336 - -Fixes: b2030e6730a2 ('amd/virt_ssbd: set SSBD at vCPU context switch') -Reported-by: Andrew Cooper -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/cpu/amd.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index caafe4474021..9a1a3858edd4 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -783,12 +783,23 @@ bool __init amd_setup_legacy_ssbd(void) - return true; - } - -+/* -+ * legacy_ssbd is always initialized to false because when SSBD is set -+ * from the command line guest attempts to change it are a no-op (see -+ * amd_set_legacy_ssbd()), whereas when SSBD is inactive hardware will -+ * be forced into that mode (see amd_init_ssbd()). -+ */ -+static DEFINE_PER_CPU(bool, legacy_ssbd); -+ -+/* Must be called only when the SSBD setting needs toggling. */ - static void core_set_legacy_ssbd(bool enable) - { - const struct cpuinfo_x86 *c = ¤t_cpu_data; - struct ssbd_ls_cfg *status; - unsigned long flags; - -+ BUG_ON(this_cpu(legacy_ssbd) == enable); -+ - if ((c->x86 != 0x17 && c->x86 != 0x18) || c->x86_num_siblings <= 1) { - BUG_ON(!set_legacy_ssbd(c, enable)); - return; -@@ -816,12 +827,17 @@ void amd_set_legacy_ssbd(bool enable) - */ - return; - -+ if (this_cpu(legacy_ssbd) == enable) -+ return; -+ - if (cpu_has_virt_ssbd) - wrmsr(MSR_VIRT_SPEC_CTRL, enable ? SPEC_CTRL_SSBD : 0, 0); - else if (amd_legacy_ssbd) - core_set_legacy_ssbd(enable); - else - ASSERT_UNREACHABLE(); -+ -+ this_cpu(legacy_ssbd) = enable; - } - - /* --- -2.40.0 - diff --git a/xsa433-4.17.patch b/xsa433-4.17.patch deleted file mode 100644 index 668f556..0000000 --- a/xsa433-4.17.patch +++ /dev/null @@ -1,138 +0,0 @@ -From: Andrew Cooper -Subject: x86/amd: Mitigations for Zenbleed - -Zenbleed is a malfunction on AMD Zen2 uarch parts which results in corruption -of the vector registers. An attacker can trigger this bug deliberately in -order to access stale data in the physical vector register file. This can -include data from sibling threads, or a higher-privilege context. - -Microcode is the preferred mitigation but in the case that's not available use -the chickenbit as instructed by AMD. Re-evaluate the mitigation on late -microcode load too. - -This is XSA-433 / CVE-2023-20593. - -Signed-off-by: Andrew Cooper -Acked-by: Roger Pau Monné - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index b6a20d375ad1..8d23a5be0c5f 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #include "cpu.h" - -@@ -878,6 +879,72 @@ void __init detect_zen2_null_seg_behaviour(void) - - } - -+void amd_check_zenbleed(void) -+{ -+ const struct cpu_signature *sig = &this_cpu(cpu_sig); -+ unsigned int good_rev, chickenbit = (1 << 9); -+ uint64_t val, old_val; -+ -+ /* -+ * If we're virtualised, we can't do family/model checks safely, and -+ * we likely wouldn't have access to DE_CFG even if we could see a -+ * microcode revision. -+ * -+ * A hypervisor may hide AVX as a stopgap mitigation. We're not in a -+ * position to care either way. An admin doesn't want to be disabling -+ * AVX as a mitigation on any build of Xen with this logic present. -+ */ -+ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17) -+ return; -+ -+ switch (boot_cpu_data.x86_model) { -+ case 0x30 ... 0x3f: good_rev = 0x0830107a; break; -+ case 0x60 ... 0x67: good_rev = 0x0860010b; break; -+ case 0x68 ... 0x6f: good_rev = 0x08608105; break; -+ case 0x70 ... 0x7f: good_rev = 0x08701032; break; -+ case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; -+ default: -+ /* -+ * With the Fam17h check above, parts getting here are Zen1. -+ * They're not affected. -+ */ -+ return; -+ } -+ -+ rdmsrl(MSR_AMD64_DE_CFG, val); -+ old_val = val; -+ -+ /* -+ * Microcode is the preferred mitigation, in terms of performance. -+ * However, without microcode, this chickenbit (specific to the Zen2 -+ * uarch) disables Floating Point Mov-Elimination to mitigate the -+ * issue. -+ */ -+ val &= ~chickenbit; -+ if (sig->rev < good_rev) -+ val |= chickenbit; -+ -+ if (val == old_val) -+ /* Nothing to change. */ -+ return; -+ -+ /* -+ * DE_CFG is a Core-scoped MSR, and this write is racy during late -+ * microcode load. However, both threads calculate the new value from -+ * state which is shared, and unrelated to the old value, so the -+ * result should be consistent. -+ */ -+ wrmsrl(MSR_AMD64_DE_CFG, val); -+ -+ /* -+ * Inform the admin that we changed something, but don't spam, -+ * especially during a late microcode load. -+ */ -+ if (smp_processor_id() == 0) -+ printk(XENLOG_INFO "Zenbleed mitigation - using %s\n", -+ val & chickenbit ? "chickenbit" : "microcode"); -+} -+ - static void cf_check init_amd(struct cpuinfo_x86 *c) - { - u32 l, h; -@@ -1150,6 +1217,8 @@ static void cf_check init_amd(struct cpuinfo_x86 *c) - if ((smp_processor_id() == 1) && !cpu_has(c, X86_FEATURE_ITSC)) - disable_c1_ramping(); - -+ amd_check_zenbleed(); -+ - check_syscfg_dram_mod_en(); - - amd_log_freq(c); -diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c -index ded8fe90e650..c6d13f3fb35f 100644 ---- a/xen/arch/x86/cpu/microcode/amd.c -+++ b/xen/arch/x86/cpu/microcode/amd.c -@@ -262,6 +262,8 @@ static int cf_check apply_microcode(const struct microcode_patch *patch) - "microcode: CPU%u updated from revision %#x to %#x, date = %04x-%02x-%02x\n", - cpu, old_rev, rev, patch->year, patch->month, patch->day); - -+ amd_check_zenbleed(); -+ - return 0; - } - -diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h -index 8e2816fae9b9..66611df6efc1 100644 ---- a/xen/arch/x86/include/asm/processor.h -+++ b/xen/arch/x86/include/asm/processor.h -@@ -637,6 +637,8 @@ enum ap_boot_method { - }; - extern enum ap_boot_method ap_boot_method; - -+void amd_check_zenbleed(void); -+ - #endif /* !__ASSEMBLY__ */ - - #endif /* __ASM_X86_PROCESSOR_H */ - diff --git a/xsa433-bugfix.patch b/xsa433-bugfix.patch deleted file mode 100644 index 8ad4eda..0000000 --- a/xsa433-bugfix.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Andrew Cooper -Subject: x86/amd: Fix DE_CFG truncation in amd_check_zenbleed() - -This line: - - val &= ~chickenbit; - -ends up truncating val to 32 bits, and turning off various errata workarounds -in Zen2 systems. - -Fixes: f91c5ea97067 ("x86/amd: Mitigations for Zenbleed") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index 3ed06f670491..df2681b7c455 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -909,8 +909,8 @@ void __init detect_zen2_null_seg_behaviour(void) - void amd_check_zenbleed(void) - { - const struct cpu_signature *sig = &this_cpu(cpu_sig); -- unsigned int good_rev, chickenbit = (1 << 9); -- uint64_t val, old_val; -+ unsigned int good_rev; -+ uint64_t val, old_val, chickenbit = (1 << 9); - - /* - * If we're virtualised, we can't do family/model checks safely, and diff --git a/xsa436.patch b/xsa436.patch deleted file mode 100644 index 02c04f2..0000000 --- a/xsa436.patch +++ /dev/null @@ -1,288 +0,0 @@ -From b6c28b0a7fa91e9c92caf388ac875639c424abce Mon Sep 17 00:00:00 2001 -From: Luca Fancellu -Date: Mon, 17 Jul 2023 13:25:46 +0100 -Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling - -Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence of a -store-exclusive or read of PAR_EL1 and a load with device or non-cacheable -memory attributes. -A workaround is available, but it depends on a firmware counterpart. - -The proposed workaround from the errata document is to modify the software -running at EL1 and above to include a DMB SY before and after accessing -PAR_EL1. - -In conjunction to the above, the firmware needs to use a specific write -sequence to several IMPLEMENTATION DEFINED registers to have the hardware -insert a DMB SY after all load-exclusive and store-exclusive instructions. - -Apply the workaround to Xen where PAR_EL1 is read, implementing an helper -function to do that. -Since Xen can be interrupted by irqs in any moment, add a barrier on -entry/exit when we are running on the affected cores. - -A guest without the workaround can deadlock the system, so warn the users -of Xen with the above type of cores to use only trusted guests, by -printing a message on Xen startup. - -Signed-off-by: Luca Fancellu -Reviewed-by: Bertrand Marquis -Reviewed-by: Julien Grall ---- - SUPPORT.md | 2 ++ - docs/misc/arm/silicon-errata.txt | 1 + - xen/arch/arm/Kconfig | 21 +++++++++++++++++++++ - xen/arch/arm/arm64/entry.S | 19 +++++++++++++++++++ - xen/arch/arm/cpuerrata.c | 16 ++++++++++++---- - xen/arch/arm/domain.c | 2 +- - xen/arch/arm/include/asm/arm64/page.h | 12 ++++++------ - xen/arch/arm/include/asm/cpufeature.h | 3 ++- - xen/arch/arm/include/asm/sysregs.h | 24 ++++++++++++++++++++++++ - 9 files changed, 88 insertions(+), 12 deletions(-) - -diff --git a/SUPPORT.md b/SUPPORT.md -index 8e040d1c1ef5..b63376f4d8d2 100644 ---- a/SUPPORT.md -+++ b/SUPPORT.md -@@ -39,8 +39,10 @@ supported in this document. - - Status: Supported - Status, Cortex A57 r0p0-r1p1: Supported, not security supported -+ Status, Cortex A77 r0p0-r1p0: Supported, not security supported - - For the Cortex A57 r0p0 - r1p1, see Errata 832075. -+For the Cortex A77 r0p0 - r1p0, see Errata 1508412. - - ## Host hardware support - -diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt -index 1925d8fd4ee0..c4e82df53566 100644 ---- a/docs/misc/arm/silicon-errata.txt -+++ b/docs/misc/arm/silicon-errata.txt -@@ -58,4 +58,5 @@ stable hypervisors. - | ARM | Cortex-A76 | #1286807 | ARM64_ERRATUM_1286807 | - | ARM | Neoverse-N1 | #1165522 | N/A - | ARM | Neoverse-N1 | #1286807 | ARM64_ERRATUM_1286807 | -+| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 | - | ARM | MMU-500 | #842869 | N/A | -diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig -index 33e004d702bf..6ed1d51791e1 100644 ---- a/xen/arch/arm/Kconfig -+++ b/xen/arch/arm/Kconfig -@@ -312,6 +312,27 @@ config ARM64_ERRATUM_1286807 - - If unsure, say Y. - -+config ARM64_ERRATUM_1508412 -+ bool "Cortex-A77: 1508412: possible deadlock on sequence of NC/Device load and store exclusive or PAR read" -+ default y -+ depends on ARM_64 -+ help -+ This option adds a workaround for Arm Cortex-A77 erratum 1508412. -+ -+ Affected Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence -+ of a store-exclusive or read of PAR_EL1 and a load with device or -+ non-cacheable memory attributes. The workaround depends on a firmware -+ counterpart. -+ -+ Xen guests must also have the workaround implemented or they can -+ deadlock the system. -+ -+ Work around the issue by inserting DMB SY barriers around PAR_EL1 -+ register reads and warning Xen users. The DMB barrier is sufficient -+ to prevent a speculative PAR_EL1 read. -+ -+ If unsure, say Y. -+ - endmenu - - config ARM64_HARDEN_BRANCH_PREDICTOR -diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S -index 95f1a9268419..95ff4e3e0517 100644 ---- a/xen/arch/arm/arm64/entry.S -+++ b/xen/arch/arm/arm64/entry.S -@@ -134,6 +134,16 @@ - * position on the stack before. - */ - .macro entry, hyp, compat, save_x0_x1=1 -+ -+ /* -+ * Ensure any PAR_EL1 reads complete, in case we were interrupted -+ * between the PAR_EL1 read and the memory barrier for the erratum -+ * 1508412 workaround. -+ */ -+ alternative_if ARM64_WORKAROUND_1508412 -+ dmb sy -+ alternative_else_nop_endif -+ - sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ - - .if \hyp == 0 /* Guest mode */ -@@ -492,6 +502,15 @@ return_from_trap: - - ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ - -+ /* -+ * Ensure any device/NC reads complete, in case we were interrupted -+ * between the memory barrier for the erratum 1508412 workaround and -+ * any PAR_EL1 read. -+ */ -+ alternative_if ARM64_WORKAROUND_1508412 -+ dmb sy -+ alternative_else_nop_endif -+ - eret - sb - -diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c -index ae649d16ef02..ea680fac2e44 100644 ---- a/xen/arch/arm/cpuerrata.c -+++ b/xen/arch/arm/cpuerrata.c -@@ -668,6 +668,14 @@ static const struct arm_cpu_capabilities arm_errata[] = { - .capability = ARM64_WORKAROUND_AT_SPECULATE, - MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), - }, -+#ifdef CONFIG_ARM64_ERRATUM_1508412 -+ { -+ /* Cortex-A77 r0p0 - r1p0 */ -+ .desc = "ARM erratum 1508412 (hypervisor portion)", -+ .capability = ARM64_WORKAROUND_1508412, -+ MIDR_RANGE(MIDR_CORTEX_A77, 0, 1), -+ }, -+#endif - { - /* Cortex-A55 (All versions as erratum is open in SDEN v14) */ - .desc = "ARM erratum 1530923", -@@ -686,11 +694,11 @@ void __init enable_errata_workarounds(void) - { - enable_cpu_capabilities(arm_errata); - --#ifdef CONFIG_ARM64_ERRATUM_832075 -- if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ) -+#if defined(CONFIG_ARM64_ERRATUM_832075) || defined(CONFIG_ARM64_ERRATUM_1508412) -+ if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) || -+ cpus_have_cap(ARM64_WORKAROUND_1508412) ) - { -- printk_once("**** This CPU is affected by the errata 832075. ****\n" -- "**** Guests without CPU erratum workarounds can deadlock the system! ****\n" -+ printk_once("**** Guests without CPU erratum workarounds can deadlock the system! ****\n" - "**** Only trusted guests should be used. ****\n"); - - /* Taint the machine has being insecure */ -diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c -index 2cd481979cf1..3e372fb70b99 100644 ---- a/xen/arch/arm/domain.c -+++ b/xen/arch/arm/domain.c -@@ -137,7 +137,7 @@ static void ctxt_switch_from(struct vcpu *p) - p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1); - if ( is_32bit_domain(p->domain) ) - p->arch.dacr = READ_SYSREG(DACR32_EL2); -- p->arch.par = READ_SYSREG64(PAR_EL1); -+ p->arch.par = read_sysreg_par(); - #if defined(CONFIG_ARM_32) - p->arch.mair0 = READ_CP32(MAIR0); - p->arch.mair1 = READ_CP32(MAIR1); -diff --git a/xen/arch/arm/include/asm/arm64/page.h b/xen/arch/arm/include/asm/arm64/page.h -index 0cba2663733b..fbfe67bf8951 100644 ---- a/xen/arch/arm/include/asm/arm64/page.h -+++ b/xen/arch/arm/include/asm/arm64/page.h -@@ -48,11 +48,11 @@ static inline void invalidate_icache_local(void) - /* Ask the MMU to translate a VA for us */ - static inline uint64_t __va_to_par(vaddr_t va) - { -- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); -+ uint64_t par, tmp = read_sysreg_par(); - - asm volatile ("at s1e2r, %0;" : : "r" (va)); - isb(); -- par = READ_SYSREG64(PAR_EL1); -+ par = read_sysreg_par(); - WRITE_SYSREG64(tmp, PAR_EL1); - return par; - } -@@ -60,28 +60,28 @@ static inline uint64_t __va_to_par(vaddr_t va) - /* Ask the MMU to translate a Guest VA for us */ - static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags) - { -- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); -+ uint64_t par, tmp = read_sysreg_par(); - - if ( (flags & GV2M_WRITE) == GV2M_WRITE ) - asm volatile ("at s12e1w, %0;" : : "r" (va)); - else - asm volatile ("at s12e1r, %0;" : : "r" (va)); - isb(); -- par = READ_SYSREG64(PAR_EL1); -+ par = read_sysreg_par(); - WRITE_SYSREG64(tmp, PAR_EL1); - return par; - } - - static inline uint64_t gva_to_ipa_par(vaddr_t va, unsigned int flags) - { -- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); -+ uint64_t par, tmp = read_sysreg_par(); - - if ( (flags & GV2M_WRITE) == GV2M_WRITE ) - asm volatile ("at s1e1w, %0;" : : "r" (va)); - else - asm volatile ("at s1e1r, %0;" : : "r" (va)); - isb(); -- par = READ_SYSREG64(PAR_EL1); -+ par = read_sysreg_par(); - WRITE_SYSREG64(tmp, PAR_EL1); - return par; - } -diff --git a/xen/arch/arm/include/asm/cpufeature.h b/xen/arch/arm/include/asm/cpufeature.h -index c86a2e7f291c..3a39fe4b5afe 100644 ---- a/xen/arch/arm/include/asm/cpufeature.h -+++ b/xen/arch/arm/include/asm/cpufeature.h -@@ -68,8 +68,9 @@ - #define ARM_WORKAROUND_BHB_LOOP_32 14 - #define ARM_WORKAROUND_BHB_SMCC_3 15 - #define ARM_HAS_SB 16 -+#define ARM64_WORKAROUND_1508412 17 - --#define ARM_NCAPS 17 -+#define ARM_NCAPS 18 - - #ifndef __ASSEMBLY__ - -diff --git a/xen/arch/arm/include/asm/sysregs.h b/xen/arch/arm/include/asm/sysregs.h -index 5c5c51bbcdbf..61e30c9e517c 100644 ---- a/xen/arch/arm/include/asm/sysregs.h -+++ b/xen/arch/arm/include/asm/sysregs.h -@@ -9,6 +9,30 @@ - # error "unknown ARM variant" - #endif - -+#ifndef __ASSEMBLY__ -+ -+#include -+ -+static inline register_t read_sysreg_par(void) -+{ -+ register_t par_el1; -+ -+ /* -+ * On Cortex-A77 r0p0 and r1p0, read access to PAR_EL1 shall include a -+ * DMB SY before and after accessing it, as part of the workaround for the -+ * errata 1508412. -+ */ -+ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, -+ CONFIG_ARM64_ERRATUM_1508412)); -+ par_el1 = READ_SYSREG64(PAR_EL1); -+ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, -+ CONFIG_ARM64_ERRATUM_1508412)); -+ -+ return par_el1; -+} -+ -+#endif /* !__ASSEMBLY__ */ -+ - #endif /* __ASM_ARM_SYSREGS_H */ - /* - * Local variables: --- -2.40.1 - From 046e9e564a7f3d6b0f5566e4720050f35a30819e Mon Sep 17 00:00:00 2001 From: Michael Young Date: Fri, 11 Aug 2023 19:41:01 +0100 Subject: [PATCH 33/99] update to xen-4.16.5 which includes security updates x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569] x86/Intel: Gather Data Sampling [XSA-435, CVE-2022-40982] remove patches now included upstream --- .gitignore | 2 +- sources | 2 +- xen.spec | 16 +-- xsa433-4.16.patch | 138 --------------------- xsa433-bugfix.patch | 29 ----- xsa436-4.16.patch | 288 -------------------------------------------- 6 files changed, 10 insertions(+), 465 deletions(-) delete mode 100644 xsa433-4.16.patch delete mode 100644 xsa433-bugfix.patch delete mode 100644 xsa436-4.16.patch diff --git a/.gitignore b/.gitignore index d252877..e8e5147 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.16.4.tar.gz +/xen-4.16.5.tar.gz diff --git a/sources b/sources index 55e15c7..b7ed437 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.16.4.tar.gz) = 1b5a167a9f5537b5311ef1cb56e0e6ffda0e4e569ef0534e47b4f4a528067bda46fb58b2a01abc02e8c38b2b70207fb201a5d4d10274fba70135eaa8e318e055 +SHA512 (xen-4.16.5.tar.gz) = 2f370787b72b2cd9d81c0b5f138133e676d2b9c8c76e31e6439649d7145242a6b7be0d51a7ff4f4197a99e3f6b24ac50e63d2fa49368da440d3f555e70c4ebd3 diff --git a/xen.spec b/xen.spec index c692d17..aeff813 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.16.4 -Release: 4%{?dist} +Version: 4.16.5 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,9 +111,6 @@ Patch43: xen.gcc11.fixes.patch Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch -Patch47: xsa433-4.16.patch -Patch48: xsa433-bugfix.patch -Patch49: xsa436-4.16.patch %if %build_qemutrad @@ -326,9 +323,6 @@ manage Xen virtual machines. %patch44 -p1 %patch45 -p1 %patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -937,6 +931,12 @@ fi %endif %changelog +* Fri Aug 11 2023 Michael Young - 4.16.5-1 +- update to xen-4.16.5 which includes + x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569] + x86/Intel: Gather Data Sampling [XSA-435, CVE-2022-40982] +- remove patches now included upstream + * Tue Aug 01 2023 Michael Young - 4.16.4-4 - arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] (#2228238) diff --git a/xsa433-4.16.patch b/xsa433-4.16.patch deleted file mode 100644 index eab4204..0000000 --- a/xsa433-4.16.patch +++ /dev/null @@ -1,138 +0,0 @@ -From: Andrew Cooper -Subject: x86/amd: Mitigations for Zenbleed - -Zenbleed is a malfunction on AMD Zen2 uarch parts which results in corruption -of the vector registers. An attacker can trigger this bug deliberately in -order to access stale data in the physical vector register file. This can -include data from sibling threads, or a higher-privilege context. - -Microcode is the preferred mitigation but in the case that's not available use -the chickenbit as instructed by AMD. Re-evaluate the mitigation on late -microcode load too. - -This is XSA-433 / CVE-2023-20593. - -Signed-off-by: Andrew Cooper -Acked-by: Roger Pau Monné - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index 08e3e1e8a2d8..4ed08df4a8ce 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #include "cpu.h" - -@@ -769,6 +770,72 @@ void __init detect_zen2_null_seg_behaviour(void) - - } - -+void amd_check_zenbleed(void) -+{ -+ const struct cpu_signature *sig = &this_cpu(cpu_sig); -+ unsigned int good_rev, chickenbit = (1 << 9); -+ uint64_t val, old_val; -+ -+ /* -+ * If we're virtualised, we can't do family/model checks safely, and -+ * we likely wouldn't have access to DE_CFG even if we could see a -+ * microcode revision. -+ * -+ * A hypervisor may hide AVX as a stopgap mitigation. We're not in a -+ * position to care either way. An admin doesn't want to be disabling -+ * AVX as a mitigation on any build of Xen with this logic present. -+ */ -+ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17) -+ return; -+ -+ switch (boot_cpu_data.x86_model) { -+ case 0x30 ... 0x3f: good_rev = 0x0830107a; break; -+ case 0x60 ... 0x67: good_rev = 0x0860010b; break; -+ case 0x68 ... 0x6f: good_rev = 0x08608105; break; -+ case 0x70 ... 0x7f: good_rev = 0x08701032; break; -+ case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; -+ default: -+ /* -+ * With the Fam17h check above, parts getting here are Zen1. -+ * They're not affected. -+ */ -+ return; -+ } -+ -+ rdmsrl(MSR_AMD64_DE_CFG, val); -+ old_val = val; -+ -+ /* -+ * Microcode is the preferred mitigation, in terms of performance. -+ * However, without microcode, this chickenbit (specific to the Zen2 -+ * uarch) disables Floating Point Mov-Elimination to mitigate the -+ * issue. -+ */ -+ val &= ~chickenbit; -+ if (sig->rev < good_rev) -+ val |= chickenbit; -+ -+ if (val == old_val) -+ /* Nothing to change. */ -+ return; -+ -+ /* -+ * DE_CFG is a Core-scoped MSR, and this write is racy during late -+ * microcode load. However, both threads calculate the new value from -+ * state which is shared, and unrelated to the old value, so the -+ * result should be consistent. -+ */ -+ wrmsrl(MSR_AMD64_DE_CFG, val); -+ -+ /* -+ * Inform the admin that we changed something, but don't spam, -+ * especially during a late microcode load. -+ */ -+ if (smp_processor_id() == 0) -+ printk(XENLOG_INFO "Zenbleed mitigation - using %s\n", -+ val & chickenbit ? "chickenbit" : "microcode"); -+} -+ - static void init_amd(struct cpuinfo_x86 *c) - { - u32 l, h; -@@ -1041,6 +1108,8 @@ static void init_amd(struct cpuinfo_x86 *c) - if ((smp_processor_id() == 1) && !cpu_has(c, X86_FEATURE_ITSC)) - disable_c1_ramping(); - -+ amd_check_zenbleed(); -+ - check_syscfg_dram_mod_en(); - - amd_log_freq(c); -diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c -index 52182c1a2383..483a9b547f80 100644 ---- a/xen/arch/x86/cpu/microcode/amd.c -+++ b/xen/arch/x86/cpu/microcode/amd.c -@@ -262,6 +262,8 @@ static int apply_microcode(const struct microcode_patch *patch) - "microcode: CPU%u updated from revision %#x to %#x, date = %04x-%02x-%02x\n", - cpu, old_rev, rev, patch->year, patch->month, patch->day); - -+ amd_check_zenbleed(); -+ - return 0; - } - -diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h -index 3d8aacd3aab2..96621ec39f8b 100644 ---- a/xen/include/asm-x86/processor.h -+++ b/xen/include/asm-x86/processor.h -@@ -639,6 +639,8 @@ enum ap_boot_method { - }; - extern enum ap_boot_method ap_boot_method; - -+void amd_check_zenbleed(void); -+ - #endif /* !__ASSEMBLY__ */ - - #endif /* __ASM_X86_PROCESSOR_H */ - diff --git a/xsa433-bugfix.patch b/xsa433-bugfix.patch deleted file mode 100644 index 8ad4eda..0000000 --- a/xsa433-bugfix.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Andrew Cooper -Subject: x86/amd: Fix DE_CFG truncation in amd_check_zenbleed() - -This line: - - val &= ~chickenbit; - -ends up truncating val to 32 bits, and turning off various errata workarounds -in Zen2 systems. - -Fixes: f91c5ea97067 ("x86/amd: Mitigations for Zenbleed") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index 3ed06f670491..df2681b7c455 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -909,8 +909,8 @@ void __init detect_zen2_null_seg_behaviour(void) - void amd_check_zenbleed(void) - { - const struct cpu_signature *sig = &this_cpu(cpu_sig); -- unsigned int good_rev, chickenbit = (1 << 9); -- uint64_t val, old_val; -+ unsigned int good_rev; -+ uint64_t val, old_val, chickenbit = (1 << 9); - - /* - * If we're virtualised, we can't do family/model checks safely, and diff --git a/xsa436-4.16.patch b/xsa436-4.16.patch deleted file mode 100644 index 43819b3..0000000 --- a/xsa436-4.16.patch +++ /dev/null @@ -1,288 +0,0 @@ -From 5083b8b4a425c64820ac106ce0f79cc5af195b5b Mon Sep 17 00:00:00 2001 -From: Luca Fancellu -Date: Mon, 17 Jul 2023 13:25:46 +0100 -Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling - -Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence of a -store-exclusive or read of PAR_EL1 and a load with device or non-cacheable -memory attributes. -A workaround is available, but it depends on a firmware counterpart. - -The proposed workaround from the errata document is to modify the software -running at EL1 and above to include a DMB SY before and after accessing -PAR_EL1. - -In conjunction to the above, the firmware needs to use a specific write -sequence to several IMPLEMENTATION DEFINED registers to have the hardware -insert a DMB SY after all load-exclusive and store-exclusive instructions. - -Apply the workaround to Xen where PAR_EL1 is read, implementing an helper -function to do that. -Since Xen can be interrupted by irqs in any moment, add a barrier on -entry/exit when we are running on the affected cores. - -A guest without the workaround can deadlock the system, so warn the users -of Xen with the above type of cores to use only trusted guests, by -printing a message on Xen startup. - -Signed-off-by: Luca Fancellu -Reviewed-by: Bertrand Marquis -Reviewed-by: Julien Grall ---- - SUPPORT.md | 2 ++ - docs/misc/arm/silicon-errata.txt | 1 + - xen/arch/arm/Kconfig | 21 +++++++++++++++++++++ - xen/arch/arm/arm64/entry.S | 19 +++++++++++++++++++ - xen/arch/arm/cpuerrata.c | 16 ++++++++++++---- - xen/arch/arm/domain.c | 2 +- - xen/include/asm-arm/arm64/page.h | 12 ++++++------ - xen/include/asm-arm/cpufeature.h | 3 ++- - xen/include/asm-arm/sysregs.h | 24 ++++++++++++++++++++++++ - 9 files changed, 88 insertions(+), 12 deletions(-) - -diff --git a/SUPPORT.md b/SUPPORT.md -index 85726102eab8..78a93159e3da 100644 ---- a/SUPPORT.md -+++ b/SUPPORT.md -@@ -39,8 +39,10 @@ supported in this document. - - Status: Supported - Status, Cortex A57 r0p0-r1p1: Supported, not security supported -+ Status, Cortex A77 r0p0-r1p0: Supported, not security supported - - For the Cortex A57 r0p0 - r1p1, see Errata 832075. -+For the Cortex A77 r0p0 - r1p0, see Errata 1508412. - - ## Host hardware support - -diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt -index 1925d8fd4ee0..c4e82df53566 100644 ---- a/docs/misc/arm/silicon-errata.txt -+++ b/docs/misc/arm/silicon-errata.txt -@@ -58,4 +58,5 @@ stable hypervisors. - | ARM | Cortex-A76 | #1286807 | ARM64_ERRATUM_1286807 | - | ARM | Neoverse-N1 | #1165522 | N/A - | ARM | Neoverse-N1 | #1286807 | ARM64_ERRATUM_1286807 | -+| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 | - | ARM | MMU-500 | #842869 | N/A | -diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig -index ecfa6822e4d3..c787a042a0a2 100644 ---- a/xen/arch/arm/Kconfig -+++ b/xen/arch/arm/Kconfig -@@ -278,6 +278,27 @@ config ARM64_ERRATUM_1286807 - - If unsure, say Y. - -+config ARM64_ERRATUM_1508412 -+ bool "Cortex-A77: 1508412: possible deadlock on sequence of NC/Device load and store exclusive or PAR read" -+ default y -+ depends on ARM_64 -+ help -+ This option adds a workaround for Arm Cortex-A77 erratum 1508412. -+ -+ Affected Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence -+ of a store-exclusive or read of PAR_EL1 and a load with device or -+ non-cacheable memory attributes. The workaround depends on a firmware -+ counterpart. -+ -+ Xen guests must also have the workaround implemented or they can -+ deadlock the system. -+ -+ Work around the issue by inserting DMB SY barriers around PAR_EL1 -+ register reads and warning Xen users. The DMB barrier is sufficient -+ to prevent a speculative PAR_EL1 read. -+ -+ If unsure, say Y. -+ - endmenu - - config ARM64_HARDEN_BRANCH_PREDICTOR -diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S -index 95f1a9268419..95ff4e3e0517 100644 ---- a/xen/arch/arm/arm64/entry.S -+++ b/xen/arch/arm/arm64/entry.S -@@ -134,6 +134,16 @@ - * position on the stack before. - */ - .macro entry, hyp, compat, save_x0_x1=1 -+ -+ /* -+ * Ensure any PAR_EL1 reads complete, in case we were interrupted -+ * between the PAR_EL1 read and the memory barrier for the erratum -+ * 1508412 workaround. -+ */ -+ alternative_if ARM64_WORKAROUND_1508412 -+ dmb sy -+ alternative_else_nop_endif -+ - sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ - - .if \hyp == 0 /* Guest mode */ -@@ -492,6 +502,15 @@ return_from_trap: - - ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ - -+ /* -+ * Ensure any device/NC reads complete, in case we were interrupted -+ * between the memory barrier for the erratum 1508412 workaround and -+ * any PAR_EL1 read. -+ */ -+ alternative_if ARM64_WORKAROUND_1508412 -+ dmb sy -+ alternative_else_nop_endif -+ - eret - sb - -diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c -index ae649d16ef02..ea680fac2e44 100644 ---- a/xen/arch/arm/cpuerrata.c -+++ b/xen/arch/arm/cpuerrata.c -@@ -668,6 +668,14 @@ static const struct arm_cpu_capabilities arm_errata[] = { - .capability = ARM64_WORKAROUND_AT_SPECULATE, - MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), - }, -+#ifdef CONFIG_ARM64_ERRATUM_1508412 -+ { -+ /* Cortex-A77 r0p0 - r1p0 */ -+ .desc = "ARM erratum 1508412 (hypervisor portion)", -+ .capability = ARM64_WORKAROUND_1508412, -+ MIDR_RANGE(MIDR_CORTEX_A77, 0, 1), -+ }, -+#endif - { - /* Cortex-A55 (All versions as erratum is open in SDEN v14) */ - .desc = "ARM erratum 1530923", -@@ -686,11 +694,11 @@ void __init enable_errata_workarounds(void) - { - enable_cpu_capabilities(arm_errata); - --#ifdef CONFIG_ARM64_ERRATUM_832075 -- if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ) -+#if defined(CONFIG_ARM64_ERRATUM_832075) || defined(CONFIG_ARM64_ERRATUM_1508412) -+ if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) || -+ cpus_have_cap(ARM64_WORKAROUND_1508412) ) - { -- printk_once("**** This CPU is affected by the errata 832075. ****\n" -- "**** Guests without CPU erratum workarounds can deadlock the system! ****\n" -+ printk_once("**** Guests without CPU erratum workarounds can deadlock the system! ****\n" - "**** Only trusted guests should be used. ****\n"); - - /* Taint the machine has being insecure */ -diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c -index 96e1b235501d..cb1d54ba8549 100644 ---- a/xen/arch/arm/domain.c -+++ b/xen/arch/arm/domain.c -@@ -137,7 +137,7 @@ static void ctxt_switch_from(struct vcpu *p) - p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1); - if ( is_32bit_domain(p->domain) ) - p->arch.dacr = READ_SYSREG(DACR32_EL2); -- p->arch.par = READ_SYSREG64(PAR_EL1); -+ p->arch.par = read_sysreg_par(); - #if defined(CONFIG_ARM_32) - p->arch.mair0 = READ_CP32(MAIR0); - p->arch.mair1 = READ_CP32(MAIR1); -diff --git a/xen/include/asm-arm/arm64/page.h b/xen/include/asm-arm/arm64/page.h -index 0cba2663733b..fbfe67bf8951 100644 ---- a/xen/include/asm-arm/arm64/page.h -+++ b/xen/include/asm-arm/arm64/page.h -@@ -48,11 +48,11 @@ static inline void invalidate_icache_local(void) - /* Ask the MMU to translate a VA for us */ - static inline uint64_t __va_to_par(vaddr_t va) - { -- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); -+ uint64_t par, tmp = read_sysreg_par(); - - asm volatile ("at s1e2r, %0;" : : "r" (va)); - isb(); -- par = READ_SYSREG64(PAR_EL1); -+ par = read_sysreg_par(); - WRITE_SYSREG64(tmp, PAR_EL1); - return par; - } -@@ -60,28 +60,28 @@ static inline uint64_t __va_to_par(vaddr_t va) - /* Ask the MMU to translate a Guest VA for us */ - static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags) - { -- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); -+ uint64_t par, tmp = read_sysreg_par(); - - if ( (flags & GV2M_WRITE) == GV2M_WRITE ) - asm volatile ("at s12e1w, %0;" : : "r" (va)); - else - asm volatile ("at s12e1r, %0;" : : "r" (va)); - isb(); -- par = READ_SYSREG64(PAR_EL1); -+ par = read_sysreg_par(); - WRITE_SYSREG64(tmp, PAR_EL1); - return par; - } - - static inline uint64_t gva_to_ipa_par(vaddr_t va, unsigned int flags) - { -- uint64_t par, tmp = READ_SYSREG64(PAR_EL1); -+ uint64_t par, tmp = read_sysreg_par(); - - if ( (flags & GV2M_WRITE) == GV2M_WRITE ) - asm volatile ("at s1e1w, %0;" : : "r" (va)); - else - asm volatile ("at s1e1r, %0;" : : "r" (va)); - isb(); -- par = READ_SYSREG64(PAR_EL1); -+ par = read_sysreg_par(); - WRITE_SYSREG64(tmp, PAR_EL1); - return par; - } -diff --git a/xen/include/asm-arm/cpufeature.h b/xen/include/asm-arm/cpufeature.h -index f7368766c07c..2f38137f39d5 100644 ---- a/xen/include/asm-arm/cpufeature.h -+++ b/xen/include/asm-arm/cpufeature.h -@@ -67,8 +67,9 @@ - #define ARM_WORKAROUND_BHB_LOOP_24 13 - #define ARM_WORKAROUND_BHB_LOOP_32 14 - #define ARM_WORKAROUND_BHB_SMCC_3 15 -+#define ARM64_WORKAROUND_1508412 16 - --#define ARM_NCAPS 16 -+#define ARM_NCAPS 17 - - #ifndef __ASSEMBLY__ - -diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h -index 5c5c51bbcdbf..61e30c9e517c 100644 ---- a/xen/include/asm-arm/sysregs.h -+++ b/xen/include/asm-arm/sysregs.h -@@ -9,6 +9,30 @@ - # error "unknown ARM variant" - #endif - -+#ifndef __ASSEMBLY__ -+ -+#include -+ -+static inline register_t read_sysreg_par(void) -+{ -+ register_t par_el1; -+ -+ /* -+ * On Cortex-A77 r0p0 and r1p0, read access to PAR_EL1 shall include a -+ * DMB SY before and after accessing it, as part of the workaround for the -+ * errata 1508412. -+ */ -+ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, -+ CONFIG_ARM64_ERRATUM_1508412)); -+ par_el1 = READ_SYSREG64(PAR_EL1); -+ asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412, -+ CONFIG_ARM64_ERRATUM_1508412)); -+ -+ return par_el1; -+} -+ -+#endif /* !__ASSEMBLY__ */ -+ - #endif /* __ASM_ARM_SYSREGS_H */ - /* - * Local variables: --- -2.40.1 - From afce7b2845e4f1fee296daa141c72e9a194554bd Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 26 Sep 2023 15:20:03 +0100 Subject: [PATCH 34/99] 3 security issues - arm32: The cache may not be properly cleaned/invalidated [XSA-437, CVE-2023-34321] - top-level shadow reference dropped too early for 64-bit PV guests [XSA-438, CVE-2023-34322] - x86/AMD: Divide speculative information leak [XSA-439, CVE-2023-20588] --- xen.spec | 33 +- xsa437.patch | 110 +++++ xsa438-4.17.patch | 416 ++++++++++++++++++ ...enbleed-check-to-models-good-ucode-i.patch | 49 +++ ...x-confusion-between-SPEC_CTRL_EXIT_T.patch | 77 ++++ ...ld-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch | 88 ++++ ...rn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch | 86 ++++ ...prove-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch | 109 +++++ ...-restore_all_xen-to-hold-stack_end-i.patch | 77 ++++ ...the-IST-ness-of-an-entry-for-the-exi.patch | 112 +++++ ...rl-Issue-VERW-during-IST-exit-to-Xen.patch | 92 ++++ ...troduce-is_zen-1-2-_uarch-predicates.patch | 94 ++++ ...c-ctrl-Mitigate-the-Zen1-DIV-leakage.patch | 231 ++++++++++ 13 files changed, 1573 insertions(+), 1 deletion(-) create mode 100644 xsa437.patch create mode 100644 xsa438-4.17.patch create mode 100644 xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch create mode 100644 xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch create mode 100644 xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch create mode 100644 xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch create mode 100644 xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch create mode 100644 xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch create mode 100644 xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch create mode 100644 xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch create mode 100644 xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch create mode 100644 xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch diff --git a/xen.spec b/xen.spec index dda5785..778a2e5 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.2 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,18 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch +Patch51: xsa437.patch +Patch52: xsa438-4.17.patch +Patch53: xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch +Patch54: xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch +Patch55: xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch +Patch56: xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch +Patch57: xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch +Patch58: xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch +Patch59: xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch +Patch60: xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch +Patch61: xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch +Patch62: xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch %if %build_qemutrad @@ -328,6 +340,18 @@ manage Xen virtual machines. %if "%dist" != ".fc38" %patch 50 -p1 %endif +%patch 51 -p1 +%patch 52 -p1 +%patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 +%patch 56 -p1 +%patch 57 -p1 +%patch 58 -p1 +%patch 59 -p1 +%patch 60 -p1 +%patch 61 -p1 +%patch 62 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -935,6 +959,13 @@ fi %endif %changelog +* Tue Sep 26 2023 Michael Young - 4.17.2-2 +- arm32: The cache may not be properly cleaned/invalidated [XSA-437, + CVE-2023-34321] +- top-level shadow reference dropped too early for 64-bit PV guests + [XSA-438, CVE-2023-34322] +- x86/AMD: Divide speculative information leak [XSA-439, CVE-2023-20588] + * Thu Aug 10 2023 Michael Young - 4.17.2-1 - update to xen-4.17.2 which includes x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569] diff --git a/xsa437.patch b/xsa437.patch new file mode 100644 index 0000000..18c9f8f --- /dev/null +++ b/xsa437.patch @@ -0,0 +1,110 @@ +From 7fac5971340a13ca9458195305bcfe14df2e52d2 Mon Sep 17 00:00:00 2001 +From: Stefano Stabellini +Date: Thu, 17 Aug 2023 13:41:35 +0100 +Subject: [PATCH] xen/arm: page: Handle cache flush of an element at the top of + the address space + +The region that needs to be cleaned/invalidated may be at the top +of the address space. This means that 'end' (i.e. 'p + size') will +be 0 and therefore nothing will be cleaned/invalidated as the check +in the loop will always be false. + +On Arm64, we only support we only support up to 48-bit Virtual +address space. So this is not a concern there. However, for 32-bit, +the mapcache is using the last 2GB of the address space. Therefore +we may not clean/invalidate properly some pages. This could lead +to memory corruption or data leakage (the scrubbed value may +still sit in the cache when the guest could read directly the memory +and therefore read the old content). + +Rework invalidate_dcache_va_range(), clean_dcache_va_range(), +clean_and_invalidate_dcache_va_range() to handle a cache flush +with an element at the top of the address space. + +This is CVE-2023-34321 / XSA-437. + +Reported-by: Julien Grall +Signed-off-by: Stefano Stabellini +Signed-off-by: Julien Grall +Acked-by: Bertrand Marquis + +--- + xen/arch/arm/include/asm/page.h | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h +index e7cd62190c7f..d7fe770a5e49 100644 +--- a/xen/arch/arm/include/asm/page.h ++++ b/xen/arch/arm/include/asm/page.h +@@ -160,26 +160,25 @@ static inline size_t read_dcache_line_bytes(void) + + static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + { +- const void *end = p + size; + size_t cacheline_mask = dcache_line_bytes - 1; + + dsb(sy); /* So the CPU issues all writes to the range */ + + if ( (uintptr_t)p & cacheline_mask ) + { ++ size -= dcache_line_bytes - ((uintptr_t)p & cacheline_mask); + p = (void *)((uintptr_t)p & ~cacheline_mask); + asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); + p += dcache_line_bytes; + } +- if ( (uintptr_t)end & cacheline_mask ) +- { +- end = (void *)((uintptr_t)end & ~cacheline_mask); +- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (end)); +- } + +- for ( ; p < end; p += dcache_line_bytes ) ++ for ( ; size >= dcache_line_bytes; ++ p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__invalidate_dcache_one(0) : : "r" (p)); + ++ if ( size > 0 ) ++ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); ++ + dsb(sy); /* So we know the flushes happen before continuing */ + + return 0; +@@ -187,10 +186,14 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + + static inline int clean_dcache_va_range(const void *p, unsigned long size) + { +- const void *end = p + size; ++ size_t cacheline_mask = dcache_line_bytes - 1; ++ + dsb(sy); /* So the CPU issues all writes to the range */ +- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1)); +- for ( ; p < end; p += dcache_line_bytes ) ++ size += (uintptr_t)p & cacheline_mask; ++ size = (size + cacheline_mask) & ~cacheline_mask; ++ p = (void *)((uintptr_t)p & ~cacheline_mask); ++ for ( ; size >= dcache_line_bytes; ++ p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__clean_dcache_one(0) : : "r" (p)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ +@@ -200,10 +203,14 @@ static inline int clean_dcache_va_range(const void *p, unsigned long size) + static inline int clean_and_invalidate_dcache_va_range + (const void *p, unsigned long size) + { +- const void *end = p + size; ++ size_t cacheline_mask = dcache_line_bytes - 1; ++ + dsb(sy); /* So the CPU issues all writes to the range */ +- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1)); +- for ( ; p < end; p += dcache_line_bytes ) ++ size += (uintptr_t)p & cacheline_mask; ++ size = (size + cacheline_mask) & ~cacheline_mask; ++ p = (void *)((uintptr_t)p & ~cacheline_mask); ++ for ( ; size >= dcache_line_bytes; ++ p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ +-- +2.40.1 + diff --git a/xsa438-4.17.patch b/xsa438-4.17.patch new file mode 100644 index 0000000..12d6ec7 --- /dev/null +++ b/xsa438-4.17.patch @@ -0,0 +1,416 @@ +From: Jan Beulich +Subject: x86/shadow: defer releasing of PV's top-level shadow reference + +sh_set_toplevel_shadow() re-pinning the top-level shadow we may be +running on is not enough (and at the same time unnecessary when the +shadow isn't what we're running on): That shadow becomes eligible for +blowing away (from e.g. shadow_prealloc()) immediately after the +paging lock was dropped. Yet it needs to remain valid until the actual +page table switch occurred. + +Propagate up the call chain the shadow entry that needs releasing +eventually, and carry out the release immediately after switching page +tables. Handle update_cr3() failures by switching to idle pagetables. +Note that various further uses of update_cr3() are HVM-only or only act +on paused vCPU-s, in which case sh_set_toplevel_shadow() will not defer +releasing of the reference. + +While changing the update_cr3() hook, also convert the "do_locking" +parameter to boolean. + +This is CVE-2023-34322 / XSA-438. + +Reported-by: Tim Deegan +Signed-off-by: Jan Beulich +Reviewed-by: George Dunlap + +--- a/xen/arch/x86/include/asm/mm.h ++++ b/xen/arch/x86/include/asm/mm.h +@@ -552,7 +552,7 @@ void audit_domains(void); + #endif + + void make_cr3(struct vcpu *v, mfn_t mfn); +-void update_cr3(struct vcpu *v); ++pagetable_t update_cr3(struct vcpu *v); + int vcpu_destroy_pagetables(struct vcpu *); + void *do_page_walk(struct vcpu *v, unsigned long addr); + +--- a/xen/arch/x86/include/asm/paging.h ++++ b/xen/arch/x86/include/asm/paging.h +@@ -138,7 +138,7 @@ struct paging_mode { + paddr_t ga, uint32_t *pfec, + unsigned int *page_order); + #endif +- void (*update_cr3 )(struct vcpu *v, int do_locking, ++ pagetable_t (*update_cr3 )(struct vcpu *v, bool do_locking, + bool noflush); + void (*update_paging_modes )(struct vcpu *v); + bool (*flush_tlb )(const unsigned long *vcpu_bitmap); +@@ -310,9 +310,9 @@ static inline unsigned long paging_ga_to + /* Update all the things that are derived from the guest's CR3. + * Called when the guest changes CR3; the caller can then use v->arch.cr3 + * as the value to load into the host CR3 to schedule this vcpu */ +-static inline void paging_update_cr3(struct vcpu *v, bool noflush) ++static inline pagetable_t paging_update_cr3(struct vcpu *v, bool noflush) + { +- paging_get_hostmode(v)->update_cr3(v, 1, noflush); ++ return paging_get_hostmode(v)->update_cr3(v, 1, noflush); + } + + /* Update all the things that are derived from the guest's CR0/CR3/CR4. +--- a/xen/arch/x86/include/asm/shadow.h ++++ b/xen/arch/x86/include/asm/shadow.h +@@ -99,6 +99,9 @@ int shadow_set_allocation(struct domain + + int shadow_get_allocation_bytes(struct domain *d, uint64_t *size); + ++/* Helper to invoke for deferred releasing of a top-level shadow's reference. */ ++void shadow_put_top_level(struct domain *d, pagetable_t old); ++ + #else /* !CONFIG_SHADOW_PAGING */ + + #define shadow_vcpu_teardown(v) ASSERT(is_pv_vcpu(v)) +@@ -121,6 +124,11 @@ static inline void shadow_prepare_page_t + + static inline void shadow_blow_tables_per_domain(struct domain *d) {} + ++static inline void shadow_put_top_level(struct domain *d, pagetable_t old) ++{ ++ ASSERT_UNREACHABLE(); ++} ++ + static inline int shadow_domctl(struct domain *d, + struct xen_domctl_shadow_op *sc, + XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) +--- a/xen/arch/x86/mm/hap/hap.c ++++ b/xen/arch/x86/mm/hap/hap.c +@@ -739,11 +739,13 @@ static bool cf_check hap_invlpg(struct v + return 1; + } + +-static void cf_check hap_update_cr3( +- struct vcpu *v, int do_locking, bool noflush) ++static pagetable_t cf_check hap_update_cr3( ++ struct vcpu *v, bool do_locking, bool noflush) + { + v->arch.hvm.hw_cr[3] = v->arch.hvm.guest_cr[3]; + hvm_update_guest_cr3(v, noflush); ++ ++ return pagetable_null(); + } + + static bool flush_vcpu(const struct vcpu *v, const unsigned long *vcpu_bitmap) +--- a/xen/arch/x86/mm/shadow/common.c ++++ b/xen/arch/x86/mm/shadow/common.c +@@ -2590,13 +2590,13 @@ void cf_check shadow_update_paging_modes + } + + /* Set up the top-level shadow and install it in slot 'slot' of shadow_table */ +-void sh_set_toplevel_shadow(struct vcpu *v, +- unsigned int slot, +- mfn_t gmfn, +- unsigned int root_type, +- mfn_t (*make_shadow)(struct vcpu *v, +- mfn_t gmfn, +- uint32_t shadow_type)) ++pagetable_t sh_set_toplevel_shadow(struct vcpu *v, ++ unsigned int slot, ++ mfn_t gmfn, ++ unsigned int root_type, ++ mfn_t (*make_shadow)(struct vcpu *v, ++ mfn_t gmfn, ++ uint32_t shadow_type)) + { + mfn_t smfn; + pagetable_t old_entry, new_entry; +@@ -2653,20 +2653,37 @@ void sh_set_toplevel_shadow(struct vcpu + mfn_x(gmfn), mfn_x(pagetable_get_mfn(new_entry))); + v->arch.paging.shadow.shadow_table[slot] = new_entry; + +- /* Decrement the refcount of the old contents of this slot */ +- if ( !pagetable_is_null(old_entry) ) ++ /* ++ * Decrement the refcount of the old contents of this slot, unless ++ * we're still running on that shadow - in that case it'll need holding ++ * on to until the actual page table switch did occur. ++ */ ++ if ( !pagetable_is_null(old_entry) && (v != current || !is_pv_domain(d)) ) + { +- mfn_t old_smfn = pagetable_get_mfn(old_entry); +- /* Need to repin the old toplevel shadow if it's been unpinned +- * by shadow_prealloc(): in PV mode we're still running on this +- * shadow and it's not safe to free it yet. */ +- if ( !mfn_to_page(old_smfn)->u.sh.pinned && !sh_pin(d, old_smfn) ) +- { +- printk(XENLOG_G_ERR "can't re-pin %"PRI_mfn"\n", mfn_x(old_smfn)); +- domain_crash(d); +- } +- sh_put_ref(d, old_smfn, 0); ++ sh_put_ref(d, pagetable_get_mfn(old_entry), 0); ++ old_entry = pagetable_null(); + } ++ ++ /* ++ * 2- and 3-level shadow mode is used for HVM only. Therefore we never run ++ * on such a shadow, so only call sites requesting an L4 shadow need to pay ++ * attention to the returned value. ++ */ ++ ASSERT(pagetable_is_null(old_entry) || root_type == SH_type_l4_64_shadow); ++ ++ return old_entry; ++} ++ ++/* ++ * Helper invoked when releasing of a top-level shadow's reference was ++ * deferred in sh_set_toplevel_shadow() above. ++ */ ++void shadow_put_top_level(struct domain *d, pagetable_t old_entry) ++{ ++ ASSERT(!pagetable_is_null(old_entry)); ++ paging_lock(d); ++ sh_put_ref(d, pagetable_get_mfn(old_entry), 0); ++ paging_unlock(d); + } + + /**************************************************************************/ +--- a/xen/arch/x86/mm/shadow/multi.c ++++ b/xen/arch/x86/mm/shadow/multi.c +@@ -3224,7 +3224,8 @@ static void cf_check sh_detach_old_table + } + } + +-static void cf_check sh_update_cr3(struct vcpu *v, int do_locking, bool noflush) ++static pagetable_t cf_check sh_update_cr3(struct vcpu *v, bool do_locking, ++ bool noflush) + /* Updates vcpu->arch.cr3 after the guest has changed CR3. + * Paravirtual guests should set v->arch.guest_table (and guest_table_user, + * if appropriate). +@@ -3238,6 +3239,7 @@ static void cf_check sh_update_cr3(struc + { + struct domain *d = v->domain; + mfn_t gmfn; ++ pagetable_t old_entry = pagetable_null(); + #if GUEST_PAGING_LEVELS == 3 + const guest_l3e_t *gl3e; + unsigned int i, guest_idx; +@@ -3247,7 +3249,7 @@ static void cf_check sh_update_cr3(struc + if ( !is_hvm_domain(d) && !v->is_initialised ) + { + ASSERT(v->arch.cr3 == 0); +- return; ++ return old_entry; + } + + if ( do_locking ) paging_lock(v->domain); +@@ -3320,11 +3322,12 @@ static void cf_check sh_update_cr3(struc + #if GUEST_PAGING_LEVELS == 4 + if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 ) + guest_flush_tlb_mask(d, d->dirty_cpumask); +- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, ++ sh_make_shadow); + if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) + { + ASSERT(d->is_dying || d->is_shutting_down); +- return; ++ return old_entry; + } + if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) ) + { +@@ -3368,24 +3371,30 @@ static void cf_check sh_update_cr3(struc + gl2gfn = guest_l3e_get_gfn(gl3e[i]); + gl2mfn = get_gfn_query_unlocked(d, gfn_x(gl2gfn), &p2mt); + if ( p2m_is_ram(p2mt) ) +- sh_set_toplevel_shadow(v, i, gl2mfn, SH_type_l2_shadow, +- sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, i, gl2mfn, ++ SH_type_l2_shadow, ++ sh_make_shadow); + else +- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, +- sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, ++ sh_make_shadow); + } + else +- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, ++ sh_make_shadow); ++ ++ ASSERT(pagetable_is_null(old_entry)); + } + } + #elif GUEST_PAGING_LEVELS == 2 + if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 ) + guest_flush_tlb_mask(d, d->dirty_cpumask); +- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, ++ sh_make_shadow); ++ ASSERT(pagetable_is_null(old_entry)); + if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) + { + ASSERT(d->is_dying || d->is_shutting_down); +- return; ++ return old_entry; + } + #else + #error This should never happen +@@ -3473,6 +3482,8 @@ static void cf_check sh_update_cr3(struc + + /* Release the lock, if we took it (otherwise it's the caller's problem) */ + if ( do_locking ) paging_unlock(v->domain); ++ ++ return old_entry; + } + + +--- a/xen/arch/x86/mm/shadow/none.c ++++ b/xen/arch/x86/mm/shadow/none.c +@@ -52,9 +52,11 @@ static unsigned long cf_check _gva_to_gf + } + #endif + +-static void cf_check _update_cr3(struct vcpu *v, int do_locking, bool noflush) ++static pagetable_t cf_check _update_cr3(struct vcpu *v, bool do_locking, ++ bool noflush) + { + ASSERT_UNREACHABLE(); ++ return pagetable_null(); + } + + static void cf_check _update_paging_modes(struct vcpu *v) +--- a/xen/arch/x86/mm/shadow/private.h ++++ b/xen/arch/x86/mm/shadow/private.h +@@ -391,13 +391,13 @@ mfn_t shadow_alloc(struct domain *d, + void shadow_free(struct domain *d, mfn_t smfn); + + /* Set up the top-level shadow and install it in slot 'slot' of shadow_table */ +-void sh_set_toplevel_shadow(struct vcpu *v, +- unsigned int slot, +- mfn_t gmfn, +- unsigned int root_type, +- mfn_t (*make_shadow)(struct vcpu *v, +- mfn_t gmfn, +- uint32_t shadow_type)); ++pagetable_t sh_set_toplevel_shadow(struct vcpu *v, ++ unsigned int slot, ++ mfn_t gmfn, ++ unsigned int root_type, ++ mfn_t (*make_shadow)(struct vcpu *v, ++ mfn_t gmfn, ++ uint32_t shadow_type)); + + /* Update the shadows in response to a pagetable write from Xen */ + int sh_validate_guest_entry(struct vcpu *v, mfn_t gmfn, void *entry, u32 size); +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -567,15 +567,12 @@ void write_ptbase(struct vcpu *v) + * + * Update ref counts to shadow tables appropriately. + */ +-void update_cr3(struct vcpu *v) ++pagetable_t update_cr3(struct vcpu *v) + { + mfn_t cr3_mfn; + + if ( paging_mode_enabled(v->domain) ) +- { +- paging_update_cr3(v, false); +- return; +- } ++ return paging_update_cr3(v, false); + + if ( !(v->arch.flags & TF_kernel_mode) ) + cr3_mfn = pagetable_get_mfn(v->arch.guest_table_user); +@@ -583,6 +580,8 @@ void update_cr3(struct vcpu *v) + cr3_mfn = pagetable_get_mfn(v->arch.guest_table); + + make_cr3(v, cr3_mfn); ++ ++ return pagetable_null(); + } + + static inline void set_tlbflush_timestamp(struct page_info *page) +@@ -3285,6 +3284,7 @@ int new_guest_cr3(mfn_t mfn) + struct domain *d = curr->domain; + int rc; + mfn_t old_base_mfn; ++ pagetable_t old_shadow; + + if ( is_pv_32bit_domain(d) ) + { +@@ -3352,9 +3352,22 @@ int new_guest_cr3(mfn_t mfn) + if ( !VM_ASSIST(d, m2p_strict) ) + fill_ro_mpt(mfn); + curr->arch.guest_table = pagetable_from_mfn(mfn); +- update_cr3(curr); ++ old_shadow = update_cr3(curr); ++ ++ /* ++ * In shadow mode update_cr3() can fail, in which case here we're still ++ * running on the prior top-level shadow (which we're about to release). ++ * Switch to the idle page tables in such an event; the guest will have ++ * been crashed already. ++ */ ++ if ( likely(!mfn_eq(pagetable_get_mfn(old_shadow), ++ maddr_to_mfn(curr->arch.cr3 & ~X86_CR3_NOFLUSH))) ) ++ write_ptbase(curr); ++ else ++ write_ptbase(idle_vcpu[curr->processor]); + +- write_ptbase(curr); ++ if ( !pagetable_is_null(old_shadow) ) ++ shadow_put_top_level(d, old_shadow); + + if ( likely(mfn_x(old_base_mfn) != 0) ) + { +--- a/xen/arch/x86/pv/domain.c ++++ b/xen/arch/x86/pv/domain.c +@@ -424,10 +424,13 @@ bool __init xpti_pcid_enabled(void) + + static void _toggle_guest_pt(struct vcpu *v) + { ++ bool guest_update; ++ pagetable_t old_shadow; + unsigned long cr3; + + v->arch.flags ^= TF_kernel_mode; +- update_cr3(v); ++ guest_update = v->arch.flags & TF_kernel_mode; ++ old_shadow = update_cr3(v); + + /* + * Don't flush user global mappings from the TLB. Don't tick TLB clock. +@@ -436,13 +439,31 @@ static void _toggle_guest_pt(struct vcpu + * TLB flush (for just the incoming PCID), as the top level page table may + * have changed behind our backs. To be on the safe side, suppress the + * no-flush unconditionally in this case. ++ * ++ * Furthermore in shadow mode update_cr3() can fail, in which case here ++ * we're still running on the prior top-level shadow (which we're about ++ * to release). Switch to the idle page tables in such an event; the ++ * guest will have been crashed already. + */ + cr3 = v->arch.cr3; + if ( shadow_mode_enabled(v->domain) ) ++ { + cr3 &= ~X86_CR3_NOFLUSH; ++ ++ if ( unlikely(mfn_eq(pagetable_get_mfn(old_shadow), ++ maddr_to_mfn(cr3))) ) ++ { ++ cr3 = idle_vcpu[v->processor]->arch.cr3; ++ /* Also suppress runstate/time area updates below. */ ++ guest_update = false; ++ } ++ } + write_cr3(cr3); + +- if ( !(v->arch.flags & TF_kernel_mode) ) ++ if ( !pagetable_is_null(old_shadow) ) ++ shadow_put_top_level(v->domain, old_shadow); ++ ++ if ( !guest_update ) + return; + + if ( v->arch.pv.need_update_runstate_area && update_runstate_area(v) ) diff --git a/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch b/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch new file mode 100644 index 0000000..96e56ec --- /dev/null +++ b/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch @@ -0,0 +1,49 @@ +From d2d2dcae879c6cc05227c9620f0a772f35fe6886 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Jan Beulich +Date: Wed, 23 Aug 2023 09:26:36 +0200 +Subject: [XEN PATCH 01/10] x86/AMD: extend Zenbleed check to models "good" + ucode isn't known for + +Reportedly the AMD Custom APU 0405 found on SteamDeck, models 0x90 and +0x91, (quoting the respective Linux commit) is similarly affected. Put +another instance of our Zen1 vs Zen2 distinction checks in +amd_check_zenbleed(), forcing use of the chickenbit irrespective of +ucode version (building upon real hardware never surfacing a version of +0xffffffff). + +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper +(cherry picked from commit 145a69c0944ac70cfcf9d247c85dee9e99d9d302) +--- + xen/arch/x86/cpu/amd.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 3ea214fc2e..1bb3044be1 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -909,10 +909,17 @@ void amd_check_zenbleed(void) + case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; + default: + /* +- * With the Fam17h check above, parts getting here are Zen1. +- * They're not affected. ++ * With the Fam17h check above, most parts getting here are ++ * Zen1. They're not affected. Assume Zen2 ones making it ++ * here are affected regardless of microcode version. ++ * ++ * Zen1 vs Zen2 isn't a simple model number comparison, so use ++ * STIBP as a heuristic to distinguish. + */ +- return; ++ if (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ return; ++ good_rev = ~0U; ++ break; + } + + rdmsrl(MSR_AMD64_DE_CFG, val); +-- +2.41.0 + diff --git a/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch b/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch new file mode 100644 index 0000000..8b8e30a --- /dev/null +++ b/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch @@ -0,0 +1,77 @@ +From dc28aba565f226f9bec24cfde993e78478acfb4e Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Andrew Cooper +Date: Tue, 12 Sep 2023 15:06:49 +0100 +Subject: [XEN PATCH 02/10] x86/spec-ctrl: Fix confusion between + SPEC_CTRL_EXIT_TO_XEN{,_IST} + +c/s 3fffaf9c13e9 ("x86/entry: Avoid using alternatives in NMI/#MC paths") +dropped the only user, leaving behind the (incorrect) implication that Xen had +split exit paths. + +Delete the unused SPEC_CTRL_EXIT_TO_XEN and rename SPEC_CTRL_EXIT_TO_XEN_IST +to SPEC_CTRL_EXIT_TO_XEN for consistency. + +No functional change. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 1c18d73774533a55ba9d1cbee8bdace03efdb5e7) +--- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 10 ++-------- + xen/arch/x86/x86_64/entry.S | 2 +- + 2 files changed, 3 insertions(+), 9 deletions(-) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index f23bb105c5..e8fd01243c 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -79,7 +79,6 @@ + * - SPEC_CTRL_ENTRY_FROM_PV + * - SPEC_CTRL_ENTRY_FROM_INTR + * - SPEC_CTRL_ENTRY_FROM_INTR_IST +- * - SPEC_CTRL_EXIT_TO_XEN_IST + * - SPEC_CTRL_EXIT_TO_XEN + * - SPEC_CTRL_EXIT_TO_PV + * +@@ -268,11 +267,6 @@ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ + X86_FEATURE_SC_MSR_PV + +-/* Use when exiting to Xen context. */ +-#define SPEC_CTRL_EXIT_TO_XEN \ +- ALTERNATIVE "", \ +- DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_SC_MSR_PV +- + /* Use when exiting to PV guest context. */ + #define SPEC_CTRL_EXIT_TO_PV \ + ALTERNATIVE "", \ +@@ -339,8 +333,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + UNLIKELY_END(\@_serialise) + .endm + +-/* Use when exiting to Xen in IST context. */ +-.macro SPEC_CTRL_EXIT_TO_XEN_IST ++/* Use when exiting to Xen context. */ ++.macro SPEC_CTRL_EXIT_TO_XEN + /* + * Requires %rbx=stack_end + * Clobbers %rax, %rcx, %rdx +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 7675a59ff0..b45a09823a 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -673,7 +673,7 @@ UNLIKELY_START(ne, exit_cr3) + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN_IST /* Req: %rbx=end, Clob: acd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */ + + RESTORE_ALL adj=8 + iretq +-- +2.41.0 + diff --git a/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch b/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch new file mode 100644 index 0000000..547032e --- /dev/null +++ b/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch @@ -0,0 +1,88 @@ +From 84690fb82c4f4aecb72a6789d8994efa74841e09 Mon Sep 17 00:00:00 2001 +Message-ID: <84690fb82c4f4aecb72a6789d8994efa74841e09.1695733540.git.m.a.young@durham.ac.uk> +In-Reply-To: +References: +From: Andrew Cooper +Date: Tue, 12 Sep 2023 17:03:16 +0100 +Subject: [XEN PATCH 03/10] x86/spec-ctrl: Fold DO_SPEC_CTRL_EXIT_TO_XEN into + it's single user + +With the SPEC_CTRL_EXIT_TO_XEN{,_IST} confusion fixed, it's now obvious that +there's only a single EXIT_TO_XEN path. Fold DO_SPEC_CTRL_EXIT_TO_XEN into +SPEC_CTRL_EXIT_TO_XEN to simplify further fixes. + +When merging labels, switch the name to .L\@_skip_sc_msr as "skip" on its own +is going to be too generic shortly. + +No functional change. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 694bb0f280fd08a4377e36e32b84b5062def4de2) +--- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 40 ++++++++++-------------- + 1 file changed, 16 insertions(+), 24 deletions(-) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index e8fd01243c..d5f65d80ea 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -211,27 +211,6 @@ + wrmsr + .endm + +-.macro DO_SPEC_CTRL_EXIT_TO_XEN +-/* +- * Requires %rbx=stack_end +- * Clobbers %rax, %rcx, %rdx +- * +- * When returning to Xen context, look to see whether SPEC_CTRL shadowing is +- * in effect, and reload the shadow value. This covers race conditions which +- * exist with an NMI/MCE/etc hitting late in the return-to-guest path. +- */ +- xor %edx, %edx +- +- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) +- jz .L\@_skip +- +- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax +- mov $MSR_SPEC_CTRL, %ecx +- wrmsr +- +-.L\@_skip: +-.endm +- + .macro DO_SPEC_CTRL_EXIT_TO_GUEST + /* + * Requires %eax=spec_ctrl, %rsp=regs/cpuinfo +@@ -340,11 +319,24 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + * Clobbers %rax, %rcx, %rdx + */ + testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) +- jz .L\@_skip ++ jz .L\@_skip_sc_msr + +- DO_SPEC_CTRL_EXIT_TO_XEN ++ /* ++ * When returning to Xen context, look to see whether SPEC_CTRL shadowing ++ * is in effect, and reload the shadow value. This covers race conditions ++ * which exist with an NMI/MCE/etc hitting late in the return-to-guest ++ * path. ++ */ ++ xor %edx, %edx + +-.L\@_skip: ++ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) ++ jz .L\@_skip_sc_msr ++ ++ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax ++ mov $MSR_SPEC_CTRL, %ecx ++ wrmsr ++ ++.L\@_skip_sc_msr: + .endm + + #endif /* __ASSEMBLY__ */ +-- +2.41.0 + diff --git a/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch b/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch new file mode 100644 index 0000000..3350750 --- /dev/null +++ b/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch @@ -0,0 +1,86 @@ +From 3952c73bdbd05f0e666986fce633a591237b3c88 Mon Sep 17 00:00:00 2001 +Message-ID: <3952c73bdbd05f0e666986fce633a591237b3c88.1695733540.git.m.a.young@durham.ac.uk> +In-Reply-To: +References: +From: Andrew Cooper +Date: Fri, 1 Sep 2023 11:38:44 +0100 +Subject: [XEN PATCH 04/10] x86/spec-ctrl: Turn the remaining + SPEC_CTRL_{ENTRY,EXIT}_* into asm macros + +These have grown more complex over time, with some already having been +converted. + +Provide full Requires/Clobbers comments, otherwise missing at this level of +indirection. + +No functional change. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 7125429aafb9e3c9c88fc93001fc2300e0ac2cc8) +--- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 37 ++++++++++++++++++------ + 1 file changed, 28 insertions(+), 9 deletions(-) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index d5f65d80ea..c6d5f2ad01 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -231,26 +231,45 @@ + .endm + + /* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ +-#define SPEC_CTRL_ENTRY_FROM_PV \ ++.macro SPEC_CTRL_ENTRY_FROM_PV ++/* ++ * Requires %rsp=regs/cpuinfo, %rdx=0 ++ * Clobbers %rax, %rcx, %rdx ++ */ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=0), \ +- X86_FEATURE_IBPB_ENTRY_PV; \ +- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ ++ X86_FEATURE_IBPB_ENTRY_PV ++ ++ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV ++ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), \ + X86_FEATURE_SC_MSR_PV ++.endm + + /* Use in interrupt/exception context. May interrupt Xen or PV context. */ +-#define SPEC_CTRL_ENTRY_FROM_INTR \ ++.macro SPEC_CTRL_ENTRY_FROM_INTR ++/* ++ * Requires %rsp=regs, %r14=stack_end, %rdx=0 ++ * Clobbers %rax, %rcx, %rdx ++ */ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=1), \ +- X86_FEATURE_IBPB_ENTRY_PV; \ +- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ ++ X86_FEATURE_IBPB_ENTRY_PV ++ ++ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV ++ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ + X86_FEATURE_SC_MSR_PV ++.endm + + /* Use when exiting to PV guest context. */ +-#define SPEC_CTRL_EXIT_TO_PV \ +- ALTERNATIVE "", \ +- DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV; \ ++.macro SPEC_CTRL_EXIT_TO_PV ++/* ++ * Requires %rax=spec_ctrl, %rsp=regs/info ++ * Clobbers %rcx, %rdx ++ */ ++ ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV ++ + DO_SPEC_CTRL_COND_VERW ++.endm + + /* + * Use in IST interrupt/exception context. May interrupt Xen or PV context. +-- +2.41.0 + diff --git a/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch b/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch new file mode 100644 index 0000000..dda088a --- /dev/null +++ b/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch @@ -0,0 +1,109 @@ +From ba023e93d0b1e60b80251bf080bab694efb9f8e3 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Andrew Cooper +Date: Wed, 30 Aug 2023 20:11:50 +0100 +Subject: [XEN PATCH 05/10] x86/spec-ctrl: Improve all SPEC_CTRL_{ENTER,EXIT}_* + comments + +... to better explain how they're used. + +Doing so highlights that SPEC_CTRL_EXIT_TO_XEN is missing a VERW flush for the +corner case when e.g. an NMI hits late in an exit-to-guest path. + +Leave a TODO, which will be addressed in subsequent patches which arrange for +VERW flushing to be safe within SPEC_CTRL_EXIT_TO_XEN. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 45f00557350dc7d0756551069803fc49c29184ca) +--- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 36 ++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 5 deletions(-) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index c6d5f2ad01..97c4db31cd 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -230,7 +230,10 @@ + wrmsr + .endm + +-/* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ ++/* ++ * Used after an entry from PV context: SYSCALL, SYSENTER, INT, ++ * etc. There is always a guest speculation state in context. ++ */ + .macro SPEC_CTRL_ENTRY_FROM_PV + /* + * Requires %rsp=regs/cpuinfo, %rdx=0 +@@ -245,7 +248,11 @@ + X86_FEATURE_SC_MSR_PV + .endm + +-/* Use in interrupt/exception context. May interrupt Xen or PV context. */ ++/* ++ * Used after an exception or maskable interrupt, hitting Xen or PV context. ++ * There will either be a guest speculation context, or (barring fatal ++ * exceptions) a well-formed Xen speculation context. ++ */ + .macro SPEC_CTRL_ENTRY_FROM_INTR + /* + * Requires %rsp=regs, %r14=stack_end, %rdx=0 +@@ -260,7 +267,10 @@ + X86_FEATURE_SC_MSR_PV + .endm + +-/* Use when exiting to PV guest context. */ ++/* ++ * Used when exiting from any entry context, back to PV context. This ++ * includes from an IST entry which moved onto the primary stack. ++ */ + .macro SPEC_CTRL_EXIT_TO_PV + /* + * Requires %rax=spec_ctrl, %rsp=regs/info +@@ -272,7 +282,13 @@ + .endm + + /* +- * Use in IST interrupt/exception context. May interrupt Xen or PV context. ++ * Used after an IST entry hitting Xen or PV context. Special care is needed, ++ * because when hitting Xen context, there may not be a well-formed ++ * speculation context. (i.e. it can hit in the middle of ++ * SPEC_CTRL_{ENTRY,EXIT}_* regions.) ++ * ++ * An IST entry which hits PV context moves onto the primary stack and leaves ++ * via SPEC_CTRL_EXIT_TO_PV, *not* SPEC_CTRL_EXIT_TO_XEN. + */ + .macro SPEC_CTRL_ENTRY_FROM_INTR_IST + /* +@@ -331,7 +347,14 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + UNLIKELY_END(\@_serialise) + .endm + +-/* Use when exiting to Xen context. */ ++/* ++ * Use when exiting from any entry context, back to Xen context. This ++ * includes returning to other SPEC_CTRL_{ENTRY,EXIT}_* regions with an ++ * incomplete speculation context. ++ * ++ * Because we might have interrupted Xen beyond SPEC_CTRL_EXIT_TO_$GUEST, we ++ * need to treat this as if it were an EXIT_TO_$GUEST case too. ++ */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* + * Requires %rbx=stack_end +@@ -356,6 +379,9 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + wrmsr + + .L\@_skip_sc_msr: ++ ++ /* TODO VERW */ ++ + .endm + + #endif /* __ASSEMBLY__ */ +-- +2.41.0 + diff --git a/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch b/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch new file mode 100644 index 0000000..e44998e --- /dev/null +++ b/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch @@ -0,0 +1,77 @@ +From 5f7efd47c8273fde972637d0360851802f76eca9 Mon Sep 17 00:00:00 2001 +Message-ID: <5f7efd47c8273fde972637d0360851802f76eca9.1695733540.git.m.a.young@durham.ac.uk> +In-Reply-To: +References: +From: Andrew Cooper +Date: Wed, 13 Sep 2023 13:48:16 +0100 +Subject: [XEN PATCH 06/10] x86/entry: Adjust restore_all_xen to hold stack_end + in %r14 + +All other SPEC_CTRL_{ENTRY,EXIT}_* helpers hold stack_end in %r14. Adjust it +for consistency. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 7aa28849a1155d856e214e9a80a7e65fffdc3e58) +--- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 8 ++++---- + xen/arch/x86/x86_64/entry.S | 8 ++++---- + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index 97c4db31cd..66c706496f 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -357,10 +357,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* +- * Requires %rbx=stack_end ++ * Requires %r14=stack_end + * Clobbers %rax, %rcx, %rdx + */ +- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) ++ testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) + jz .L\@_skip_sc_msr + + /* +@@ -371,10 +371,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + xor %edx, %edx + +- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) ++ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) + jz .L\@_skip_sc_msr + +- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax ++ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax + mov $MSR_SPEC_CTRL, %ecx + wrmsr + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index b45a09823a..92279a225d 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -665,15 +665,15 @@ restore_all_xen: + * Check whether we need to switch to the per-CPU page tables, in + * case we return to late PV exit code (from an NMI or #MC). + */ +- GET_STACK_END(bx) +- cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) ++ GET_STACK_END(14) ++ cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) + UNLIKELY_START(ne, exit_cr3) +- mov STACK_CPUINFO_FIELD(pv_cr3)(%rbx), %rax ++ mov STACK_CPUINFO_FIELD(pv_cr3)(%r14), %rax + mov %rax, %cr3 + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */ + + RESTORE_ALL adj=8 + iretq +-- +2.41.0 + diff --git a/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch b/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch new file mode 100644 index 0000000..2e36bcc --- /dev/null +++ b/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch @@ -0,0 +1,112 @@ +From e4a71bc0da0baf7464bb0d8e33053f330e5ea366 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Andrew Cooper +Date: Wed, 13 Sep 2023 12:20:12 +0100 +Subject: [XEN PATCH 07/10] x86/entry: Track the IST-ness of an entry for the + exit paths + +Use %r12 to hold an ist_exit boolean. This register is zero elsewhere in the +entry/exit asm, so it only needs setting in the IST path. + +As this is subtle and fragile, add check_ist_exit() to be used in debugging +builds to cross-check that the ist_exit boolean matches the entry vector. + +Write check_ist_exit() it in C, because it's debug only and the logic more +complicated than I care to maintain in asm. + +For now, we only need to use this signal in the exit-to-Xen path, but some +exit-to-guest paths happen in IST context too. Check the correctness in all +exit paths to avoid the logic bit-rotting. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 21bdc25b05a0f8ab6bc73520a9ca01327360732c) + +x86/entry: Partially revert IST-exit checks + +The patch adding check_ist_exit() didn't account for the fact that +reset_stack_and_jump() is not an ABI-preserving boundary. The IST-ness in +%r12 doesn't survive into the next context, and is a stale value C. + +This shows up in Gitlab CI for the Clang build: + + https://gitlab.com/xen-project/people/andyhhp/xen/-/jobs/5112783827 + +and in OSSTest for GCC 8: + + http://logs.test-lab.xenproject.org/osstest/logs/183045/test-amd64-amd64-xl-qemuu-debianhvm-amd64/serial-pinot0.log + +There's no straightforward way to reconstruct the IST-exit-ness on the +exit-to-guest path after a context switch. For now, we only need IST-exit on +the return-to-Xen path. + +Fixes: 21bdc25b05a0 ("x86/entry: Track the IST-ness of an entry for the exit paths") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 9b57c800b79b96769ea3dcd6468578fa664d19f9) +--- + xen/arch/x86/traps.c | 13 +++++++++++++ + xen/arch/x86/x86_64/entry.S | 13 ++++++++++++- + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c +index d12004b1c6..e65cc60041 100644 +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -2315,6 +2315,19 @@ void asm_domain_crash_synchronous(unsigned long addr) + do_softirq(); + } + ++#ifdef CONFIG_DEBUG ++void check_ist_exit(const struct cpu_user_regs *regs, bool ist_exit) ++{ ++ const unsigned int ist_mask = ++ (1U << X86_EXC_NMI) | (1U << X86_EXC_DB) | ++ (1U << X86_EXC_DF) | (1U << X86_EXC_MC); ++ uint8_t ev = regs->entry_vector; ++ bool is_ist = (ev < TRAP_nr) && ((1U << ev) & ist_mask); ++ ++ ASSERT(is_ist == ist_exit); ++} ++#endif ++ + /* + * Local variables: + * mode: C +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 92279a225d..4cebc4fbe3 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -659,8 +659,15 @@ ENTRY(early_page_fault) + .section .text.entry, "ax", @progbits + + ALIGN +-/* No special register assumptions. */ ++/* %r12=ist_exit */ + restore_all_xen: ++ ++#ifdef CONFIG_DEBUG ++ mov %rsp, %rdi ++ mov %r12, %rsi ++ call check_ist_exit ++#endif ++ + /* + * Check whether we need to switch to the per-CPU page tables, in + * case we return to late PV exit code (from an NMI or #MC). +@@ -1091,6 +1098,10 @@ handle_ist_exception: + .L_ist_dispatch_done: + mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) + mov %bl, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) ++ ++ /* This is an IST exit */ ++ mov $1, %r12d ++ + cmpb $TRAP_nmi,UREGS_entry_vector(%rsp) + jne ret_from_intr + +-- +2.41.0 + diff --git a/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch b/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch new file mode 100644 index 0000000..6e00ca6 --- /dev/null +++ b/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch @@ -0,0 +1,92 @@ +From 2e2c3efcfc9f183674a8de6ed954ffbe7188b70d Mon Sep 17 00:00:00 2001 +Message-ID: <2e2c3efcfc9f183674a8de6ed954ffbe7188b70d.1695733540.git.m.a.young@durham.ac.uk> +In-Reply-To: +References: +From: Andrew Cooper +Date: Wed, 13 Sep 2023 13:53:33 +0100 +Subject: [XEN PATCH 08/10] x86/spec-ctrl: Issue VERW during IST exit to Xen + +There is a corner case where e.g. an NMI hitting an exit-to-guest path after +SPEC_CTRL_EXIT_TO_* would have run the entire NMI handler *after* the VERW +flush to scrub potentially sensitive data from uarch buffers. + +In order to compensate, issue VERW when exiting to Xen from an IST entry. + +SPEC_CTRL_EXIT_TO_XEN already has two reads of spec_ctrl_flags off the stack, +and we're about to add a third. Load the field into %ebx, and list the +register as clobbered. + +%r12 has been arranged to be the ist_exit signal, so add this as an input +dependency and use it to identify when to issue a VERW. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 3ee6066bcd737756b0990d417d94eddc0b0d2585) +--- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 20 +++++++++++++++----- + xen/arch/x86/x86_64/entry.S | 2 +- + 2 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index 66c706496f..28a75796e6 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -357,10 +357,12 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* +- * Requires %r14=stack_end +- * Clobbers %rax, %rcx, %rdx ++ * Requires %r12=ist_exit, %r14=stack_end ++ * Clobbers %rax, %rbx, %rcx, %rdx + */ +- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) ++ movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx ++ ++ testb $SCF_ist_sc_msr, %bl + jz .L\@_skip_sc_msr + + /* +@@ -371,7 +373,7 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + xor %edx, %edx + +- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) ++ testb $SCF_use_shadow, %bl + jz .L\@_skip_sc_msr + + mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax +@@ -380,8 +382,16 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + + .L\@_skip_sc_msr: + +- /* TODO VERW */ ++ test %r12, %r12 ++ jz .L\@_skip_ist_exit ++ ++ /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */ ++ testb $SCF_verw, %bl ++ jz .L\@_skip_verw ++ verw STACK_CPUINFO_FIELD(verw_sel)(%r14) ++.L\@_skip_verw: + ++.L\@_skip_ist_exit: + .endm + + #endif /* __ASSEMBLY__ */ +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 4cebc4fbe3..c12e011b4d 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -680,7 +680,7 @@ UNLIKELY_START(ne, exit_cr3) + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */ + + RESTORE_ALL adj=8 + iretq +-- +2.41.0 + diff --git a/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch b/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch new file mode 100644 index 0000000..5f063b1 --- /dev/null +++ b/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch @@ -0,0 +1,94 @@ +From 19ee1e1faa32b79274b3484cb1170a5970f1e602 Mon Sep 17 00:00:00 2001 +Message-ID: <19ee1e1faa32b79274b3484cb1170a5970f1e602.1695733540.git.m.a.young@durham.ac.uk> +In-Reply-To: +References: +From: Andrew Cooper +Date: Fri, 15 Sep 2023 12:13:51 +0100 +Subject: [XEN PATCH 09/10] x86/amd: Introduce is_zen{1,2}_uarch() predicates + +We already have 3 cases using STIBP as a Zen1/2 heuristic, and are about to +introduce a 4th. Wrap the heuristic into a pair of predicates rather than +opencoding it, and the explanation of the heuristic, at each usage site. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit de1d265001397f308c5c3c5d3ffc30e7ef8c0705) +--- + xen/arch/x86/cpu/amd.c | 18 ++++-------------- + xen/arch/x86/include/asm/amd.h | 11 +++++++++++ + 2 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 1bb3044be1..e94ba5a0e0 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -855,15 +855,13 @@ void amd_set_legacy_ssbd(bool enable) + * non-branch instructions to be ignored. It is to be set unilaterally in + * newer microcode. + * +- * This chickenbit is something unrelated on Zen1, and Zen1 vs Zen2 isn't a +- * simple model number comparison, so use STIBP as a heuristic to separate the +- * two uarches in Fam17h(AMD)/18h(Hygon). ++ * This chickenbit is something unrelated on Zen1. + */ + void amd_init_spectral_chicken(void) + { + uint64_t val, chickenbit = 1 << 1; + +- if (cpu_has_hypervisor || !boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ if (cpu_has_hypervisor || !is_zen2_uarch()) + return; + + if (rdmsr_safe(MSR_AMD64_DE_CFG2, val) == 0 && !(val & chickenbit)) +@@ -912,11 +910,8 @@ void amd_check_zenbleed(void) + * With the Fam17h check above, most parts getting here are + * Zen1. They're not affected. Assume Zen2 ones making it + * here are affected regardless of microcode version. +- * +- * Zen1 vs Zen2 isn't a simple model number comparison, so use +- * STIBP as a heuristic to distinguish. + */ +- if (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ if (is_zen1_uarch()) + return; + good_rev = ~0U; + break; +@@ -1277,12 +1272,7 @@ static int __init cf_check zen2_c6_errata_check(void) + */ + s_time_t delta; + +- /* +- * Zen1 vs Zen2 isn't a simple model number comparison, so use STIBP as +- * a heuristic to separate the two uarches in Fam17h. +- */ +- if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || +- !boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || !is_zen2_uarch()) + return 0; + + /* +diff --git a/xen/arch/x86/include/asm/amd.h b/xen/arch/x86/include/asm/amd.h +index a975d3de26..82324110ab 100644 +--- a/xen/arch/x86/include/asm/amd.h ++++ b/xen/arch/x86/include/asm/amd.h +@@ -140,6 +140,17 @@ + AMD_MODEL_RANGE(0x11, 0x0, 0x0, 0xff, 0xf), \ + AMD_MODEL_RANGE(0x12, 0x0, 0x0, 0xff, 0xf)) + ++/* ++ * The Zen1 and Zen2 microarchitectures are implemented by AMD (Fam17h) and ++ * Hygon (Fam18h) but without simple model number rules. Instead, use STIBP ++ * as a heuristic that distinguishes the two. ++ * ++ * The caller is required to perform the appropriate vendor/family checks ++ * first. ++ */ ++#define is_zen1_uarch() (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++#define is_zen2_uarch() boot_cpu_has(X86_FEATURE_AMD_STIBP) ++ + struct cpuinfo_x86; + int cpu_has_amd_erratum(const struct cpuinfo_x86 *, int, ...); + +-- +2.41.0 + diff --git a/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch b/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch new file mode 100644 index 0000000..0dc6780 --- /dev/null +++ b/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch @@ -0,0 +1,231 @@ +From 9ac2f49f5fa3a5159409241d4f74fb0d721dd4c5 Mon Sep 17 00:00:00 2001 +Message-ID: <9ac2f49f5fa3a5159409241d4f74fb0d721dd4c5.1695733540.git.m.a.young@durham.ac.uk> +In-Reply-To: +References: +From: Andrew Cooper +Date: Wed, 30 Aug 2023 20:24:25 +0100 +Subject: [XEN PATCH 10/10] x86/spec-ctrl: Mitigate the Zen1 DIV leakage + +In the Zen1 microarchitecure, there is one divider in the pipeline which +services uops from both threads. In the case of #DE, the latched result from +the previous DIV to execute will be forwarded speculatively. + +This is an interesting covert channel that allows two threads to communicate +without any system calls. In also allows userspace to obtain the result of +the most recent DIV instruction executed (even speculatively) in the core, +which can be from a higher privilege context. + +Scrub the result from the divider by executing a non-faulting divide. This +needs performing on the exit-to-guest paths, and ist_exit-to-Xen. + +Alternatives in IST context is believed safe now that it's done in NMI +context. + +This is XSA-439 / CVE-2023-20588. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit b5926c6ecf05c28ee99c6248c42d691ccbf0c315) +--- + docs/misc/xen-command-line.pandoc | 6 ++- + xen/arch/x86/hvm/svm/entry.S | 1 + + xen/arch/x86/include/asm/cpufeatures.h | 2 +- + xen/arch/x86/include/asm/spec_ctrl_asm.h | 17 +++++++++ + xen/arch/x86/spec_ctrl.c | 48 +++++++++++++++++++++++- + 5 files changed, 71 insertions(+), 3 deletions(-) + +diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc +index d9dae740cc..b92c8f969c 100644 +--- a/docs/misc/xen-command-line.pandoc ++++ b/docs/misc/xen-command-line.pandoc +@@ -2315,7 +2315,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). + > {msr-sc,rsb,md-clear,ibpb-entry}=|{pv,hvm}=, + > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, + > eager-fpu,l1d-flush,branch-harden,srb-lock, +-> unpriv-mmio,gds-mit}= ]` ++> unpriv-mmio,gds-mit,div-scrub}= ]` + + Controls for speculative execution sidechannel mitigations. By default, Xen + will pick the most appropriate mitigations based on compiled in support, +@@ -2437,6 +2437,10 @@ has elected not to lock the configuration, Xen will use GDS_CTRL to mitigate + GDS with. Otherwise, Xen will mitigate by disabling AVX, which blocks the use + of the AVX2 Gather instructions. + ++On all hardware, the `div-scrub=` option can be used to force or prevent Xen ++from mitigating the DIV-leakage vulnerability. By default, Xen will mitigate ++DIV-leakage on hardware believed to be vulnerable. ++ + ### sync_console + > `= ` + +diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S +index 981cd82e7c..934f12cf5c 100644 +--- a/xen/arch/x86/hvm/svm/entry.S ++++ b/xen/arch/x86/hvm/svm/entry.S +@@ -74,6 +74,7 @@ __UNLIKELY_END(nsvm_hap) + 1: /* No Spectre v1 concerns. Execution will hit VMRUN imminently. */ + .endm + ALTERNATIVE "", svm_vmentry_spec_ctrl, X86_FEATURE_SC_MSR_HVM ++ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV + + pop %r15 + pop %r14 +diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h +index da0593de85..c3aad21c3b 100644 +--- a/xen/arch/x86/include/asm/cpufeatures.h ++++ b/xen/arch/x86/include/asm/cpufeatures.h +@@ -35,7 +35,7 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM + XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ + XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ + XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ +-/* Bits 23 unused. */ ++XEN_CPUFEATURE(SC_DIV, X86_SYNTH(23)) /* DIV scrub needed */ + XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ + XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ + XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index 28a75796e6..f4b8b9d956 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -177,6 +177,19 @@ + .L\@_verw_skip: + .endm + ++.macro DO_SPEC_CTRL_DIV ++/* ++ * Requires nothing ++ * Clobbers %rax ++ * ++ * Issue a DIV for its flushing side effect (Zen1 uarch specific). Any ++ * non-faulting DIV will do; a byte DIV has least latency, and doesn't clobber ++ * %rdx. ++ */ ++ mov $1, %eax ++ div %al ++.endm ++ + .macro DO_SPEC_CTRL_ENTRY maybexen:req + /* + * Requires %rsp=regs (also cpuinfo if !maybexen) +@@ -279,6 +292,8 @@ + ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV + + DO_SPEC_CTRL_COND_VERW ++ ++ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV + .endm + + /* +@@ -391,6 +406,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + verw STACK_CPUINFO_FIELD(verw_sel)(%r14) + .L\@_skip_verw: + ++ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV ++ + .L\@_skip_ist_exit: + .endm + +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 79b98f0fe7..0ff3c895ac 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -79,6 +79,7 @@ static int8_t __initdata opt_srb_lock = -1; + static bool __initdata opt_unpriv_mmio; + static bool __ro_after_init opt_fb_clear_mmio; + static int8_t __initdata opt_gds_mit = -1; ++static int8_t __initdata opt_div_scrub = -1; + + static int __init cf_check parse_spec_ctrl(const char *s) + { +@@ -133,6 +134,7 @@ static int __init cf_check parse_spec_ctrl(const char *s) + opt_srb_lock = 0; + opt_unpriv_mmio = false; + opt_gds_mit = 0; ++ opt_div_scrub = 0; + } + else if ( val > 0 ) + rc = -EINVAL; +@@ -285,6 +287,8 @@ static int __init cf_check parse_spec_ctrl(const char *s) + opt_unpriv_mmio = val; + else if ( (val = parse_boolean("gds-mit", s, ss)) >= 0 ) + opt_gds_mit = val; ++ else if ( (val = parse_boolean("div-scrub", s, ss)) >= 0 ) ++ opt_div_scrub = val; + else + rc = -EINVAL; + +@@ -485,7 +489,7 @@ static void __init print_details(enum ind_thunk thunk) + "\n"); + + /* Settings for Xen's protection, irrespective of guests. */ +- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s\n", ++ printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", + thunk == THUNK_NONE ? "N/A" : + thunk == THUNK_RETPOLINE ? "RETPOLINE" : + thunk == THUNK_LFENCE ? "LFENCE" : +@@ -510,6 +514,7 @@ static void __init print_details(enum ind_thunk thunk) + opt_l1d_flush ? " L1D_FLUSH" : "", + opt_md_clear_pv || opt_md_clear_hvm || + opt_fb_clear_mmio ? " VERW" : "", ++ opt_div_scrub ? " DIV" : "", + opt_branch_harden ? " BRANCH_HARDEN" : ""); + + /* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */ +@@ -967,6 +972,45 @@ static void __init srso_calculations(bool hw_smt_enabled) + setup_force_cpu_cap(X86_FEATURE_SRSO_NO); + } + ++/* ++ * The Div leakage issue is specific to the AMD Zen1 microarchitecure. ++ * ++ * However, there's no $FOO_NO bit defined, so if we're virtualised we have no ++ * hope of spotting the case where we might move to vulnerable hardware. We ++ * also can't make any useful conclusion about SMT-ness. ++ * ++ * Don't check the hypervisor bit, so at least we do the safe thing when ++ * booting on something that looks like a Zen1 CPU. ++ */ ++static bool __init has_div_vuln(void) ++{ ++ if ( !(boot_cpu_data.x86_vendor & ++ (X86_VENDOR_AMD | X86_VENDOR_HYGON)) ) ++ return false; ++ ++ if ( boot_cpu_data.x86 != 0x17 && boot_cpu_data.x86 != 0x18 ) ++ return false; ++ ++ return is_zen1_uarch(); ++} ++ ++static void __init div_calculations(bool hw_smt_enabled) ++{ ++ bool cpu_bug_div = has_div_vuln(); ++ ++ if ( opt_div_scrub == -1 ) ++ opt_div_scrub = cpu_bug_div; ++ ++ if ( opt_div_scrub ) ++ setup_force_cpu_cap(X86_FEATURE_SC_DIV); ++ ++ if ( opt_smt == -1 && !cpu_has_hypervisor && cpu_bug_div && hw_smt_enabled ) ++ warning_add( ++ "Booted on leaky-DIV hardware with SMT/Hyperthreading\n" ++ "enabled. Please assess your configuration and choose an\n" ++ "explicit 'smt=' setting. See XSA-439.\n"); ++} ++ + static void __init ibpb_calculations(void) + { + bool def_ibpb_entry = false; +@@ -1726,6 +1770,8 @@ void __init init_speculation_mitigations(void) + + ibpb_calculations(); + ++ div_calculations(hw_smt_enabled); ++ + /* Check whether Eager FPU should be enabled by default. */ + if ( opt_eager_fpu == -1 ) + opt_eager_fpu = should_use_eager_fpu(); +-- +2.41.0 + From a65ac23041114531b5a203905a9d8cb7afe6c0f0 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 26 Sep 2023 16:50:31 +0100 Subject: [PATCH 35/99] 3 security issues - arm32: The cache may not be properly cleaned/invalidated [XSA-437, CVE-2023-34321] - top-level shadow reference dropped too early for 64-bit PV guests [XSA-438, CVE-2023-34322] - x86/AMD: Divide speculative information leak [XSA-439, CVE-2023-20588] --- xen.spec | 33 +- xsa437-4.16.patch | 110 +++++ xsa438-4.16.patch | 414 ++++++++++++++++++ ...enbleed-check-to-models-good-ucode-i.patch | 49 +++ ...x-confusion-between-SPEC_CTRL_EXIT_T.patch | 77 ++++ ...ld-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch | 88 ++++ ...rn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch | 86 ++++ ...prove-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch | 109 +++++ ...-restore_all_xen-to-hold-stack_end-i.patch | 77 ++++ ...the-IST-ness-of-an-entry-for-the-exi.patch | 112 +++++ ...rl-Issue-VERW-during-IST-exit-to-Xen.patch | 92 ++++ ...troduce-is_zen-1-2-_uarch-predicates.patch | 94 ++++ ...c-ctrl-Mitigate-the-Zen1-DIV-leakage.patch | 239 ++++++++++ 13 files changed, 1579 insertions(+), 1 deletion(-) create mode 100644 xsa437-4.16.patch create mode 100644 xsa438-4.16.patch create mode 100644 xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch create mode 100644 xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch create mode 100644 xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch create mode 100644 xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch create mode 100644 xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch create mode 100644 xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch create mode 100644 xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch create mode 100644 xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch create mode 100644 xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch create mode 100644 xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch diff --git a/xen.spec b/xen.spec index aeff813..7c731d8 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.5 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -111,6 +111,18 @@ Patch43: xen.gcc11.fixes.patch Patch44: xsa376.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch +Patch47: xsa437-4.16.patch +Patch48: xsa438-4.16.patch +Patch49: xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch +Patch50: xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch +Patch51: xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch +Patch52: xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch +Patch53: xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch +Patch54: xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch +Patch55: xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch +Patch56: xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch +Patch57: xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch +Patch58: xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch %if %build_qemutrad @@ -323,6 +335,18 @@ manage Xen virtual machines. %patch44 -p1 %patch45 -p1 %patch46 -p1 +%patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 +%patch51 -p1 +%patch52 -p1 +%patch53 -p1 +%patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -931,6 +955,13 @@ fi %endif %changelog +* Tue Sep 26 2023 Michael Young - 4.16.5-2 +- arm32: The cache may not be properly cleaned/invalidated [XSA-437, + CVE-2023-34321] +- top-level shadow reference dropped too early for 64-bit PV guests + [XSA-438, CVE-2023-34322] +- x86/AMD: Divide speculative information leak [XSA-439, CVE-2023-20588] + * Fri Aug 11 2023 Michael Young - 4.16.5-1 - update to xen-4.16.5 which includes x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569] diff --git a/xsa437-4.16.patch b/xsa437-4.16.patch new file mode 100644 index 0000000..21cdb4a --- /dev/null +++ b/xsa437-4.16.patch @@ -0,0 +1,110 @@ +From 2b21319eecd8623078f27f0bccbbfdeb26606ff1 Mon Sep 17 00:00:00 2001 +From: Stefano Stabellini +Date: Thu, 17 Aug 2023 13:41:35 +0100 +Subject: [PATCH] xen/arm: page: Handle cache flush of an element at the top of + the address space + +The region that needs to be cleaned/invalidated may be at the top +of the address space. This means that 'end' (i.e. 'p + size') will +be 0 and therefore nothing will be cleaned/invalidated as the check +in the loop will always be false. + +On Arm64, we only support we only support up to 48-bit Virtual +address space. So this is not a concern there. However, for 32-bit, +the mapcache is using the last 2GB of the address space. Therefore +we may not clean/invalidate properly some pages. This could lead +to memory corruption or data leakage (the scrubbed value may +still sit in the cache when the guest could read directly the memory +and therefore read the old content). + +Rework invalidate_dcache_va_range(), clean_dcache_va_range(), +clean_and_invalidate_dcache_va_range() to handle a cache flush +with an element at the top of the address space. + +This is CVE-2023-34321 / XSA-437. + +Reported-by: Julien Grall +Signed-off-by: Stefano Stabellini +Signed-off-by: Julien Grall +Acked-by: Bertrand Marquis + +--- + xen/include/asm-arm/page.h | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/xen/include/asm-arm/page.h b/xen/include/asm-arm/page.h +index c6f9fb0d4e0c..eff5883ef87b 100644 +--- a/xen/include/asm-arm/page.h ++++ b/xen/include/asm-arm/page.h +@@ -152,26 +152,25 @@ static inline size_t read_dcache_line_bytes(void) + + static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + { +- const void *end = p + size; + size_t cacheline_mask = dcache_line_bytes - 1; + + dsb(sy); /* So the CPU issues all writes to the range */ + + if ( (uintptr_t)p & cacheline_mask ) + { ++ size -= dcache_line_bytes - ((uintptr_t)p & cacheline_mask); + p = (void *)((uintptr_t)p & ~cacheline_mask); + asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); + p += dcache_line_bytes; + } +- if ( (uintptr_t)end & cacheline_mask ) +- { +- end = (void *)((uintptr_t)end & ~cacheline_mask); +- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (end)); +- } + +- for ( ; p < end; p += dcache_line_bytes ) ++ for ( ; size >= dcache_line_bytes; ++ p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__invalidate_dcache_one(0) : : "r" (p)); + ++ if ( size > 0 ) ++ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); ++ + dsb(sy); /* So we know the flushes happen before continuing */ + + return 0; +@@ -179,10 +178,14 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + + static inline int clean_dcache_va_range(const void *p, unsigned long size) + { +- const void *end = p + size; ++ size_t cacheline_mask = dcache_line_bytes - 1; ++ + dsb(sy); /* So the CPU issues all writes to the range */ +- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1)); +- for ( ; p < end; p += dcache_line_bytes ) ++ size += (uintptr_t)p & cacheline_mask; ++ size = (size + cacheline_mask) & ~cacheline_mask; ++ p = (void *)((uintptr_t)p & ~cacheline_mask); ++ for ( ; size >= dcache_line_bytes; ++ p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__clean_dcache_one(0) : : "r" (p)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ +@@ -192,10 +195,14 @@ static inline int clean_dcache_va_range(const void *p, unsigned long size) + static inline int clean_and_invalidate_dcache_va_range + (const void *p, unsigned long size) + { +- const void *end = p + size; ++ size_t cacheline_mask = dcache_line_bytes - 1; ++ + dsb(sy); /* So the CPU issues all writes to the range */ +- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1)); +- for ( ; p < end; p += dcache_line_bytes ) ++ size += (uintptr_t)p & cacheline_mask; ++ size = (size + cacheline_mask) & ~cacheline_mask; ++ p = (void *)((uintptr_t)p & ~cacheline_mask); ++ for ( ; size >= dcache_line_bytes; ++ p += dcache_line_bytes, size -= dcache_line_bytes ) + asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ +-- +2.40.1 + diff --git a/xsa438-4.16.patch b/xsa438-4.16.patch new file mode 100644 index 0000000..f6817a3 --- /dev/null +++ b/xsa438-4.16.patch @@ -0,0 +1,414 @@ +From: Jan Beulich +Subject: x86/shadow: defer releasing of PV's top-level shadow reference + +sh_set_toplevel_shadow() re-pinning the top-level shadow we may be +running on is not enough (and at the same time unnecessary when the +shadow isn't what we're running on): That shadow becomes eligible for +blowing away (from e.g. shadow_prealloc()) immediately after the +paging lock was dropped. Yet it needs to remain valid until the actual +page table switch occurred. + +Propagate up the call chain the shadow entry that needs releasing +eventually, and carry out the release immediately after switching page +tables. Handle update_cr3() failures by switching to idle pagetables. +Note that various further uses of update_cr3() are HVM-only or only act +on paused vCPU-s, in which case sh_set_toplevel_shadow() will not defer +releasing of the reference. + +While changing the update_cr3() hook, also convert the "do_locking" +parameter to boolean. + +This is CVE-2023-34322 / XSA-438. + +Reported-by: Tim Deegan +Signed-off-by: Jan Beulich +Reviewed-by: George Dunlap + +--- a/xen/arch/x86/mm/hap/hap.c ++++ b/xen/arch/x86/mm/hap/hap.c +@@ -728,10 +728,12 @@ static bool_t hap_invlpg(struct vcpu *v, + return 1; + } + +-static void hap_update_cr3(struct vcpu *v, int do_locking, bool noflush) ++static pagetable_t hap_update_cr3(struct vcpu *v, bool do_locking, bool noflush) + { + v->arch.hvm.hw_cr[3] = v->arch.hvm.guest_cr[3]; + hvm_update_guest_cr3(v, noflush); ++ ++ return pagetable_null(); + } + + /* +--- a/xen/arch/x86/mm/shadow/common.c ++++ b/xen/arch/x86/mm/shadow/common.c +@@ -2574,13 +2574,13 @@ void shadow_update_paging_modes(struct v + } + + /* Set up the top-level shadow and install it in slot 'slot' of shadow_table */ +-void sh_set_toplevel_shadow(struct vcpu *v, +- unsigned int slot, +- mfn_t gmfn, +- unsigned int root_type, +- mfn_t (*make_shadow)(struct vcpu *v, +- mfn_t gmfn, +- uint32_t shadow_type)) ++pagetable_t sh_set_toplevel_shadow(struct vcpu *v, ++ unsigned int slot, ++ mfn_t gmfn, ++ unsigned int root_type, ++ mfn_t (*make_shadow)(struct vcpu *v, ++ mfn_t gmfn, ++ uint32_t shadow_type)) + { + mfn_t smfn; + pagetable_t old_entry, new_entry; +@@ -2637,20 +2637,37 @@ void sh_set_toplevel_shadow(struct vcpu + mfn_x(gmfn), mfn_x(pagetable_get_mfn(new_entry))); + v->arch.paging.shadow.shadow_table[slot] = new_entry; + +- /* Decrement the refcount of the old contents of this slot */ +- if ( !pagetable_is_null(old_entry) ) ++ /* ++ * Decrement the refcount of the old contents of this slot, unless ++ * we're still running on that shadow - in that case it'll need holding ++ * on to until the actual page table switch did occur. ++ */ ++ if ( !pagetable_is_null(old_entry) && (v != current || !is_pv_domain(d)) ) + { +- mfn_t old_smfn = pagetable_get_mfn(old_entry); +- /* Need to repin the old toplevel shadow if it's been unpinned +- * by shadow_prealloc(): in PV mode we're still running on this +- * shadow and it's not safe to free it yet. */ +- if ( !mfn_to_page(old_smfn)->u.sh.pinned && !sh_pin(d, old_smfn) ) +- { +- printk(XENLOG_G_ERR "can't re-pin %"PRI_mfn"\n", mfn_x(old_smfn)); +- domain_crash(d); +- } +- sh_put_ref(d, old_smfn, 0); ++ sh_put_ref(d, pagetable_get_mfn(old_entry), 0); ++ old_entry = pagetable_null(); + } ++ ++ /* ++ * 2- and 3-level shadow mode is used for HVM only. Therefore we never run ++ * on such a shadow, so only call sites requesting an L4 shadow need to pay ++ * attention to the returned value. ++ */ ++ ASSERT(pagetable_is_null(old_entry) || root_type == SH_type_l4_64_shadow); ++ ++ return old_entry; ++} ++ ++/* ++ * Helper invoked when releasing of a top-level shadow's reference was ++ * deferred in sh_set_toplevel_shadow() above. ++ */ ++void shadow_put_top_level(struct domain *d, pagetable_t old_entry) ++{ ++ ASSERT(!pagetable_is_null(old_entry)); ++ paging_lock(d); ++ sh_put_ref(d, pagetable_get_mfn(old_entry), 0); ++ paging_unlock(d); + } + + /**************************************************************************/ +--- a/xen/arch/x86/mm/shadow/multi.c ++++ b/xen/arch/x86/mm/shadow/multi.c +@@ -3219,8 +3219,8 @@ sh_detach_old_tables(struct vcpu *v) + } + } + +-static void +-sh_update_cr3(struct vcpu *v, int do_locking, bool noflush) ++static pagetable_t ++sh_update_cr3(struct vcpu *v, bool do_locking, bool noflush) + /* Updates vcpu->arch.cr3 after the guest has changed CR3. + * Paravirtual guests should set v->arch.guest_table (and guest_table_user, + * if appropriate). +@@ -3234,6 +3234,7 @@ sh_update_cr3(struct vcpu *v, int do_loc + { + struct domain *d = v->domain; + mfn_t gmfn; ++ pagetable_t old_entry = pagetable_null(); + #if GUEST_PAGING_LEVELS == 3 && defined(CONFIG_HVM) + const guest_l3e_t *gl3e; + unsigned int i, guest_idx; +@@ -3243,7 +3244,7 @@ sh_update_cr3(struct vcpu *v, int do_loc + if ( !is_hvm_domain(d) && !v->is_initialised ) + { + ASSERT(v->arch.cr3 == 0); +- return; ++ return old_entry; + } + + if ( do_locking ) paging_lock(v->domain); +@@ -3316,11 +3317,12 @@ sh_update_cr3(struct vcpu *v, int do_loc + #if GUEST_PAGING_LEVELS == 4 + if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 ) + guest_flush_tlb_mask(d, d->dirty_cpumask); +- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, ++ sh_make_shadow); + if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) + { + ASSERT(d->is_dying || d->is_shutting_down); +- return; ++ return old_entry; + } + if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) ) + { +@@ -3366,24 +3368,30 @@ sh_update_cr3(struct vcpu *v, int do_loc + gl2gfn = guest_l3e_get_gfn(gl3e[i]); + gl2mfn = get_gfn_query_unlocked(d, gfn_x(gl2gfn), &p2mt); + if ( p2m_is_ram(p2mt) ) +- sh_set_toplevel_shadow(v, i, gl2mfn, SH_type_l2_shadow, +- sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, i, gl2mfn, ++ SH_type_l2_shadow, ++ sh_make_shadow); + else +- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, +- sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, ++ sh_make_shadow); + } + else +- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, ++ sh_make_shadow); ++ ++ ASSERT(pagetable_is_null(old_entry)); + } + } + #elif GUEST_PAGING_LEVELS == 2 + if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 ) + guest_flush_tlb_mask(d, d->dirty_cpumask); +- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, sh_make_shadow); ++ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, ++ sh_make_shadow); ++ ASSERT(pagetable_is_null(old_entry)); + if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) + { + ASSERT(d->is_dying || d->is_shutting_down); +- return; ++ return old_entry; + } + #else + #error This should never happen +@@ -3477,6 +3485,8 @@ sh_update_cr3(struct vcpu *v, int do_loc + + /* Release the lock, if we took it (otherwise it's the caller's problem) */ + if ( do_locking ) paging_unlock(v->domain); ++ ++ return old_entry; + } + + +--- a/xen/arch/x86/mm/shadow/none.c ++++ b/xen/arch/x86/mm/shadow/none.c +@@ -52,9 +52,10 @@ static unsigned long _gva_to_gfn(struct + } + #endif + +-static void _update_cr3(struct vcpu *v, int do_locking, bool noflush) ++static pagetable_t _update_cr3(struct vcpu *v, bool do_locking, bool noflush) + { + ASSERT_UNREACHABLE(); ++ return pagetable_null(); + } + + static void _update_paging_modes(struct vcpu *v) +--- a/xen/arch/x86/mm/shadow/private.h ++++ b/xen/arch/x86/mm/shadow/private.h +@@ -391,13 +391,13 @@ mfn_t shadow_alloc(struct domain *d, + void shadow_free(struct domain *d, mfn_t smfn); + + /* Set up the top-level shadow and install it in slot 'slot' of shadow_table */ +-void sh_set_toplevel_shadow(struct vcpu *v, +- unsigned int slot, +- mfn_t gmfn, +- unsigned int root_type, +- mfn_t (*make_shadow)(struct vcpu *v, +- mfn_t gmfn, +- uint32_t shadow_type)); ++pagetable_t sh_set_toplevel_shadow(struct vcpu *v, ++ unsigned int slot, ++ mfn_t gmfn, ++ unsigned int root_type, ++ mfn_t (*make_shadow)(struct vcpu *v, ++ mfn_t gmfn, ++ uint32_t shadow_type)); + + /* Update the shadows in response to a pagetable write from Xen */ + int sh_validate_guest_entry(struct vcpu *v, mfn_t gmfn, void *entry, u32 size); +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -565,15 +565,12 @@ void write_ptbase(struct vcpu *v) + * + * Update ref counts to shadow tables appropriately. + */ +-void update_cr3(struct vcpu *v) ++pagetable_t update_cr3(struct vcpu *v) + { + mfn_t cr3_mfn; + + if ( paging_mode_enabled(v->domain) ) +- { +- paging_update_cr3(v, false); +- return; +- } ++ return paging_update_cr3(v, false); + + if ( !(v->arch.flags & TF_kernel_mode) ) + cr3_mfn = pagetable_get_mfn(v->arch.guest_table_user); +@@ -581,6 +578,8 @@ void update_cr3(struct vcpu *v) + cr3_mfn = pagetable_get_mfn(v->arch.guest_table); + + make_cr3(v, cr3_mfn); ++ ++ return pagetable_null(); + } + + static inline void set_tlbflush_timestamp(struct page_info *page) +@@ -3254,6 +3253,7 @@ int new_guest_cr3(mfn_t mfn) + struct domain *d = curr->domain; + int rc; + mfn_t old_base_mfn; ++ pagetable_t old_shadow; + + if ( is_pv_32bit_domain(d) ) + { +@@ -3321,9 +3321,22 @@ int new_guest_cr3(mfn_t mfn) + if ( !VM_ASSIST(d, m2p_strict) ) + fill_ro_mpt(mfn); + curr->arch.guest_table = pagetable_from_mfn(mfn); +- update_cr3(curr); ++ old_shadow = update_cr3(curr); ++ ++ /* ++ * In shadow mode update_cr3() can fail, in which case here we're still ++ * running on the prior top-level shadow (which we're about to release). ++ * Switch to the idle page tables in such an event; the guest will have ++ * been crashed already. ++ */ ++ if ( likely(!mfn_eq(pagetable_get_mfn(old_shadow), ++ maddr_to_mfn(curr->arch.cr3 & ~X86_CR3_NOFLUSH))) ) ++ write_ptbase(curr); ++ else ++ write_ptbase(idle_vcpu[curr->processor]); + +- write_ptbase(curr); ++ if ( !pagetable_is_null(old_shadow) ) ++ shadow_put_top_level(d, old_shadow); + + if ( likely(mfn_x(old_base_mfn) != 0) ) + { +--- a/xen/arch/x86/pv/domain.c ++++ b/xen/arch/x86/pv/domain.c +@@ -424,10 +424,13 @@ bool __init xpti_pcid_enabled(void) + + static void _toggle_guest_pt(struct vcpu *v) + { ++ bool guest_update; ++ pagetable_t old_shadow; + unsigned long cr3; + + v->arch.flags ^= TF_kernel_mode; +- update_cr3(v); ++ guest_update = v->arch.flags & TF_kernel_mode; ++ old_shadow = update_cr3(v); + + /* + * Don't flush user global mappings from the TLB. Don't tick TLB clock. +@@ -436,13 +439,31 @@ static void _toggle_guest_pt(struct vcpu + * TLB flush (for just the incoming PCID), as the top level page table may + * have changed behind our backs. To be on the safe side, suppress the + * no-flush unconditionally in this case. ++ * ++ * Furthermore in shadow mode update_cr3() can fail, in which case here ++ * we're still running on the prior top-level shadow (which we're about ++ * to release). Switch to the idle page tables in such an event; the ++ * guest will have been crashed already. + */ + cr3 = v->arch.cr3; + if ( shadow_mode_enabled(v->domain) ) ++ { + cr3 &= ~X86_CR3_NOFLUSH; ++ ++ if ( unlikely(mfn_eq(pagetable_get_mfn(old_shadow), ++ maddr_to_mfn(cr3))) ) ++ { ++ cr3 = idle_vcpu[v->processor]->arch.cr3; ++ /* Also suppress runstate/time area updates below. */ ++ guest_update = false; ++ } ++ } + write_cr3(cr3); + +- if ( !(v->arch.flags & TF_kernel_mode) ) ++ if ( !pagetable_is_null(old_shadow) ) ++ shadow_put_top_level(v->domain, old_shadow); ++ ++ if ( !guest_update ) + return; + + if ( v->arch.pv.need_update_runstate_area && update_runstate_area(v) ) +--- a/xen/include/asm-x86/mm.h ++++ b/xen/include/asm-x86/mm.h +@@ -564,7 +564,7 @@ void audit_domains(void); + #endif + + void make_cr3(struct vcpu *v, mfn_t mfn); +-void update_cr3(struct vcpu *v); ++pagetable_t update_cr3(struct vcpu *v); + int vcpu_destroy_pagetables(struct vcpu *); + void *do_page_walk(struct vcpu *v, unsigned long addr); + +--- a/xen/include/asm-x86/paging.h ++++ b/xen/include/asm-x86/paging.h +@@ -138,7 +138,7 @@ struct paging_mode { + paddr_t ga, uint32_t *pfec, + unsigned int *page_order); + #endif +- void (*update_cr3 )(struct vcpu *v, int do_locking, ++ pagetable_t (*update_cr3 )(struct vcpu *v, bool do_locking, + bool noflush); + void (*update_paging_modes )(struct vcpu *v); + bool (*flush_tlb )(bool (*flush_vcpu)(void *ctxt, +@@ -315,9 +315,9 @@ static inline unsigned long paging_ga_to + /* Update all the things that are derived from the guest's CR3. + * Called when the guest changes CR3; the caller can then use v->arch.cr3 + * as the value to load into the host CR3 to schedule this vcpu */ +-static inline void paging_update_cr3(struct vcpu *v, bool noflush) ++static inline pagetable_t paging_update_cr3(struct vcpu *v, bool noflush) + { +- paging_get_hostmode(v)->update_cr3(v, 1, noflush); ++ return paging_get_hostmode(v)->update_cr3(v, 1, noflush); + } + + /* Update all the things that are derived from the guest's CR0/CR3/CR4. +--- a/xen/include/asm-x86/shadow.h ++++ b/xen/include/asm-x86/shadow.h +@@ -97,6 +97,9 @@ void shadow_blow_tables_per_domain(struc + int shadow_set_allocation(struct domain *d, unsigned int pages, + bool *preempted); + ++/* Helper to invoke for deferred releasing of a top-level shadow's reference. */ ++void shadow_put_top_level(struct domain *d, pagetable_t old); ++ + #else /* !CONFIG_SHADOW_PAGING */ + + #define shadow_vcpu_teardown(v) ASSERT(is_pv_vcpu(v)) +@@ -118,6 +121,11 @@ static inline void shadow_prepare_page_t + + static inline void shadow_blow_tables_per_domain(struct domain *d) {} + ++static inline void shadow_put_top_level(struct domain *d, pagetable_t old) ++{ ++ ASSERT_UNREACHABLE(); ++} ++ + static inline int shadow_domctl(struct domain *d, + struct xen_domctl_shadow_op *sc, + XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) diff --git a/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch b/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch new file mode 100644 index 0000000..a01c726 --- /dev/null +++ b/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch @@ -0,0 +1,49 @@ +From 08539e8315fdae5f5bfd655d53ed35fd2922fe6c Mon Sep 17 00:00:00 2001 +Message-ID: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Jan Beulich +Date: Wed, 23 Aug 2023 09:26:36 +0200 +Subject: [XEN PATCH 01/10] x86/AMD: extend Zenbleed check to models "good" + ucode isn't known for + +Reportedly the AMD Custom APU 0405 found on SteamDeck, models 0x90 and +0x91, (quoting the respective Linux commit) is similarly affected. Put +another instance of our Zen1 vs Zen2 distinction checks in +amd_check_zenbleed(), forcing use of the chickenbit irrespective of +ucode version (building upon real hardware never surfacing a version of +0xffffffff). + +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper +(cherry picked from commit 145a69c0944ac70cfcf9d247c85dee9e99d9d302) +--- + xen/arch/x86/cpu/amd.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 60c6d88edf..a591038757 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -800,10 +800,17 @@ void amd_check_zenbleed(void) + case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; + default: + /* +- * With the Fam17h check above, parts getting here are Zen1. +- * They're not affected. ++ * With the Fam17h check above, most parts getting here are ++ * Zen1. They're not affected. Assume Zen2 ones making it ++ * here are affected regardless of microcode version. ++ * ++ * Zen1 vs Zen2 isn't a simple model number comparison, so use ++ * STIBP as a heuristic to distinguish. + */ +- return; ++ if (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ return; ++ good_rev = ~0U; ++ break; + } + + rdmsrl(MSR_AMD64_DE_CFG, val); +-- +2.41.0 + diff --git a/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch b/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch new file mode 100644 index 0000000..edff254 --- /dev/null +++ b/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch @@ -0,0 +1,77 @@ +From 1e52cdf07cdf52e5d99957c3ecbddf5b1feda963 Mon Sep 17 00:00:00 2001 +Message-ID: <1e52cdf07cdf52e5d99957c3ecbddf5b1feda963.1695742580.git.m.a.young@durham.ac.uk> +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Tue, 12 Sep 2023 15:06:49 +0100 +Subject: [XEN PATCH 02/10] x86/spec-ctrl: Fix confusion between + SPEC_CTRL_EXIT_TO_XEN{,_IST} + +c/s 3fffaf9c13e9 ("x86/entry: Avoid using alternatives in NMI/#MC paths") +dropped the only user, leaving behind the (incorrect) implication that Xen had +split exit paths. + +Delete the unused SPEC_CTRL_EXIT_TO_XEN and rename SPEC_CTRL_EXIT_TO_XEN_IST +to SPEC_CTRL_EXIT_TO_XEN for consistency. + +No functional change. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 1c18d73774533a55ba9d1cbee8bdace03efdb5e7) +--- + xen/arch/x86/x86_64/entry.S | 2 +- + xen/include/asm-x86/spec_ctrl_asm.h | 10 ++-------- + 2 files changed, 3 insertions(+), 9 deletions(-) + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index db2ea7871e..59f2040787 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -664,7 +664,7 @@ UNLIKELY_START(ne, exit_cr3) + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN_IST /* Req: %rbx=end, Clob: acd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */ + + RESTORE_ALL adj=8 + iretq +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index b61a5571ae..f5110616e4 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -79,7 +79,6 @@ + * - SPEC_CTRL_ENTRY_FROM_PV + * - SPEC_CTRL_ENTRY_FROM_INTR + * - SPEC_CTRL_ENTRY_FROM_INTR_IST +- * - SPEC_CTRL_EXIT_TO_XEN_IST + * - SPEC_CTRL_EXIT_TO_XEN + * - SPEC_CTRL_EXIT_TO_PV + * +@@ -273,11 +272,6 @@ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ + X86_FEATURE_SC_MSR_PV + +-/* Use when exiting to Xen context. */ +-#define SPEC_CTRL_EXIT_TO_XEN \ +- ALTERNATIVE "", \ +- DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_SC_MSR_PV +- + /* Use when exiting to PV guest context. */ + #define SPEC_CTRL_EXIT_TO_PV \ + ALTERNATIVE "", \ +@@ -344,8 +338,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + UNLIKELY_END(\@_serialise) + .endm + +-/* Use when exiting to Xen in IST context. */ +-.macro SPEC_CTRL_EXIT_TO_XEN_IST ++/* Use when exiting to Xen context. */ ++.macro SPEC_CTRL_EXIT_TO_XEN + /* + * Requires %rbx=stack_end + * Clobbers %rax, %rcx, %rdx +-- +2.41.0 + diff --git a/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch b/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch new file mode 100644 index 0000000..f3d6120 --- /dev/null +++ b/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch @@ -0,0 +1,88 @@ +From afa5b17f385372226de6b0862f12ab39fda16b5c Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Tue, 12 Sep 2023 17:03:16 +0100 +Subject: [XEN PATCH 03/10] x86/spec-ctrl: Fold DO_SPEC_CTRL_EXIT_TO_XEN into + it's single user + +With the SPEC_CTRL_EXIT_TO_XEN{,_IST} confusion fixed, it's now obvious that +there's only a single EXIT_TO_XEN path. Fold DO_SPEC_CTRL_EXIT_TO_XEN into +SPEC_CTRL_EXIT_TO_XEN to simplify further fixes. + +When merging labels, switch the name to .L\@_skip_sc_msr as "skip" on its own +is going to be too generic shortly. + +No functional change. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 694bb0f280fd08a4377e36e32b84b5062def4de2) +--- + xen/include/asm-x86/spec_ctrl_asm.h | 40 ++++++++++++----------------- + 1 file changed, 16 insertions(+), 24 deletions(-) + +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index f5110616e4..251c30eee5 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -216,27 +216,6 @@ + wrmsr + .endm + +-.macro DO_SPEC_CTRL_EXIT_TO_XEN +-/* +- * Requires %rbx=stack_end +- * Clobbers %rax, %rcx, %rdx +- * +- * When returning to Xen context, look to see whether SPEC_CTRL shadowing is +- * in effect, and reload the shadow value. This covers race conditions which +- * exist with an NMI/MCE/etc hitting late in the return-to-guest path. +- */ +- xor %edx, %edx +- +- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) +- jz .L\@_skip +- +- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax +- mov $MSR_SPEC_CTRL, %ecx +- wrmsr +- +-.L\@_skip: +-.endm +- + .macro DO_SPEC_CTRL_EXIT_TO_GUEST + /* + * Requires %eax=spec_ctrl, %rsp=regs/cpuinfo +@@ -345,11 +324,24 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + * Clobbers %rax, %rcx, %rdx + */ + testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) +- jz .L\@_skip ++ jz .L\@_skip_sc_msr + +- DO_SPEC_CTRL_EXIT_TO_XEN ++ /* ++ * When returning to Xen context, look to see whether SPEC_CTRL shadowing ++ * is in effect, and reload the shadow value. This covers race conditions ++ * which exist with an NMI/MCE/etc hitting late in the return-to-guest ++ * path. ++ */ ++ xor %edx, %edx + +-.L\@_skip: ++ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) ++ jz .L\@_skip_sc_msr ++ ++ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax ++ mov $MSR_SPEC_CTRL, %ecx ++ wrmsr ++ ++.L\@_skip_sc_msr: + .endm + + #endif /* __ASSEMBLY__ */ +-- +2.41.0 + diff --git a/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch b/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch new file mode 100644 index 0000000..8f44144 --- /dev/null +++ b/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch @@ -0,0 +1,86 @@ +From 353e876a9dd5a93d0bf8819e77613c33db0de97b Mon Sep 17 00:00:00 2001 +Message-ID: <353e876a9dd5a93d0bf8819e77613c33db0de97b.1695742580.git.m.a.young@durham.ac.uk> +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Fri, 1 Sep 2023 11:38:44 +0100 +Subject: [XEN PATCH 04/10] x86/spec-ctrl: Turn the remaining + SPEC_CTRL_{ENTRY,EXIT}_* into asm macros + +These have grown more complex over time, with some already having been +converted. + +Provide full Requires/Clobbers comments, otherwise missing at this level of +indirection. + +No functional change. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 7125429aafb9e3c9c88fc93001fc2300e0ac2cc8) +--- + xen/include/asm-x86/spec_ctrl_asm.h | 37 ++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 9 deletions(-) + +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index 251c30eee5..94ed5dc880 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -236,26 +236,45 @@ + .endm + + /* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ +-#define SPEC_CTRL_ENTRY_FROM_PV \ ++.macro SPEC_CTRL_ENTRY_FROM_PV ++/* ++ * Requires %rsp=regs/cpuinfo, %rdx=0 ++ * Clobbers %rax, %rcx, %rdx ++ */ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=0), \ +- X86_FEATURE_IBPB_ENTRY_PV; \ +- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ ++ X86_FEATURE_IBPB_ENTRY_PV ++ ++ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV ++ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), \ + X86_FEATURE_SC_MSR_PV ++.endm + + /* Use in interrupt/exception context. May interrupt Xen or PV context. */ +-#define SPEC_CTRL_ENTRY_FROM_INTR \ ++.macro SPEC_CTRL_ENTRY_FROM_INTR ++/* ++ * Requires %rsp=regs, %r14=stack_end, %rdx=0 ++ * Clobbers %rax, %rcx, %rdx ++ */ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=1), \ +- X86_FEATURE_IBPB_ENTRY_PV; \ +- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ ++ X86_FEATURE_IBPB_ENTRY_PV ++ ++ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV ++ + ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ + X86_FEATURE_SC_MSR_PV ++.endm + + /* Use when exiting to PV guest context. */ +-#define SPEC_CTRL_EXIT_TO_PV \ +- ALTERNATIVE "", \ +- DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV; \ ++.macro SPEC_CTRL_EXIT_TO_PV ++/* ++ * Requires %rax=spec_ctrl, %rsp=regs/info ++ * Clobbers %rcx, %rdx ++ */ ++ ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV ++ + DO_SPEC_CTRL_COND_VERW ++.endm + + /* + * Use in IST interrupt/exception context. May interrupt Xen or PV context. +-- +2.41.0 + diff --git a/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch b/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch new file mode 100644 index 0000000..4571046 --- /dev/null +++ b/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch @@ -0,0 +1,109 @@ +From 6cc49c355e952f4ff564c6b817e7eff57c5a02c7 Mon Sep 17 00:00:00 2001 +Message-ID: <6cc49c355e952f4ff564c6b817e7eff57c5a02c7.1695742580.git.m.a.young@durham.ac.uk> +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Wed, 30 Aug 2023 20:11:50 +0100 +Subject: [XEN PATCH 05/10] x86/spec-ctrl: Improve all SPEC_CTRL_{ENTER,EXIT}_* + comments + +... to better explain how they're used. + +Doing so highlights that SPEC_CTRL_EXIT_TO_XEN is missing a VERW flush for the +corner case when e.g. an NMI hits late in an exit-to-guest path. + +Leave a TODO, which will be addressed in subsequent patches which arrange for +VERW flushing to be safe within SPEC_CTRL_EXIT_TO_XEN. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 45f00557350dc7d0756551069803fc49c29184ca) +--- + xen/include/asm-x86/spec_ctrl_asm.h | 36 +++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 5 deletions(-) + +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index 94ed5dc880..9c397f7cbd 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -235,7 +235,10 @@ + wrmsr + .endm + +-/* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ ++/* ++ * Used after an entry from PV context: SYSCALL, SYSENTER, INT, ++ * etc. There is always a guest speculation state in context. ++ */ + .macro SPEC_CTRL_ENTRY_FROM_PV + /* + * Requires %rsp=regs/cpuinfo, %rdx=0 +@@ -250,7 +253,11 @@ + X86_FEATURE_SC_MSR_PV + .endm + +-/* Use in interrupt/exception context. May interrupt Xen or PV context. */ ++/* ++ * Used after an exception or maskable interrupt, hitting Xen or PV context. ++ * There will either be a guest speculation context, or (barring fatal ++ * exceptions) a well-formed Xen speculation context. ++ */ + .macro SPEC_CTRL_ENTRY_FROM_INTR + /* + * Requires %rsp=regs, %r14=stack_end, %rdx=0 +@@ -265,7 +272,10 @@ + X86_FEATURE_SC_MSR_PV + .endm + +-/* Use when exiting to PV guest context. */ ++/* ++ * Used when exiting from any entry context, back to PV context. This ++ * includes from an IST entry which moved onto the primary stack. ++ */ + .macro SPEC_CTRL_EXIT_TO_PV + /* + * Requires %rax=spec_ctrl, %rsp=regs/info +@@ -277,7 +287,13 @@ + .endm + + /* +- * Use in IST interrupt/exception context. May interrupt Xen or PV context. ++ * Used after an IST entry hitting Xen or PV context. Special care is needed, ++ * because when hitting Xen context, there may not be a well-formed ++ * speculation context. (i.e. it can hit in the middle of ++ * SPEC_CTRL_{ENTRY,EXIT}_* regions.) ++ * ++ * An IST entry which hits PV context moves onto the primary stack and leaves ++ * via SPEC_CTRL_EXIT_TO_PV, *not* SPEC_CTRL_EXIT_TO_XEN. + */ + .macro SPEC_CTRL_ENTRY_FROM_INTR_IST + /* +@@ -336,7 +352,14 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + UNLIKELY_END(\@_serialise) + .endm + +-/* Use when exiting to Xen context. */ ++/* ++ * Use when exiting from any entry context, back to Xen context. This ++ * includes returning to other SPEC_CTRL_{ENTRY,EXIT}_* regions with an ++ * incomplete speculation context. ++ * ++ * Because we might have interrupted Xen beyond SPEC_CTRL_EXIT_TO_$GUEST, we ++ * need to treat this as if it were an EXIT_TO_$GUEST case too. ++ */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* + * Requires %rbx=stack_end +@@ -361,6 +384,9 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + wrmsr + + .L\@_skip_sc_msr: ++ ++ /* TODO VERW */ ++ + .endm + + #endif /* __ASSEMBLY__ */ +-- +2.41.0 + diff --git a/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch b/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch new file mode 100644 index 0000000..08b96f9 --- /dev/null +++ b/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch @@ -0,0 +1,77 @@ +From 19aca8f32778f289112fc8db2ee547cdf29c81ca Mon Sep 17 00:00:00 2001 +Message-ID: <19aca8f32778f289112fc8db2ee547cdf29c81ca.1695742580.git.m.a.young@durham.ac.uk> +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Wed, 13 Sep 2023 13:48:16 +0100 +Subject: [XEN PATCH 06/10] x86/entry: Adjust restore_all_xen to hold stack_end + in %r14 + +All other SPEC_CTRL_{ENTRY,EXIT}_* helpers hold stack_end in %r14. Adjust it +for consistency. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 7aa28849a1155d856e214e9a80a7e65fffdc3e58) +--- + xen/arch/x86/x86_64/entry.S | 8 ++++---- + xen/include/asm-x86/spec_ctrl_asm.h | 8 ++++---- + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 59f2040787..266c0a0990 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -656,15 +656,15 @@ restore_all_xen: + * Check whether we need to switch to the per-CPU page tables, in + * case we return to late PV exit code (from an NMI or #MC). + */ +- GET_STACK_END(bx) +- cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) ++ GET_STACK_END(14) ++ cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) + UNLIKELY_START(ne, exit_cr3) +- mov STACK_CPUINFO_FIELD(pv_cr3)(%rbx), %rax ++ mov STACK_CPUINFO_FIELD(pv_cr3)(%r14), %rax + mov %rax, %cr3 + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */ + + RESTORE_ALL adj=8 + iretq +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index 9c397f7cbd..3e745813cf 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -362,10 +362,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* +- * Requires %rbx=stack_end ++ * Requires %r14=stack_end + * Clobbers %rax, %rcx, %rdx + */ +- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) ++ testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) + jz .L\@_skip_sc_msr + + /* +@@ -376,10 +376,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + xor %edx, %edx + +- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) ++ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) + jz .L\@_skip_sc_msr + +- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax ++ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax + mov $MSR_SPEC_CTRL, %ecx + wrmsr + +-- +2.41.0 + diff --git a/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch b/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch new file mode 100644 index 0000000..4cd0838 --- /dev/null +++ b/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch @@ -0,0 +1,112 @@ +From 8064cbdbef79e328fad5158beeaf1c45bd0f5bd3 Mon Sep 17 00:00:00 2001 +Message-ID: <8064cbdbef79e328fad5158beeaf1c45bd0f5bd3.1695742580.git.m.a.young@durham.ac.uk> +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Wed, 13 Sep 2023 12:20:12 +0100 +Subject: [XEN PATCH 07/10] x86/entry: Track the IST-ness of an entry for the + exit paths + +Use %r12 to hold an ist_exit boolean. This register is zero elsewhere in the +entry/exit asm, so it only needs setting in the IST path. + +As this is subtle and fragile, add check_ist_exit() to be used in debugging +builds to cross-check that the ist_exit boolean matches the entry vector. + +Write check_ist_exit() it in C, because it's debug only and the logic more +complicated than I care to maintain in asm. + +For now, we only need to use this signal in the exit-to-Xen path, but some +exit-to-guest paths happen in IST context too. Check the correctness in all +exit paths to avoid the logic bit-rotting. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 21bdc25b05a0f8ab6bc73520a9ca01327360732c) + +x86/entry: Partially revert IST-exit checks + +The patch adding check_ist_exit() didn't account for the fact that +reset_stack_and_jump() is not an ABI-preserving boundary. The IST-ness in +%r12 doesn't survive into the next context, and is a stale value C. + +This shows up in Gitlab CI for the Clang build: + + https://gitlab.com/xen-project/people/andyhhp/xen/-/jobs/5112783827 + +and in OSSTest for GCC 8: + + http://logs.test-lab.xenproject.org/osstest/logs/183045/test-amd64-amd64-xl-qemuu-debianhvm-amd64/serial-pinot0.log + +There's no straightforward way to reconstruct the IST-exit-ness on the +exit-to-guest path after a context switch. For now, we only need IST-exit on +the return-to-Xen path. + +Fixes: 21bdc25b05a0 ("x86/entry: Track the IST-ness of an entry for the exit paths") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 9b57c800b79b96769ea3dcd6468578fa664d19f9) +--- + xen/arch/x86/traps.c | 13 +++++++++++++ + xen/arch/x86/x86_64/entry.S | 13 ++++++++++++- + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c +index 9679bfdb08..f7992ff230 100644 +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -2348,6 +2348,19 @@ void asm_domain_crash_synchronous(unsigned long addr) + do_softirq(); + } + ++#ifdef CONFIG_DEBUG ++void check_ist_exit(const struct cpu_user_regs *regs, bool ist_exit) ++{ ++ const unsigned int ist_mask = ++ (1U << X86_EXC_NMI) | (1U << X86_EXC_DB) | ++ (1U << X86_EXC_DF) | (1U << X86_EXC_MC); ++ uint8_t ev = regs->entry_vector; ++ bool is_ist = (ev < TRAP_nr) && ((1U << ev) & ist_mask); ++ ++ ASSERT(is_ist == ist_exit); ++} ++#endif ++ + /* + * Local variables: + * mode: C +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 266c0a0990..671e3b3fd5 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -650,8 +650,15 @@ ret_from_intr: + .section .text.entry, "ax", @progbits + + ALIGN +-/* No special register assumptions. */ ++/* %r12=ist_exit */ + restore_all_xen: ++ ++#ifdef CONFIG_DEBUG ++ mov %rsp, %rdi ++ mov %r12, %rsi ++ call check_ist_exit ++#endif ++ + /* + * Check whether we need to switch to the per-CPU page tables, in + * case we return to late PV exit code (from an NMI or #MC). +@@ -1032,6 +1039,10 @@ handle_ist_exception: + INDIRECT_CALL %rdx + mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) + mov %bl, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) ++ ++ /* This is an IST exit */ ++ mov $1, %r12d ++ + cmpb $TRAP_nmi,UREGS_entry_vector(%rsp) + jne ret_from_intr + +-- +2.41.0 + diff --git a/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch b/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch new file mode 100644 index 0000000..1c8cdb0 --- /dev/null +++ b/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch @@ -0,0 +1,92 @@ +From 3e51782ebb088fde39fdcfa30d002baddd1a9e06 Mon Sep 17 00:00:00 2001 +Message-ID: <3e51782ebb088fde39fdcfa30d002baddd1a9e06.1695742580.git.m.a.young@durham.ac.uk> +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Wed, 13 Sep 2023 13:53:33 +0100 +Subject: [XEN PATCH 08/10] x86/spec-ctrl: Issue VERW during IST exit to Xen + +There is a corner case where e.g. an NMI hitting an exit-to-guest path after +SPEC_CTRL_EXIT_TO_* would have run the entire NMI handler *after* the VERW +flush to scrub potentially sensitive data from uarch buffers. + +In order to compensate, issue VERW when exiting to Xen from an IST entry. + +SPEC_CTRL_EXIT_TO_XEN already has two reads of spec_ctrl_flags off the stack, +and we're about to add a third. Load the field into %ebx, and list the +register as clobbered. + +%r12 has been arranged to be the ist_exit signal, so add this as an input +dependency and use it to identify when to issue a VERW. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 3ee6066bcd737756b0990d417d94eddc0b0d2585) +--- + xen/arch/x86/x86_64/entry.S | 2 +- + xen/include/asm-x86/spec_ctrl_asm.h | 20 +++++++++++++++----- + 2 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 671e3b3fd5..88ff5c150f 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -671,7 +671,7 @@ UNLIKELY_START(ne, exit_cr3) + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */ + + RESTORE_ALL adj=8 + iretq +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index 3e745813cf..8a816b8cf6 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -362,10 +362,12 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* +- * Requires %r14=stack_end +- * Clobbers %rax, %rcx, %rdx ++ * Requires %r12=ist_exit, %r14=stack_end ++ * Clobbers %rax, %rbx, %rcx, %rdx + */ +- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) ++ movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx ++ ++ testb $SCF_ist_sc_msr, %bl + jz .L\@_skip_sc_msr + + /* +@@ -376,7 +378,7 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + xor %edx, %edx + +- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) ++ testb $SCF_use_shadow, %bl + jz .L\@_skip_sc_msr + + mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax +@@ -385,8 +387,16 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + + .L\@_skip_sc_msr: + +- /* TODO VERW */ ++ test %r12, %r12 ++ jz .L\@_skip_ist_exit ++ ++ /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */ ++ testb $SCF_verw, %bl ++ jz .L\@_skip_verw ++ verw STACK_CPUINFO_FIELD(verw_sel)(%r14) ++.L\@_skip_verw: + ++.L\@_skip_ist_exit: + .endm + + #endif /* __ASSEMBLY__ */ +-- +2.41.0 + diff --git a/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch b/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch new file mode 100644 index 0000000..59075ce --- /dev/null +++ b/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch @@ -0,0 +1,94 @@ +From a5857f1eca17a609119ae928c9fa73bb0996ddd9 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Fri, 15 Sep 2023 12:13:51 +0100 +Subject: [XEN PATCH 09/10] x86/amd: Introduce is_zen{1,2}_uarch() predicates + +We already have 3 cases using STIBP as a Zen1/2 heuristic, and are about to +introduce a 4th. Wrap the heuristic into a pair of predicates rather than +opencoding it, and the explanation of the heuristic, at each usage site. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit de1d265001397f308c5c3c5d3ffc30e7ef8c0705) +--- + xen/arch/x86/cpu/amd.c | 18 ++++-------------- + xen/include/asm-x86/amd.h | 11 +++++++++++ + 2 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index a591038757..b71d891901 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -746,15 +746,13 @@ void amd_init_ssbd(const struct cpuinfo_x86 *c) + * non-branch instructions to be ignored. It is to be set unilaterally in + * newer microcode. + * +- * This chickenbit is something unrelated on Zen1, and Zen1 vs Zen2 isn't a +- * simple model number comparison, so use STIBP as a heuristic to separate the +- * two uarches in Fam17h(AMD)/18h(Hygon). ++ * This chickenbit is something unrelated on Zen1. + */ + void amd_init_spectral_chicken(void) + { + uint64_t val, chickenbit = 1 << 1; + +- if (cpu_has_hypervisor || !boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ if (cpu_has_hypervisor || !is_zen2_uarch()) + return; + + if (rdmsr_safe(MSR_AMD64_DE_CFG2, val) == 0 && !(val & chickenbit)) +@@ -803,11 +801,8 @@ void amd_check_zenbleed(void) + * With the Fam17h check above, most parts getting here are + * Zen1. They're not affected. Assume Zen2 ones making it + * here are affected regardless of microcode version. +- * +- * Zen1 vs Zen2 isn't a simple model number comparison, so use +- * STIBP as a heuristic to distinguish. + */ +- if (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ if (is_zen1_uarch()) + return; + good_rev = ~0U; + break; +@@ -1168,12 +1163,7 @@ static int __init zen2_c6_errata_check(void) + */ + s_time_t delta; + +- /* +- * Zen1 vs Zen2 isn't a simple model number comparison, so use STIBP as +- * a heuristic to separate the two uarches in Fam17h. +- */ +- if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || +- !boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || !is_zen2_uarch()) + return 0; + + /* +diff --git a/xen/include/asm-x86/amd.h b/xen/include/asm-x86/amd.h +index a82382e6bf..7fe1e19217 100644 +--- a/xen/include/asm-x86/amd.h ++++ b/xen/include/asm-x86/amd.h +@@ -140,6 +140,17 @@ + AMD_MODEL_RANGE(0x11, 0x0, 0x0, 0xff, 0xf), \ + AMD_MODEL_RANGE(0x12, 0x0, 0x0, 0xff, 0xf)) + ++/* ++ * The Zen1 and Zen2 microarchitectures are implemented by AMD (Fam17h) and ++ * Hygon (Fam18h) but without simple model number rules. Instead, use STIBP ++ * as a heuristic that distinguishes the two. ++ * ++ * The caller is required to perform the appropriate vendor/family checks ++ * first. ++ */ ++#define is_zen1_uarch() (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) ++#define is_zen2_uarch() boot_cpu_has(X86_FEATURE_AMD_STIBP) ++ + struct cpuinfo_x86; + int cpu_has_amd_erratum(const struct cpuinfo_x86 *, int, ...); + +-- +2.41.0 + diff --git a/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch b/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch new file mode 100644 index 0000000..0b063fb --- /dev/null +++ b/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch @@ -0,0 +1,239 @@ +From de751c3d906d17b2e25ee429f81b17a689c7c6c0 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk> +From: Andrew Cooper +Date: Wed, 30 Aug 2023 20:24:25 +0100 +Subject: [XEN PATCH 10/10] x86/spec-ctrl: Mitigate the Zen1 DIV leakage + +In the Zen1 microarchitecure, there is one divider in the pipeline which +services uops from both threads. In the case of #DE, the latched result from +the previous DIV to execute will be forwarded speculatively. + +This is an interesting covert channel that allows two threads to communicate +without any system calls. In also allows userspace to obtain the result of +the most recent DIV instruction executed (even speculatively) in the core, +which can be from a higher privilege context. + +Scrub the result from the divider by executing a non-faulting divide. This +needs performing on the exit-to-guest paths, and ist_exit-to-Xen. + +Alternatives in IST context is believed safe now that it's done in NMI +context. + +This is XSA-439 / CVE-2023-20588. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit b5926c6ecf05c28ee99c6248c42d691ccbf0c315) +--- + docs/misc/xen-command-line.pandoc | 6 +++- + xen/arch/x86/hvm/svm/entry.S | 1 + + xen/arch/x86/spec_ctrl.c | 49 ++++++++++++++++++++++++++++- + xen/include/asm-x86/cpufeatures.h | 2 +- + xen/include/asm-x86/spec_ctrl_asm.h | 17 ++++++++++ + 5 files changed, 72 insertions(+), 3 deletions(-) + +diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc +index a37a3890d1..a7a1362bac 100644 +--- a/docs/misc/xen-command-line.pandoc ++++ b/docs/misc/xen-command-line.pandoc +@@ -2263,7 +2263,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). + > {msr-sc,rsb,md-clear,ibpb-entry}=|{pv,hvm}=, + > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, + > eager-fpu,l1d-flush,branch-harden,srb-lock, +-> unpriv-mmio,gds-mit}= ]` ++> unpriv-mmio,gds-mit,div-scrub}= ]` + + Controls for speculative execution sidechannel mitigations. By default, Xen + will pick the most appropriate mitigations based on compiled in support, +@@ -2383,6 +2383,10 @@ has elected not to lock the configuration, Xen will use GDS_CTRL to mitigate + GDS with. Otherwise, Xen will mitigate by disabling AVX, which blocks the use + of the AVX2 Gather instructions. + ++On all hardware, the `div-scrub=` option can be used to force or prevent Xen ++from mitigating the DIV-leakage vulnerability. By default, Xen will mitigate ++DIV-leakage on hardware believed to be vulnerable. ++ + ### sync_console + > `= ` + +diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S +index 0ff4008060..ad5ca50c12 100644 +--- a/xen/arch/x86/hvm/svm/entry.S ++++ b/xen/arch/x86/hvm/svm/entry.S +@@ -72,6 +72,7 @@ __UNLIKELY_END(nsvm_hap) + 1: /* No Spectre v1 concerns. Execution will hit VMRUN imminently. */ + .endm + ALTERNATIVE "", svm_vmentry_spec_ctrl, X86_FEATURE_SC_MSR_HVM ++ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV + + pop %r15 + pop %r14 +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 082445179d..6e82a126a3 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -22,6 +22,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -78,6 +79,7 @@ static int8_t __initdata opt_srb_lock = -1; + static bool __initdata opt_unpriv_mmio; + static bool __read_mostly opt_fb_clear_mmio; + static int8_t __initdata opt_gds_mit = -1; ++static int8_t __initdata opt_div_scrub = -1; + + static int __init parse_spec_ctrl(const char *s) + { +@@ -132,6 +134,7 @@ static int __init parse_spec_ctrl(const char *s) + opt_srb_lock = 0; + opt_unpriv_mmio = false; + opt_gds_mit = 0; ++ opt_div_scrub = 0; + } + else if ( val > 0 ) + rc = -EINVAL; +@@ -284,6 +287,8 @@ static int __init parse_spec_ctrl(const char *s) + opt_unpriv_mmio = val; + else if ( (val = parse_boolean("gds-mit", s, ss)) >= 0 ) + opt_gds_mit = val; ++ else if ( (val = parse_boolean("div-scrub", s, ss)) >= 0 ) ++ opt_div_scrub = val; + else + rc = -EINVAL; + +@@ -484,7 +489,7 @@ static void __init print_details(enum ind_thunk thunk) + "\n"); + + /* Settings for Xen's protection, irrespective of guests. */ +- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s\n", ++ printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", + thunk == THUNK_NONE ? "N/A" : + thunk == THUNK_RETPOLINE ? "RETPOLINE" : + thunk == THUNK_LFENCE ? "LFENCE" : +@@ -509,6 +514,7 @@ static void __init print_details(enum ind_thunk thunk) + opt_l1d_flush ? " L1D_FLUSH" : "", + opt_md_clear_pv || opt_md_clear_hvm || + opt_fb_clear_mmio ? " VERW" : "", ++ opt_div_scrub ? " DIV" : "", + opt_branch_harden ? " BRANCH_HARDEN" : ""); + + /* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */ +@@ -962,6 +968,45 @@ static void __init srso_calculations(bool hw_smt_enabled) + setup_force_cpu_cap(X86_FEATURE_SRSO_NO); + } + ++/* ++ * The Div leakage issue is specific to the AMD Zen1 microarchitecure. ++ * ++ * However, there's no $FOO_NO bit defined, so if we're virtualised we have no ++ * hope of spotting the case where we might move to vulnerable hardware. We ++ * also can't make any useful conclusion about SMT-ness. ++ * ++ * Don't check the hypervisor bit, so at least we do the safe thing when ++ * booting on something that looks like a Zen1 CPU. ++ */ ++static bool __init has_div_vuln(void) ++{ ++ if ( !(boot_cpu_data.x86_vendor & ++ (X86_VENDOR_AMD | X86_VENDOR_HYGON)) ) ++ return false; ++ ++ if ( boot_cpu_data.x86 != 0x17 && boot_cpu_data.x86 != 0x18 ) ++ return false; ++ ++ return is_zen1_uarch(); ++} ++ ++static void __init div_calculations(bool hw_smt_enabled) ++{ ++ bool cpu_bug_div = has_div_vuln(); ++ ++ if ( opt_div_scrub == -1 ) ++ opt_div_scrub = cpu_bug_div; ++ ++ if ( opt_div_scrub ) ++ setup_force_cpu_cap(X86_FEATURE_SC_DIV); ++ ++ if ( opt_smt == -1 && !cpu_has_hypervisor && cpu_bug_div && hw_smt_enabled ) ++ warning_add( ++ "Booted on leaky-DIV hardware with SMT/Hyperthreading\n" ++ "enabled. Please assess your configuration and choose an\n" ++ "explicit 'smt=' setting. See XSA-439.\n"); ++} ++ + static void __init ibpb_calculations(void) + { + bool def_ibpb_entry = false; +@@ -1716,6 +1761,8 @@ void __init init_speculation_mitigations(void) + + ibpb_calculations(); + ++ div_calculations(hw_smt_enabled); ++ + /* Check whether Eager FPU should be enabled by default. */ + if ( opt_eager_fpu == -1 ) + opt_eager_fpu = should_use_eager_fpu(); +diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h +index ccf9d7287c..70b93b6b44 100644 +--- a/xen/include/asm-x86/cpufeatures.h ++++ b/xen/include/asm-x86/cpufeatures.h +@@ -35,7 +35,7 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM + XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ + XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ + XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ +-/* Bits 23 unused. */ ++XEN_CPUFEATURE(SC_DIV, X86_SYNTH(23)) /* DIV scrub needed */ + XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ + XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ + XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ +diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h +index 8a816b8cf6..0e69971f66 100644 +--- a/xen/include/asm-x86/spec_ctrl_asm.h ++++ b/xen/include/asm-x86/spec_ctrl_asm.h +@@ -182,6 +182,19 @@ + .L\@_verw_skip: + .endm + ++.macro DO_SPEC_CTRL_DIV ++/* ++ * Requires nothing ++ * Clobbers %rax ++ * ++ * Issue a DIV for its flushing side effect (Zen1 uarch specific). Any ++ * non-faulting DIV will do; a byte DIV has least latency, and doesn't clobber ++ * %rdx. ++ */ ++ mov $1, %eax ++ div %al ++.endm ++ + .macro DO_SPEC_CTRL_ENTRY maybexen:req + /* + * Requires %rsp=regs (also cpuinfo if !maybexen) +@@ -284,6 +297,8 @@ + ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV + + DO_SPEC_CTRL_COND_VERW ++ ++ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV + .endm + + /* +@@ -396,6 +411,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + verw STACK_CPUINFO_FIELD(verw_sel)(%r14) + .L\@_skip_verw: + ++ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV ++ + .L\@_skip_ist_exit: + .endm + +-- +2.41.0 + From 7fa4a3eee62bba7719bdc19908fc91822f9c5fe3 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sun, 8 Oct 2023 12:02:22 +0100 Subject: [PATCH 36/99] rebuild for OCaml 5.1 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 778a2e5..29c69a4 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.2 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -959,6 +959,9 @@ fi %endif %changelog +* Sun Oct 08 2023 Michael Young - 4.17.2-3 +- rebuild (f40) for OCaml 5.1 + * Tue Sep 26 2023 Michael Young - 4.17.2-2 - arm32: The cache may not be properly cleaned/invalidated [XSA-437, CVE-2023-34321] From ad078f957fcdc8755a8585f90368a012a6e8c530 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 10 Oct 2023 21:42:36 +0100 Subject: [PATCH 37/99] 4 security issues xenstored: A transaction conflict can crash C Xenstored [XSA-440, CVE-2023-34323] x86/AMD: missing IOMMU TLB flushing [XSA-442, CVE-2023-34326] Multiple vulnerabilities in libfsimage disk handling [XSA-443, CVE-2023-34325] x86/AMD: Debug Mask handling [XSA-444, CVE-2023-34327, CVE-2023-34328] --- xen.spec | 41 +++++- xsa440-4.17.patch | 58 ++++++++ xsa442-4.17.patch | 185 ++++++++++++++++++++++++++ xsa443-4.17-01.patch | 70 ++++++++++ xsa443-4.17-02.patch | 32 +++++ xsa443-4.17-03.patch | 137 +++++++++++++++++++ xsa443-4.17-04.patch | 61 +++++++++ xsa443-4.17-05.patch | 59 +++++++++ xsa443-4.17-06.patch | 65 +++++++++ xsa443-4.17-07.patch | 105 +++++++++++++++ xsa443-4.17-08.patch | 126 ++++++++++++++++++ xsa443-4.17-09.patch | 307 +++++++++++++++++++++++++++++++++++++++++++ xsa443-4.17-10.patch | 250 +++++++++++++++++++++++++++++++++++ xsa443-4.17-11.patch | 157 ++++++++++++++++++++++ xsa444-4.17-1.patch | 93 +++++++++++++ xsa444-4.17-2.patch | 72 ++++++++++ 16 files changed, 1817 insertions(+), 1 deletion(-) create mode 100644 xsa440-4.17.patch create mode 100644 xsa442-4.17.patch create mode 100644 xsa443-4.17-01.patch create mode 100644 xsa443-4.17-02.patch create mode 100644 xsa443-4.17-03.patch create mode 100644 xsa443-4.17-04.patch create mode 100644 xsa443-4.17-05.patch create mode 100644 xsa443-4.17-06.patch create mode 100644 xsa443-4.17-07.patch create mode 100644 xsa443-4.17-08.patch create mode 100644 xsa443-4.17-09.patch create mode 100644 xsa443-4.17-10.patch create mode 100644 xsa443-4.17-11.patch create mode 100644 xsa444-4.17-1.patch create mode 100644 xsa444-4.17-2.patch diff --git a/xen.spec b/xen.spec index 29c69a4..fde47fb 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.2 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -124,6 +124,21 @@ Patch59: xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch Patch60: xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch Patch61: xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch Patch62: xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch +Patch63: xsa440-4.17.patch +Patch64: xsa442-4.17.patch +Patch65: xsa443-4.17-01.patch +Patch66: xsa443-4.17-02.patch +Patch67: xsa443-4.17-03.patch +Patch68: xsa443-4.17-04.patch +Patch69: xsa443-4.17-05.patch +Patch70: xsa443-4.17-06.patch +Patch71: xsa443-4.17-07.patch +Patch72: xsa443-4.17-08.patch +Patch73: xsa443-4.17-09.patch +Patch74: xsa443-4.17-10.patch +Patch75: xsa443-4.17-11.patch +Patch76: xsa444-4.17-1.patch +Patch77: xsa444-4.17-2.patch %if %build_qemutrad @@ -352,6 +367,21 @@ manage Xen virtual machines. %patch 60 -p1 %patch 61 -p1 %patch 62 -p1 +%patch 63 -p1 +%patch 64 -p1 +%patch 65 -p1 +%patch 66 -p1 +%patch 67 -p1 +%patch 68 -p1 +%patch 69 -p1 +%patch 70 -p1 +%patch 71 -p1 +%patch 72 -p1 +%patch 73 -p1 +%patch 74 -p1 +%patch 75 -p1 +%patch 76 -p1 +%patch 77 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -959,6 +989,15 @@ fi %endif %changelog +* Tue Oct 10 2023 Michael Young - 4.17.2-4 +- xenstored: A transaction conflict can crash C Xenstored [XSA-440, + CVE-2023-34323] +- x86/AMD: missing IOMMU TLB flushing [XSA-442, CVE-2023-34326] +- Multiple vulnerabilities in libfsimage disk handling [XSA-443, + CVE-2023-34325] +- x86/AMD: Debug Mask handling [XSA-444, CVE-2023-34327, + CVE-2023-34328] + * Sun Oct 08 2023 Michael Young - 4.17.2-3 - rebuild (f40) for OCaml 5.1 diff --git a/xsa440-4.17.patch b/xsa440-4.17.patch new file mode 100644 index 0000000..4941afc --- /dev/null +++ b/xsa440-4.17.patch @@ -0,0 +1,58 @@ +From 5d8b3d1ec98e56155d9650d7f4a70cd8ba9dc27d Mon Sep 17 00:00:00 2001 +From: Julien Grall +Date: Fri, 22 Sep 2023 11:32:16 +0100 +Subject: tools/xenstored: domain_entry_fix(): Handle conflicting transaction + +The function domain_entry_fix() will be initially called to check if the +quota is correct before attempt to commit any nodes. So it would be +possible that accounting is temporarily negative. This is the case +in the following sequence: + + 1) Create 50 nodes + 2) Start two transactions + 3) Delete all the nodes in each transaction + 4) Commit the two transactions + +Because the first transaction will have succeed and updated the +accounting, there is no guarantee that 'd->nbentry + num' will still +be above 0. So the assert() would be triggered. +The assert() was introduced in dbef1f748289 ("tools/xenstore: simplify +and fix per domain node accounting") with the assumption that the +value can't be negative. As this is not true revert to the original +check but restricted to the path where we don't update. Take the +opportunity to explain the rationale behind the check. + +This CVE-2023-34323 / XSA-440. + +Reported-by: Stanislav Uschakow +Fixes: dbef1f748289 ("tools/xenstore: simplify and fix per domain node accounting") +Signed-off-by: Julien Grall +Reviewed-by: Juergen Gross + +diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c +index aa86892fed9e..6074df210c6e 100644 +--- a/tools/xenstore/xenstored_domain.c ++++ b/tools/xenstore/xenstored_domain.c +@@ -1094,10 +1094,20 @@ int domain_entry_fix(unsigned int domid, int num, bool update) + } + + cnt = d->nbentry + num; +- assert(cnt >= 0); + +- if (update) ++ if (update) { ++ assert(cnt >= 0); + d->nbentry = cnt; ++ } else if (cnt < 0) { ++ /* ++ * In a transaction when a node is being added/removed AND ++ * the same node has been added/removed outside the ++ * transaction in parallel, the result value may be negative. ++ * This is no problem, as the transaction will fail due to ++ * the resulting conflict. So override 'cnt'. ++ */ ++ cnt = 0; ++ } + + return domid_is_unprivileged(domid) ? cnt : 0; + } diff --git a/xsa442-4.17.patch b/xsa442-4.17.patch new file mode 100644 index 0000000..a78bfdd --- /dev/null +++ b/xsa442-4.17.patch @@ -0,0 +1,185 @@ +From 5b2ccb60ff22fbff44dd66214c2956a434ee6271 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Tue, 13 Jun 2023 15:01:05 +0200 +Subject: [PATCH] iommu/amd-vi: flush IOMMU TLB when flushing the DTE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The caching invalidation guidelines from the AMD-Vi specification (48882—Rev +3.07-PUB—Oct 2022) seem to be misleading on some hardware, as devices will +malfunction (see stale DMA mappings) if some fields of the DTE are updated but +the IOMMU TLB is not flushed. This has been observed in practice on AMD +systems. Due to the lack of guidance from the currently published +specification this patch aims to increase the flushing done in order to prevent +device malfunction. + +In order to fix, issue an INVALIDATE_IOMMU_PAGES command from +amd_iommu_flush_device(), flushing all the address space. Note this requires +callers to be adjusted in order to pass the DomID on the DTE previous to the +modification. + +Some call sites don't provide a valid DomID to amd_iommu_flush_device() in +order to avoid the flush. That's because the device had address translations +disabled and hence the previous DomID on the DTE is not valid. Note the +current logic relies on the entity disabling address translations to also flush +the TLB of the in use DomID. + +Device I/O TLB flushing when ATS are enabled is not covered by the current +change, as ATS usage is not security supported. + +This is XSA-442 / CVE-2023-34326 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/drivers/passthrough/amd/iommu.h | 3 ++- + xen/drivers/passthrough/amd/iommu_cmd.c | 10 +++++++++- + xen/drivers/passthrough/amd/iommu_guest.c | 5 +++-- + xen/drivers/passthrough/amd/iommu_init.c | 6 +++++- + xen/drivers/passthrough/amd/pci_amd_iommu.c | 14 ++++++++++---- + 5 files changed, 29 insertions(+), 9 deletions(-) + +diff --git a/xen/drivers/passthrough/amd/iommu.h b/xen/drivers/passthrough/amd/iommu.h +index 5429ada58ef5..a58be28bf96d 100644 +--- a/xen/drivers/passthrough/amd/iommu.h ++++ b/xen/drivers/passthrough/amd/iommu.h +@@ -283,7 +283,8 @@ void amd_iommu_flush_pages(struct domain *d, unsigned long dfn, + unsigned int order); + void amd_iommu_flush_iotlb(u8 devfn, const struct pci_dev *pdev, + uint64_t gaddr, unsigned int order); +-void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf); ++void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf, ++ domid_t domid); + void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf); + void amd_iommu_flush_all_caches(struct amd_iommu *iommu); + +diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c b/xen/drivers/passthrough/amd/iommu_cmd.c +index 40ddf366bb4d..cb28b36abc38 100644 +--- a/xen/drivers/passthrough/amd/iommu_cmd.c ++++ b/xen/drivers/passthrough/amd/iommu_cmd.c +@@ -363,10 +363,18 @@ void amd_iommu_flush_pages(struct domain *d, + _amd_iommu_flush_pages(d, __dfn_to_daddr(dfn), order); + } + +-void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf) ++void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf, ++ domid_t domid) + { + invalidate_dev_table_entry(iommu, bdf); + flush_command_buffer(iommu, 0); ++ ++ /* Also invalidate IOMMU TLB entries when flushing the DTE. */ ++ if ( domid != DOMID_INVALID ) ++ { ++ invalidate_iommu_pages(iommu, INV_IOMMU_ALL_PAGES_ADDRESS, domid, 0); ++ flush_command_buffer(iommu, 0); ++ } + } + + void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf) +diff --git a/xen/drivers/passthrough/amd/iommu_guest.c b/xen/drivers/passthrough/amd/iommu_guest.c +index 80a331f546ed..be86bce6fb03 100644 +--- a/xen/drivers/passthrough/amd/iommu_guest.c ++++ b/xen/drivers/passthrough/amd/iommu_guest.c +@@ -385,7 +385,7 @@ static int do_completion_wait(struct domain *d, cmd_entry_t *cmd) + + static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd) + { +- uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id; ++ uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id, prev_domid; + struct amd_iommu_dte *gdte, *mdte, *dte_base; + struct amd_iommu *iommu = NULL; + struct guest_iommu *g_iommu; +@@ -445,13 +445,14 @@ static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd) + req_id = get_dma_requestor_id(iommu->seg, mbdf); + dte_base = iommu->dev_table.buffer; + mdte = &dte_base[req_id]; ++ prev_domid = mdte->domain_id; + + spin_lock_irqsave(&iommu->lock, flags); + dte_set_gcr3_table(mdte, hdom_id, gcr3_mfn << PAGE_SHIFT, gv, glx); + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ amd_iommu_flush_device(iommu, req_id, prev_domid); + + return 0; + } +diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c +index 166570648d26..101a60ce1794 100644 +--- a/xen/drivers/passthrough/amd/iommu_init.c ++++ b/xen/drivers/passthrough/amd/iommu_init.c +@@ -1547,7 +1547,11 @@ static int cf_check _invalidate_all_devices( + req_id = ivrs_mappings[bdf].dte_requestor_id; + if ( iommu ) + { +- amd_iommu_flush_device(iommu, req_id); ++ /* ++ * IOMMU TLB flush performed separately (see ++ * invalidate_all_domain_pages()). ++ */ ++ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID); + amd_iommu_flush_intremap(iommu, req_id); + } + } +diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c +index 94e37755064b..8641b84712a0 100644 +--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c ++++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c +@@ -192,10 +192,13 @@ static int __must_check amd_iommu_setup_domain_device( + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ /* DTE didn't have DMA translations enabled, do not flush the TLB. */ ++ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID); + } + else if ( dte->pt_root != mfn_x(page_to_mfn(root_pg)) ) + { ++ domid_t prev_domid = dte->domain_id; ++ + /* + * Strictly speaking if the device is the only one with this requestor + * ID, it could be allowed to be re-assigned regardless of unity map +@@ -252,7 +255,7 @@ static int __must_check amd_iommu_setup_domain_device( + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ amd_iommu_flush_device(iommu, req_id, prev_domid); + } + else + spin_unlock_irqrestore(&iommu->lock, flags); +@@ -421,6 +424,8 @@ static void amd_iommu_disable_domain_device(const struct domain *domain, + spin_lock_irqsave(&iommu->lock, flags); + if ( dte->tv || dte->v ) + { ++ domid_t prev_domid = dte->domain_id; ++ + /* See the comment in amd_iommu_setup_device_table(). */ + dte->int_ctl = IOMMU_DEV_TABLE_INT_CONTROL_ABORTED; + smp_wmb(); +@@ -439,7 +444,7 @@ static void amd_iommu_disable_domain_device(const struct domain *domain, + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ amd_iommu_flush_device(iommu, req_id, prev_domid); + + AMD_IOMMU_DEBUG("Disable: device id = %#x, " + "domain = %d, paging mode = %d\n", +@@ -610,7 +615,8 @@ static int cf_check amd_iommu_add_device(u8 devfn, struct pci_dev *pdev) + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, bdf); ++ /* DTE didn't have DMA translations enabled, do not flush the TLB. */ ++ amd_iommu_flush_device(iommu, bdf, DOMID_INVALID); + } + + if ( amd_iommu_reserve_domain_unity_map( +-- +2.42.0 + diff --git a/xsa443-4.17-01.patch b/xsa443-4.17-01.patch new file mode 100644 index 0000000..d9ca3f8 --- /dev/null +++ b/xsa443-4.17-01.patch @@ -0,0 +1,70 @@ +From 7e48562bf34e90f907491a0595782d2daa1ff3ad Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:50 +0100 +Subject: [PATCH 01/11] libfsimage/xfs: Remove dead code + +xfs_info.agnolog (and related code) and XFS_INO_AGBNO_BITS are dead code +that serve no purpose. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Reviewed-by: Jan Beulich +--- + tools/libfsimage/xfs/fsys_xfs.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index d735a88e55f3..2800699f5985 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -37,7 +37,6 @@ struct xfs_info { + int blklog; + int inopblog; + int agblklog; +- int agnolog; + unsigned int nextents; + xfs_daddr_t next; + xfs_daddr_t daddr; +@@ -65,9 +64,7 @@ static struct xfs_info xfs; + + #define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1)) + #define XFS_INO_OFFSET_BITS xfs.inopblog +-#define XFS_INO_AGBNO_BITS xfs.agblklog + #define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog) +-#define XFS_INO_AGNO_BITS xfs.agnolog + + static inline xfs_agblock_t + agino2agbno (xfs_agino_t agino) +@@ -149,20 +146,6 @@ xt_len (xfs_bmbt_rec_32_t *r) + return le32(r->l3) & mask32lo(21); + } + +-static inline int +-xfs_highbit32(xfs_uint32_t v) +-{ +- int i; +- +- if (--v) { +- for (i = 0; i < 31; i++, v >>= 1) { +- if (v == 0) +- return i; +- } +- } +- return 0; +-} +- + static int + isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len) + { +@@ -472,7 +455,6 @@ xfs_mount (fsi_file_t *ffi, const char *options) + + xfs.inopblog = super.sb_inopblog; + xfs.agblklog = super.sb_agblklog; +- xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount)); + + xfs.btnode_ptr0_off = + ((xfs.bsize - sizeof(xfs_btree_block_t)) / +-- +2.42.0 + diff --git a/xsa443-4.17-02.patch b/xsa443-4.17-02.patch new file mode 100644 index 0000000..0f2edaf --- /dev/null +++ b/xsa443-4.17-02.patch @@ -0,0 +1,32 @@ +From c26327795b78c93f6fa6d5d46e34f59dc4046601 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:51 +0100 +Subject: [PATCH 02/11] libfsimage/xfs: Amend mask32lo() to allow the value 32 + +agblklog could plausibly be 32, but that would overflow this shift. +Perform the shift as ULL and cast to u32 at the end instead. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Jan Beulich +--- + tools/libfsimage/xfs/fsys_xfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index 2800699f5985..4720bb4505c8 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -60,7 +60,7 @@ static struct xfs_info xfs; + #define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192)) + #define icore (inode->di_core) + +-#define mask32lo(n) (((xfs_uint32_t)1 << (n)) - 1) ++#define mask32lo(n) ((xfs_uint32_t)((1ull << (n)) - 1)) + + #define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1)) + #define XFS_INO_OFFSET_BITS xfs.inopblog +-- +2.42.0 + diff --git a/xsa443-4.17-03.patch b/xsa443-4.17-03.patch new file mode 100644 index 0000000..b89721a --- /dev/null +++ b/xsa443-4.17-03.patch @@ -0,0 +1,137 @@ +From 199f0538bbec052028679a55ea512437170854c9 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:52 +0100 +Subject: [PATCH 03/11] libfsimage/xfs: Sanity-check the superblock during + mounts + +Sanity-check the XFS superblock for wellformedness at the mount handler. +This forces pygrub to abort parsing a potentially malformed filesystem and +ensures the invariants assumed throughout the rest of the code hold. + +Also, derive parameters from previously sanitized parameters where possible +(rather than reading them off the superblock) + +The code doesn't try to avoid overflowing the end of the disk, because +that's an unlikely and benign error. Parameters used in calculations of +xfs_daddr_t (like the root inode index) aren't in critical need of being +sanitized. + +The sanitization of agblklog is basically checking that no obvious +overflows happen on agblklog, and then ensuring agblocks is contained in +the range (2^(sb_agblklog-1), 2^sb_agblklog]. + +This is part of XSA-443 / CVE-2023-34325 + +Reported-by: Ferdinand Nölscher +Signed-off-by: Alejandro Vallejo +Reviewed-by: Jan Beulich +--- + tools/libfsimage/xfs/fsys_xfs.c | 48 ++++++++++++++++++++++++++------- + tools/libfsimage/xfs/xfs.h | 12 +++++++++ + 2 files changed, 50 insertions(+), 10 deletions(-) + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index 4720bb4505c8..e4eb7e1ee26f 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -17,6 +17,7 @@ + * along with this program; If not, see . + */ + ++#include + #include + #include "xfs.h" + +@@ -433,29 +434,56 @@ first_dentry (fsi_file_t *ffi, xfs_ino_t *ino) + return next_dentry (ffi, ino); + } + ++static bool ++xfs_sb_is_invalid (const xfs_sb_t *super) ++{ ++ return (le32(super->sb_magicnum) != XFS_SB_MAGIC) ++ || ((le16(super->sb_versionnum) & XFS_SB_VERSION_NUMBITS) != ++ XFS_SB_VERSION_4) ++ || (super->sb_inodelog < XFS_SB_INODELOG_MIN) ++ || (super->sb_inodelog > XFS_SB_INODELOG_MAX) ++ || (super->sb_blocklog < XFS_SB_BLOCKLOG_MIN) ++ || (super->sb_blocklog > XFS_SB_BLOCKLOG_MAX) ++ || (super->sb_blocklog < super->sb_inodelog) ++ || (super->sb_agblklog > XFS_SB_AGBLKLOG_MAX) ++ || ((1ull << super->sb_agblklog) < le32(super->sb_agblocks)) ++ || (((1ull << super->sb_agblklog) >> 1) >= ++ le32(super->sb_agblocks)) ++ || ((super->sb_blocklog + super->sb_dirblklog) >= ++ XFS_SB_DIRBLK_NUMBITS); ++} ++ + static int + xfs_mount (fsi_file_t *ffi, const char *options) + { + xfs_sb_t super; + + if (!devread (ffi, 0, 0, sizeof(super), (char *)&super) +- || (le32(super.sb_magicnum) != XFS_SB_MAGIC) +- || ((le16(super.sb_versionnum) +- & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) { ++ || xfs_sb_is_invalid(&super)) { + return 0; + } + +- xfs.bsize = le32 (super.sb_blocksize); +- xfs.blklog = super.sb_blocklog; +- xfs.bdlog = xfs.blklog - SECTOR_BITS; ++ /* ++ * Not sanitized. It's exclusively used to generate disk addresses, ++ * so it's not important from a security standpoint. ++ */ + xfs.rootino = le64 (super.sb_rootino); +- xfs.isize = le16 (super.sb_inodesize); +- xfs.agblocks = le32 (super.sb_agblocks); +- xfs.dirbsize = xfs.bsize << super.sb_dirblklog; + +- xfs.inopblog = super.sb_inopblog; ++ /* ++ * Sanitized to be consistent with each other, only used to ++ * generate disk addresses, so it's safe ++ */ ++ xfs.agblocks = le32 (super.sb_agblocks); + xfs.agblklog = super.sb_agblklog; + ++ /* Derived from sanitized parameters */ ++ xfs.bsize = 1 << super.sb_blocklog; ++ xfs.blklog = super.sb_blocklog; ++ xfs.bdlog = super.sb_blocklog - SECTOR_BITS; ++ xfs.isize = 1 << super.sb_inodelog; ++ xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog); ++ xfs.inopblog = super.sb_blocklog - super.sb_inodelog; ++ + xfs.btnode_ptr0_off = + ((xfs.bsize - sizeof(xfs_btree_block_t)) / + (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t))) +diff --git a/tools/libfsimage/xfs/xfs.h b/tools/libfsimage/xfs/xfs.h +index 40699281e44d..b87e37d3d7e9 100644 +--- a/tools/libfsimage/xfs/xfs.h ++++ b/tools/libfsimage/xfs/xfs.h +@@ -134,6 +134,18 @@ typedef struct xfs_sb + xfs_uint8_t sb_dummy[7]; /* padding */ + } xfs_sb_t; + ++/* Bound taken from xfs.c in GRUB2. It doesn't exist in the spec */ ++#define XFS_SB_DIRBLK_NUMBITS 27 ++/* Implied by the XFS specification. The minimum block size is 512 octets */ ++#define XFS_SB_BLOCKLOG_MIN 9 ++/* Implied by the XFS specification. The maximum block size is 65536 octets */ ++#define XFS_SB_BLOCKLOG_MAX 16 ++/* Implied by the XFS specification. The minimum inode size is 256 octets */ ++#define XFS_SB_INODELOG_MIN 8 ++/* Implied by the XFS specification. The maximum inode size is 2048 octets */ ++#define XFS_SB_INODELOG_MAX 11 ++/* High bound for sb_agblklog */ ++#define XFS_SB_AGBLKLOG_MAX 32 + + /* those are from xfs_btree.h */ + +-- +2.42.0 + diff --git a/xsa443-4.17-04.patch b/xsa443-4.17-04.patch new file mode 100644 index 0000000..dde095e --- /dev/null +++ b/xsa443-4.17-04.patch @@ -0,0 +1,61 @@ +From c66fd01277939634c624c8340838682d9d4fd839 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:53 +0100 +Subject: [PATCH 04/11] libfsimage/xfs: Add compile-time check to libfsimage + +Adds the common tools include folder to the -I compile flags +of libfsimage. This allows us to use: + xen-tools/common-macros.h:BUILD_BUG_ON() + +With it, statically assert a sanitized "blocklog - SECTOR_BITS" cannot +underflow. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Reviewed-by: Jan Beulich +--- + tools/libfsimage/common.mk | 2 +- + tools/libfsimage/xfs/fsys_xfs.c | 4 +++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/libfsimage/common.mk b/tools/libfsimage/common.mk +index 4fc8c6679599..e4336837d045 100644 +--- a/tools/libfsimage/common.mk ++++ b/tools/libfsimage/common.mk +@@ -1,7 +1,7 @@ + include $(XEN_ROOT)/tools/Rules.mk + + FSDIR := $(libdir)/xenfsimage +-CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ -DFSIMAGE_FSDIR=\"$(FSDIR)\" ++CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ $(CFLAGS_xeninclude) -DFSIMAGE_FSDIR=\"$(FSDIR)\" + CFLAGS += -D_GNU_SOURCE + LDFLAGS += -L../common/ + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index e4eb7e1ee26f..4a8dd6f2397b 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include "xfs.h" + + #define MAX_LINK_COUNT 8 +@@ -477,9 +478,10 @@ xfs_mount (fsi_file_t *ffi, const char *options) + xfs.agblklog = super.sb_agblklog; + + /* Derived from sanitized parameters */ ++ BUILD_BUG_ON(XFS_SB_BLOCKLOG_MIN < SECTOR_BITS); ++ xfs.bdlog = super.sb_blocklog - SECTOR_BITS; + xfs.bsize = 1 << super.sb_blocklog; + xfs.blklog = super.sb_blocklog; +- xfs.bdlog = super.sb_blocklog - SECTOR_BITS; + xfs.isize = 1 << super.sb_inodelog; + xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog); + xfs.inopblog = super.sb_blocklog - super.sb_inodelog; +-- +2.42.0 + diff --git a/xsa443-4.17-05.patch b/xsa443-4.17-05.patch new file mode 100644 index 0000000..b2f5daa --- /dev/null +++ b/xsa443-4.17-05.patch @@ -0,0 +1,59 @@ +From ad5d0db5e68e5d4e79255fa85d9cb0069bb1c5d5 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:21 +0100 +Subject: [PATCH 05/11] tools/pygrub: Remove unnecessary hypercall + +There's a hypercall being issued in order to determine whether PV64 is +supported, but since Xen 4.3 that's strictly true so it's not required. + +Plus, this way we can avoid mapping the privcmd interface altogether in the +depriv pygrub. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Reviewed-by: Andrew Cooper +--- + tools/pygrub/src/pygrub | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index ce7ab0eb8cf3..ce4e07d3e823 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -18,7 +18,6 @@ import os, sys, string, struct, tempfile, re, traceback, stat, errno + import copy + import logging + import platform +-import xen.lowlevel.xc + + import curses, _curses, curses.textpad, curses.ascii + import getopt +@@ -668,14 +667,6 @@ def run_grub(file, entry, fs, cfg_args): + + return grubcfg + +-def supports64bitPVguest(): +- xc = xen.lowlevel.xc.xc() +- caps = xc.xeninfo()['xen_caps'].split(" ") +- for cap in caps: +- if cap == "xen-3.0-x86_64": +- return True +- return False +- + # If nothing has been specified, look for a Solaris domU. If found, perform the + # necessary tweaks. + def sniff_solaris(fs, cfg): +@@ -684,8 +675,7 @@ def sniff_solaris(fs, cfg): + return cfg + + if not cfg["kernel"]: +- if supports64bitPVguest() and \ +- fs.file_exists("/platform/i86xpv/kernel/amd64/unix"): ++ if fs.file_exists("/platform/i86xpv/kernel/amd64/unix"): + cfg["kernel"] = "/platform/i86xpv/kernel/amd64/unix" + cfg["ramdisk"] = "/platform/i86pc/amd64/boot_archive" + elif fs.file_exists("/platform/i86xpv/kernel/unix"): +-- +2.42.0 + diff --git a/xsa443-4.17-06.patch b/xsa443-4.17-06.patch new file mode 100644 index 0000000..22af109 --- /dev/null +++ b/xsa443-4.17-06.patch @@ -0,0 +1,65 @@ +From d3ceb0b314005a656dd2ca4b2821575a36f8426d Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:22 +0100 +Subject: [PATCH 06/11] tools/pygrub: Small refactors + +Small tidy up to ensure output_directory always has a trailing '/' to ease +concatenating paths and that `output` can only be a filename or None. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/pygrub/src/pygrub | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index ce4e07d3e823..1042c05b8676 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -793,7 +793,7 @@ if __name__ == "__main__": + debug = False + not_really = False + output_format = "sxp" +- output_directory = "/var/run/xen/pygrub" ++ output_directory = "/var/run/xen/pygrub/" + + # what was passed in + incfg = { "kernel": None, "ramdisk": None, "args": "" } +@@ -815,7 +815,8 @@ if __name__ == "__main__": + usage() + sys.exit() + elif o in ("--output",): +- output = a ++ if a != "-": ++ output = a + elif o in ("--kernel",): + incfg["kernel"] = a + elif o in ("--ramdisk",): +@@ -847,12 +848,11 @@ if __name__ == "__main__": + if not os.path.isdir(a): + print("%s is not an existing directory" % a) + sys.exit(1) +- output_directory = a ++ output_directory = a + '/' + + if debug: + logging.basicConfig(level=logging.DEBUG) + +- + try: + os.makedirs(output_directory, 0o700) + except OSError as e: +@@ -861,7 +861,7 @@ if __name__ == "__main__": + else: + raise + +- if output is None or output == "-": ++ if output is None: + fd = sys.stdout.fileno() + else: + fd = os.open(output, os.O_WRONLY) +-- +2.42.0 + diff --git a/xsa443-4.17-07.patch b/xsa443-4.17-07.patch new file mode 100644 index 0000000..94da883 --- /dev/null +++ b/xsa443-4.17-07.patch @@ -0,0 +1,105 @@ +From 9e80cfecde338cea0db136c2fb5ed78d6081e05f Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:23 +0100 +Subject: [PATCH 07/11] tools/pygrub: Open the output files earlier + +This patch allows pygrub to get ahold of every RW file descriptor it needs +early on. A later patch will clamp the filesystem it can access so it can't +obtain any others. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/pygrub/src/pygrub | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index 1042c05b8676..91e2ec2ab105 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -738,8 +738,7 @@ if __name__ == "__main__": + def usage(): + print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] " %(sys.argv[0],), file=sys.stderr) + +- def copy_from_image(fs, file_to_read, file_type, output_directory, +- not_really): ++ def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really): + if not_really: + if fs.file_exists(file_to_read): + return "<%s:%s>" % (file_type, file_to_read) +@@ -750,21 +749,18 @@ if __name__ == "__main__": + except Exception as e: + print(e, file=sys.stderr) + sys.exit("Error opening %s in guest" % file_to_read) +- (tfd, ret) = tempfile.mkstemp(prefix="boot_"+file_type+".", +- dir=output_directory) + dataoff = 0 + while True: + data = datafile.read(FS_READ_MAX, dataoff) + if len(data) == 0: +- os.close(tfd) ++ os.close(fd_dst) + del datafile +- return ret ++ return + try: +- os.write(tfd, data) ++ os.write(fd_dst, data) + except Exception as e: + print(e, file=sys.stderr) +- os.close(tfd) +- os.unlink(ret) ++ os.unlink(path_dst) + del datafile + sys.exit("Error writing temporary copy of "+file_type) + dataoff += len(data) +@@ -861,6 +857,14 @@ if __name__ == "__main__": + else: + raise + ++ if not_really: ++ fd_kernel = path_kernel = fd_ramdisk = path_ramdisk = None ++ else: ++ (fd_kernel, path_kernel) = tempfile.mkstemp(prefix="boot_kernel.", ++ dir=output_directory) ++ (fd_ramdisk, path_ramdisk) = tempfile.mkstemp(prefix="boot_ramdisk.", ++ dir=output_directory) ++ + if output is None: + fd = sys.stdout.fileno() + else: +@@ -920,20 +924,23 @@ if __name__ == "__main__": + if fs is None: + raise RuntimeError("Unable to find partition containing kernel") + +- bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel", +- output_directory, not_really) ++ copy_from_image(fs, chosencfg["kernel"], "kernel", ++ fd_kernel, path_kernel, not_really) ++ bootcfg["kernel"] = path_kernel + + if chosencfg["ramdisk"]: + try: +- bootcfg["ramdisk"] = copy_from_image(fs, chosencfg["ramdisk"], +- "ramdisk", output_directory, +- not_really) ++ copy_from_image(fs, chosencfg["ramdisk"], "ramdisk", ++ fd_ramdisk, path_ramdisk, not_really) + except: + if not not_really: +- os.unlink(bootcfg["kernel"]) ++ os.unlink(path_kernel) + raise ++ bootcfg["ramdisk"] = path_ramdisk + else: + initrd = None ++ if not not_really: ++ os.unlink(path_ramdisk) + + args = None + if chosencfg["args"]: +-- +2.42.0 + diff --git a/xsa443-4.17-08.patch b/xsa443-4.17-08.patch new file mode 100644 index 0000000..bd7de1d --- /dev/null +++ b/xsa443-4.17-08.patch @@ -0,0 +1,126 @@ +From 2fb4cdcedd8720f78c4bd44739a5d30dd1a7d9a5 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:24 +0100 +Subject: [PATCH 08/11] tools/libfsimage: Export a new function to preload all + plugins + +This is work required in order to let pygrub operate in highly deprivileged +chroot mode. This patch adds a function that preloads every plugin, hence +ensuring that a on function exit, every shared library is loaded in memory. + +The new "init" function is supposed to be used before depriv, but that's +fine because it's not acting on untrusted data. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/libfsimage/common/fsimage_plugin.c | 4 ++-- + tools/libfsimage/common/mapfile-GNU | 1 + + tools/libfsimage/common/mapfile-SunOS | 1 + + tools/libfsimage/common/xenfsimage.h | 8 ++++++++ + tools/pygrub/src/fsimage/fsimage.c | 15 +++++++++++++++ + 5 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/tools/libfsimage/common/fsimage_plugin.c b/tools/libfsimage/common/fsimage_plugin.c +index de1412b4233a..d0cb9e96a654 100644 +--- a/tools/libfsimage/common/fsimage_plugin.c ++++ b/tools/libfsimage/common/fsimage_plugin.c +@@ -119,7 +119,7 @@ fail: + return (-1); + } + +-static int load_plugins(void) ++int fsi_init(void) + { + const char *fsdir = getenv("XEN_FSIMAGE_FSDIR"); + struct dirent *dp = NULL; +@@ -180,7 +180,7 @@ int find_plugin(fsi_t *fsi, const char *path, const char *options) + fsi_plugin_t *fp; + int ret = 0; + +- if (plugins == NULL && (ret = load_plugins()) != 0) ++ if (plugins == NULL && (ret = fsi_init()) != 0) + goto out; + + for (fp = plugins; fp != NULL; fp = fp->fp_next) { +diff --git a/tools/libfsimage/common/mapfile-GNU b/tools/libfsimage/common/mapfile-GNU +index 26d4d7a69ec7..2d54d527d7f5 100644 +--- a/tools/libfsimage/common/mapfile-GNU ++++ b/tools/libfsimage/common/mapfile-GNU +@@ -1,6 +1,7 @@ + VERSION { + libfsimage.so.1.0 { + global: ++ fsi_init; + fsi_open_fsimage; + fsi_close_fsimage; + fsi_file_exists; +diff --git a/tools/libfsimage/common/mapfile-SunOS b/tools/libfsimage/common/mapfile-SunOS +index e99b90b65077..48deedb4252f 100644 +--- a/tools/libfsimage/common/mapfile-SunOS ++++ b/tools/libfsimage/common/mapfile-SunOS +@@ -1,5 +1,6 @@ + libfsimage.so.1.0 { + global: ++ fsi_init; + fsi_open_fsimage; + fsi_close_fsimage; + fsi_file_exists; +diff --git a/tools/libfsimage/common/xenfsimage.h b/tools/libfsimage/common/xenfsimage.h +index 201abd54f23a..341883b2d71a 100644 +--- a/tools/libfsimage/common/xenfsimage.h ++++ b/tools/libfsimage/common/xenfsimage.h +@@ -35,6 +35,14 @@ extern C { + typedef struct fsi fsi_t; + typedef struct fsi_file fsi_file_t; + ++/* ++ * Optional initialization function. If invoked it loads the associated ++ * dynamic libraries for the backends ahead of time. This is required if ++ * the library is to run as part of a highly deprivileged executable, as ++ * the libraries may not be reachable after depriv. ++ */ ++int fsi_init(void); ++ + fsi_t *fsi_open_fsimage(const char *, uint64_t, const char *); + void fsi_close_fsimage(fsi_t *); + +diff --git a/tools/pygrub/src/fsimage/fsimage.c b/tools/pygrub/src/fsimage/fsimage.c +index 2ebbbe35df92..92fbf2851f01 100644 +--- a/tools/pygrub/src/fsimage/fsimage.c ++++ b/tools/pygrub/src/fsimage/fsimage.c +@@ -286,6 +286,15 @@ fsimage_getbootstring(PyObject *o, PyObject *args) + return Py_BuildValue("s", bootstring); + } + ++static PyObject * ++fsimage_init(PyObject *o, PyObject *args) ++{ ++ if (!PyArg_ParseTuple(args, "")) ++ return (NULL); ++ ++ return Py_BuildValue("i", fsi_init()); ++} ++ + PyDoc_STRVAR(fsimage_open__doc__, + "open(name, [offset=off]) - Open the given file as a filesystem image.\n" + "\n" +@@ -297,7 +306,13 @@ PyDoc_STRVAR(fsimage_getbootstring__doc__, + "getbootstring(fs) - Return the boot string needed for this file system " + "or NULL if none is needed.\n"); + ++PyDoc_STRVAR(fsimage_init__doc__, ++ "init() - Loads every dynamic library contained in xenfsimage " ++ "into memory so that it can be used in chrooted environments.\n"); ++ + static struct PyMethodDef fsimage_module_methods[] = { ++ { "init", (PyCFunction)fsimage_init, ++ METH_VARARGS, fsimage_init__doc__ }, + { "open", (PyCFunction)fsimage_open, + METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ }, + { "getbootstring", (PyCFunction)fsimage_getbootstring, +-- +2.42.0 + diff --git a/xsa443-4.17-09.patch b/xsa443-4.17-09.patch new file mode 100644 index 0000000..2e3ebd8 --- /dev/null +++ b/xsa443-4.17-09.patch @@ -0,0 +1,307 @@ +From 150771ce86a07e469e34941a63c56e2cf242223b Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:25 +0100 +Subject: [PATCH 09/11] tools/pygrub: Deprivilege pygrub + +Introduce a --runas= flag to deprivilege pygrub on Linux and *BSDs. It +also implicitly creates a chroot env where it drops a deprivileged forked +process. The chroot itself is cleaned up at the end. + +If the --runas arg is present, then pygrub forks, leaving the child to +deprivilege itself, and waiting for it to complete. When the child exists, +the parent performs cleanup and exits with the same error code. + +This is roughly what the child does: + 1. Initialize libfsimage (this loads every .so in memory so the chroot + can avoid bind-mounting /{,usr}/lib* + 2. Create a temporary empty chroot directory + 3. Mount tmpfs in it + 4. Bind mount the disk inside, because libfsimage expects a path, not a + file descriptor. + 5. Remount the root tmpfs to be stricter (ro,nosuid,nodev) + 6. Set RLIMIT_FSIZE to a sensibly high amount (128 MiB) + 7. Depriv gid, groups and uid + +With this scheme in place, the "output" files are writable (up to +RLIMIT_FSIZE octets) and the exposed filesystem is immutable and contains +the single only file we can't easily get rid of (the disk). + +If running on Linux, the child process also unshares mount, IPC, and +network namespaces before dropping its privileges. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/pygrub/setup.py | 2 +- + tools/pygrub/src/pygrub | 162 +++++++++++++++++++++++++++++++++++++--- + 2 files changed, 154 insertions(+), 10 deletions(-) + +diff --git a/tools/pygrub/setup.py b/tools/pygrub/setup.py +index 0e4e3d02d372..06b96733d020 100644 +--- a/tools/pygrub/setup.py ++++ b/tools/pygrub/setup.py +@@ -17,7 +17,7 @@ xenfsimage = Extension("xenfsimage", + pkgs = [ 'grub' ] + + setup(name='pygrub', +- version='0.6', ++ version='0.7', + description='Boot loader that looks a lot like grub for Xen', + author='Jeremy Katz', + author_email='katzj@redhat.com', +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index 91e2ec2ab105..7cea496ade08 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -16,8 +16,11 @@ from __future__ import print_function + + import os, sys, string, struct, tempfile, re, traceback, stat, errno + import copy ++import ctypes, ctypes.util + import logging + import platform ++import resource ++import subprocess + + import curses, _curses, curses.textpad, curses.ascii + import getopt +@@ -27,10 +30,135 @@ import grub.GrubConf + import grub.LiloConf + import grub.ExtLinuxConf + +-PYGRUB_VER = 0.6 ++PYGRUB_VER = 0.7 + FS_READ_MAX = 1024 * 1024 + SECTOR_SIZE = 512 + ++# Unless provided through the env variable PYGRUB_MAX_FILE_SIZE_MB, then ++# this is the maximum filesize allowed for files written by the depriv ++# pygrub ++LIMIT_FSIZE = 128 << 20 ++ ++CLONE_NEWNS = 0x00020000 # mount namespace ++CLONE_NEWNET = 0x40000000 # network namespace ++CLONE_NEWIPC = 0x08000000 # IPC namespace ++ ++def unshare(flags): ++ if not sys.platform.startswith("linux"): ++ print("skip_unshare reason=not_linux platform=%s", sys.platform, file=sys.stderr) ++ return ++ ++ libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) ++ unshare_prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True) ++ unshare = unshare_prototype(('unshare', libc)) ++ ++ if unshare(flags) < 0: ++ raise OSError(ctypes.get_errno(), os.strerror(ctypes.get_errno())) ++ ++def bind_mount(src, dst, options): ++ open(dst, "a").close() # touch ++ ++ rc = subprocess.call(["mount", "--bind", "-o", options, src, dst]) ++ if rc != 0: ++ raise RuntimeError("bad_mount: src=%s dst=%s opts=%s" % ++ (src, dst, options)) ++ ++def downgrade_rlimits(): ++ # Wipe the authority to use unrequired resources ++ resource.setrlimit(resource.RLIMIT_NPROC, (0, 0)) ++ resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) ++ resource.setrlimit(resource.RLIMIT_MEMLOCK, (0, 0)) ++ ++ # py2's resource module doesn't know about resource.RLIMIT_MSGQUEUE ++ # ++ # TODO: Use resource.RLIMIT_MSGQUEUE after python2 is deprecated ++ if sys.platform.startswith('linux'): ++ RLIMIT_MSGQUEUE = 12 ++ resource.setrlimit(RLIMIT_MSGQUEUE, (0, 0)) ++ ++ # The final look of the filesystem for this process is fully RO, but ++ # note we have some file descriptor already open (notably, kernel and ++ # ramdisk). In order to avoid a compromised pygrub from filling up the ++ # filesystem we set RLIMIT_FSIZE to a high bound, so that the file ++ # write permissions are bound. ++ fsize = LIMIT_FSIZE ++ if "PYGRUB_MAX_FILE_SIZE_MB" in os.environ.keys(): ++ fsize = os.environ["PYGRUB_MAX_FILE_SIZE_MB"] << 20 ++ ++ resource.setrlimit(resource.RLIMIT_FSIZE, (fsize, fsize)) ++ ++def depriv(output_directory, output, device, uid, path_kernel, path_ramdisk): ++ # The only point of this call is to force the loading of libfsimage. ++ # That way, we don't need to bind-mount it into the chroot ++ rc = xenfsimage.init() ++ if rc != 0: ++ os.unlink(path_ramdisk) ++ os.unlink(path_kernel) ++ raise RuntimeError("bad_xenfsimage: rc=%d" % rc) ++ ++ # Create a temporary directory for the chroot ++ chroot = tempfile.mkdtemp(prefix=str(uid)+'-', dir=output_directory) + '/' ++ device_path = '/device' ++ ++ pid = os.fork() ++ if pid: ++ # parent ++ _, rc = os.waitpid(pid, 0) ++ ++ for path in [path_kernel, path_ramdisk]: ++ # If the child didn't write anything, just get rid of it, ++ # otherwise we end up consuming a 0-size file when parsing ++ # systems without a ramdisk that the ultimate caller of pygrub ++ # may just be unaware of ++ if rc != 0 or os.path.getsize(path) == 0: ++ os.unlink(path) ++ ++ # Normally, unshare(CLONE_NEWNS) will ensure this is not required. ++ # However, this syscall doesn't exist in *BSD systems and doesn't ++ # auto-unmount everything on older Linux kernels (At least as of ++ # Linux 4.19, but it seems fixed in 5.15). Either way, ++ # recursively unmount everything if needed. Quietly. ++ with open('/dev/null', 'w') as devnull: ++ subprocess.call(["umount", "-f", chroot + device_path], ++ stdout=devnull, stderr=devnull) ++ subprocess.call(["umount", "-f", chroot], ++ stdout=devnull, stderr=devnull) ++ os.rmdir(chroot) ++ ++ sys.exit(rc) ++ ++ # By unsharing the namespace we're making sure it's all bulk-released ++ # at the end, when the namespaces disappear. This means the kernel does ++ # (almost) all the cleanup for us and the parent just has to remove the ++ # temporary directory. ++ unshare(CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET) ++ ++ # Set sensible limits using the setrlimit interface ++ downgrade_rlimits() ++ ++ # We'll mount tmpfs on the chroot to ensure the deprivileged child ++ # cannot affect the persistent state. It's RW now in order to ++ # bind-mount the device, but note it's remounted RO after that. ++ rc = subprocess.call(["mount", "-t", "tmpfs", "none", chroot]) ++ if rc != 0: ++ raise RuntimeError("mount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot)) ++ ++ # Bind the untrusted device RO ++ bind_mount(device, chroot + device_path, "ro,nosuid,noexec") ++ ++ rc = subprocess.call(["mount", "-t", "tmpfs", "-o", "remount,ro,nosuid,noexec,nodev", "none", chroot]) ++ if rc != 0: ++ raise RuntimeError("remount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot)) ++ ++ # Drop superpowers! ++ os.chroot(chroot) ++ os.chdir('/') ++ os.setgid(uid) ++ os.setgroups([uid]) ++ os.setuid(uid) ++ ++ return device_path ++ + def read_size_roundup(fd, size): + if platform.system() != 'FreeBSD': + return size +@@ -736,7 +864,7 @@ if __name__ == "__main__": + sel = None + + def usage(): +- print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] " %(sys.argv[0],), file=sys.stderr) ++ print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--runas=] [--offset=] " %(sys.argv[0],), file=sys.stderr) + + def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really): + if not_really: +@@ -760,7 +888,8 @@ if __name__ == "__main__": + os.write(fd_dst, data) + except Exception as e: + print(e, file=sys.stderr) +- os.unlink(path_dst) ++ if path_dst: ++ os.unlink(path_dst) + del datafile + sys.exit("Error writing temporary copy of "+file_type) + dataoff += len(data) +@@ -769,7 +898,7 @@ if __name__ == "__main__": + opts, args = getopt.gnu_getopt(sys.argv[1:], 'qilnh::', + ["quiet", "interactive", "list-entries", "not-really", "help", + "output=", "output-format=", "output-directory=", "offset=", +- "entry=", "kernel=", ++ "runas=", "entry=", "kernel=", + "ramdisk=", "args=", "isconfig", "debug"]) + except getopt.GetoptError: + usage() +@@ -790,6 +919,7 @@ if __name__ == "__main__": + not_really = False + output_format = "sxp" + output_directory = "/var/run/xen/pygrub/" ++ uid = None + + # what was passed in + incfg = { "kernel": None, "ramdisk": None, "args": "" } +@@ -813,6 +943,13 @@ if __name__ == "__main__": + elif o in ("--output",): + if a != "-": + output = a ++ elif o in ("--runas",): ++ try: ++ uid = int(a) ++ except ValueError: ++ print("runas value must be an integer user id") ++ usage() ++ sys.exit(1) + elif o in ("--kernel",): + incfg["kernel"] = a + elif o in ("--ramdisk",): +@@ -849,6 +986,10 @@ if __name__ == "__main__": + if debug: + logging.basicConfig(level=logging.DEBUG) + ++ if interactive and uid: ++ print("In order to use --runas, you must also set --entry or -q", file=sys.stderr) ++ sys.exit(1) ++ + try: + os.makedirs(output_directory, 0o700) + except OSError as e: +@@ -870,6 +1011,9 @@ if __name__ == "__main__": + else: + fd = os.open(output, os.O_WRONLY) + ++ if uid: ++ file = depriv(output_directory, output, file, uid, path_kernel, path_ramdisk) ++ + # debug + if isconfig: + chosencfg = run_grub(file, entry, fs, incfg["args"]) +@@ -925,21 +1069,21 @@ if __name__ == "__main__": + raise RuntimeError("Unable to find partition containing kernel") + + copy_from_image(fs, chosencfg["kernel"], "kernel", +- fd_kernel, path_kernel, not_really) ++ fd_kernel, None if uid else path_kernel, not_really) + bootcfg["kernel"] = path_kernel + + if chosencfg["ramdisk"]: + try: + copy_from_image(fs, chosencfg["ramdisk"], "ramdisk", +- fd_ramdisk, path_ramdisk, not_really) ++ fd_ramdisk, None if uid else path_ramdisk, not_really) + except: +- if not not_really: +- os.unlink(path_kernel) ++ if not uid and not not_really: ++ os.unlink(path_kernel) + raise + bootcfg["ramdisk"] = path_ramdisk + else: + initrd = None +- if not not_really: ++ if not uid and not not_really: + os.unlink(path_ramdisk) + + args = None +-- +2.42.0 + diff --git a/xsa443-4.17-10.patch b/xsa443-4.17-10.patch new file mode 100644 index 0000000..7c91f32 --- /dev/null +++ b/xsa443-4.17-10.patch @@ -0,0 +1,250 @@ +From 698b451473a6d868ca0f60a124fc4f31d81cd7b1 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Mon, 25 Sep 2023 14:30:20 +0200 +Subject: [PATCH 10/11] libxl: add support for running bootloader in restricted + mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Much like the device model depriv mode, add the same kind of support for the +bootloader. Such feature allows passing a UID as a parameter for the +bootloader to run as, together with the bootloader itself taking the necessary +actions to isolate. + +Note that the user to run the bootloader as must have the right permissions to +access the guest disk image (in read mode only), and that the bootloader will +be run in non-interactive mode when restricted. + +If enabled bootloader restrict mode will attempt to re-use the user(s) from the +QEMU depriv implementation if no user is provided on the configuration file or +the environment. See docs/features/qemu-deprivilege.pandoc for more +information about how to setup those users. + +Bootloader restrict mode is not enabled by default as it requires certain +setup to be done first (setup of the user(s) to use in restrict mode). + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Anthony PERARD +--- + docs/man/xl.1.pod.in | 33 +++++++++++ + tools/libs/light/libxl_bootloader.c | 89 ++++++++++++++++++++++++++++- + tools/libs/light/libxl_dm.c | 8 +-- + tools/libs/light/libxl_internal.h | 8 +++ + 4 files changed, 131 insertions(+), 7 deletions(-) + +diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in +index 101e14241d1c..4831e122427d 100644 +--- a/docs/man/xl.1.pod.in ++++ b/docs/man/xl.1.pod.in +@@ -1957,6 +1957,39 @@ ignored: + + =back + ++=head1 ENVIRONMENT VARIABLES ++ ++The following environment variables shall affect the execution of xl: ++ ++=over 4 ++ ++=item LIBXL_BOOTLOADER_RESTRICT ++ ++Attempt to restrict the bootloader after startup, to limit the ++consequences of security vulnerabilities due to parsing guest ++owned image files. ++ ++See docs/features/qemu-deprivilege.pandoc for more information ++on how to setup the unprivileged users. ++ ++Note that running the bootloader in restricted mode also implies using ++non-interactive mode, and the disk image must be readable by the ++restricted user. ++ ++Having this variable set is equivalent to enabling the option, even if the ++value is 0. ++ ++=item LIBXL_BOOTLOADER_USER ++ ++When using bootloader_restrict, run the bootloader as this user. If ++not set the default QEMU restrict users will be used. ++ ++NOTE: Each domain MUST have a SEPARATE username. ++ ++See docs/features/qemu-deprivilege.pandoc for more information. ++ ++=back ++ + =head1 SEE ALSO + + The following man pages: +diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c +index 108329b4a5bb..23c0ef3e8935 100644 +--- a/tools/libs/light/libxl_bootloader.c ++++ b/tools/libs/light/libxl_bootloader.c +@@ -14,6 +14,7 @@ + + #include "libxl_osdeps.h" /* must come before any other headers */ + ++#include + #include + #ifdef HAVE_UTMP_H + #include +@@ -42,8 +43,71 @@ static void bootloader_arg(libxl__bootloader_state *bl, const char *arg) + bl->args[bl->nargs++] = arg; + } + +-static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, +- const char *bootloader_path) ++static int bootloader_uid(libxl__gc *gc, domid_t guest_domid, ++ const char *user, uid_t *intended_uid) ++{ ++ struct passwd *user_base, user_pwbuf; ++ int rc; ++ ++ if (user) { ++ rc = userlookup_helper_getpwnam(gc, user, &user_pwbuf, &user_base); ++ if (rc) return rc; ++ ++ if (!user_base) { ++ LOGD(ERROR, guest_domid, "Couldn't find user %s", user); ++ return ERROR_INVAL; ++ } ++ ++ *intended_uid = user_base->pw_uid; ++ return 0; ++ } ++ ++ /* Re-use QEMU user range for the bootloader. */ ++ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_RANGE_BASE, ++ &user_pwbuf, &user_base); ++ if (rc) return rc; ++ ++ if (user_base) { ++ struct passwd *user_clash, user_clash_pwbuf; ++ uid_t temp_uid = user_base->pw_uid + guest_domid; ++ ++ rc = userlookup_helper_getpwuid(gc, temp_uid, &user_clash_pwbuf, ++ &user_clash); ++ if (rc) return rc; ++ ++ if (user_clash) { ++ LOGD(ERROR, guest_domid, ++ "wanted to use uid %ld (%s + %d) but that is user %s !", ++ (long)temp_uid, LIBXL_QEMU_USER_RANGE_BASE, ++ guest_domid, user_clash->pw_name); ++ return ERROR_INVAL; ++ } ++ ++ *intended_uid = temp_uid; ++ return 0; ++ } ++ ++ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_SHARED, &user_pwbuf, ++ &user_base); ++ if (rc) return rc; ++ ++ if (user_base) { ++ LOGD(WARN, guest_domid, "Could not find user %s, falling back to %s", ++ LIBXL_QEMU_USER_RANGE_BASE, LIBXL_QEMU_USER_SHARED); ++ *intended_uid = user_base->pw_uid; ++ ++ return 0; ++ } ++ ++ LOGD(ERROR, guest_domid, ++ "Could not find user %s or range base pseudo-user %s, cannot restrict", ++ LIBXL_QEMU_USER_SHARED, LIBXL_QEMU_USER_RANGE_BASE); ++ ++ return ERROR_INVAL; ++} ++ ++static int make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, ++ const char *bootloader_path) + { + const libxl_domain_build_info *info = bl->info; + +@@ -61,6 +125,23 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, + ARG(GCSPRINTF("--ramdisk=%s", info->ramdisk)); + if (info->cmdline && *info->cmdline != '\0') + ARG(GCSPRINTF("--args=%s", info->cmdline)); ++ if (getenv("LIBXL_BOOTLOADER_RESTRICT") || ++ getenv("LIBXL_BOOTLOADER_USER")) { ++ uid_t uid = -1; ++ int rc = bootloader_uid(gc, bl->domid, getenv("LIBXL_BOOTLOADER_USER"), ++ &uid); ++ ++ if (rc) return rc; ++ ++ assert(uid != -1); ++ if (!uid) { ++ LOGD(ERROR, bl->domid, "bootloader restrict UID is 0 (root)!"); ++ return ERROR_INVAL; ++ } ++ LOGD(DEBUG, bl->domid, "using uid %ld", (long)uid); ++ ARG(GCSPRINTF("--runas=%ld", (long)uid)); ++ ARG("--quiet"); ++ } + + ARG(GCSPRINTF("--output=%s", bl->outputpath)); + ARG("--output-format=simple0"); +@@ -79,6 +160,7 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, + /* Sentinel for execv */ + ARG(NULL); + ++ return 0; + #undef ARG + } + +@@ -443,7 +525,8 @@ static void bootloader_disk_attached_cb(libxl__egc *egc, + bootloader = bltmp; + } + +- make_bootloader_args(gc, bl, bootloader); ++ rc = make_bootloader_args(gc, bl, bootloader); ++ if (rc) goto out; + + bl->openpty.ao = ao; + bl->openpty.callback = bootloader_gotptys; +diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c +index fc264a3a13a6..14b593110f7c 100644 +--- a/tools/libs/light/libxl_dm.c ++++ b/tools/libs/light/libxl_dm.c +@@ -80,10 +80,10 @@ static int libxl__create_qemu_logfile(libxl__gc *gc, char *name) + * On error, return a libxl-style error code. + */ + #define DEFINE_USERLOOKUP_HELPER(NAME,SPEC_TYPE,STRUCTNAME,SYSCONF) \ +- static int userlookup_helper_##NAME(libxl__gc *gc, \ +- SPEC_TYPE spec, \ +- struct STRUCTNAME *resultbuf, \ +- struct STRUCTNAME **out) \ ++ int userlookup_helper_##NAME(libxl__gc *gc, \ ++ SPEC_TYPE spec, \ ++ struct STRUCTNAME *resultbuf, \ ++ struct STRUCTNAME **out) \ + { \ + struct STRUCTNAME *resultp = NULL; \ + char *buf = NULL; \ +diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h +index 7ad38de30e0b..f1e3a9a15b13 100644 +--- a/tools/libs/light/libxl_internal.h ++++ b/tools/libs/light/libxl_internal.h +@@ -4873,6 +4873,14 @@ struct libxl__cpu_policy { + struct xc_msr *msr; + }; + ++struct passwd; ++_hidden int userlookup_helper_getpwnam(libxl__gc*, const char *user, ++ struct passwd *res, ++ struct passwd **out); ++_hidden int userlookup_helper_getpwuid(libxl__gc*, uid_t uid, ++ struct passwd *res, ++ struct passwd **out); ++ + #endif + + /* +-- +2.42.0 + diff --git a/xsa443-4.17-11.patch b/xsa443-4.17-11.patch new file mode 100644 index 0000000..27e6f78 --- /dev/null +++ b/xsa443-4.17-11.patch @@ -0,0 +1,157 @@ +From 9d480426bfa2c68843ac8395b512e06fbdbcf53e Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Thu, 28 Sep 2023 12:22:35 +0200 +Subject: [PATCH 11/11] libxl: limit bootloader execution in restricted mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a timeout for bootloader execution when running in restricted mode. + +Allow overwriting the default time out with an environment provided value. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Anthony PERARD +--- + docs/man/xl.1.pod.in | 8 ++++++ + tools/libs/light/libxl_bootloader.c | 40 +++++++++++++++++++++++++++++ + tools/libs/light/libxl_internal.h | 2 ++ + 3 files changed, 50 insertions(+) + +diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in +index 4831e122427d..c3eb6570ab8b 100644 +--- a/docs/man/xl.1.pod.in ++++ b/docs/man/xl.1.pod.in +@@ -1988,6 +1988,14 @@ NOTE: Each domain MUST have a SEPARATE username. + + See docs/features/qemu-deprivilege.pandoc for more information. + ++=item LIBXL_BOOTLOADER_TIMEOUT ++ ++Timeout in seconds for bootloader execution when running in restricted mode. ++Otherwise the build time default in LIBXL_BOOTLOADER_TIMEOUT will be used. ++ ++If defined the value must be an unsigned integer between 0 and INT_MAX, ++otherwise behavior is undefined. Setting to 0 disables the timeout. ++ + =back + + =head1 SEE ALSO +diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c +index 23c0ef3e8935..ee26d08f3765 100644 +--- a/tools/libs/light/libxl_bootloader.c ++++ b/tools/libs/light/libxl_bootloader.c +@@ -30,6 +30,8 @@ static void bootloader_keystrokes_copyfail(libxl__egc *egc, + libxl__datacopier_state *dc, int rc, int onwrite, int errnoval); + static void bootloader_display_copyfail(libxl__egc *egc, + libxl__datacopier_state *dc, int rc, int onwrite, int errnoval); ++static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev, ++ const struct timeval *requested_abs, int rc); + static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc, + int rc); + static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child, +@@ -297,6 +299,7 @@ void libxl__bootloader_init(libxl__bootloader_state *bl) + bl->ptys[0].master = bl->ptys[0].slave = 0; + bl->ptys[1].master = bl->ptys[1].slave = 0; + libxl__ev_child_init(&bl->child); ++ libxl__ev_time_init(&bl->time); + libxl__domaindeathcheck_init(&bl->deathcheck); + bl->keystrokes.ao = bl->ao; libxl__datacopier_init(&bl->keystrokes); + bl->display.ao = bl->ao; libxl__datacopier_init(&bl->display); +@@ -314,6 +317,7 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl) + libxl__domaindeathcheck_stop(gc,&bl->deathcheck); + libxl__datacopier_kill(&bl->keystrokes); + libxl__datacopier_kill(&bl->display); ++ libxl__ev_time_deregister(gc, &bl->time); + for (i=0; i<2; i++) { + libxl__carefd_close(bl->ptys[i].master); + libxl__carefd_close(bl->ptys[i].slave); +@@ -375,6 +379,7 @@ static void bootloader_stop(libxl__egc *egc, + + libxl__datacopier_kill(&bl->keystrokes); + libxl__datacopier_kill(&bl->display); ++ libxl__ev_time_deregister(gc, &bl->time); + if (libxl__ev_child_inuse(&bl->child)) { + r = kill(bl->child.pid, SIGTERM); + if (r) LOGED(WARN, bl->domid, "%sfailed to kill bootloader [%lu]", +@@ -637,6 +642,25 @@ static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op) + + struct termios termattr; + ++ if (getenv("LIBXL_BOOTLOADER_RESTRICT") || ++ getenv("LIBXL_BOOTLOADER_USER")) { ++ const char *timeout_env = getenv("LIBXL_BOOTLOADER_TIMEOUT"); ++ int timeout = timeout_env ? atoi(timeout_env) ++ : LIBXL_BOOTLOADER_TIMEOUT; ++ ++ if (timeout) { ++ /* Set execution timeout */ ++ rc = libxl__ev_time_register_rel(ao, &bl->time, ++ bootloader_timeout, ++ timeout * 1000); ++ if (rc) { ++ LOGED(ERROR, bl->domid, ++ "unable to register timeout for bootloader execution"); ++ goto out; ++ } ++ } ++ } ++ + pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished); + if (pid == -1) { + rc = ERROR_FAIL; +@@ -702,6 +726,21 @@ static void bootloader_display_copyfail(libxl__egc *egc, + libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, display); + bootloader_copyfail(egc, "bootloader output", bl, 1, rc,onwrite,errnoval); + } ++static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev, ++ const struct timeval *requested_abs, int rc) ++{ ++ libxl__bootloader_state *bl = CONTAINER_OF(ev, *bl, time); ++ STATE_AO_GC(bl->ao); ++ ++ libxl__ev_time_deregister(gc, &bl->time); ++ ++ assert(libxl__ev_child_inuse(&bl->child)); ++ LOGD(ERROR, bl->domid, "killing bootloader because of timeout"); ++ ++ libxl__ev_child_kill_deregister(ao, &bl->child, SIGKILL); ++ ++ bootloader_callback(egc, bl, rc); ++} + + static void bootloader_domaindeath(libxl__egc *egc, + libxl__domaindeathcheck *dc, +@@ -718,6 +757,7 @@ static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child, + STATE_AO_GC(bl->ao); + int rc; + ++ libxl__ev_time_deregister(gc, &bl->time); + libxl__datacopier_kill(&bl->keystrokes); + libxl__datacopier_kill(&bl->display); + +diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h +index f1e3a9a15b13..d05783617ff5 100644 +--- a/tools/libs/light/libxl_internal.h ++++ b/tools/libs/light/libxl_internal.h +@@ -102,6 +102,7 @@ + #define LIBXL_QMP_CMD_TIMEOUT 10 + #define LIBXL_STUBDOM_START_TIMEOUT 30 + #define LIBXL_QEMU_BODGE_TIMEOUT 2 ++#define LIBXL_BOOTLOADER_TIMEOUT 120 + #define LIBXL_XENCONSOLE_LIMIT 1048576 + #define LIBXL_XENCONSOLE_PROTOCOL "vt100" + #define LIBXL_MAXMEM_CONSTANT 1024 +@@ -3744,6 +3745,7 @@ struct libxl__bootloader_state { + libxl__openpty_state openpty; + libxl__openpty_result ptys[2]; /* [0] is for bootloader */ + libxl__ev_child child; ++ libxl__ev_time time; + libxl__domaindeathcheck deathcheck; + int nargs, argsspace; + const char **args; +-- +2.42.0 + diff --git a/xsa444-4.17-1.patch b/xsa444-4.17-1.patch new file mode 100644 index 0000000..5a4b2e5 --- /dev/null +++ b/xsa444-4.17-1.patch @@ -0,0 +1,93 @@ +From: Andrew Cooper +Subject: x86/svm: Fix asymmetry with AMD DR MASK context switching + +The handling of MSR_DR{0..3}_MASK is asymmetric between PV and HVM guests. + +HVM guests context switch in based on the guest view of DBEXT, whereas PV +guest switch in base on the host capability. Both guest types leave the +context dirty for the next vCPU. + +This leads to the following issue: + + * PV or HVM guest has debugging active (%dr7 + mask) + * Switch-out deactivates %dr7 but leaves other state stale in hardware + * Another HVM guest with masks unavailable has debugging active + * Switch in loads %dr7 but leaves the mask MSRs alone + +Now, the second guest's vCPU is operating in the context of the prior vCPU's +mask MSR, while the environment the vCPU can see says there are no mask MSRs. + +As a stopgap, adjust the HVM path to switch in the masks based on host +capabilities rather than guest visibility (i.e. like the PV path). Adjustment +of the intercepts still needs to be dependent on the guest visibility of +DBEXT. + +This is part of XSA-444 / CVE-2023-34327 + +Fixes: c097f54912d3 ("x86/SVM: support data breakpoint extension registers") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c +index e8f50e7c5ec7..fd32600ae364 100644 +--- a/xen/arch/x86/hvm/svm/svm.c ++++ b/xen/arch/x86/hvm/svm/svm.c +@@ -339,6 +339,10 @@ static void svm_save_dr(struct vcpu *v) + v->arch.hvm.flag_dr_dirty = 0; + vmcb_set_dr_intercepts(vmcb, ~0u); + ++ /* ++ * The guest can only have changed the mask MSRs if we previous dropped ++ * intercepts. Re-read them from hardware. ++ */ + if ( v->domain->arch.cpuid->extd.dbext ) + { + svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_RW); +@@ -370,17 +374,25 @@ static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v) + + ASSERT(v == current); + +- if ( v->domain->arch.cpuid->extd.dbext ) ++ /* ++ * Both the PV and HVM paths leave stale DR_MASK values in hardware on ++ * context-switch-out. If we're activating %dr7 for the guest, we must ++ * sync the DR_MASKs too, whether or not the guest can see them. ++ */ ++ if ( boot_cpu_has(X86_FEATURE_DBEXT) ) + { +- svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- + wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, v->arch.msrs->dr_mask[0]); + wrmsrl(MSR_AMD64_DR1_ADDRESS_MASK, v->arch.msrs->dr_mask[1]); + wrmsrl(MSR_AMD64_DR2_ADDRESS_MASK, v->arch.msrs->dr_mask[2]); + wrmsrl(MSR_AMD64_DR3_ADDRESS_MASK, v->arch.msrs->dr_mask[3]); ++ ++ if ( v->domain->arch.cpuid->extd.dbext ) ++ { ++ svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ } + } + + write_debugreg(0, v->arch.dr[0]); +diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c +index e65cc6004148..06c4f3868b7a 100644 +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -2281,6 +2281,11 @@ void activate_debugregs(const struct vcpu *curr) + if ( curr->arch.dr7 & DR7_ACTIVE_MASK ) + write_debugreg(7, curr->arch.dr7); + ++ /* ++ * Both the PV and HVM paths leave stale DR_MASK values in hardware on ++ * context-switch-out. If we're activating %dr7 for the guest, we must ++ * sync the DR_MASKs too, whether or not the guest can see them. ++ */ + if ( boot_cpu_has(X86_FEATURE_DBEXT) ) + { + wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, curr->arch.msrs->dr_mask[0]); diff --git a/xsa444-4.17-2.patch b/xsa444-4.17-2.patch new file mode 100644 index 0000000..2687bd1 --- /dev/null +++ b/xsa444-4.17-2.patch @@ -0,0 +1,72 @@ +From: Andrew Cooper +Subject: x86/pv: Correct the auditing of guest breakpoint addresses + +The use of access_ok() is buggy, because it permits access to the compat +translation area. 64bit PV guests don't use the XLAT area, but on AMD +hardware, the DBEXT feature allows a breakpoint to match up to a 4G aligned +region, allowing the breakpoint to reach outside of the XLAT area. + +Prior to c/s cda16c1bb223 ("x86: mirror compat argument translation area for +32-bit PV"), the live GDT was within 4G of the XLAT area. + +All together, this allowed a malicious 64bit PV guest on AMD hardware to place +a breakpoint over the live GDT, and trigger a #DB livelock (CVE-2015-8104). + +Introduce breakpoint_addr_ok() and explain why __addr_ok() happens to be an +appropriate check in this case. + +For Xen 4.14 and later, this is a latent bug because the XLAT area has moved +to be on its own with nothing interesting adjacent. For Xen 4.13 and older on +AMD hardware, this fixes a PV-trigger-able DoS. + +This is part of XSA-444 / CVE-2023-34328. + +Fixes: 65e355490817 ("x86/PV: support data breakpoint extension registers") +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/include/asm/debugreg.h b/xen/arch/x86/include/asm/debugreg.h +index c57914efc6e8..cc298265244b 100644 +--- a/xen/arch/x86/include/asm/debugreg.h ++++ b/xen/arch/x86/include/asm/debugreg.h +@@ -77,6 +77,26 @@ + asm volatile ( "mov %%db" #reg ",%0" : "=r" (__val) ); \ + __val; \ + }) ++ ++/* ++ * Architecturally, %dr{0..3} can have any arbitrary value. However, Xen ++ * can't allow the guest to breakpoint the Xen address range, so we limit the ++ * guest to the lower canonical half, or above the Xen range in the higher ++ * canonical half. ++ * ++ * Breakpoint lengths are specified to mask the low order address bits, ++ * meaning all breakpoints are naturally aligned. With %dr7, the widest ++ * breakpoint is 8 bytes. With DBEXT, the widest breakpoint is 4G. Both of ++ * the Xen boundaries have >4G alignment. ++ * ++ * In principle we should account for HYPERVISOR_COMPAT_VIRT_START(d), but ++ * 64bit Xen has never enforced this for compat guests, and there's no problem ++ * (to Xen) if the guest breakpoints it's alias of the M2P. Skipping this ++ * aspect simplifies the logic, and causes us not to reject a migrating guest ++ * which operated fine on prior versions of Xen. ++ */ ++#define breakpoint_addr_ok(a) __addr_ok(a) ++ + long set_debugreg(struct vcpu *, unsigned int reg, unsigned long value); + void activate_debugregs(const struct vcpu *); + +diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c +index aaaf70eb6330..f8636de907ae 100644 +--- a/xen/arch/x86/pv/misc-hypercalls.c ++++ b/xen/arch/x86/pv/misc-hypercalls.c +@@ -72,7 +72,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) + switch ( reg ) + { + case 0 ... 3: +- if ( !access_ok(value, sizeof(long)) ) ++ if ( !breakpoint_addr_ok(value) ) + return -EPERM; + + v->arch.dr[reg] = value; From 8b84ab579c25078db4fb4dc765d0f6489223fb59 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 11 Oct 2023 19:47:00 +0100 Subject: [PATCH 38/99] 4 security issues xenstored: A transaction conflict can crash C Xenstored [XSA-440, CVE-2023-34323] x86/AMD: missing IOMMU TLB flushing [XSA-442, CVE-2023-34326] Multiple vulnerabilities in libfsimage disk handling [XSA-443, CVE-2023-34325] x86/AMD: Debug Mask handling [XSA-444, CVE-2023-34327, CVE-2023-34328] --- xen.spec | 41 +++++- xsa440-4.17.patch | 58 ++++++++ xsa442-4.17.patch | 185 ++++++++++++++++++++++++++ xsa443-4.16-01.patch | 70 ++++++++++ xsa443-4.16-02.patch | 32 +++++ xsa443-4.16-03.patch | 137 +++++++++++++++++++ xsa443-4.16-04.patch | 60 +++++++++ xsa443-4.16-05.patch | 59 +++++++++ xsa443-4.16-06.patch | 65 +++++++++ xsa443-4.16-07.patch | 105 +++++++++++++++ xsa443-4.16-08.patch | 126 ++++++++++++++++++ xsa443-4.16-09.patch | 307 +++++++++++++++++++++++++++++++++++++++++++ xsa443-4.16-10.patch | 250 +++++++++++++++++++++++++++++++++++ xsa443-4.16-11.patch | 157 ++++++++++++++++++++++ xsa444-4.16-1.patch | 93 +++++++++++++ xsa444-4.16-2.patch | 72 ++++++++++ 16 files changed, 1816 insertions(+), 1 deletion(-) create mode 100644 xsa440-4.17.patch create mode 100644 xsa442-4.17.patch create mode 100644 xsa443-4.16-01.patch create mode 100644 xsa443-4.16-02.patch create mode 100644 xsa443-4.16-03.patch create mode 100644 xsa443-4.16-04.patch create mode 100644 xsa443-4.16-05.patch create mode 100644 xsa443-4.16-06.patch create mode 100644 xsa443-4.16-07.patch create mode 100644 xsa443-4.16-08.patch create mode 100644 xsa443-4.16-09.patch create mode 100644 xsa443-4.16-10.patch create mode 100644 xsa443-4.16-11.patch create mode 100644 xsa444-4.16-1.patch create mode 100644 xsa444-4.16-2.patch diff --git a/xen.spec b/xen.spec index 7c731d8..ee3bae8 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.5 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -123,6 +123,21 @@ Patch55: xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch Patch56: xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch Patch57: xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch Patch58: xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch +Patch59: xsa440-4.17.patch +Patch60: xsa442-4.17.patch +Patch61: xsa443-4.16-01.patch +Patch62: xsa443-4.16-02.patch +Patch63: xsa443-4.16-03.patch +Patch64: xsa443-4.16-04.patch +Patch65: xsa443-4.16-05.patch +Patch66: xsa443-4.16-06.patch +Patch67: xsa443-4.16-07.patch +Patch68: xsa443-4.16-08.patch +Patch69: xsa443-4.16-09.patch +Patch70: xsa443-4.16-10.patch +Patch71: xsa443-4.16-11.patch +Patch72: xsa444-4.16-1.patch +Patch73: xsa444-4.16-2.patch %if %build_qemutrad @@ -347,6 +362,21 @@ manage Xen virtual machines. %patch56 -p1 %patch57 -p1 %patch58 -p1 +%patch59 -p1 +%patch60 -p1 +%patch61 -p1 +%patch62 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 +%patch68 -p1 +%patch69 -p1 +%patch70 -p1 +%patch71 -p1 +%patch72 -p1 +%patch73 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -955,6 +985,15 @@ fi %endif %changelog +* Wed Oct 11 2023 Michael Young - 4.16.5-3 +- xenstored: A transaction conflict can crash C Xenstored [XSA-440, + CVE-2023-34323] +- x86/AMD: missing IOMMU TLB flushing [XSA-442, CVE-2023-34326] +- Multiple vulnerabilities in libfsimage disk handling [XSA-443, + CVE-2023-34325] +- x86/AMD: Debug Mask handling [XSA-444, CVE-2023-34327, + CVE-2023-34328] + * Tue Sep 26 2023 Michael Young - 4.16.5-2 - arm32: The cache may not be properly cleaned/invalidated [XSA-437, CVE-2023-34321] diff --git a/xsa440-4.17.patch b/xsa440-4.17.patch new file mode 100644 index 0000000..4941afc --- /dev/null +++ b/xsa440-4.17.patch @@ -0,0 +1,58 @@ +From 5d8b3d1ec98e56155d9650d7f4a70cd8ba9dc27d Mon Sep 17 00:00:00 2001 +From: Julien Grall +Date: Fri, 22 Sep 2023 11:32:16 +0100 +Subject: tools/xenstored: domain_entry_fix(): Handle conflicting transaction + +The function domain_entry_fix() will be initially called to check if the +quota is correct before attempt to commit any nodes. So it would be +possible that accounting is temporarily negative. This is the case +in the following sequence: + + 1) Create 50 nodes + 2) Start two transactions + 3) Delete all the nodes in each transaction + 4) Commit the two transactions + +Because the first transaction will have succeed and updated the +accounting, there is no guarantee that 'd->nbentry + num' will still +be above 0. So the assert() would be triggered. +The assert() was introduced in dbef1f748289 ("tools/xenstore: simplify +and fix per domain node accounting") with the assumption that the +value can't be negative. As this is not true revert to the original +check but restricted to the path where we don't update. Take the +opportunity to explain the rationale behind the check. + +This CVE-2023-34323 / XSA-440. + +Reported-by: Stanislav Uschakow +Fixes: dbef1f748289 ("tools/xenstore: simplify and fix per domain node accounting") +Signed-off-by: Julien Grall +Reviewed-by: Juergen Gross + +diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c +index aa86892fed9e..6074df210c6e 100644 +--- a/tools/xenstore/xenstored_domain.c ++++ b/tools/xenstore/xenstored_domain.c +@@ -1094,10 +1094,20 @@ int domain_entry_fix(unsigned int domid, int num, bool update) + } + + cnt = d->nbentry + num; +- assert(cnt >= 0); + +- if (update) ++ if (update) { ++ assert(cnt >= 0); + d->nbentry = cnt; ++ } else if (cnt < 0) { ++ /* ++ * In a transaction when a node is being added/removed AND ++ * the same node has been added/removed outside the ++ * transaction in parallel, the result value may be negative. ++ * This is no problem, as the transaction will fail due to ++ * the resulting conflict. So override 'cnt'. ++ */ ++ cnt = 0; ++ } + + return domid_is_unprivileged(domid) ? cnt : 0; + } diff --git a/xsa442-4.17.patch b/xsa442-4.17.patch new file mode 100644 index 0000000..a78bfdd --- /dev/null +++ b/xsa442-4.17.patch @@ -0,0 +1,185 @@ +From 5b2ccb60ff22fbff44dd66214c2956a434ee6271 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Tue, 13 Jun 2023 15:01:05 +0200 +Subject: [PATCH] iommu/amd-vi: flush IOMMU TLB when flushing the DTE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The caching invalidation guidelines from the AMD-Vi specification (48882—Rev +3.07-PUB—Oct 2022) seem to be misleading on some hardware, as devices will +malfunction (see stale DMA mappings) if some fields of the DTE are updated but +the IOMMU TLB is not flushed. This has been observed in practice on AMD +systems. Due to the lack of guidance from the currently published +specification this patch aims to increase the flushing done in order to prevent +device malfunction. + +In order to fix, issue an INVALIDATE_IOMMU_PAGES command from +amd_iommu_flush_device(), flushing all the address space. Note this requires +callers to be adjusted in order to pass the DomID on the DTE previous to the +modification. + +Some call sites don't provide a valid DomID to amd_iommu_flush_device() in +order to avoid the flush. That's because the device had address translations +disabled and hence the previous DomID on the DTE is not valid. Note the +current logic relies on the entity disabling address translations to also flush +the TLB of the in use DomID. + +Device I/O TLB flushing when ATS are enabled is not covered by the current +change, as ATS usage is not security supported. + +This is XSA-442 / CVE-2023-34326 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/drivers/passthrough/amd/iommu.h | 3 ++- + xen/drivers/passthrough/amd/iommu_cmd.c | 10 +++++++++- + xen/drivers/passthrough/amd/iommu_guest.c | 5 +++-- + xen/drivers/passthrough/amd/iommu_init.c | 6 +++++- + xen/drivers/passthrough/amd/pci_amd_iommu.c | 14 ++++++++++---- + 5 files changed, 29 insertions(+), 9 deletions(-) + +diff --git a/xen/drivers/passthrough/amd/iommu.h b/xen/drivers/passthrough/amd/iommu.h +index 5429ada58ef5..a58be28bf96d 100644 +--- a/xen/drivers/passthrough/amd/iommu.h ++++ b/xen/drivers/passthrough/amd/iommu.h +@@ -283,7 +283,8 @@ void amd_iommu_flush_pages(struct domain *d, unsigned long dfn, + unsigned int order); + void amd_iommu_flush_iotlb(u8 devfn, const struct pci_dev *pdev, + uint64_t gaddr, unsigned int order); +-void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf); ++void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf, ++ domid_t domid); + void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf); + void amd_iommu_flush_all_caches(struct amd_iommu *iommu); + +diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c b/xen/drivers/passthrough/amd/iommu_cmd.c +index 40ddf366bb4d..cb28b36abc38 100644 +--- a/xen/drivers/passthrough/amd/iommu_cmd.c ++++ b/xen/drivers/passthrough/amd/iommu_cmd.c +@@ -363,10 +363,18 @@ void amd_iommu_flush_pages(struct domain *d, + _amd_iommu_flush_pages(d, __dfn_to_daddr(dfn), order); + } + +-void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf) ++void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf, ++ domid_t domid) + { + invalidate_dev_table_entry(iommu, bdf); + flush_command_buffer(iommu, 0); ++ ++ /* Also invalidate IOMMU TLB entries when flushing the DTE. */ ++ if ( domid != DOMID_INVALID ) ++ { ++ invalidate_iommu_pages(iommu, INV_IOMMU_ALL_PAGES_ADDRESS, domid, 0); ++ flush_command_buffer(iommu, 0); ++ } + } + + void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf) +diff --git a/xen/drivers/passthrough/amd/iommu_guest.c b/xen/drivers/passthrough/amd/iommu_guest.c +index 80a331f546ed..be86bce6fb03 100644 +--- a/xen/drivers/passthrough/amd/iommu_guest.c ++++ b/xen/drivers/passthrough/amd/iommu_guest.c +@@ -385,7 +385,7 @@ static int do_completion_wait(struct domain *d, cmd_entry_t *cmd) + + static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd) + { +- uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id; ++ uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id, prev_domid; + struct amd_iommu_dte *gdte, *mdte, *dte_base; + struct amd_iommu *iommu = NULL; + struct guest_iommu *g_iommu; +@@ -445,13 +445,14 @@ static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd) + req_id = get_dma_requestor_id(iommu->seg, mbdf); + dte_base = iommu->dev_table.buffer; + mdte = &dte_base[req_id]; ++ prev_domid = mdte->domain_id; + + spin_lock_irqsave(&iommu->lock, flags); + dte_set_gcr3_table(mdte, hdom_id, gcr3_mfn << PAGE_SHIFT, gv, glx); + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ amd_iommu_flush_device(iommu, req_id, prev_domid); + + return 0; + } +diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c +index 166570648d26..101a60ce1794 100644 +--- a/xen/drivers/passthrough/amd/iommu_init.c ++++ b/xen/drivers/passthrough/amd/iommu_init.c +@@ -1547,7 +1547,11 @@ static int cf_check _invalidate_all_devices( + req_id = ivrs_mappings[bdf].dte_requestor_id; + if ( iommu ) + { +- amd_iommu_flush_device(iommu, req_id); ++ /* ++ * IOMMU TLB flush performed separately (see ++ * invalidate_all_domain_pages()). ++ */ ++ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID); + amd_iommu_flush_intremap(iommu, req_id); + } + } +diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c +index 94e37755064b..8641b84712a0 100644 +--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c ++++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c +@@ -192,10 +192,13 @@ static int __must_check amd_iommu_setup_domain_device( + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ /* DTE didn't have DMA translations enabled, do not flush the TLB. */ ++ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID); + } + else if ( dte->pt_root != mfn_x(page_to_mfn(root_pg)) ) + { ++ domid_t prev_domid = dte->domain_id; ++ + /* + * Strictly speaking if the device is the only one with this requestor + * ID, it could be allowed to be re-assigned regardless of unity map +@@ -252,7 +255,7 @@ static int __must_check amd_iommu_setup_domain_device( + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ amd_iommu_flush_device(iommu, req_id, prev_domid); + } + else + spin_unlock_irqrestore(&iommu->lock, flags); +@@ -421,6 +424,8 @@ static void amd_iommu_disable_domain_device(const struct domain *domain, + spin_lock_irqsave(&iommu->lock, flags); + if ( dte->tv || dte->v ) + { ++ domid_t prev_domid = dte->domain_id; ++ + /* See the comment in amd_iommu_setup_device_table(). */ + dte->int_ctl = IOMMU_DEV_TABLE_INT_CONTROL_ABORTED; + smp_wmb(); +@@ -439,7 +444,7 @@ static void amd_iommu_disable_domain_device(const struct domain *domain, + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, req_id); ++ amd_iommu_flush_device(iommu, req_id, prev_domid); + + AMD_IOMMU_DEBUG("Disable: device id = %#x, " + "domain = %d, paging mode = %d\n", +@@ -610,7 +615,8 @@ static int cf_check amd_iommu_add_device(u8 devfn, struct pci_dev *pdev) + + spin_unlock_irqrestore(&iommu->lock, flags); + +- amd_iommu_flush_device(iommu, bdf); ++ /* DTE didn't have DMA translations enabled, do not flush the TLB. */ ++ amd_iommu_flush_device(iommu, bdf, DOMID_INVALID); + } + + if ( amd_iommu_reserve_domain_unity_map( +-- +2.42.0 + diff --git a/xsa443-4.16-01.patch b/xsa443-4.16-01.patch new file mode 100644 index 0000000..48370d3 --- /dev/null +++ b/xsa443-4.16-01.patch @@ -0,0 +1,70 @@ +From c4d597f63832a53bbb1b826af7a4677e40e9fded Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:50 +0100 +Subject: [PATCH 01/11] libfsimage/xfs: Remove dead code + +xfs_info.agnolog (and related code) and XFS_INO_AGBNO_BITS are dead code +that serve no purpose. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Reviewed-by: Jan Beulich +--- + tools/libfsimage/xfs/fsys_xfs.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index d735a88e55f3..2800699f5985 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -37,7 +37,6 @@ struct xfs_info { + int blklog; + int inopblog; + int agblklog; +- int agnolog; + unsigned int nextents; + xfs_daddr_t next; + xfs_daddr_t daddr; +@@ -65,9 +64,7 @@ static struct xfs_info xfs; + + #define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1)) + #define XFS_INO_OFFSET_BITS xfs.inopblog +-#define XFS_INO_AGBNO_BITS xfs.agblklog + #define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog) +-#define XFS_INO_AGNO_BITS xfs.agnolog + + static inline xfs_agblock_t + agino2agbno (xfs_agino_t agino) +@@ -149,20 +146,6 @@ xt_len (xfs_bmbt_rec_32_t *r) + return le32(r->l3) & mask32lo(21); + } + +-static inline int +-xfs_highbit32(xfs_uint32_t v) +-{ +- int i; +- +- if (--v) { +- for (i = 0; i < 31; i++, v >>= 1) { +- if (v == 0) +- return i; +- } +- } +- return 0; +-} +- + static int + isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len) + { +@@ -472,7 +455,6 @@ xfs_mount (fsi_file_t *ffi, const char *options) + + xfs.inopblog = super.sb_inopblog; + xfs.agblklog = super.sb_agblklog; +- xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount)); + + xfs.btnode_ptr0_off = + ((xfs.bsize - sizeof(xfs_btree_block_t)) / +-- +2.42.0 + diff --git a/xsa443-4.16-02.patch b/xsa443-4.16-02.patch new file mode 100644 index 0000000..2acc03f --- /dev/null +++ b/xsa443-4.16-02.patch @@ -0,0 +1,32 @@ +From f75b0a70da392672fb7d9feed2a9e9515d74df2c Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:51 +0100 +Subject: [PATCH 02/11] libfsimage/xfs: Amend mask32lo() to allow the value 32 + +agblklog could plausibly be 32, but that would overflow this shift. +Perform the shift as ULL and cast to u32 at the end instead. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Jan Beulich +--- + tools/libfsimage/xfs/fsys_xfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index 2800699f5985..4720bb4505c8 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -60,7 +60,7 @@ static struct xfs_info xfs; + #define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192)) + #define icore (inode->di_core) + +-#define mask32lo(n) (((xfs_uint32_t)1 << (n)) - 1) ++#define mask32lo(n) ((xfs_uint32_t)((1ull << (n)) - 1)) + + #define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1)) + #define XFS_INO_OFFSET_BITS xfs.inopblog +-- +2.42.0 + diff --git a/xsa443-4.16-03.patch b/xsa443-4.16-03.patch new file mode 100644 index 0000000..b0ad1fb --- /dev/null +++ b/xsa443-4.16-03.patch @@ -0,0 +1,137 @@ +From 25fae23b32ee4d990ae11368ee21e28e66dbfa25 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:52 +0100 +Subject: [PATCH 03/11] libfsimage/xfs: Sanity-check the superblock during + mounts + +Sanity-check the XFS superblock for wellformedness at the mount handler. +This forces pygrub to abort parsing a potentially malformed filesystem and +ensures the invariants assumed throughout the rest of the code hold. + +Also, derive parameters from previously sanitized parameters where possible +(rather than reading them off the superblock) + +The code doesn't try to avoid overflowing the end of the disk, because +that's an unlikely and benign error. Parameters used in calculations of +xfs_daddr_t (like the root inode index) aren't in critical need of being +sanitized. + +The sanitization of agblklog is basically checking that no obvious +overflows happen on agblklog, and then ensuring agblocks is contained in +the range (2^(sb_agblklog-1), 2^sb_agblklog]. + +This is part of XSA-443 / CVE-2023-34325 + +Reported-by: Ferdinand Nölscher +Signed-off-by: Alejandro Vallejo +Reviewed-by: Jan Beulich +--- + tools/libfsimage/xfs/fsys_xfs.c | 48 ++++++++++++++++++++++++++------- + tools/libfsimage/xfs/xfs.h | 12 +++++++++ + 2 files changed, 50 insertions(+), 10 deletions(-) + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index 4720bb4505c8..e4eb7e1ee26f 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -17,6 +17,7 @@ + * along with this program; If not, see . + */ + ++#include + #include + #include "xfs.h" + +@@ -433,29 +434,56 @@ first_dentry (fsi_file_t *ffi, xfs_ino_t *ino) + return next_dentry (ffi, ino); + } + ++static bool ++xfs_sb_is_invalid (const xfs_sb_t *super) ++{ ++ return (le32(super->sb_magicnum) != XFS_SB_MAGIC) ++ || ((le16(super->sb_versionnum) & XFS_SB_VERSION_NUMBITS) != ++ XFS_SB_VERSION_4) ++ || (super->sb_inodelog < XFS_SB_INODELOG_MIN) ++ || (super->sb_inodelog > XFS_SB_INODELOG_MAX) ++ || (super->sb_blocklog < XFS_SB_BLOCKLOG_MIN) ++ || (super->sb_blocklog > XFS_SB_BLOCKLOG_MAX) ++ || (super->sb_blocklog < super->sb_inodelog) ++ || (super->sb_agblklog > XFS_SB_AGBLKLOG_MAX) ++ || ((1ull << super->sb_agblklog) < le32(super->sb_agblocks)) ++ || (((1ull << super->sb_agblklog) >> 1) >= ++ le32(super->sb_agblocks)) ++ || ((super->sb_blocklog + super->sb_dirblklog) >= ++ XFS_SB_DIRBLK_NUMBITS); ++} ++ + static int + xfs_mount (fsi_file_t *ffi, const char *options) + { + xfs_sb_t super; + + if (!devread (ffi, 0, 0, sizeof(super), (char *)&super) +- || (le32(super.sb_magicnum) != XFS_SB_MAGIC) +- || ((le16(super.sb_versionnum) +- & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) { ++ || xfs_sb_is_invalid(&super)) { + return 0; + } + +- xfs.bsize = le32 (super.sb_blocksize); +- xfs.blklog = super.sb_blocklog; +- xfs.bdlog = xfs.blklog - SECTOR_BITS; ++ /* ++ * Not sanitized. It's exclusively used to generate disk addresses, ++ * so it's not important from a security standpoint. ++ */ + xfs.rootino = le64 (super.sb_rootino); +- xfs.isize = le16 (super.sb_inodesize); +- xfs.agblocks = le32 (super.sb_agblocks); +- xfs.dirbsize = xfs.bsize << super.sb_dirblklog; + +- xfs.inopblog = super.sb_inopblog; ++ /* ++ * Sanitized to be consistent with each other, only used to ++ * generate disk addresses, so it's safe ++ */ ++ xfs.agblocks = le32 (super.sb_agblocks); + xfs.agblklog = super.sb_agblklog; + ++ /* Derived from sanitized parameters */ ++ xfs.bsize = 1 << super.sb_blocklog; ++ xfs.blklog = super.sb_blocklog; ++ xfs.bdlog = super.sb_blocklog - SECTOR_BITS; ++ xfs.isize = 1 << super.sb_inodelog; ++ xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog); ++ xfs.inopblog = super.sb_blocklog - super.sb_inodelog; ++ + xfs.btnode_ptr0_off = + ((xfs.bsize - sizeof(xfs_btree_block_t)) / + (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t))) +diff --git a/tools/libfsimage/xfs/xfs.h b/tools/libfsimage/xfs/xfs.h +index 40699281e44d..b87e37d3d7e9 100644 +--- a/tools/libfsimage/xfs/xfs.h ++++ b/tools/libfsimage/xfs/xfs.h +@@ -134,6 +134,18 @@ typedef struct xfs_sb + xfs_uint8_t sb_dummy[7]; /* padding */ + } xfs_sb_t; + ++/* Bound taken from xfs.c in GRUB2. It doesn't exist in the spec */ ++#define XFS_SB_DIRBLK_NUMBITS 27 ++/* Implied by the XFS specification. The minimum block size is 512 octets */ ++#define XFS_SB_BLOCKLOG_MIN 9 ++/* Implied by the XFS specification. The maximum block size is 65536 octets */ ++#define XFS_SB_BLOCKLOG_MAX 16 ++/* Implied by the XFS specification. The minimum inode size is 256 octets */ ++#define XFS_SB_INODELOG_MIN 8 ++/* Implied by the XFS specification. The maximum inode size is 2048 octets */ ++#define XFS_SB_INODELOG_MAX 11 ++/* High bound for sb_agblklog */ ++#define XFS_SB_AGBLKLOG_MAX 32 + + /* those are from xfs_btree.h */ + +-- +2.42.0 + diff --git a/xsa443-4.16-04.patch b/xsa443-4.16-04.patch new file mode 100644 index 0000000..1c23377 --- /dev/null +++ b/xsa443-4.16-04.patch @@ -0,0 +1,60 @@ +From e72c68e702dd930bc6013182bb44d3e8fbbb6bf4 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Thu, 14 Sep 2023 13:22:53 +0100 +Subject: [PATCH 04/11] libfsimage/xfs: Add compile-time check to libfsimage + +Adds the common tools include folder to the -I compile flags +of libfsimage. This allows us to use: + xen-tools/common-macros.h:BUILD_BUG_ON() + +With it, statically assert a sanitized "blocklog - SECTOR_BITS" cannot +underflow. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Reviewed-by: Jan Beulich +--- + tools/libfsimage/Rules.mk | 2 +- + tools/libfsimage/xfs/fsys_xfs.c | 4 +++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/libfsimage/Rules.mk b/tools/libfsimage/Rules.mk +index bb6d42abb494..80598fb70aa7 100644 +--- a/tools/libfsimage/Rules.mk ++++ b/tools/libfsimage/Rules.mk +@@ -1,6 +1,6 @@ + include $(XEN_ROOT)/tools/Rules.mk + +-CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ -DFSIMAGE_FSDIR=\"$(FSDIR)\" ++CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ $(CFLAGS_xeninclude) -DFSIMAGE_FSDIR=\"$(FSDIR)\" + CFLAGS += -Werror -D_GNU_SOURCE + LDFLAGS += -L../common/ + +diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c +index e4eb7e1ee26f..4a8dd6f2397b 100644 +--- a/tools/libfsimage/xfs/fsys_xfs.c ++++ b/tools/libfsimage/xfs/fsys_xfs.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include "xfs.h" + + #define MAX_LINK_COUNT 8 +@@ -477,9 +478,10 @@ xfs_mount (fsi_file_t *ffi, const char *options) + xfs.agblklog = super.sb_agblklog; + + /* Derived from sanitized parameters */ ++ BUILD_BUG_ON(XFS_SB_BLOCKLOG_MIN < SECTOR_BITS); ++ xfs.bdlog = super.sb_blocklog - SECTOR_BITS; + xfs.bsize = 1 << super.sb_blocklog; + xfs.blklog = super.sb_blocklog; +- xfs.bdlog = super.sb_blocklog - SECTOR_BITS; + xfs.isize = 1 << super.sb_inodelog; + xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog); + xfs.inopblog = super.sb_blocklog - super.sb_inodelog; +-- +2.42.0 + diff --git a/xsa443-4.16-05.patch b/xsa443-4.16-05.patch new file mode 100644 index 0000000..8bf9915 --- /dev/null +++ b/xsa443-4.16-05.patch @@ -0,0 +1,59 @@ +From 75fdc03c5a6b7fac0c3a5ac06a5beaac73aad36f Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:21 +0100 +Subject: [PATCH 05/11] tools/pygrub: Remove unnecessary hypercall + +There's a hypercall being issued in order to determine whether PV64 is +supported, but since Xen 4.3 that's strictly true so it's not required. + +Plus, this way we can avoid mapping the privcmd interface altogether in the +depriv pygrub. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Reviewed-by: Andrew Cooper +--- + tools/pygrub/src/pygrub | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index ce7ab0eb8cf3..ce4e07d3e823 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -18,7 +18,6 @@ import os, sys, string, struct, tempfile, re, traceback, stat, errno + import copy + import logging + import platform +-import xen.lowlevel.xc + + import curses, _curses, curses.textpad, curses.ascii + import getopt +@@ -668,14 +667,6 @@ def run_grub(file, entry, fs, cfg_args): + + return grubcfg + +-def supports64bitPVguest(): +- xc = xen.lowlevel.xc.xc() +- caps = xc.xeninfo()['xen_caps'].split(" ") +- for cap in caps: +- if cap == "xen-3.0-x86_64": +- return True +- return False +- + # If nothing has been specified, look for a Solaris domU. If found, perform the + # necessary tweaks. + def sniff_solaris(fs, cfg): +@@ -684,8 +675,7 @@ def sniff_solaris(fs, cfg): + return cfg + + if not cfg["kernel"]: +- if supports64bitPVguest() and \ +- fs.file_exists("/platform/i86xpv/kernel/amd64/unix"): ++ if fs.file_exists("/platform/i86xpv/kernel/amd64/unix"): + cfg["kernel"] = "/platform/i86xpv/kernel/amd64/unix" + cfg["ramdisk"] = "/platform/i86pc/amd64/boot_archive" + elif fs.file_exists("/platform/i86xpv/kernel/unix"): +-- +2.42.0 + diff --git a/xsa443-4.16-06.patch b/xsa443-4.16-06.patch new file mode 100644 index 0000000..cb18ee2 --- /dev/null +++ b/xsa443-4.16-06.patch @@ -0,0 +1,65 @@ +From 1083a16f63461e844e9515ac4d35d48bf55785af Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:22 +0100 +Subject: [PATCH 06/11] tools/pygrub: Small refactors + +Small tidy up to ensure output_directory always has a trailing '/' to ease +concatenating paths and that `output` can only be a filename or None. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/pygrub/src/pygrub | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index ce4e07d3e823..1042c05b8676 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -793,7 +793,7 @@ if __name__ == "__main__": + debug = False + not_really = False + output_format = "sxp" +- output_directory = "/var/run/xen/pygrub" ++ output_directory = "/var/run/xen/pygrub/" + + # what was passed in + incfg = { "kernel": None, "ramdisk": None, "args": "" } +@@ -815,7 +815,8 @@ if __name__ == "__main__": + usage() + sys.exit() + elif o in ("--output",): +- output = a ++ if a != "-": ++ output = a + elif o in ("--kernel",): + incfg["kernel"] = a + elif o in ("--ramdisk",): +@@ -847,12 +848,11 @@ if __name__ == "__main__": + if not os.path.isdir(a): + print("%s is not an existing directory" % a) + sys.exit(1) +- output_directory = a ++ output_directory = a + '/' + + if debug: + logging.basicConfig(level=logging.DEBUG) + +- + try: + os.makedirs(output_directory, 0o700) + except OSError as e: +@@ -861,7 +861,7 @@ if __name__ == "__main__": + else: + raise + +- if output is None or output == "-": ++ if output is None: + fd = sys.stdout.fileno() + else: + fd = os.open(output, os.O_WRONLY) +-- +2.42.0 + diff --git a/xsa443-4.16-07.patch b/xsa443-4.16-07.patch new file mode 100644 index 0000000..088c5eb --- /dev/null +++ b/xsa443-4.16-07.patch @@ -0,0 +1,105 @@ +From 350db30e33f39af40c1e3752d73c0a30ef2d26e7 Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:23 +0100 +Subject: [PATCH 07/11] tools/pygrub: Open the output files earlier + +This patch allows pygrub to get ahold of every RW file descriptor it needs +early on. A later patch will clamp the filesystem it can access so it can't +obtain any others. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/pygrub/src/pygrub | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index 1042c05b8676..91e2ec2ab105 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -738,8 +738,7 @@ if __name__ == "__main__": + def usage(): + print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] " %(sys.argv[0],), file=sys.stderr) + +- def copy_from_image(fs, file_to_read, file_type, output_directory, +- not_really): ++ def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really): + if not_really: + if fs.file_exists(file_to_read): + return "<%s:%s>" % (file_type, file_to_read) +@@ -750,21 +749,18 @@ if __name__ == "__main__": + except Exception as e: + print(e, file=sys.stderr) + sys.exit("Error opening %s in guest" % file_to_read) +- (tfd, ret) = tempfile.mkstemp(prefix="boot_"+file_type+".", +- dir=output_directory) + dataoff = 0 + while True: + data = datafile.read(FS_READ_MAX, dataoff) + if len(data) == 0: +- os.close(tfd) ++ os.close(fd_dst) + del datafile +- return ret ++ return + try: +- os.write(tfd, data) ++ os.write(fd_dst, data) + except Exception as e: + print(e, file=sys.stderr) +- os.close(tfd) +- os.unlink(ret) ++ os.unlink(path_dst) + del datafile + sys.exit("Error writing temporary copy of "+file_type) + dataoff += len(data) +@@ -861,6 +857,14 @@ if __name__ == "__main__": + else: + raise + ++ if not_really: ++ fd_kernel = path_kernel = fd_ramdisk = path_ramdisk = None ++ else: ++ (fd_kernel, path_kernel) = tempfile.mkstemp(prefix="boot_kernel.", ++ dir=output_directory) ++ (fd_ramdisk, path_ramdisk) = tempfile.mkstemp(prefix="boot_ramdisk.", ++ dir=output_directory) ++ + if output is None: + fd = sys.stdout.fileno() + else: +@@ -920,20 +924,23 @@ if __name__ == "__main__": + if fs is None: + raise RuntimeError("Unable to find partition containing kernel") + +- bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel", +- output_directory, not_really) ++ copy_from_image(fs, chosencfg["kernel"], "kernel", ++ fd_kernel, path_kernel, not_really) ++ bootcfg["kernel"] = path_kernel + + if chosencfg["ramdisk"]: + try: +- bootcfg["ramdisk"] = copy_from_image(fs, chosencfg["ramdisk"], +- "ramdisk", output_directory, +- not_really) ++ copy_from_image(fs, chosencfg["ramdisk"], "ramdisk", ++ fd_ramdisk, path_ramdisk, not_really) + except: + if not not_really: +- os.unlink(bootcfg["kernel"]) ++ os.unlink(path_kernel) + raise ++ bootcfg["ramdisk"] = path_ramdisk + else: + initrd = None ++ if not not_really: ++ os.unlink(path_ramdisk) + + args = None + if chosencfg["args"]: +-- +2.42.0 + diff --git a/xsa443-4.16-08.patch b/xsa443-4.16-08.patch new file mode 100644 index 0000000..40c28e1 --- /dev/null +++ b/xsa443-4.16-08.patch @@ -0,0 +1,126 @@ +From 1548ad2291ec7a72ae6949c11d2e50cea135a48d Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:24 +0100 +Subject: [PATCH 08/11] tools/libfsimage: Export a new function to preload all + plugins + +This is work required in order to let pygrub operate in highly deprivileged +chroot mode. This patch adds a function that preloads every plugin, hence +ensuring that a on function exit, every shared library is loaded in memory. + +The new "init" function is supposed to be used before depriv, but that's +fine because it's not acting on untrusted data. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/libfsimage/common/fsimage_plugin.c | 4 ++-- + tools/libfsimage/common/mapfile-GNU | 1 + + tools/libfsimage/common/mapfile-SunOS | 1 + + tools/libfsimage/common/xenfsimage.h | 8 ++++++++ + tools/pygrub/src/fsimage/fsimage.c | 15 +++++++++++++++ + 5 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/tools/libfsimage/common/fsimage_plugin.c b/tools/libfsimage/common/fsimage_plugin.c +index de1412b4233a..d0cb9e96a654 100644 +--- a/tools/libfsimage/common/fsimage_plugin.c ++++ b/tools/libfsimage/common/fsimage_plugin.c +@@ -119,7 +119,7 @@ fail: + return (-1); + } + +-static int load_plugins(void) ++int fsi_init(void) + { + const char *fsdir = getenv("XEN_FSIMAGE_FSDIR"); + struct dirent *dp = NULL; +@@ -180,7 +180,7 @@ int find_plugin(fsi_t *fsi, const char *path, const char *options) + fsi_plugin_t *fp; + int ret = 0; + +- if (plugins == NULL && (ret = load_plugins()) != 0) ++ if (plugins == NULL && (ret = fsi_init()) != 0) + goto out; + + for (fp = plugins; fp != NULL; fp = fp->fp_next) { +diff --git a/tools/libfsimage/common/mapfile-GNU b/tools/libfsimage/common/mapfile-GNU +index 26d4d7a69ec7..2d54d527d7f5 100644 +--- a/tools/libfsimage/common/mapfile-GNU ++++ b/tools/libfsimage/common/mapfile-GNU +@@ -1,6 +1,7 @@ + VERSION { + libfsimage.so.1.0 { + global: ++ fsi_init; + fsi_open_fsimage; + fsi_close_fsimage; + fsi_file_exists; +diff --git a/tools/libfsimage/common/mapfile-SunOS b/tools/libfsimage/common/mapfile-SunOS +index e99b90b65077..48deedb4252f 100644 +--- a/tools/libfsimage/common/mapfile-SunOS ++++ b/tools/libfsimage/common/mapfile-SunOS +@@ -1,5 +1,6 @@ + libfsimage.so.1.0 { + global: ++ fsi_init; + fsi_open_fsimage; + fsi_close_fsimage; + fsi_file_exists; +diff --git a/tools/libfsimage/common/xenfsimage.h b/tools/libfsimage/common/xenfsimage.h +index 201abd54f23a..341883b2d71a 100644 +--- a/tools/libfsimage/common/xenfsimage.h ++++ b/tools/libfsimage/common/xenfsimage.h +@@ -35,6 +35,14 @@ extern C { + typedef struct fsi fsi_t; + typedef struct fsi_file fsi_file_t; + ++/* ++ * Optional initialization function. If invoked it loads the associated ++ * dynamic libraries for the backends ahead of time. This is required if ++ * the library is to run as part of a highly deprivileged executable, as ++ * the libraries may not be reachable after depriv. ++ */ ++int fsi_init(void); ++ + fsi_t *fsi_open_fsimage(const char *, uint64_t, const char *); + void fsi_close_fsimage(fsi_t *); + +diff --git a/tools/pygrub/src/fsimage/fsimage.c b/tools/pygrub/src/fsimage/fsimage.c +index 2ebbbe35df92..92fbf2851f01 100644 +--- a/tools/pygrub/src/fsimage/fsimage.c ++++ b/tools/pygrub/src/fsimage/fsimage.c +@@ -286,6 +286,15 @@ fsimage_getbootstring(PyObject *o, PyObject *args) + return Py_BuildValue("s", bootstring); + } + ++static PyObject * ++fsimage_init(PyObject *o, PyObject *args) ++{ ++ if (!PyArg_ParseTuple(args, "")) ++ return (NULL); ++ ++ return Py_BuildValue("i", fsi_init()); ++} ++ + PyDoc_STRVAR(fsimage_open__doc__, + "open(name, [offset=off]) - Open the given file as a filesystem image.\n" + "\n" +@@ -297,7 +306,13 @@ PyDoc_STRVAR(fsimage_getbootstring__doc__, + "getbootstring(fs) - Return the boot string needed for this file system " + "or NULL if none is needed.\n"); + ++PyDoc_STRVAR(fsimage_init__doc__, ++ "init() - Loads every dynamic library contained in xenfsimage " ++ "into memory so that it can be used in chrooted environments.\n"); ++ + static struct PyMethodDef fsimage_module_methods[] = { ++ { "init", (PyCFunction)fsimage_init, ++ METH_VARARGS, fsimage_init__doc__ }, + { "open", (PyCFunction)fsimage_open, + METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ }, + { "getbootstring", (PyCFunction)fsimage_getbootstring, +-- +2.42.0 + diff --git a/xsa443-4.16-09.patch b/xsa443-4.16-09.patch new file mode 100644 index 0000000..77d0d66 --- /dev/null +++ b/xsa443-4.16-09.patch @@ -0,0 +1,307 @@ +From 4d331b0b914dfc17bd2d883bc55aeb798930832a Mon Sep 17 00:00:00 2001 +From: Alejandro Vallejo +Date: Mon, 25 Sep 2023 18:32:25 +0100 +Subject: [PATCH 09/11] tools/pygrub: Deprivilege pygrub + +Introduce a --runas= flag to deprivilege pygrub on Linux and *BSDs. It +also implicitly creates a chroot env where it drops a deprivileged forked +process. The chroot itself is cleaned up at the end. + +If the --runas arg is present, then pygrub forks, leaving the child to +deprivilege itself, and waiting for it to complete. When the child exists, +the parent performs cleanup and exits with the same error code. + +This is roughly what the child does: + 1. Initialize libfsimage (this loads every .so in memory so the chroot + can avoid bind-mounting /{,usr}/lib* + 2. Create a temporary empty chroot directory + 3. Mount tmpfs in it + 4. Bind mount the disk inside, because libfsimage expects a path, not a + file descriptor. + 5. Remount the root tmpfs to be stricter (ro,nosuid,nodev) + 6. Set RLIMIT_FSIZE to a sensibly high amount (128 MiB) + 7. Depriv gid, groups and uid + +With this scheme in place, the "output" files are writable (up to +RLIMIT_FSIZE octets) and the exposed filesystem is immutable and contains +the single only file we can't easily get rid of (the disk). + +If running on Linux, the child process also unshares mount, IPC, and +network namespaces before dropping its privileges. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Alejandro Vallejo +Acked-by: Andrew Cooper +--- + tools/pygrub/setup.py | 2 +- + tools/pygrub/src/pygrub | 162 +++++++++++++++++++++++++++++++++++++--- + 2 files changed, 154 insertions(+), 10 deletions(-) + +diff --git a/tools/pygrub/setup.py b/tools/pygrub/setup.py +index b8f1dc4590cf..f16187b6d118 100644 +--- a/tools/pygrub/setup.py ++++ b/tools/pygrub/setup.py +@@ -17,7 +17,7 @@ xenfsimage = Extension("xenfsimage", + pkgs = [ 'grub' ] + + setup(name='pygrub', +- version='0.6', ++ version='0.7', + description='Boot loader that looks a lot like grub for Xen', + author='Jeremy Katz', + author_email='katzj@redhat.com', +diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub +index 91e2ec2ab105..7cea496ade08 100755 +--- a/tools/pygrub/src/pygrub ++++ b/tools/pygrub/src/pygrub +@@ -16,8 +16,11 @@ from __future__ import print_function + + import os, sys, string, struct, tempfile, re, traceback, stat, errno + import copy ++import ctypes, ctypes.util + import logging + import platform ++import resource ++import subprocess + + import curses, _curses, curses.textpad, curses.ascii + import getopt +@@ -27,10 +30,135 @@ import grub.GrubConf + import grub.LiloConf + import grub.ExtLinuxConf + +-PYGRUB_VER = 0.6 ++PYGRUB_VER = 0.7 + FS_READ_MAX = 1024 * 1024 + SECTOR_SIZE = 512 + ++# Unless provided through the env variable PYGRUB_MAX_FILE_SIZE_MB, then ++# this is the maximum filesize allowed for files written by the depriv ++# pygrub ++LIMIT_FSIZE = 128 << 20 ++ ++CLONE_NEWNS = 0x00020000 # mount namespace ++CLONE_NEWNET = 0x40000000 # network namespace ++CLONE_NEWIPC = 0x08000000 # IPC namespace ++ ++def unshare(flags): ++ if not sys.platform.startswith("linux"): ++ print("skip_unshare reason=not_linux platform=%s", sys.platform, file=sys.stderr) ++ return ++ ++ libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) ++ unshare_prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True) ++ unshare = unshare_prototype(('unshare', libc)) ++ ++ if unshare(flags) < 0: ++ raise OSError(ctypes.get_errno(), os.strerror(ctypes.get_errno())) ++ ++def bind_mount(src, dst, options): ++ open(dst, "a").close() # touch ++ ++ rc = subprocess.call(["mount", "--bind", "-o", options, src, dst]) ++ if rc != 0: ++ raise RuntimeError("bad_mount: src=%s dst=%s opts=%s" % ++ (src, dst, options)) ++ ++def downgrade_rlimits(): ++ # Wipe the authority to use unrequired resources ++ resource.setrlimit(resource.RLIMIT_NPROC, (0, 0)) ++ resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) ++ resource.setrlimit(resource.RLIMIT_MEMLOCK, (0, 0)) ++ ++ # py2's resource module doesn't know about resource.RLIMIT_MSGQUEUE ++ # ++ # TODO: Use resource.RLIMIT_MSGQUEUE after python2 is deprecated ++ if sys.platform.startswith('linux'): ++ RLIMIT_MSGQUEUE = 12 ++ resource.setrlimit(RLIMIT_MSGQUEUE, (0, 0)) ++ ++ # The final look of the filesystem for this process is fully RO, but ++ # note we have some file descriptor already open (notably, kernel and ++ # ramdisk). In order to avoid a compromised pygrub from filling up the ++ # filesystem we set RLIMIT_FSIZE to a high bound, so that the file ++ # write permissions are bound. ++ fsize = LIMIT_FSIZE ++ if "PYGRUB_MAX_FILE_SIZE_MB" in os.environ.keys(): ++ fsize = os.environ["PYGRUB_MAX_FILE_SIZE_MB"] << 20 ++ ++ resource.setrlimit(resource.RLIMIT_FSIZE, (fsize, fsize)) ++ ++def depriv(output_directory, output, device, uid, path_kernel, path_ramdisk): ++ # The only point of this call is to force the loading of libfsimage. ++ # That way, we don't need to bind-mount it into the chroot ++ rc = xenfsimage.init() ++ if rc != 0: ++ os.unlink(path_ramdisk) ++ os.unlink(path_kernel) ++ raise RuntimeError("bad_xenfsimage: rc=%d" % rc) ++ ++ # Create a temporary directory for the chroot ++ chroot = tempfile.mkdtemp(prefix=str(uid)+'-', dir=output_directory) + '/' ++ device_path = '/device' ++ ++ pid = os.fork() ++ if pid: ++ # parent ++ _, rc = os.waitpid(pid, 0) ++ ++ for path in [path_kernel, path_ramdisk]: ++ # If the child didn't write anything, just get rid of it, ++ # otherwise we end up consuming a 0-size file when parsing ++ # systems without a ramdisk that the ultimate caller of pygrub ++ # may just be unaware of ++ if rc != 0 or os.path.getsize(path) == 0: ++ os.unlink(path) ++ ++ # Normally, unshare(CLONE_NEWNS) will ensure this is not required. ++ # However, this syscall doesn't exist in *BSD systems and doesn't ++ # auto-unmount everything on older Linux kernels (At least as of ++ # Linux 4.19, but it seems fixed in 5.15). Either way, ++ # recursively unmount everything if needed. Quietly. ++ with open('/dev/null', 'w') as devnull: ++ subprocess.call(["umount", "-f", chroot + device_path], ++ stdout=devnull, stderr=devnull) ++ subprocess.call(["umount", "-f", chroot], ++ stdout=devnull, stderr=devnull) ++ os.rmdir(chroot) ++ ++ sys.exit(rc) ++ ++ # By unsharing the namespace we're making sure it's all bulk-released ++ # at the end, when the namespaces disappear. This means the kernel does ++ # (almost) all the cleanup for us and the parent just has to remove the ++ # temporary directory. ++ unshare(CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET) ++ ++ # Set sensible limits using the setrlimit interface ++ downgrade_rlimits() ++ ++ # We'll mount tmpfs on the chroot to ensure the deprivileged child ++ # cannot affect the persistent state. It's RW now in order to ++ # bind-mount the device, but note it's remounted RO after that. ++ rc = subprocess.call(["mount", "-t", "tmpfs", "none", chroot]) ++ if rc != 0: ++ raise RuntimeError("mount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot)) ++ ++ # Bind the untrusted device RO ++ bind_mount(device, chroot + device_path, "ro,nosuid,noexec") ++ ++ rc = subprocess.call(["mount", "-t", "tmpfs", "-o", "remount,ro,nosuid,noexec,nodev", "none", chroot]) ++ if rc != 0: ++ raise RuntimeError("remount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot)) ++ ++ # Drop superpowers! ++ os.chroot(chroot) ++ os.chdir('/') ++ os.setgid(uid) ++ os.setgroups([uid]) ++ os.setuid(uid) ++ ++ return device_path ++ + def read_size_roundup(fd, size): + if platform.system() != 'FreeBSD': + return size +@@ -736,7 +864,7 @@ if __name__ == "__main__": + sel = None + + def usage(): +- print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] " %(sys.argv[0],), file=sys.stderr) ++ print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--runas=] [--offset=] " %(sys.argv[0],), file=sys.stderr) + + def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really): + if not_really: +@@ -760,7 +888,8 @@ if __name__ == "__main__": + os.write(fd_dst, data) + except Exception as e: + print(e, file=sys.stderr) +- os.unlink(path_dst) ++ if path_dst: ++ os.unlink(path_dst) + del datafile + sys.exit("Error writing temporary copy of "+file_type) + dataoff += len(data) +@@ -769,7 +898,7 @@ if __name__ == "__main__": + opts, args = getopt.gnu_getopt(sys.argv[1:], 'qilnh::', + ["quiet", "interactive", "list-entries", "not-really", "help", + "output=", "output-format=", "output-directory=", "offset=", +- "entry=", "kernel=", ++ "runas=", "entry=", "kernel=", + "ramdisk=", "args=", "isconfig", "debug"]) + except getopt.GetoptError: + usage() +@@ -790,6 +919,7 @@ if __name__ == "__main__": + not_really = False + output_format = "sxp" + output_directory = "/var/run/xen/pygrub/" ++ uid = None + + # what was passed in + incfg = { "kernel": None, "ramdisk": None, "args": "" } +@@ -813,6 +943,13 @@ if __name__ == "__main__": + elif o in ("--output",): + if a != "-": + output = a ++ elif o in ("--runas",): ++ try: ++ uid = int(a) ++ except ValueError: ++ print("runas value must be an integer user id") ++ usage() ++ sys.exit(1) + elif o in ("--kernel",): + incfg["kernel"] = a + elif o in ("--ramdisk",): +@@ -849,6 +986,10 @@ if __name__ == "__main__": + if debug: + logging.basicConfig(level=logging.DEBUG) + ++ if interactive and uid: ++ print("In order to use --runas, you must also set --entry or -q", file=sys.stderr) ++ sys.exit(1) ++ + try: + os.makedirs(output_directory, 0o700) + except OSError as e: +@@ -870,6 +1011,9 @@ if __name__ == "__main__": + else: + fd = os.open(output, os.O_WRONLY) + ++ if uid: ++ file = depriv(output_directory, output, file, uid, path_kernel, path_ramdisk) ++ + # debug + if isconfig: + chosencfg = run_grub(file, entry, fs, incfg["args"]) +@@ -925,21 +1069,21 @@ if __name__ == "__main__": + raise RuntimeError("Unable to find partition containing kernel") + + copy_from_image(fs, chosencfg["kernel"], "kernel", +- fd_kernel, path_kernel, not_really) ++ fd_kernel, None if uid else path_kernel, not_really) + bootcfg["kernel"] = path_kernel + + if chosencfg["ramdisk"]: + try: + copy_from_image(fs, chosencfg["ramdisk"], "ramdisk", +- fd_ramdisk, path_ramdisk, not_really) ++ fd_ramdisk, None if uid else path_ramdisk, not_really) + except: +- if not not_really: +- os.unlink(path_kernel) ++ if not uid and not not_really: ++ os.unlink(path_kernel) + raise + bootcfg["ramdisk"] = path_ramdisk + else: + initrd = None +- if not not_really: ++ if not uid and not not_really: + os.unlink(path_ramdisk) + + args = None +-- +2.42.0 + diff --git a/xsa443-4.16-10.patch b/xsa443-4.16-10.patch new file mode 100644 index 0000000..7c65748 --- /dev/null +++ b/xsa443-4.16-10.patch @@ -0,0 +1,250 @@ +From a5be7e8b054f586ad934e786232af29fdc6e3ead Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Mon, 25 Sep 2023 14:30:20 +0200 +Subject: [PATCH 10/11] libxl: add support for running bootloader in restricted + mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Much like the device model depriv mode, add the same kind of support for the +bootloader. Such feature allows passing a UID as a parameter for the +bootloader to run as, together with the bootloader itself taking the necessary +actions to isolate. + +Note that the user to run the bootloader as must have the right permissions to +access the guest disk image (in read mode only), and that the bootloader will +be run in non-interactive mode when restricted. + +If enabled bootloader restrict mode will attempt to re-use the user(s) from the +QEMU depriv implementation if no user is provided on the configuration file or +the environment. See docs/features/qemu-deprivilege.pandoc for more +information about how to setup those users. + +Bootloader restrict mode is not enabled by default as it requires certain +setup to be done first (setup of the user(s) to use in restrict mode). + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Anthony PERARD +--- + docs/man/xl.1.pod.in | 33 +++++++++++ + tools/libs/light/libxl_bootloader.c | 89 ++++++++++++++++++++++++++++- + tools/libs/light/libxl_dm.c | 8 +-- + tools/libs/light/libxl_internal.h | 8 +++ + 4 files changed, 131 insertions(+), 7 deletions(-) + +diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in +index 45e1430aeb74..96e6fb1c32a3 100644 +--- a/docs/man/xl.1.pod.in ++++ b/docs/man/xl.1.pod.in +@@ -1976,6 +1976,39 @@ ignored: + + =back + ++=head1 ENVIRONMENT VARIABLES ++ ++The following environment variables shall affect the execution of xl: ++ ++=over 4 ++ ++=item LIBXL_BOOTLOADER_RESTRICT ++ ++Attempt to restrict the bootloader after startup, to limit the ++consequences of security vulnerabilities due to parsing guest ++owned image files. ++ ++See docs/features/qemu-deprivilege.pandoc for more information ++on how to setup the unprivileged users. ++ ++Note that running the bootloader in restricted mode also implies using ++non-interactive mode, and the disk image must be readable by the ++restricted user. ++ ++Having this variable set is equivalent to enabling the option, even if the ++value is 0. ++ ++=item LIBXL_BOOTLOADER_USER ++ ++When using bootloader_restrict, run the bootloader as this user. If ++not set the default QEMU restrict users will be used. ++ ++NOTE: Each domain MUST have a SEPARATE username. ++ ++See docs/features/qemu-deprivilege.pandoc for more information. ++ ++=back ++ + =head1 SEE ALSO + + The following man pages: +diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c +index 1bc6e51827b9..d3a8a4a9ba59 100644 +--- a/tools/libs/light/libxl_bootloader.c ++++ b/tools/libs/light/libxl_bootloader.c +@@ -14,6 +14,7 @@ + + #include "libxl_osdeps.h" /* must come before any other headers */ + ++#include + #include + #ifdef HAVE_UTMP_H + #include +@@ -42,8 +43,71 @@ static void bootloader_arg(libxl__bootloader_state *bl, const char *arg) + bl->args[bl->nargs++] = arg; + } + +-static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, +- const char *bootloader_path) ++static int bootloader_uid(libxl__gc *gc, domid_t guest_domid, ++ const char *user, uid_t *intended_uid) ++{ ++ struct passwd *user_base, user_pwbuf; ++ int rc; ++ ++ if (user) { ++ rc = userlookup_helper_getpwnam(gc, user, &user_pwbuf, &user_base); ++ if (rc) return rc; ++ ++ if (!user_base) { ++ LOGD(ERROR, guest_domid, "Couldn't find user %s", user); ++ return ERROR_INVAL; ++ } ++ ++ *intended_uid = user_base->pw_uid; ++ return 0; ++ } ++ ++ /* Re-use QEMU user range for the bootloader. */ ++ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_RANGE_BASE, ++ &user_pwbuf, &user_base); ++ if (rc) return rc; ++ ++ if (user_base) { ++ struct passwd *user_clash, user_clash_pwbuf; ++ uid_t temp_uid = user_base->pw_uid + guest_domid; ++ ++ rc = userlookup_helper_getpwuid(gc, temp_uid, &user_clash_pwbuf, ++ &user_clash); ++ if (rc) return rc; ++ ++ if (user_clash) { ++ LOGD(ERROR, guest_domid, ++ "wanted to use uid %ld (%s + %d) but that is user %s !", ++ (long)temp_uid, LIBXL_QEMU_USER_RANGE_BASE, ++ guest_domid, user_clash->pw_name); ++ return ERROR_INVAL; ++ } ++ ++ *intended_uid = temp_uid; ++ return 0; ++ } ++ ++ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_SHARED, &user_pwbuf, ++ &user_base); ++ if (rc) return rc; ++ ++ if (user_base) { ++ LOGD(WARN, guest_domid, "Could not find user %s, falling back to %s", ++ LIBXL_QEMU_USER_RANGE_BASE, LIBXL_QEMU_USER_SHARED); ++ *intended_uid = user_base->pw_uid; ++ ++ return 0; ++ } ++ ++ LOGD(ERROR, guest_domid, ++ "Could not find user %s or range base pseudo-user %s, cannot restrict", ++ LIBXL_QEMU_USER_SHARED, LIBXL_QEMU_USER_RANGE_BASE); ++ ++ return ERROR_INVAL; ++} ++ ++static int make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, ++ const char *bootloader_path) + { + const libxl_domain_build_info *info = bl->info; + +@@ -61,6 +125,23 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, + ARG(GCSPRINTF("--ramdisk=%s", info->ramdisk)); + if (info->cmdline && *info->cmdline != '\0') + ARG(GCSPRINTF("--args=%s", info->cmdline)); ++ if (getenv("LIBXL_BOOTLOADER_RESTRICT") || ++ getenv("LIBXL_BOOTLOADER_USER")) { ++ uid_t uid = -1; ++ int rc = bootloader_uid(gc, bl->domid, getenv("LIBXL_BOOTLOADER_USER"), ++ &uid); ++ ++ if (rc) return rc; ++ ++ assert(uid != -1); ++ if (!uid) { ++ LOGD(ERROR, bl->domid, "bootloader restrict UID is 0 (root)!"); ++ return ERROR_INVAL; ++ } ++ LOGD(DEBUG, bl->domid, "using uid %ld", (long)uid); ++ ARG(GCSPRINTF("--runas=%ld", (long)uid)); ++ ARG("--quiet"); ++ } + + ARG(GCSPRINTF("--output=%s", bl->outputpath)); + ARG("--output-format=simple0"); +@@ -79,6 +160,7 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, + /* Sentinel for execv */ + ARG(NULL); + ++ return 0; + #undef ARG + } + +@@ -443,7 +525,8 @@ static void bootloader_disk_attached_cb(libxl__egc *egc, + bootloader = bltmp; + } + +- make_bootloader_args(gc, bl, bootloader); ++ rc = make_bootloader_args(gc, bl, bootloader); ++ if (rc) goto out; + + bl->openpty.ao = ao; + bl->openpty.callback = bootloader_gotptys; +diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c +index fc264a3a13a6..14b593110f7c 100644 +--- a/tools/libs/light/libxl_dm.c ++++ b/tools/libs/light/libxl_dm.c +@@ -80,10 +80,10 @@ static int libxl__create_qemu_logfile(libxl__gc *gc, char *name) + * On error, return a libxl-style error code. + */ + #define DEFINE_USERLOOKUP_HELPER(NAME,SPEC_TYPE,STRUCTNAME,SYSCONF) \ +- static int userlookup_helper_##NAME(libxl__gc *gc, \ +- SPEC_TYPE spec, \ +- struct STRUCTNAME *resultbuf, \ +- struct STRUCTNAME **out) \ ++ int userlookup_helper_##NAME(libxl__gc *gc, \ ++ SPEC_TYPE spec, \ ++ struct STRUCTNAME *resultbuf, \ ++ struct STRUCTNAME **out) \ + { \ + struct STRUCTNAME *resultp = NULL; \ + char *buf = NULL; \ +diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h +index cc27c72ecf30..8415d1feed16 100644 +--- a/tools/libs/light/libxl_internal.h ++++ b/tools/libs/light/libxl_internal.h +@@ -4864,6 +4864,14 @@ struct libxl__cpu_policy { + struct xc_msr *msr; + }; + ++struct passwd; ++_hidden int userlookup_helper_getpwnam(libxl__gc*, const char *user, ++ struct passwd *res, ++ struct passwd **out); ++_hidden int userlookup_helper_getpwuid(libxl__gc*, uid_t uid, ++ struct passwd *res, ++ struct passwd **out); ++ + #endif + + /* +-- +2.42.0 + diff --git a/xsa443-4.16-11.patch b/xsa443-4.16-11.patch new file mode 100644 index 0000000..b3d066b --- /dev/null +++ b/xsa443-4.16-11.patch @@ -0,0 +1,157 @@ +From 273cc7ecf0a66334f24f6f740bcd441b542b3323 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Thu, 28 Sep 2023 12:22:35 +0200 +Subject: [PATCH 11/11] libxl: limit bootloader execution in restricted mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a timeout for bootloader execution when running in restricted mode. + +Allow overwriting the default time out with an environment provided value. + +This is part of XSA-443 / CVE-2023-34325 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Anthony PERARD +--- + docs/man/xl.1.pod.in | 8 ++++++ + tools/libs/light/libxl_bootloader.c | 40 +++++++++++++++++++++++++++++ + tools/libs/light/libxl_internal.h | 2 ++ + 3 files changed, 50 insertions(+) + +diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in +index 96e6fb1c32a3..8f056450a730 100644 +--- a/docs/man/xl.1.pod.in ++++ b/docs/man/xl.1.pod.in +@@ -2007,6 +2007,14 @@ NOTE: Each domain MUST have a SEPARATE username. + + See docs/features/qemu-deprivilege.pandoc for more information. + ++=item LIBXL_BOOTLOADER_TIMEOUT ++ ++Timeout in seconds for bootloader execution when running in restricted mode. ++Otherwise the build time default in LIBXL_BOOTLOADER_TIMEOUT will be used. ++ ++If defined the value must be an unsigned integer between 0 and INT_MAX, ++otherwise behavior is undefined. Setting to 0 disables the timeout. ++ + =back + + =head1 SEE ALSO +diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c +index d3a8a4a9ba59..a4beff42654c 100644 +--- a/tools/libs/light/libxl_bootloader.c ++++ b/tools/libs/light/libxl_bootloader.c +@@ -30,6 +30,8 @@ static void bootloader_keystrokes_copyfail(libxl__egc *egc, + libxl__datacopier_state *dc, int rc, int onwrite, int errnoval); + static void bootloader_display_copyfail(libxl__egc *egc, + libxl__datacopier_state *dc, int rc, int onwrite, int errnoval); ++static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev, ++ const struct timeval *requested_abs, int rc); + static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc, + int rc); + static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child, +@@ -297,6 +299,7 @@ void libxl__bootloader_init(libxl__bootloader_state *bl) + bl->ptys[0].master = bl->ptys[0].slave = 0; + bl->ptys[1].master = bl->ptys[1].slave = 0; + libxl__ev_child_init(&bl->child); ++ libxl__ev_time_init(&bl->time); + libxl__domaindeathcheck_init(&bl->deathcheck); + bl->keystrokes.ao = bl->ao; libxl__datacopier_init(&bl->keystrokes); + bl->display.ao = bl->ao; libxl__datacopier_init(&bl->display); +@@ -314,6 +317,7 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl) + libxl__domaindeathcheck_stop(gc,&bl->deathcheck); + libxl__datacopier_kill(&bl->keystrokes); + libxl__datacopier_kill(&bl->display); ++ libxl__ev_time_deregister(gc, &bl->time); + for (i=0; i<2; i++) { + libxl__carefd_close(bl->ptys[i].master); + libxl__carefd_close(bl->ptys[i].slave); +@@ -375,6 +379,7 @@ static void bootloader_stop(libxl__egc *egc, + + libxl__datacopier_kill(&bl->keystrokes); + libxl__datacopier_kill(&bl->display); ++ libxl__ev_time_deregister(gc, &bl->time); + if (libxl__ev_child_inuse(&bl->child)) { + r = kill(bl->child.pid, SIGTERM); + if (r) LOGED(WARN, bl->domid, "%sfailed to kill bootloader [%lu]", +@@ -637,6 +642,25 @@ static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op) + + struct termios termattr; + ++ if (getenv("LIBXL_BOOTLOADER_RESTRICT") || ++ getenv("LIBXL_BOOTLOADER_USER")) { ++ const char *timeout_env = getenv("LIBXL_BOOTLOADER_TIMEOUT"); ++ int timeout = timeout_env ? atoi(timeout_env) ++ : LIBXL_BOOTLOADER_TIMEOUT; ++ ++ if (timeout) { ++ /* Set execution timeout */ ++ rc = libxl__ev_time_register_rel(ao, &bl->time, ++ bootloader_timeout, ++ timeout * 1000); ++ if (rc) { ++ LOGED(ERROR, bl->domid, ++ "unable to register timeout for bootloader execution"); ++ goto out; ++ } ++ } ++ } ++ + pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished); + if (pid == -1) { + rc = ERROR_FAIL; +@@ -702,6 +726,21 @@ static void bootloader_display_copyfail(libxl__egc *egc, + libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, display); + bootloader_copyfail(egc, "bootloader output", bl, 1, rc,onwrite,errnoval); + } ++static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev, ++ const struct timeval *requested_abs, int rc) ++{ ++ libxl__bootloader_state *bl = CONTAINER_OF(ev, *bl, time); ++ STATE_AO_GC(bl->ao); ++ ++ libxl__ev_time_deregister(gc, &bl->time); ++ ++ assert(libxl__ev_child_inuse(&bl->child)); ++ LOGD(ERROR, bl->domid, "killing bootloader because of timeout"); ++ ++ libxl__ev_child_kill_deregister(ao, &bl->child, SIGKILL); ++ ++ bootloader_callback(egc, bl, rc); ++} + + static void bootloader_domaindeath(libxl__egc *egc, + libxl__domaindeathcheck *dc, +@@ -718,6 +757,7 @@ static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child, + STATE_AO_GC(bl->ao); + int rc; + ++ libxl__ev_time_deregister(gc, &bl->time); + libxl__datacopier_kill(&bl->keystrokes); + libxl__datacopier_kill(&bl->display); + +diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h +index 8415d1feed16..a9581289f462 100644 +--- a/tools/libs/light/libxl_internal.h ++++ b/tools/libs/light/libxl_internal.h +@@ -103,6 +103,7 @@ + #define LIBXL_QMP_CMD_TIMEOUT 10 + #define LIBXL_STUBDOM_START_TIMEOUT 30 + #define LIBXL_QEMU_BODGE_TIMEOUT 2 ++#define LIBXL_BOOTLOADER_TIMEOUT 120 + #define LIBXL_XENCONSOLE_LIMIT 1048576 + #define LIBXL_XENCONSOLE_PROTOCOL "vt100" + #define LIBXL_MAXMEM_CONSTANT 1024 +@@ -3738,6 +3739,7 @@ struct libxl__bootloader_state { + libxl__openpty_state openpty; + libxl__openpty_result ptys[2]; /* [0] is for bootloader */ + libxl__ev_child child; ++ libxl__ev_time time; + libxl__domaindeathcheck deathcheck; + int nargs, argsspace; + const char **args; +-- +2.42.0 + diff --git a/xsa444-4.16-1.patch b/xsa444-4.16-1.patch new file mode 100644 index 0000000..ca20f96 --- /dev/null +++ b/xsa444-4.16-1.patch @@ -0,0 +1,93 @@ +From: Andrew Cooper +Subject: x86/svm: Fix asymmetry with AMD DR MASK context switching + +The handling of MSR_DR{0..3}_MASK is asymmetric between PV and HVM guests. + +HVM guests context switch in based on the guest view of DBEXT, whereas PV +guest switch in base on the host capability. Both guest types leave the +context dirty for the next vCPU. + +This leads to the following issue: + + * PV or HVM guest has debugging active (%dr7 + mask) + * Switch-out deactivates %dr7 but leaves other state stale in hardware + * Another HVM guest with masks unavailable has debugging active + * Switch in loads %dr7 but leaves the mask MSRs alone + +Now, the second guest's vCPU is operating in the context of the prior vCPU's +mask MSR, while the environment the vCPU can see says there are no mask MSRs. + +As a stopgap, adjust the HVM path to switch in the masks based on host +capabilities rather than guest visibility (i.e. like the PV path). Adjustment +of the intercepts still needs to be dependent on the guest visibility of +DBEXT. + +This is part of XSA-444 / CVE-2023-34327 + +Fixes: c097f54912d3 ("x86/SVM: support data breakpoint extension registers") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c +index a019d196e071..ba4069f9100a 100644 +--- a/xen/arch/x86/hvm/svm/svm.c ++++ b/xen/arch/x86/hvm/svm/svm.c +@@ -185,6 +185,10 @@ static void svm_save_dr(struct vcpu *v) + v->arch.hvm.flag_dr_dirty = 0; + vmcb_set_dr_intercepts(vmcb, ~0u); + ++ /* ++ * The guest can only have changed the mask MSRs if we previous dropped ++ * intercepts. Re-read them from hardware. ++ */ + if ( v->domain->arch.cpuid->extd.dbext ) + { + svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_RW); +@@ -216,17 +220,25 @@ static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v) + + ASSERT(v == current); + +- if ( v->domain->arch.cpuid->extd.dbext ) ++ /* ++ * Both the PV and HVM paths leave stale DR_MASK values in hardware on ++ * context-switch-out. If we're activating %dr7 for the guest, we must ++ * sync the DR_MASKs too, whether or not the guest can see them. ++ */ ++ if ( boot_cpu_has(X86_FEATURE_DBEXT) ) + { +- svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE); +- + wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, v->arch.msrs->dr_mask[0]); + wrmsrl(MSR_AMD64_DR1_ADDRESS_MASK, v->arch.msrs->dr_mask[1]); + wrmsrl(MSR_AMD64_DR2_ADDRESS_MASK, v->arch.msrs->dr_mask[2]); + wrmsrl(MSR_AMD64_DR3_ADDRESS_MASK, v->arch.msrs->dr_mask[3]); ++ ++ if ( v->domain->arch.cpuid->extd.dbext ) ++ { ++ svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE); ++ } + } + + write_debugreg(0, v->arch.dr[0]); +diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c +index f7992ff230b5..a142a63dd869 100644 +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -2314,6 +2314,11 @@ void activate_debugregs(const struct vcpu *curr) + if ( curr->arch.dr7 & DR7_ACTIVE_MASK ) + write_debugreg(7, curr->arch.dr7); + ++ /* ++ * Both the PV and HVM paths leave stale DR_MASK values in hardware on ++ * context-switch-out. If we're activating %dr7 for the guest, we must ++ * sync the DR_MASKs too, whether or not the guest can see them. ++ */ + if ( boot_cpu_has(X86_FEATURE_DBEXT) ) + { + wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, curr->arch.msrs->dr_mask[0]); diff --git a/xsa444-4.16-2.patch b/xsa444-4.16-2.patch new file mode 100644 index 0000000..b296edf --- /dev/null +++ b/xsa444-4.16-2.patch @@ -0,0 +1,72 @@ +From: Andrew Cooper +Subject: x86/pv: Correct the auditing of guest breakpoint addresses + +The use of access_ok() is buggy, because it permits access to the compat +translation area. 64bit PV guests don't use the XLAT area, but on AMD +hardware, the DBEXT feature allows a breakpoint to match up to a 4G aligned +region, allowing the breakpoint to reach outside of the XLAT area. + +Prior to c/s cda16c1bb223 ("x86: mirror compat argument translation area for +32-bit PV"), the live GDT was within 4G of the XLAT area. + +All together, this allowed a malicious 64bit PV guest on AMD hardware to place +a breakpoint over the live GDT, and trigger a #DB livelock (CVE-2015-8104). + +Introduce breakpoint_addr_ok() and explain why __addr_ok() happens to be an +appropriate check in this case. + +For Xen 4.14 and later, this is a latent bug because the XLAT area has moved +to be on its own with nothing interesting adjacent. For Xen 4.13 and older on +AMD hardware, this fixes a PV-trigger-able DoS. + +This is part of XSA-444 / CVE-2023-34328. + +Fixes: 65e355490817 ("x86/PV: support data breakpoint extension registers") +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c +index 5dade2472687..681c16108fd1 100644 +--- a/xen/arch/x86/pv/misc-hypercalls.c ++++ b/xen/arch/x86/pv/misc-hypercalls.c +@@ -68,7 +68,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) + switch ( reg ) + { + case 0 ... 3: +- if ( !access_ok(value, sizeof(long)) ) ++ if ( !breakpoint_addr_ok(value) ) + return -EPERM; + + v->arch.dr[reg] = value; +diff --git a/xen/include/asm-x86/debugreg.h b/xen/include/asm-x86/debugreg.h +index c57914efc6e8..cc298265244b 100644 +--- a/xen/include/asm-x86/debugreg.h ++++ b/xen/include/asm-x86/debugreg.h +@@ -77,6 +77,26 @@ + asm volatile ( "mov %%db" #reg ",%0" : "=r" (__val) ); \ + __val; \ + }) ++ ++/* ++ * Architecturally, %dr{0..3} can have any arbitrary value. However, Xen ++ * can't allow the guest to breakpoint the Xen address range, so we limit the ++ * guest to the lower canonical half, or above the Xen range in the higher ++ * canonical half. ++ * ++ * Breakpoint lengths are specified to mask the low order address bits, ++ * meaning all breakpoints are naturally aligned. With %dr7, the widest ++ * breakpoint is 8 bytes. With DBEXT, the widest breakpoint is 4G. Both of ++ * the Xen boundaries have >4G alignment. ++ * ++ * In principle we should account for HYPERVISOR_COMPAT_VIRT_START(d), but ++ * 64bit Xen has never enforced this for compat guests, and there's no problem ++ * (to Xen) if the guest breakpoints it's alias of the M2P. Skipping this ++ * aspect simplifies the logic, and causes us not to reject a migrating guest ++ * which operated fine on prior versions of Xen. ++ */ ++#define breakpoint_addr_ok(a) __addr_ok(a) ++ + long set_debugreg(struct vcpu *, unsigned int reg, unsigned long value); + void activate_debugregs(const struct vcpu *); + From b5231bddba35ce2daf5df35532b14017b3cda8a2 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 14 Nov 2023 22:32:53 +0000 Subject: [PATCH 39/99] 2 security issues x86/AMD: mismatch in IOMMU quarantine page table levels [XSA-445, CVE-2023-46835] x86: BTC/SRSO fixes not fully effective [XSA-446, CVE-2023-46836] --- xen.spec | 11 ++++- xsa445-4.17.patch | 63 +++++++++++++++++++++++++ xsa446.patch | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 xsa445-4.17.patch create mode 100644 xsa446.patch diff --git a/xen.spec b/xen.spec index fde47fb..1845570 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.17.2 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -139,6 +139,8 @@ Patch74: xsa443-4.17-10.patch Patch75: xsa443-4.17-11.patch Patch76: xsa444-4.17-1.patch Patch77: xsa444-4.17-2.patch +Patch78: xsa445-4.17.patch +Patch79: xsa446.patch %if %build_qemutrad @@ -382,6 +384,8 @@ manage Xen virtual machines. %patch 75 -p1 %patch 76 -p1 %patch 77 -p1 +%patch 78 -p1 +%patch 79 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -989,6 +993,11 @@ fi %endif %changelog +* Tue Nov 14 2023 Michael Young - 4.17.2-5 +- x86/AMD: mismatch in IOMMU quarantine page table levels [XSA-445, + CVE-2023-46835] +- x86: BTC/SRSO fixes not fully effective [XSA-446, CVE-2023-46836] + * Tue Oct 10 2023 Michael Young - 4.17.2-4 - xenstored: A transaction conflict can crash C Xenstored [XSA-440, CVE-2023-34323] diff --git a/xsa445-4.17.patch b/xsa445-4.17.patch new file mode 100644 index 0000000..db66d7c --- /dev/null +++ b/xsa445-4.17.patch @@ -0,0 +1,63 @@ +From a43127d4f1f9a364334fe16b6239c211b35fd238 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Wed, 11 Oct 2023 13:14:21 +0200 +Subject: [PATCH] iommu/amd-vi: use correct level for quarantine domain page + tables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current setup of the quarantine page tables assumes that the quarantine +domain (dom_io) has been initialized with an address width of +DEFAULT_DOMAIN_ADDRESS_WIDTH (48). + +However dom_io being a PV domain gets the AMD-Vi IOMMU page tables levels based +on the maximum (hot pluggable) RAM address, and hence on systems with no RAM +above the 512GB mark only 3 page-table levels are configured in the IOMMU. + +On systems without RAM above the 512GB boundary amd_iommu_quarantine_init() +will setup page tables for the scratch page with 4 levels, while the IOMMU will +be configured to use 3 levels only. The page destined to be used as level 1, +and to contain a directory of PTEs ends up being the address in a PTE itself, +and thus level 1 page becomes the leaf page. Without the level mismatch it's +level 0 page that should be the leaf page instead. + +The level 1 page won't be used as such, and hence it's not possible to use it +to gain access to other memory on the system. However that page is not cleared +in amd_iommu_quarantine_init() as part of re-initialization of the device +quarantine page tables, and hence data on the level 1 page can be leaked +between device usages. + +Fix this by making sure the paging levels setup by amd_iommu_quarantine_init() +match the number configured on the IOMMUs. + +Note that IVMD regions are not affected by this issue, as those areas are +mapped taking the configured paging levels into account. + +This is XSA-445 / CVE-2023-46835 + +Fixes: ea38867831da ('x86 / iommu: set up a scratch page in the quarantine domain') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/drivers/passthrough/amd/iommu_map.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/xen/drivers/passthrough/amd/iommu_map.c b/xen/drivers/passthrough/amd/iommu_map.c +index 993bac6f8878..e0f4fe736a8d 100644 +--- a/xen/drivers/passthrough/amd/iommu_map.c ++++ b/xen/drivers/passthrough/amd/iommu_map.c +@@ -837,9 +837,7 @@ static int fill_qpt(union amd_iommu_pte *this, unsigned int level, + int cf_check amd_iommu_quarantine_init(struct pci_dev *pdev, bool scratch_page) + { + struct domain_iommu *hd = dom_iommu(dom_io); +- unsigned long end_gfn = +- 1ul << (DEFAULT_DOMAIN_ADDRESS_WIDTH - PAGE_SHIFT); +- unsigned int level = amd_iommu_get_paging_mode(end_gfn); ++ unsigned int level = hd->arch.amd.paging_mode; + unsigned int req_id = get_dma_requestor_id(pdev->seg, pdev->sbdf.bdf); + const struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg); + int rc; +-- +2.42.0 + diff --git a/xsa446.patch b/xsa446.patch new file mode 100644 index 0000000..acf1d0f --- /dev/null +++ b/xsa446.patch @@ -0,0 +1,115 @@ +From 80d5aada598c3a800a350003d5d582931545e13c Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Thu, 26 Oct 2023 14:37:38 +0100 +Subject: [PATCH] x86/spec-ctrl: Remove conditional IRQs-on-ness for INT + $0x80/0x82 paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before speculation defences, some paths in Xen could genuinely get away with +being IRQs-on at entry. But XPTI invalidated this property on most paths, and +attempting to maintain it on the remaining paths was a mistake. + +Fast forward, and DO_SPEC_CTRL_COND_IBPB (protection for AMD BTC/SRSO) is not +IRQ-safe, running with IRQs enabled in some cases. The other actions taken on +these paths happen to be IRQ-safe. + +Make entry_int82() and int80_direct_trap() unconditionally Interrupt Gates +rather than Trap Gates. Remove the conditional re-adjustment of +int80_direct_trap() in smp_prepare_cpus(), and have entry_int82() explicitly +enable interrupts when safe to do so. + +In smp_prepare_cpus(), with the conditional re-adjustment removed, the +clearing of pv_cr3 is the only remaining action gated on XPTI, and it is out +of place anyway, repeating work already done by smp_prepare_boot_cpu(). Drop +the entire if() condition to avoid leaving an incorrect vestigial remnant. + +Also drop comments which make incorrect statements about when its safe to +enable interrupts. + +This is XSA-446 / CVE-2023-46836 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +--- + xen/arch/x86/pv/traps.c | 4 ++-- + xen/arch/x86/smpboot.c | 14 -------------- + xen/arch/x86/x86_64/compat/entry.S | 2 ++ + xen/arch/x86/x86_64/entry.S | 1 - + 4 files changed, 4 insertions(+), 17 deletions(-) + +diff --git a/xen/arch/x86/pv/traps.c b/xen/arch/x86/pv/traps.c +index 74f333da7e1c..240d1a2db7a3 100644 +--- a/xen/arch/x86/pv/traps.c ++++ b/xen/arch/x86/pv/traps.c +@@ -139,11 +139,11 @@ void __init pv_trap_init(void) + #ifdef CONFIG_PV32 + /* The 32-on-64 hypercall vector is only accessible from ring 1. */ + _set_gate(idt_table + HYPERCALL_VECTOR, +- SYS_DESC_trap_gate, 1, entry_int82); ++ SYS_DESC_irq_gate, 1, entry_int82); + #endif + + /* Fast trap for int80 (faster than taking the #GP-fixup path). */ +- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_trap_gate, 3, ++ _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3, + &int80_direct_trap); + + open_softirq(NMI_SOFTIRQ, nmi_softirq); +diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c +index 3a1a659082c6..4c54ecbc91d7 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -1158,20 +1158,6 @@ void __init smp_prepare_cpus(void) + + stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1)); + +- if ( opt_xpti_hwdom || opt_xpti_domu ) +- { +- get_cpu_info()->pv_cr3 = 0; +- +-#ifdef CONFIG_PV +- /* +- * All entry points which may need to switch page tables have to start +- * with interrupts off. Re-write what pv_trap_init() has put there. +- */ +- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3, +- &int80_direct_trap); +-#endif +- } +- + set_nr_sockets(); + + socket_cpumask = xzalloc_array(cpumask_t *, nr_sockets); +diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S +index bd5abd8040bd..fcc3a721f147 100644 +--- a/xen/arch/x86/x86_64/compat/entry.S ++++ b/xen/arch/x86/x86_64/compat/entry.S +@@ -21,6 +21,8 @@ ENTRY(entry_int82) + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ + /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ + ++ sti ++ + CR4_PV32_RESTORE + + GET_CURRENT(bx) +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 5ca74f5f62b2..9a7b129aa7e4 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -327,7 +327,6 @@ ENTRY(sysenter_entry) + #ifdef CONFIG_XEN_SHSTK + ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK + #endif +- /* sti could live here when we don't switch page tables below. */ + pushq $FLAT_USER_SS + pushq $0 + pushfq + +base-commit: 7befef87cc9b1bb8ca15d866ce1ecd9165ccb58c +prerequisite-patch-id: 142a87c707411d49e136c3fb76f1b14963ec6dc8 +-- +2.30.2 + From 5813d5853aa3e2e616b53a60472ee6125b000589 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 15 Nov 2023 20:40:53 +0000 Subject: [PATCH 40/99] 2 security issues x86/AMD: mismatch in IOMMU quarantine page table levels [XSA-445, CVE-2023-46835] x86: BTC/SRSO fixes not fully effective [XSA-446, CVE-2023-46836] --- xen.spec | 11 ++++- xsa445-4.16.patch | 65 ++++++++++++++++++++++++++ xsa446.patch | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 xsa445-4.16.patch create mode 100644 xsa446.patch diff --git a/xen.spec b/xen.spec index ee3bae8..456aba3 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.16.5 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -138,6 +138,8 @@ Patch70: xsa443-4.16-10.patch Patch71: xsa443-4.16-11.patch Patch72: xsa444-4.16-1.patch Patch73: xsa444-4.16-2.patch +Patch74: xsa445-4.16.patch +Patch75: xsa446.patch %if %build_qemutrad @@ -377,6 +379,8 @@ manage Xen virtual machines. %patch71 -p1 %patch72 -p1 %patch73 -p1 +%patch74 -p1 +%patch75 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -985,6 +989,11 @@ fi %endif %changelog +* Wed Nov 15 2023 Michael Young - 4.16.5-4 +- x86/AMD: mismatch in IOMMU quarantine page table levels [XSA-445, + CVE-2023-46835] +- x86: BTC/SRSO fixes not fully effective [XSA-446, CVE-2023-46836] + * Wed Oct 11 2023 Michael Young - 4.16.5-3 - xenstored: A transaction conflict can crash C Xenstored [XSA-440, CVE-2023-34323] diff --git a/xsa445-4.16.patch b/xsa445-4.16.patch new file mode 100644 index 0000000..5b41c3c --- /dev/null +++ b/xsa445-4.16.patch @@ -0,0 +1,65 @@ +From 88fa5b0db062a8f2ccac4ba05ef75768b2b03e5a Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Wed, 11 Oct 2023 13:14:21 +0200 +Subject: [PATCH] iommu/amd-vi: use correct level for quarantine domain page + tables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current setup of the quarantine page tables assumes that the quarantine +domain (dom_io) has been initialized with an address width of +DEFAULT_DOMAIN_ADDRESS_WIDTH (48). + +However dom_io being a PV domain gets the AMD-Vi IOMMU page tables levels based +on the maximum (hot pluggable) RAM address, and hence on systems with no RAM +above the 512GB mark only 3 page-table levels are configured in the IOMMU. + +On systems without RAM above the 512GB boundary amd_iommu_quarantine_init() +will setup page tables for the scratch page with 4 levels, while the IOMMU will +be configured to use 3 levels only. The page destined to be used as level 1, +and to contain a directory of PTEs ends up being the address in a PTE itself, +and thus level 1 page becomes the leaf page. Without the level mismatch it's +level 0 page that should be the leaf page instead. + +The level 1 page won't be used as such, and hence it's not possible to use it +to gain access to other memory on the system. However that page is not cleared +in amd_iommu_quarantine_init() as part of re-initialization of the device +quarantine page tables, and hence data on the level 1 page can be leaked +between device usages. + +Fix this by making sure the paging levels setup by amd_iommu_quarantine_init() +match the number configured on the IOMMUs. + +Note that IVMD regions are not affected by this issue, as those areas are +mapped taking the configured paging levels into account. + +This is XSA-445 / CVE-2023-46835 + +Fixes: ea38867831da ('x86 / iommu: set up a scratch page in the quarantine domain') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/drivers/passthrough/amd/iommu_map.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/xen/drivers/passthrough/amd/iommu_map.c b/xen/drivers/passthrough/amd/iommu_map.c +index cf6f01b633e4..1b414a413b89 100644 +--- a/xen/drivers/passthrough/amd/iommu_map.c ++++ b/xen/drivers/passthrough/amd/iommu_map.c +@@ -654,9 +654,7 @@ static int fill_qpt(union amd_iommu_pte *this, unsigned int level, + int amd_iommu_quarantine_init(struct pci_dev *pdev, bool scratch_page) + { + struct domain_iommu *hd = dom_iommu(dom_io); +- unsigned long end_gfn = +- 1ul << (DEFAULT_DOMAIN_ADDRESS_WIDTH - PAGE_SHIFT); +- unsigned int level = amd_iommu_get_paging_mode(end_gfn); ++ unsigned int level = hd->arch.amd.paging_mode; + unsigned int req_id = get_dma_requestor_id(pdev->seg, pdev->sbdf.bdf); + const struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg); + int rc; + +base-commit: 29efce0f8f10e381417a61f2f9988b40d4f6bcf0 +-- +2.30.2 + diff --git a/xsa446.patch b/xsa446.patch new file mode 100644 index 0000000..acf1d0f --- /dev/null +++ b/xsa446.patch @@ -0,0 +1,115 @@ +From 80d5aada598c3a800a350003d5d582931545e13c Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Thu, 26 Oct 2023 14:37:38 +0100 +Subject: [PATCH] x86/spec-ctrl: Remove conditional IRQs-on-ness for INT + $0x80/0x82 paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before speculation defences, some paths in Xen could genuinely get away with +being IRQs-on at entry. But XPTI invalidated this property on most paths, and +attempting to maintain it on the remaining paths was a mistake. + +Fast forward, and DO_SPEC_CTRL_COND_IBPB (protection for AMD BTC/SRSO) is not +IRQ-safe, running with IRQs enabled in some cases. The other actions taken on +these paths happen to be IRQ-safe. + +Make entry_int82() and int80_direct_trap() unconditionally Interrupt Gates +rather than Trap Gates. Remove the conditional re-adjustment of +int80_direct_trap() in smp_prepare_cpus(), and have entry_int82() explicitly +enable interrupts when safe to do so. + +In smp_prepare_cpus(), with the conditional re-adjustment removed, the +clearing of pv_cr3 is the only remaining action gated on XPTI, and it is out +of place anyway, repeating work already done by smp_prepare_boot_cpu(). Drop +the entire if() condition to avoid leaving an incorrect vestigial remnant. + +Also drop comments which make incorrect statements about when its safe to +enable interrupts. + +This is XSA-446 / CVE-2023-46836 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +--- + xen/arch/x86/pv/traps.c | 4 ++-- + xen/arch/x86/smpboot.c | 14 -------------- + xen/arch/x86/x86_64/compat/entry.S | 2 ++ + xen/arch/x86/x86_64/entry.S | 1 - + 4 files changed, 4 insertions(+), 17 deletions(-) + +diff --git a/xen/arch/x86/pv/traps.c b/xen/arch/x86/pv/traps.c +index 74f333da7e1c..240d1a2db7a3 100644 +--- a/xen/arch/x86/pv/traps.c ++++ b/xen/arch/x86/pv/traps.c +@@ -139,11 +139,11 @@ void __init pv_trap_init(void) + #ifdef CONFIG_PV32 + /* The 32-on-64 hypercall vector is only accessible from ring 1. */ + _set_gate(idt_table + HYPERCALL_VECTOR, +- SYS_DESC_trap_gate, 1, entry_int82); ++ SYS_DESC_irq_gate, 1, entry_int82); + #endif + + /* Fast trap for int80 (faster than taking the #GP-fixup path). */ +- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_trap_gate, 3, ++ _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3, + &int80_direct_trap); + + open_softirq(NMI_SOFTIRQ, nmi_softirq); +diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c +index 3a1a659082c6..4c54ecbc91d7 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -1158,20 +1158,6 @@ void __init smp_prepare_cpus(void) + + stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1)); + +- if ( opt_xpti_hwdom || opt_xpti_domu ) +- { +- get_cpu_info()->pv_cr3 = 0; +- +-#ifdef CONFIG_PV +- /* +- * All entry points which may need to switch page tables have to start +- * with interrupts off. Re-write what pv_trap_init() has put there. +- */ +- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3, +- &int80_direct_trap); +-#endif +- } +- + set_nr_sockets(); + + socket_cpumask = xzalloc_array(cpumask_t *, nr_sockets); +diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S +index bd5abd8040bd..fcc3a721f147 100644 +--- a/xen/arch/x86/x86_64/compat/entry.S ++++ b/xen/arch/x86/x86_64/compat/entry.S +@@ -21,6 +21,8 @@ ENTRY(entry_int82) + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ + /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ + ++ sti ++ + CR4_PV32_RESTORE + + GET_CURRENT(bx) +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 5ca74f5f62b2..9a7b129aa7e4 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -327,7 +327,6 @@ ENTRY(sysenter_entry) + #ifdef CONFIG_XEN_SHSTK + ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK + #endif +- /* sti could live here when we don't switch page tables below. */ + pushq $FLAT_USER_SS + pushq $0 + pushfq + +base-commit: 7befef87cc9b1bb8ca15d866ce1ecd9165ccb58c +prerequisite-patch-id: 142a87c707411d49e136c3fb76f1b14963ec6dc8 +-- +2.30.2 + From 99dc35fd60245cf181511307745ebb02164b6205 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 29 Nov 2023 19:15:48 +0000 Subject: [PATCH 41/99] update to xen-4.18.0 --- .gitignore | 2 +- sources | 2 +- xen.canonicalize.patch | 85 ++-- xen.ocaml5.fixes.patch | 42 +- xen.spec | 72 +-- xsa437.patch | 110 ----- xsa438-4.17.patch | 416 ------------------ ...enbleed-check-to-models-good-ucode-i.patch | 49 --- ...x-confusion-between-SPEC_CTRL_EXIT_T.patch | 77 ---- ...ld-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch | 88 ---- ...rn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch | 86 ---- ...prove-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch | 109 ----- ...-restore_all_xen-to-hold-stack_end-i.patch | 77 ---- ...the-IST-ness-of-an-entry-for-the-exi.patch | 112 ----- ...rl-Issue-VERW-during-IST-exit-to-Xen.patch | 92 ---- ...troduce-is_zen-1-2-_uarch-predicates.patch | 94 ---- ...c-ctrl-Mitigate-the-Zen1-DIV-leakage.patch | 231 ---------- xsa440-4.17.patch | 58 --- xsa442-4.17.patch | 185 -------- xsa443-4.17-01.patch | 70 --- xsa443-4.17-02.patch | 32 -- xsa443-4.17-03.patch | 137 ------ xsa443-4.17-04.patch | 61 --- xsa443-4.17-05.patch | 59 --- xsa443-4.17-06.patch | 65 --- xsa443-4.17-07.patch | 105 ----- xsa443-4.17-08.patch | 126 ------ xsa443-4.17-09.patch | 307 ------------- xsa443-4.17-10.patch | 250 ----------- xsa443-4.17-11.patch | 157 ------- xsa444-4.17-1.patch | 93 ---- xsa444-4.17-2.patch | 72 --- xsa445-4.17.patch | 63 --- xsa446.patch | 115 ----- 34 files changed, 65 insertions(+), 3634 deletions(-) delete mode 100644 xsa437.patch delete mode 100644 xsa438-4.17.patch delete mode 100644 xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch delete mode 100644 xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch delete mode 100644 xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch delete mode 100644 xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch delete mode 100644 xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch delete mode 100644 xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch delete mode 100644 xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch delete mode 100644 xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch delete mode 100644 xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch delete mode 100644 xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch delete mode 100644 xsa440-4.17.patch delete mode 100644 xsa442-4.17.patch delete mode 100644 xsa443-4.17-01.patch delete mode 100644 xsa443-4.17-02.patch delete mode 100644 xsa443-4.17-03.patch delete mode 100644 xsa443-4.17-04.patch delete mode 100644 xsa443-4.17-05.patch delete mode 100644 xsa443-4.17-06.patch delete mode 100644 xsa443-4.17-07.patch delete mode 100644 xsa443-4.17-08.patch delete mode 100644 xsa443-4.17-09.patch delete mode 100644 xsa443-4.17-10.patch delete mode 100644 xsa443-4.17-11.patch delete mode 100644 xsa444-4.17-1.patch delete mode 100644 xsa444-4.17-2.patch delete mode 100644 xsa445-4.17.patch delete mode 100644 xsa446.patch diff --git a/.gitignore b/.gitignore index e0e02a4..7c63a9b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.17.2.tar.gz +/xen-4.18.0.tar.gz diff --git a/sources b/sources index 730c9d1..1aaa8a6 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.17.2.tar.gz) = 0bc475483676e4aa27735695f9a8d2821059e7a55984adb8a29badb5c09a4e7cf8ea29cbc9691be616cc0d7a5ee6b6dacc59ba29c2b16e0919ebdf7dfc54201a +SHA512 (xen-4.18.0.tar.gz) = 4cc9fd155144045a173c5f8ecc45f149817f1034eec618cb6f8b0494ef2fb5b95c4c60cf0bf4bec4bef8a622c35b6a3cb7dedc38e6d95e726f1611c73ddb3273 diff --git a/xen.canonicalize.patch b/xen.canonicalize.patch index f3ae37d..45fa724 100644 --- a/xen.canonicalize.patch +++ b/xen.canonicalize.patch @@ -1,45 +1,54 @@ ---- xen-4.9.0-rc1.2/tools/xenstore/xenstored_watch.c.orig 2017-04-12 16:18:57.000000000 +0100 -+++ xen-4.9.0-rc1.2/tools/xenstore/xenstored_watch.c 2017-04-13 21:17:12.255231094 +0100 -@@ -215,7 +215,7 @@ - goto inval; - } else { - *relative = !strstarts(*path, "/"); -- *path = canonicalize(conn, ctx, *path); -+ *path = xenstore_canonicalize(conn, ctx, *path); - if (!*path) - return errno; - if (!is_valid_nodename(*path)) -@@ -305,7 +305,7 @@ +--- xen-4.18.0-rc1/tools/xenstored/watch.c.orig 2023-09-29 09:09:29.000000000 +0100 ++++ xen-4.18.0-rc1/tools/xenstored/watch.c 2023-10-02 16:12:14.971264769 +0100 +@@ -164,7 +164,7 @@ + const char **path, bool *relative) + { + *relative = !strstarts(*path, "/") && !strstarts(*path, "@"); +- *path = canonicalize(conn, ctx, *path, true); ++ *path = xenstore_canonicalize(conn, ctx, *path, true); + + return *path ? 0 : errno; + } +@@ -250,7 +250,7 @@ if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) return EINVAL; -- node = canonicalize(conn, ctx, vec[0]); -+ node = xenstore_canonicalize(conn, ctx, vec[0]); +- node = canonicalize(conn, ctx, vec[0], true); ++ node = xenstore_canonicalize(conn, ctx, vec[0], true); if (!node) - return ENOMEM; + return errno; list_for_each_entry(watch, &conn->watches, list) { ---- xen-4.9.0-rc1.2/tools/xenstore/xenstored_core.c.orig 2017-04-12 16:18:57.000000000 +0100 -+++ xen-4.9.0-rc1.2/tools/xenstore/xenstored_core.c 2017-04-13 21:19:35.668429881 +0100 -@@ -777,7 +777,7 @@ +--- xen-4.18.0-rc1/tools/xenstored/core.c.orig 2023-09-29 09:09:29.000000000 +0100 ++++ xen-4.18.0-rc1/tools/xenstored/core.c 2023-10-02 16:12:14.993264626 +0100 +@@ -1249,7 +1249,7 @@ return strings; } --char *canonicalize(struct connection *conn, const void *ctx, const char *node) -+char *xenstore_canonicalize(struct connection *conn, const void *ctx, const char *node) +-const char *canonicalize(struct connection *conn, const void *ctx, ++const char *xenstore_canonicalize(struct connection *conn, const void *ctx, + const char *node, bool allow_special) { - const char *prefix; + const char *name; +@@ -1303,7 +1303,7 @@ + { + struct node *node; -@@ -874,7 +874,7 @@ - - if (!canonical_name) - canonical_name = &tmp_name; -- *canonical_name = canonicalize(conn, ctx, name); -+ *canonical_name = xenstore_canonicalize(conn, ctx, name); +- *canonical_name = canonicalize(conn, ctx, name, allow_special); ++ *canonical_name = xenstore_canonicalize(conn, ctx, name, allow_special); if (!*canonical_name) return NULL; - return get_node(conn, ctx, *canonical_name, perm); ---- xen-4.8.0/tools/console/testsuite/console-dom0.c.orig 2016-12-05 12:03:27.000000000 +0000 -+++ xen-4.8.0/tools/console/testsuite/console-dom0.c 2017-02-26 21:52:24.554678631 +0000 + +@@ -1320,7 +1320,7 @@ + const char *tmp_name; + const struct node *node; + +- tmp_name = canonicalize(conn, ctx, name, allow_special); ++ tmp_name = xenstore_canonicalize(conn, ctx, name, allow_special); + if (!tmp_name) + return NULL; + +--- xen-4.18.0-rc1/tools/console/testsuite/console-dom0.c.orig 2023-09-29 09:09:29.000000000 +0100 ++++ xen-4.18.0-rc1/tools/console/testsuite/console-dom0.c 2023-10-02 16:12:15.001264574 +0100 @@ -18,7 +18,7 @@ } } @@ -76,8 +85,8 @@ fprintf(stderr, "%s", line); } while (strcmp(line, "Okay.\n") != 0); ---- xen-4.8.0/tools/console/testsuite/console-domU.c.orig 2016-12-05 12:03:27.000000000 +0000 -+++ xen-4.8.0/tools/console/testsuite/console-domU.c 2017-02-26 21:52:50.320622804 +0000 +--- xen-4.18.0-rc1/tools/console/testsuite/console-domU.c.orig 2023-09-29 09:09:29.000000000 +0100 ++++ xen-4.18.0-rc1/tools/console/testsuite/console-domU.c 2023-10-02 16:12:15.008264528 +0100 @@ -6,7 +6,7 @@ #include #include @@ -96,14 +105,14 @@ seed = strtoul(line, 0, 0); printf("Seed Okay.\n"); fflush(stdout); ---- xen-4.14.1/tools/xenstore/xenstored_core.h.orig 2020-12-17 16:47:25.000000000 +0000 -+++ xen-4.14.1/tools/xenstore/xenstored_core.h 2020-12-17 20:13:10.806887309 +0000 -@@ -153,7 +153,7 @@ +--- xen-4.18.0-rc1/tools/xenstored/core.h.orig 2023-09-29 09:09:29.000000000 +0100 ++++ xen-4.18.0-rc1/tools/xenstored/core.h 2023-10-02 16:12:15.015264482 +0100 +@@ -240,7 +240,7 @@ void send_ack(struct connection *conn, enum xsd_sockmsg_type type); /* Canonicalize this path if possible. */ --char *canonicalize(struct connection *conn, const void *ctx, const char *node); -+char *xenstore_canonicalize(struct connection *conn, const void *ctx, const char *node); +-const char *canonicalize(struct connection *conn, const void *ctx, ++const char *xenstore_canonicalize(struct connection *conn, const void *ctx, + const char *node, bool allow_special); /* Get access permissions. */ - unsigned int perm_for_conn(struct connection *conn, diff --git a/xen.ocaml5.fixes.patch b/xen.ocaml5.fixes.patch index 2191334..bdffd4c 100644 --- a/xen.ocaml5.fixes.patch +++ b/xen.ocaml5.fixes.patch @@ -13,36 +13,6 @@ VERSION := 4.1 ---- xen-4.17.1/tools/ocaml/libs/xentoollog/xentoollog_stubs.c.orig 2023-04-27 06:53:19.000000000 -0600 -+++ xen-4.17.1/tools/ocaml/libs/xentoollog/xentoollog_stubs.c 2023-06-20 09:04:30.375263358 -0600 -@@ -33,7 +33,7 @@ - - /* The following is equal to the CAMLreturn macro, but without the return */ - #define CAMLdone do{ \ --caml_local_roots = caml__frame; \ -+CAML_LOCAL_ROOTS = caml__frame; \ - }while (0) - - #define XTL ((xentoollog_logger *) Xtl_val(handle)) ---- xen-4.17.1/tools/ocaml/libs/xl/xenlight_stubs.c.orig 2023-04-27 06:53:19.000000000 -0600 -+++ xen-4.17.1/tools/ocaml/libs/xl/xenlight_stubs.c 2023-06-20 09:34:09.550454354 -0600 -@@ -43,14 +43,14 @@ - #ifndef CAMLreturnT - #define CAMLreturnT(type, result) do { \ - type caml__temp_result = (result); \ -- caml_local_roots = caml__frame; \ -+ CAML_LOCAL_ROOTS = caml__frame; \ - return (caml__temp_result); \ - } while (0) - #endif - - /* The following is equal to the CAMLreturn macro, but without the return */ - #define CAMLdone do{ \ --caml_local_roots = caml__frame; \ -+CAML_LOCAL_ROOTS = caml__frame; \ - }while (0) - - #define Ctx_val(x)(*((libxl_ctx **) Data_custom_val(x))) --- xen-4.17.1/tools/ocaml/Makefile.rules.orig 2023-04-27 06:53:19.000000000 -0600 +++ xen-4.17.1/tools/ocaml/Makefile.rules 2023-06-20 10:00:58.769235173 -0600 @@ -59,9 +59,9 @@ quiet-command = $(if $(V),$1,@printf " % @@ -60,11 +30,11 @@ --- xen-4.17.1/tools/ocaml/xenstored/disk.ml.orig 2023-04-27 06:53:19.000000000 -0600 +++ xen-4.17.1/tools/ocaml/xenstored/disk.ml 2023-06-20 09:49:44.361963710 -0600 @@ -30,7 +30,7 @@ let undec c = - | _ -> raise (Failure "undecify") + | _ -> raise (Failure "undecify") let unhex c = -- let c = Char.lowercase c in -+ let c = Char.lowercase_ascii c in - match c with - | '0' .. '9' -> (Char.code c) - (Char.code '0') - | 'a' .. 'f' -> (Char.code c) - (Char.code 'a') + 10 +- let c = Char.lowercase c in ++ let c = Char.lowercase_ascii c in + match c with + | '0' .. '9' -> (Char.code c) - (Char.code '0') + | 'a' .. 'f' -> (Char.code c) - (Char.code 'a') + 10 diff --git a/xen.spec b/xen.spec index 1845570..07bb3d2 100644 --- a/xen.spec +++ b/xen.spec @@ -50,12 +50,12 @@ %endif # Hypervisor ABI -%define hv_abi 4.17 +%define hv_abi 4.18 Summary: Xen is a virtual machine monitor Name: xen -Version: 4.17.2 -Release: 5%{?dist} +Version: 4.18.0 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,35 +112,6 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch -Patch51: xsa437.patch -Patch52: xsa438-4.17.patch -Patch53: xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch -Patch54: xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch -Patch55: xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch -Patch56: xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch -Patch57: xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch -Patch58: xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch -Patch59: xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch -Patch60: xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch -Patch61: xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch -Patch62: xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch -Patch63: xsa440-4.17.patch -Patch64: xsa442-4.17.patch -Patch65: xsa443-4.17-01.patch -Patch66: xsa443-4.17-02.patch -Patch67: xsa443-4.17-03.patch -Patch68: xsa443-4.17-04.patch -Patch69: xsa443-4.17-05.patch -Patch70: xsa443-4.17-06.patch -Patch71: xsa443-4.17-07.patch -Patch72: xsa443-4.17-08.patch -Patch73: xsa443-4.17-09.patch -Patch74: xsa443-4.17-10.patch -Patch75: xsa443-4.17-11.patch -Patch76: xsa444-4.17-1.patch -Patch77: xsa444-4.17-2.patch -Patch78: xsa445-4.17.patch -Patch79: xsa446.patch %if %build_qemutrad @@ -357,35 +328,6 @@ manage Xen virtual machines. %if "%dist" != ".fc38" %patch 50 -p1 %endif -%patch 51 -p1 -%patch 52 -p1 -%patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 -%patch 57 -p1 -%patch 58 -p1 -%patch 59 -p1 -%patch 60 -p1 -%patch 61 -p1 -%patch 62 -p1 -%patch 63 -p1 -%patch 64 -p1 -%patch 65 -p1 -%patch 66 -p1 -%patch 67 -p1 -%patch 68 -p1 -%patch 69 -p1 -%patch 70 -p1 -%patch 71 -p1 -%patch 72 -p1 -%patch 73 -p1 -%patch 74 -p1 -%patch 75 -p1 -%patch 76 -p1 -%patch 77 -p1 -%patch 78 -p1 -%patch 79 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -737,7 +679,6 @@ fi #files -f xen-xm.lang %files %doc COPYING README -%{_bindir}/xencons %{python3_sitearch}/%{name} %{python3_sitearch}/xen-*.egg-info @@ -993,6 +934,13 @@ fi %endif %changelog +* Wed Nov 29 2023 Michael Young - 4.18.0-1 +- update to xen-4.18.0 + rebase xen.canonicalize.patch and xen.ocaml5.fixes.patch + remove or adjust patches now included or superceded upstream +- xencons has been dropped + + * Tue Nov 14 2023 Michael Young - 4.17.2-5 - x86/AMD: mismatch in IOMMU quarantine page table levels [XSA-445, CVE-2023-46835] diff --git a/xsa437.patch b/xsa437.patch deleted file mode 100644 index 18c9f8f..0000000 --- a/xsa437.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 7fac5971340a13ca9458195305bcfe14df2e52d2 Mon Sep 17 00:00:00 2001 -From: Stefano Stabellini -Date: Thu, 17 Aug 2023 13:41:35 +0100 -Subject: [PATCH] xen/arm: page: Handle cache flush of an element at the top of - the address space - -The region that needs to be cleaned/invalidated may be at the top -of the address space. This means that 'end' (i.e. 'p + size') will -be 0 and therefore nothing will be cleaned/invalidated as the check -in the loop will always be false. - -On Arm64, we only support we only support up to 48-bit Virtual -address space. So this is not a concern there. However, for 32-bit, -the mapcache is using the last 2GB of the address space. Therefore -we may not clean/invalidate properly some pages. This could lead -to memory corruption or data leakage (the scrubbed value may -still sit in the cache when the guest could read directly the memory -and therefore read the old content). - -Rework invalidate_dcache_va_range(), clean_dcache_va_range(), -clean_and_invalidate_dcache_va_range() to handle a cache flush -with an element at the top of the address space. - -This is CVE-2023-34321 / XSA-437. - -Reported-by: Julien Grall -Signed-off-by: Stefano Stabellini -Signed-off-by: Julien Grall -Acked-by: Bertrand Marquis - ---- - xen/arch/arm/include/asm/page.h | 33 ++++++++++++++++++++------------- - 1 file changed, 20 insertions(+), 13 deletions(-) - -diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h -index e7cd62190c7f..d7fe770a5e49 100644 ---- a/xen/arch/arm/include/asm/page.h -+++ b/xen/arch/arm/include/asm/page.h -@@ -160,26 +160,25 @@ static inline size_t read_dcache_line_bytes(void) - - static inline int invalidate_dcache_va_range(const void *p, unsigned long size) - { -- const void *end = p + size; - size_t cacheline_mask = dcache_line_bytes - 1; - - dsb(sy); /* So the CPU issues all writes to the range */ - - if ( (uintptr_t)p & cacheline_mask ) - { -+ size -= dcache_line_bytes - ((uintptr_t)p & cacheline_mask); - p = (void *)((uintptr_t)p & ~cacheline_mask); - asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); - p += dcache_line_bytes; - } -- if ( (uintptr_t)end & cacheline_mask ) -- { -- end = (void *)((uintptr_t)end & ~cacheline_mask); -- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (end)); -- } - -- for ( ; p < end; p += dcache_line_bytes ) -+ for ( ; size >= dcache_line_bytes; -+ p += dcache_line_bytes, size -= dcache_line_bytes ) - asm volatile (__invalidate_dcache_one(0) : : "r" (p)); - -+ if ( size > 0 ) -+ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); -+ - dsb(sy); /* So we know the flushes happen before continuing */ - - return 0; -@@ -187,10 +186,14 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) - - static inline int clean_dcache_va_range(const void *p, unsigned long size) - { -- const void *end = p + size; -+ size_t cacheline_mask = dcache_line_bytes - 1; -+ - dsb(sy); /* So the CPU issues all writes to the range */ -- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1)); -- for ( ; p < end; p += dcache_line_bytes ) -+ size += (uintptr_t)p & cacheline_mask; -+ size = (size + cacheline_mask) & ~cacheline_mask; -+ p = (void *)((uintptr_t)p & ~cacheline_mask); -+ for ( ; size >= dcache_line_bytes; -+ p += dcache_line_bytes, size -= dcache_line_bytes ) - asm volatile (__clean_dcache_one(0) : : "r" (p)); - dsb(sy); /* So we know the flushes happen before continuing */ - /* ARM callers assume that dcache_* functions cannot fail. */ -@@ -200,10 +203,14 @@ static inline int clean_dcache_va_range(const void *p, unsigned long size) - static inline int clean_and_invalidate_dcache_va_range - (const void *p, unsigned long size) - { -- const void *end = p + size; -+ size_t cacheline_mask = dcache_line_bytes - 1; -+ - dsb(sy); /* So the CPU issues all writes to the range */ -- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1)); -- for ( ; p < end; p += dcache_line_bytes ) -+ size += (uintptr_t)p & cacheline_mask; -+ size = (size + cacheline_mask) & ~cacheline_mask; -+ p = (void *)((uintptr_t)p & ~cacheline_mask); -+ for ( ; size >= dcache_line_bytes; -+ p += dcache_line_bytes, size -= dcache_line_bytes ) - asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); - dsb(sy); /* So we know the flushes happen before continuing */ - /* ARM callers assume that dcache_* functions cannot fail. */ --- -2.40.1 - diff --git a/xsa438-4.17.patch b/xsa438-4.17.patch deleted file mode 100644 index 12d6ec7..0000000 --- a/xsa438-4.17.patch +++ /dev/null @@ -1,416 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: defer releasing of PV's top-level shadow reference - -sh_set_toplevel_shadow() re-pinning the top-level shadow we may be -running on is not enough (and at the same time unnecessary when the -shadow isn't what we're running on): That shadow becomes eligible for -blowing away (from e.g. shadow_prealloc()) immediately after the -paging lock was dropped. Yet it needs to remain valid until the actual -page table switch occurred. - -Propagate up the call chain the shadow entry that needs releasing -eventually, and carry out the release immediately after switching page -tables. Handle update_cr3() failures by switching to idle pagetables. -Note that various further uses of update_cr3() are HVM-only or only act -on paused vCPU-s, in which case sh_set_toplevel_shadow() will not defer -releasing of the reference. - -While changing the update_cr3() hook, also convert the "do_locking" -parameter to boolean. - -This is CVE-2023-34322 / XSA-438. - -Reported-by: Tim Deegan -Signed-off-by: Jan Beulich -Reviewed-by: George Dunlap - ---- a/xen/arch/x86/include/asm/mm.h -+++ b/xen/arch/x86/include/asm/mm.h -@@ -552,7 +552,7 @@ void audit_domains(void); - #endif - - void make_cr3(struct vcpu *v, mfn_t mfn); --void update_cr3(struct vcpu *v); -+pagetable_t update_cr3(struct vcpu *v); - int vcpu_destroy_pagetables(struct vcpu *); - void *do_page_walk(struct vcpu *v, unsigned long addr); - ---- a/xen/arch/x86/include/asm/paging.h -+++ b/xen/arch/x86/include/asm/paging.h -@@ -138,7 +138,7 @@ struct paging_mode { - paddr_t ga, uint32_t *pfec, - unsigned int *page_order); - #endif -- void (*update_cr3 )(struct vcpu *v, int do_locking, -+ pagetable_t (*update_cr3 )(struct vcpu *v, bool do_locking, - bool noflush); - void (*update_paging_modes )(struct vcpu *v); - bool (*flush_tlb )(const unsigned long *vcpu_bitmap); -@@ -310,9 +310,9 @@ static inline unsigned long paging_ga_to - /* Update all the things that are derived from the guest's CR3. - * Called when the guest changes CR3; the caller can then use v->arch.cr3 - * as the value to load into the host CR3 to schedule this vcpu */ --static inline void paging_update_cr3(struct vcpu *v, bool noflush) -+static inline pagetable_t paging_update_cr3(struct vcpu *v, bool noflush) - { -- paging_get_hostmode(v)->update_cr3(v, 1, noflush); -+ return paging_get_hostmode(v)->update_cr3(v, 1, noflush); - } - - /* Update all the things that are derived from the guest's CR0/CR3/CR4. ---- a/xen/arch/x86/include/asm/shadow.h -+++ b/xen/arch/x86/include/asm/shadow.h -@@ -99,6 +99,9 @@ int shadow_set_allocation(struct domain - - int shadow_get_allocation_bytes(struct domain *d, uint64_t *size); - -+/* Helper to invoke for deferred releasing of a top-level shadow's reference. */ -+void shadow_put_top_level(struct domain *d, pagetable_t old); -+ - #else /* !CONFIG_SHADOW_PAGING */ - - #define shadow_vcpu_teardown(v) ASSERT(is_pv_vcpu(v)) -@@ -121,6 +124,11 @@ static inline void shadow_prepare_page_t - - static inline void shadow_blow_tables_per_domain(struct domain *d) {} - -+static inline void shadow_put_top_level(struct domain *d, pagetable_t old) -+{ -+ ASSERT_UNREACHABLE(); -+} -+ - static inline int shadow_domctl(struct domain *d, - struct xen_domctl_shadow_op *sc, - XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) ---- a/xen/arch/x86/mm/hap/hap.c -+++ b/xen/arch/x86/mm/hap/hap.c -@@ -739,11 +739,13 @@ static bool cf_check hap_invlpg(struct v - return 1; - } - --static void cf_check hap_update_cr3( -- struct vcpu *v, int do_locking, bool noflush) -+static pagetable_t cf_check hap_update_cr3( -+ struct vcpu *v, bool do_locking, bool noflush) - { - v->arch.hvm.hw_cr[3] = v->arch.hvm.guest_cr[3]; - hvm_update_guest_cr3(v, noflush); -+ -+ return pagetable_null(); - } - - static bool flush_vcpu(const struct vcpu *v, const unsigned long *vcpu_bitmap) ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -2590,13 +2590,13 @@ void cf_check shadow_update_paging_modes - } - - /* Set up the top-level shadow and install it in slot 'slot' of shadow_table */ --void sh_set_toplevel_shadow(struct vcpu *v, -- unsigned int slot, -- mfn_t gmfn, -- unsigned int root_type, -- mfn_t (*make_shadow)(struct vcpu *v, -- mfn_t gmfn, -- uint32_t shadow_type)) -+pagetable_t sh_set_toplevel_shadow(struct vcpu *v, -+ unsigned int slot, -+ mfn_t gmfn, -+ unsigned int root_type, -+ mfn_t (*make_shadow)(struct vcpu *v, -+ mfn_t gmfn, -+ uint32_t shadow_type)) - { - mfn_t smfn; - pagetable_t old_entry, new_entry; -@@ -2653,20 +2653,37 @@ void sh_set_toplevel_shadow(struct vcpu - mfn_x(gmfn), mfn_x(pagetable_get_mfn(new_entry))); - v->arch.paging.shadow.shadow_table[slot] = new_entry; - -- /* Decrement the refcount of the old contents of this slot */ -- if ( !pagetable_is_null(old_entry) ) -+ /* -+ * Decrement the refcount of the old contents of this slot, unless -+ * we're still running on that shadow - in that case it'll need holding -+ * on to until the actual page table switch did occur. -+ */ -+ if ( !pagetable_is_null(old_entry) && (v != current || !is_pv_domain(d)) ) - { -- mfn_t old_smfn = pagetable_get_mfn(old_entry); -- /* Need to repin the old toplevel shadow if it's been unpinned -- * by shadow_prealloc(): in PV mode we're still running on this -- * shadow and it's not safe to free it yet. */ -- if ( !mfn_to_page(old_smfn)->u.sh.pinned && !sh_pin(d, old_smfn) ) -- { -- printk(XENLOG_G_ERR "can't re-pin %"PRI_mfn"\n", mfn_x(old_smfn)); -- domain_crash(d); -- } -- sh_put_ref(d, old_smfn, 0); -+ sh_put_ref(d, pagetable_get_mfn(old_entry), 0); -+ old_entry = pagetable_null(); - } -+ -+ /* -+ * 2- and 3-level shadow mode is used for HVM only. Therefore we never run -+ * on such a shadow, so only call sites requesting an L4 shadow need to pay -+ * attention to the returned value. -+ */ -+ ASSERT(pagetable_is_null(old_entry) || root_type == SH_type_l4_64_shadow); -+ -+ return old_entry; -+} -+ -+/* -+ * Helper invoked when releasing of a top-level shadow's reference was -+ * deferred in sh_set_toplevel_shadow() above. -+ */ -+void shadow_put_top_level(struct domain *d, pagetable_t old_entry) -+{ -+ ASSERT(!pagetable_is_null(old_entry)); -+ paging_lock(d); -+ sh_put_ref(d, pagetable_get_mfn(old_entry), 0); -+ paging_unlock(d); - } - - /**************************************************************************/ ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -3224,7 +3224,8 @@ static void cf_check sh_detach_old_table - } - } - --static void cf_check sh_update_cr3(struct vcpu *v, int do_locking, bool noflush) -+static pagetable_t cf_check sh_update_cr3(struct vcpu *v, bool do_locking, -+ bool noflush) - /* Updates vcpu->arch.cr3 after the guest has changed CR3. - * Paravirtual guests should set v->arch.guest_table (and guest_table_user, - * if appropriate). -@@ -3238,6 +3239,7 @@ static void cf_check sh_update_cr3(struc - { - struct domain *d = v->domain; - mfn_t gmfn; -+ pagetable_t old_entry = pagetable_null(); - #if GUEST_PAGING_LEVELS == 3 - const guest_l3e_t *gl3e; - unsigned int i, guest_idx; -@@ -3247,7 +3249,7 @@ static void cf_check sh_update_cr3(struc - if ( !is_hvm_domain(d) && !v->is_initialised ) - { - ASSERT(v->arch.cr3 == 0); -- return; -+ return old_entry; - } - - if ( do_locking ) paging_lock(v->domain); -@@ -3320,11 +3322,12 @@ static void cf_check sh_update_cr3(struc - #if GUEST_PAGING_LEVELS == 4 - if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 ) - guest_flush_tlb_mask(d, d->dirty_cpumask); -- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, sh_make_shadow); -+ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, -+ sh_make_shadow); - if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) - { - ASSERT(d->is_dying || d->is_shutting_down); -- return; -+ return old_entry; - } - if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) ) - { -@@ -3368,24 +3371,30 @@ static void cf_check sh_update_cr3(struc - gl2gfn = guest_l3e_get_gfn(gl3e[i]); - gl2mfn = get_gfn_query_unlocked(d, gfn_x(gl2gfn), &p2mt); - if ( p2m_is_ram(p2mt) ) -- sh_set_toplevel_shadow(v, i, gl2mfn, SH_type_l2_shadow, -- sh_make_shadow); -+ old_entry = sh_set_toplevel_shadow(v, i, gl2mfn, -+ SH_type_l2_shadow, -+ sh_make_shadow); - else -- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, -- sh_make_shadow); -+ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, -+ sh_make_shadow); - } - else -- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, sh_make_shadow); -+ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, -+ sh_make_shadow); -+ -+ ASSERT(pagetable_is_null(old_entry)); - } - } - #elif GUEST_PAGING_LEVELS == 2 - if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 ) - guest_flush_tlb_mask(d, d->dirty_cpumask); -- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, sh_make_shadow); -+ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, -+ sh_make_shadow); -+ ASSERT(pagetable_is_null(old_entry)); - if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) ) - { - ASSERT(d->is_dying || d->is_shutting_down); -- return; -+ return old_entry; - } - #else - #error This should never happen -@@ -3473,6 +3482,8 @@ static void cf_check sh_update_cr3(struc - - /* Release the lock, if we took it (otherwise it's the caller's problem) */ - if ( do_locking ) paging_unlock(v->domain); -+ -+ return old_entry; - } - - ---- a/xen/arch/x86/mm/shadow/none.c -+++ b/xen/arch/x86/mm/shadow/none.c -@@ -52,9 +52,11 @@ static unsigned long cf_check _gva_to_gf - } - #endif - --static void cf_check _update_cr3(struct vcpu *v, int do_locking, bool noflush) -+static pagetable_t cf_check _update_cr3(struct vcpu *v, bool do_locking, -+ bool noflush) - { - ASSERT_UNREACHABLE(); -+ return pagetable_null(); - } - - static void cf_check _update_paging_modes(struct vcpu *v) ---- a/xen/arch/x86/mm/shadow/private.h -+++ b/xen/arch/x86/mm/shadow/private.h -@@ -391,13 +391,13 @@ mfn_t shadow_alloc(struct domain *d, - void shadow_free(struct domain *d, mfn_t smfn); - - /* Set up the top-level shadow and install it in slot 'slot' of shadow_table */ --void sh_set_toplevel_shadow(struct vcpu *v, -- unsigned int slot, -- mfn_t gmfn, -- unsigned int root_type, -- mfn_t (*make_shadow)(struct vcpu *v, -- mfn_t gmfn, -- uint32_t shadow_type)); -+pagetable_t sh_set_toplevel_shadow(struct vcpu *v, -+ unsigned int slot, -+ mfn_t gmfn, -+ unsigned int root_type, -+ mfn_t (*make_shadow)(struct vcpu *v, -+ mfn_t gmfn, -+ uint32_t shadow_type)); - - /* Update the shadows in response to a pagetable write from Xen */ - int sh_validate_guest_entry(struct vcpu *v, mfn_t gmfn, void *entry, u32 size); ---- a/xen/arch/x86/mm.c -+++ b/xen/arch/x86/mm.c -@@ -567,15 +567,12 @@ void write_ptbase(struct vcpu *v) - * - * Update ref counts to shadow tables appropriately. - */ --void update_cr3(struct vcpu *v) -+pagetable_t update_cr3(struct vcpu *v) - { - mfn_t cr3_mfn; - - if ( paging_mode_enabled(v->domain) ) -- { -- paging_update_cr3(v, false); -- return; -- } -+ return paging_update_cr3(v, false); - - if ( !(v->arch.flags & TF_kernel_mode) ) - cr3_mfn = pagetable_get_mfn(v->arch.guest_table_user); -@@ -583,6 +580,8 @@ void update_cr3(struct vcpu *v) - cr3_mfn = pagetable_get_mfn(v->arch.guest_table); - - make_cr3(v, cr3_mfn); -+ -+ return pagetable_null(); - } - - static inline void set_tlbflush_timestamp(struct page_info *page) -@@ -3285,6 +3284,7 @@ int new_guest_cr3(mfn_t mfn) - struct domain *d = curr->domain; - int rc; - mfn_t old_base_mfn; -+ pagetable_t old_shadow; - - if ( is_pv_32bit_domain(d) ) - { -@@ -3352,9 +3352,22 @@ int new_guest_cr3(mfn_t mfn) - if ( !VM_ASSIST(d, m2p_strict) ) - fill_ro_mpt(mfn); - curr->arch.guest_table = pagetable_from_mfn(mfn); -- update_cr3(curr); -+ old_shadow = update_cr3(curr); -+ -+ /* -+ * In shadow mode update_cr3() can fail, in which case here we're still -+ * running on the prior top-level shadow (which we're about to release). -+ * Switch to the idle page tables in such an event; the guest will have -+ * been crashed already. -+ */ -+ if ( likely(!mfn_eq(pagetable_get_mfn(old_shadow), -+ maddr_to_mfn(curr->arch.cr3 & ~X86_CR3_NOFLUSH))) ) -+ write_ptbase(curr); -+ else -+ write_ptbase(idle_vcpu[curr->processor]); - -- write_ptbase(curr); -+ if ( !pagetable_is_null(old_shadow) ) -+ shadow_put_top_level(d, old_shadow); - - if ( likely(mfn_x(old_base_mfn) != 0) ) - { ---- a/xen/arch/x86/pv/domain.c -+++ b/xen/arch/x86/pv/domain.c -@@ -424,10 +424,13 @@ bool __init xpti_pcid_enabled(void) - - static void _toggle_guest_pt(struct vcpu *v) - { -+ bool guest_update; -+ pagetable_t old_shadow; - unsigned long cr3; - - v->arch.flags ^= TF_kernel_mode; -- update_cr3(v); -+ guest_update = v->arch.flags & TF_kernel_mode; -+ old_shadow = update_cr3(v); - - /* - * Don't flush user global mappings from the TLB. Don't tick TLB clock. -@@ -436,13 +439,31 @@ static void _toggle_guest_pt(struct vcpu - * TLB flush (for just the incoming PCID), as the top level page table may - * have changed behind our backs. To be on the safe side, suppress the - * no-flush unconditionally in this case. -+ * -+ * Furthermore in shadow mode update_cr3() can fail, in which case here -+ * we're still running on the prior top-level shadow (which we're about -+ * to release). Switch to the idle page tables in such an event; the -+ * guest will have been crashed already. - */ - cr3 = v->arch.cr3; - if ( shadow_mode_enabled(v->domain) ) -+ { - cr3 &= ~X86_CR3_NOFLUSH; -+ -+ if ( unlikely(mfn_eq(pagetable_get_mfn(old_shadow), -+ maddr_to_mfn(cr3))) ) -+ { -+ cr3 = idle_vcpu[v->processor]->arch.cr3; -+ /* Also suppress runstate/time area updates below. */ -+ guest_update = false; -+ } -+ } - write_cr3(cr3); - -- if ( !(v->arch.flags & TF_kernel_mode) ) -+ if ( !pagetable_is_null(old_shadow) ) -+ shadow_put_top_level(v->domain, old_shadow); -+ -+ if ( !guest_update ) - return; - - if ( v->arch.pv.need_update_runstate_area && update_runstate_area(v) ) diff --git a/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch b/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch deleted file mode 100644 index 96e56ec..0000000 --- a/xsa439-0001-x86-AMD-extend-Zenbleed-check-to-models-good-ucode-i.patch +++ /dev/null @@ -1,49 +0,0 @@ -From d2d2dcae879c6cc05227c9620f0a772f35fe6886 Mon Sep 17 00:00:00 2001 -Message-ID: -From: Jan Beulich -Date: Wed, 23 Aug 2023 09:26:36 +0200 -Subject: [XEN PATCH 01/10] x86/AMD: extend Zenbleed check to models "good" - ucode isn't known for - -Reportedly the AMD Custom APU 0405 found on SteamDeck, models 0x90 and -0x91, (quoting the respective Linux commit) is similarly affected. Put -another instance of our Zen1 vs Zen2 distinction checks in -amd_check_zenbleed(), forcing use of the chickenbit irrespective of -ucode version (building upon real hardware never surfacing a version of -0xffffffff). - -Signed-off-by: Jan Beulich -Reviewed-by: Andrew Cooper -(cherry picked from commit 145a69c0944ac70cfcf9d247c85dee9e99d9d302) ---- - xen/arch/x86/cpu/amd.c | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index 3ea214fc2e..1bb3044be1 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -909,10 +909,17 @@ void amd_check_zenbleed(void) - case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; - default: - /* -- * With the Fam17h check above, parts getting here are Zen1. -- * They're not affected. -+ * With the Fam17h check above, most parts getting here are -+ * Zen1. They're not affected. Assume Zen2 ones making it -+ * here are affected regardless of microcode version. -+ * -+ * Zen1 vs Zen2 isn't a simple model number comparison, so use -+ * STIBP as a heuristic to distinguish. - */ -- return; -+ if (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) -+ return; -+ good_rev = ~0U; -+ break; - } - - rdmsrl(MSR_AMD64_DE_CFG, val); --- -2.41.0 - diff --git a/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch b/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch deleted file mode 100644 index 8b8e30a..0000000 --- a/xsa439-0002-x86-spec-ctrl-Fix-confusion-between-SPEC_CTRL_EXIT_T.patch +++ /dev/null @@ -1,77 +0,0 @@ -From dc28aba565f226f9bec24cfde993e78478acfb4e Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: -References: -From: Andrew Cooper -Date: Tue, 12 Sep 2023 15:06:49 +0100 -Subject: [XEN PATCH 02/10] x86/spec-ctrl: Fix confusion between - SPEC_CTRL_EXIT_TO_XEN{,_IST} - -c/s 3fffaf9c13e9 ("x86/entry: Avoid using alternatives in NMI/#MC paths") -dropped the only user, leaving behind the (incorrect) implication that Xen had -split exit paths. - -Delete the unused SPEC_CTRL_EXIT_TO_XEN and rename SPEC_CTRL_EXIT_TO_XEN_IST -to SPEC_CTRL_EXIT_TO_XEN for consistency. - -No functional change. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 1c18d73774533a55ba9d1cbee8bdace03efdb5e7) ---- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 10 ++-------- - xen/arch/x86/x86_64/entry.S | 2 +- - 2 files changed, 3 insertions(+), 9 deletions(-) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index f23bb105c5..e8fd01243c 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -79,7 +79,6 @@ - * - SPEC_CTRL_ENTRY_FROM_PV - * - SPEC_CTRL_ENTRY_FROM_INTR - * - SPEC_CTRL_ENTRY_FROM_INTR_IST -- * - SPEC_CTRL_EXIT_TO_XEN_IST - * - SPEC_CTRL_EXIT_TO_XEN - * - SPEC_CTRL_EXIT_TO_PV - * -@@ -268,11 +267,6 @@ - ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ - X86_FEATURE_SC_MSR_PV - --/* Use when exiting to Xen context. */ --#define SPEC_CTRL_EXIT_TO_XEN \ -- ALTERNATIVE "", \ -- DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_SC_MSR_PV -- - /* Use when exiting to PV guest context. */ - #define SPEC_CTRL_EXIT_TO_PV \ - ALTERNATIVE "", \ -@@ -339,8 +333,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - UNLIKELY_END(\@_serialise) - .endm - --/* Use when exiting to Xen in IST context. */ --.macro SPEC_CTRL_EXIT_TO_XEN_IST -+/* Use when exiting to Xen context. */ -+.macro SPEC_CTRL_EXIT_TO_XEN - /* - * Requires %rbx=stack_end - * Clobbers %rax, %rcx, %rdx -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 7675a59ff0..b45a09823a 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -673,7 +673,7 @@ UNLIKELY_START(ne, exit_cr3) - UNLIKELY_END(exit_cr3) - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_XEN_IST /* Req: %rbx=end, Clob: acd */ -+ SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */ - - RESTORE_ALL adj=8 - iretq --- -2.41.0 - diff --git a/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch b/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch deleted file mode 100644 index 547032e..0000000 --- a/xsa439-0003-x86-spec-ctrl-Fold-DO_SPEC_CTRL_EXIT_TO_XEN-into-it-.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 84690fb82c4f4aecb72a6789d8994efa74841e09 Mon Sep 17 00:00:00 2001 -Message-ID: <84690fb82c4f4aecb72a6789d8994efa74841e09.1695733540.git.m.a.young@durham.ac.uk> -In-Reply-To: -References: -From: Andrew Cooper -Date: Tue, 12 Sep 2023 17:03:16 +0100 -Subject: [XEN PATCH 03/10] x86/spec-ctrl: Fold DO_SPEC_CTRL_EXIT_TO_XEN into - it's single user - -With the SPEC_CTRL_EXIT_TO_XEN{,_IST} confusion fixed, it's now obvious that -there's only a single EXIT_TO_XEN path. Fold DO_SPEC_CTRL_EXIT_TO_XEN into -SPEC_CTRL_EXIT_TO_XEN to simplify further fixes. - -When merging labels, switch the name to .L\@_skip_sc_msr as "skip" on its own -is going to be too generic shortly. - -No functional change. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 694bb0f280fd08a4377e36e32b84b5062def4de2) ---- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 40 ++++++++++-------------- - 1 file changed, 16 insertions(+), 24 deletions(-) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index e8fd01243c..d5f65d80ea 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -211,27 +211,6 @@ - wrmsr - .endm - --.macro DO_SPEC_CTRL_EXIT_TO_XEN --/* -- * Requires %rbx=stack_end -- * Clobbers %rax, %rcx, %rdx -- * -- * When returning to Xen context, look to see whether SPEC_CTRL shadowing is -- * in effect, and reload the shadow value. This covers race conditions which -- * exist with an NMI/MCE/etc hitting late in the return-to-guest path. -- */ -- xor %edx, %edx -- -- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) -- jz .L\@_skip -- -- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax -- mov $MSR_SPEC_CTRL, %ecx -- wrmsr -- --.L\@_skip: --.endm -- - .macro DO_SPEC_CTRL_EXIT_TO_GUEST - /* - * Requires %eax=spec_ctrl, %rsp=regs/cpuinfo -@@ -340,11 +319,24 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - * Clobbers %rax, %rcx, %rdx - */ - testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) -- jz .L\@_skip -+ jz .L\@_skip_sc_msr - -- DO_SPEC_CTRL_EXIT_TO_XEN -+ /* -+ * When returning to Xen context, look to see whether SPEC_CTRL shadowing -+ * is in effect, and reload the shadow value. This covers race conditions -+ * which exist with an NMI/MCE/etc hitting late in the return-to-guest -+ * path. -+ */ -+ xor %edx, %edx - --.L\@_skip: -+ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) -+ jz .L\@_skip_sc_msr -+ -+ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax -+ mov $MSR_SPEC_CTRL, %ecx -+ wrmsr -+ -+.L\@_skip_sc_msr: - .endm - - #endif /* __ASSEMBLY__ */ --- -2.41.0 - diff --git a/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch b/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch deleted file mode 100644 index 3350750..0000000 --- a/xsa439-0004-x86-spec-ctrl-Turn-the-remaining-SPEC_CTRL_-ENTRY-EX.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 3952c73bdbd05f0e666986fce633a591237b3c88 Mon Sep 17 00:00:00 2001 -Message-ID: <3952c73bdbd05f0e666986fce633a591237b3c88.1695733540.git.m.a.young@durham.ac.uk> -In-Reply-To: -References: -From: Andrew Cooper -Date: Fri, 1 Sep 2023 11:38:44 +0100 -Subject: [XEN PATCH 04/10] x86/spec-ctrl: Turn the remaining - SPEC_CTRL_{ENTRY,EXIT}_* into asm macros - -These have grown more complex over time, with some already having been -converted. - -Provide full Requires/Clobbers comments, otherwise missing at this level of -indirection. - -No functional change. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 7125429aafb9e3c9c88fc93001fc2300e0ac2cc8) ---- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 37 ++++++++++++++++++------ - 1 file changed, 28 insertions(+), 9 deletions(-) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index d5f65d80ea..c6d5f2ad01 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -231,26 +231,45 @@ - .endm - - /* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ --#define SPEC_CTRL_ENTRY_FROM_PV \ -+.macro SPEC_CTRL_ENTRY_FROM_PV -+/* -+ * Requires %rsp=regs/cpuinfo, %rdx=0 -+ * Clobbers %rax, %rcx, %rdx -+ */ - ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=0), \ -- X86_FEATURE_IBPB_ENTRY_PV; \ -- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ -+ X86_FEATURE_IBPB_ENTRY_PV -+ -+ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV -+ - ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), \ - X86_FEATURE_SC_MSR_PV -+.endm - - /* Use in interrupt/exception context. May interrupt Xen or PV context. */ --#define SPEC_CTRL_ENTRY_FROM_INTR \ -+.macro SPEC_CTRL_ENTRY_FROM_INTR -+/* -+ * Requires %rsp=regs, %r14=stack_end, %rdx=0 -+ * Clobbers %rax, %rcx, %rdx -+ */ - ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=1), \ -- X86_FEATURE_IBPB_ENTRY_PV; \ -- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ -+ X86_FEATURE_IBPB_ENTRY_PV -+ -+ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV -+ - ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ - X86_FEATURE_SC_MSR_PV -+.endm - - /* Use when exiting to PV guest context. */ --#define SPEC_CTRL_EXIT_TO_PV \ -- ALTERNATIVE "", \ -- DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV; \ -+.macro SPEC_CTRL_EXIT_TO_PV -+/* -+ * Requires %rax=spec_ctrl, %rsp=regs/info -+ * Clobbers %rcx, %rdx -+ */ -+ ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV -+ - DO_SPEC_CTRL_COND_VERW -+.endm - - /* - * Use in IST interrupt/exception context. May interrupt Xen or PV context. --- -2.41.0 - diff --git a/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch b/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch deleted file mode 100644 index dda088a..0000000 --- a/xsa439-0005-x86-spec-ctrl-Improve-all-SPEC_CTRL_-ENTER-EXIT-_-co.patch +++ /dev/null @@ -1,109 +0,0 @@ -From ba023e93d0b1e60b80251bf080bab694efb9f8e3 Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: -References: -From: Andrew Cooper -Date: Wed, 30 Aug 2023 20:11:50 +0100 -Subject: [XEN PATCH 05/10] x86/spec-ctrl: Improve all SPEC_CTRL_{ENTER,EXIT}_* - comments - -... to better explain how they're used. - -Doing so highlights that SPEC_CTRL_EXIT_TO_XEN is missing a VERW flush for the -corner case when e.g. an NMI hits late in an exit-to-guest path. - -Leave a TODO, which will be addressed in subsequent patches which arrange for -VERW flushing to be safe within SPEC_CTRL_EXIT_TO_XEN. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 45f00557350dc7d0756551069803fc49c29184ca) ---- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 36 ++++++++++++++++++++---- - 1 file changed, 31 insertions(+), 5 deletions(-) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index c6d5f2ad01..97c4db31cd 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -230,7 +230,10 @@ - wrmsr - .endm - --/* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ -+/* -+ * Used after an entry from PV context: SYSCALL, SYSENTER, INT, -+ * etc. There is always a guest speculation state in context. -+ */ - .macro SPEC_CTRL_ENTRY_FROM_PV - /* - * Requires %rsp=regs/cpuinfo, %rdx=0 -@@ -245,7 +248,11 @@ - X86_FEATURE_SC_MSR_PV - .endm - --/* Use in interrupt/exception context. May interrupt Xen or PV context. */ -+/* -+ * Used after an exception or maskable interrupt, hitting Xen or PV context. -+ * There will either be a guest speculation context, or (barring fatal -+ * exceptions) a well-formed Xen speculation context. -+ */ - .macro SPEC_CTRL_ENTRY_FROM_INTR - /* - * Requires %rsp=regs, %r14=stack_end, %rdx=0 -@@ -260,7 +267,10 @@ - X86_FEATURE_SC_MSR_PV - .endm - --/* Use when exiting to PV guest context. */ -+/* -+ * Used when exiting from any entry context, back to PV context. This -+ * includes from an IST entry which moved onto the primary stack. -+ */ - .macro SPEC_CTRL_EXIT_TO_PV - /* - * Requires %rax=spec_ctrl, %rsp=regs/info -@@ -272,7 +282,13 @@ - .endm - - /* -- * Use in IST interrupt/exception context. May interrupt Xen or PV context. -+ * Used after an IST entry hitting Xen or PV context. Special care is needed, -+ * because when hitting Xen context, there may not be a well-formed -+ * speculation context. (i.e. it can hit in the middle of -+ * SPEC_CTRL_{ENTRY,EXIT}_* regions.) -+ * -+ * An IST entry which hits PV context moves onto the primary stack and leaves -+ * via SPEC_CTRL_EXIT_TO_PV, *not* SPEC_CTRL_EXIT_TO_XEN. - */ - .macro SPEC_CTRL_ENTRY_FROM_INTR_IST - /* -@@ -331,7 +347,14 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - UNLIKELY_END(\@_serialise) - .endm - --/* Use when exiting to Xen context. */ -+/* -+ * Use when exiting from any entry context, back to Xen context. This -+ * includes returning to other SPEC_CTRL_{ENTRY,EXIT}_* regions with an -+ * incomplete speculation context. -+ * -+ * Because we might have interrupted Xen beyond SPEC_CTRL_EXIT_TO_$GUEST, we -+ * need to treat this as if it were an EXIT_TO_$GUEST case too. -+ */ - .macro SPEC_CTRL_EXIT_TO_XEN - /* - * Requires %rbx=stack_end -@@ -356,6 +379,9 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - wrmsr - - .L\@_skip_sc_msr: -+ -+ /* TODO VERW */ -+ - .endm - - #endif /* __ASSEMBLY__ */ --- -2.41.0 - diff --git a/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch b/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch deleted file mode 100644 index e44998e..0000000 --- a/xsa439-0006-x86-entry-Adjust-restore_all_xen-to-hold-stack_end-i.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 5f7efd47c8273fde972637d0360851802f76eca9 Mon Sep 17 00:00:00 2001 -Message-ID: <5f7efd47c8273fde972637d0360851802f76eca9.1695733540.git.m.a.young@durham.ac.uk> -In-Reply-To: -References: -From: Andrew Cooper -Date: Wed, 13 Sep 2023 13:48:16 +0100 -Subject: [XEN PATCH 06/10] x86/entry: Adjust restore_all_xen to hold stack_end - in %r14 - -All other SPEC_CTRL_{ENTRY,EXIT}_* helpers hold stack_end in %r14. Adjust it -for consistency. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 7aa28849a1155d856e214e9a80a7e65fffdc3e58) ---- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 8 ++++---- - xen/arch/x86/x86_64/entry.S | 8 ++++---- - 2 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index 97c4db31cd..66c706496f 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -357,10 +357,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - */ - .macro SPEC_CTRL_EXIT_TO_XEN - /* -- * Requires %rbx=stack_end -+ * Requires %r14=stack_end - * Clobbers %rax, %rcx, %rdx - */ -- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) -+ testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) - jz .L\@_skip_sc_msr - - /* -@@ -371,10 +371,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - */ - xor %edx, %edx - -- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) -+ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) - jz .L\@_skip_sc_msr - -- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax -+ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax - mov $MSR_SPEC_CTRL, %ecx - wrmsr - -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index b45a09823a..92279a225d 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -665,15 +665,15 @@ restore_all_xen: - * Check whether we need to switch to the per-CPU page tables, in - * case we return to late PV exit code (from an NMI or #MC). - */ -- GET_STACK_END(bx) -- cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) -+ GET_STACK_END(14) -+ cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - UNLIKELY_START(ne, exit_cr3) -- mov STACK_CPUINFO_FIELD(pv_cr3)(%rbx), %rax -+ mov STACK_CPUINFO_FIELD(pv_cr3)(%r14), %rax - mov %rax, %cr3 - UNLIKELY_END(exit_cr3) - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */ -+ SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */ - - RESTORE_ALL adj=8 - iretq --- -2.41.0 - diff --git a/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch b/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch deleted file mode 100644 index 2e36bcc..0000000 --- a/xsa439-0007-x86-entry-Track-the-IST-ness-of-an-entry-for-the-exi.patch +++ /dev/null @@ -1,112 +0,0 @@ -From e4a71bc0da0baf7464bb0d8e33053f330e5ea366 Mon Sep 17 00:00:00 2001 -Message-ID: -In-Reply-To: -References: -From: Andrew Cooper -Date: Wed, 13 Sep 2023 12:20:12 +0100 -Subject: [XEN PATCH 07/10] x86/entry: Track the IST-ness of an entry for the - exit paths - -Use %r12 to hold an ist_exit boolean. This register is zero elsewhere in the -entry/exit asm, so it only needs setting in the IST path. - -As this is subtle and fragile, add check_ist_exit() to be used in debugging -builds to cross-check that the ist_exit boolean matches the entry vector. - -Write check_ist_exit() it in C, because it's debug only and the logic more -complicated than I care to maintain in asm. - -For now, we only need to use this signal in the exit-to-Xen path, but some -exit-to-guest paths happen in IST context too. Check the correctness in all -exit paths to avoid the logic bit-rotting. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 21bdc25b05a0f8ab6bc73520a9ca01327360732c) - -x86/entry: Partially revert IST-exit checks - -The patch adding check_ist_exit() didn't account for the fact that -reset_stack_and_jump() is not an ABI-preserving boundary. The IST-ness in -%r12 doesn't survive into the next context, and is a stale value C. - -This shows up in Gitlab CI for the Clang build: - - https://gitlab.com/xen-project/people/andyhhp/xen/-/jobs/5112783827 - -and in OSSTest for GCC 8: - - http://logs.test-lab.xenproject.org/osstest/logs/183045/test-amd64-amd64-xl-qemuu-debianhvm-amd64/serial-pinot0.log - -There's no straightforward way to reconstruct the IST-exit-ness on the -exit-to-guest path after a context switch. For now, we only need IST-exit on -the return-to-Xen path. - -Fixes: 21bdc25b05a0 ("x86/entry: Track the IST-ness of an entry for the exit paths") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 9b57c800b79b96769ea3dcd6468578fa664d19f9) ---- - xen/arch/x86/traps.c | 13 +++++++++++++ - xen/arch/x86/x86_64/entry.S | 13 ++++++++++++- - 2 files changed, 25 insertions(+), 1 deletion(-) - -diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c -index d12004b1c6..e65cc60041 100644 ---- a/xen/arch/x86/traps.c -+++ b/xen/arch/x86/traps.c -@@ -2315,6 +2315,19 @@ void asm_domain_crash_synchronous(unsigned long addr) - do_softirq(); - } - -+#ifdef CONFIG_DEBUG -+void check_ist_exit(const struct cpu_user_regs *regs, bool ist_exit) -+{ -+ const unsigned int ist_mask = -+ (1U << X86_EXC_NMI) | (1U << X86_EXC_DB) | -+ (1U << X86_EXC_DF) | (1U << X86_EXC_MC); -+ uint8_t ev = regs->entry_vector; -+ bool is_ist = (ev < TRAP_nr) && ((1U << ev) & ist_mask); -+ -+ ASSERT(is_ist == ist_exit); -+} -+#endif -+ - /* - * Local variables: - * mode: C -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 92279a225d..4cebc4fbe3 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -659,8 +659,15 @@ ENTRY(early_page_fault) - .section .text.entry, "ax", @progbits - - ALIGN --/* No special register assumptions. */ -+/* %r12=ist_exit */ - restore_all_xen: -+ -+#ifdef CONFIG_DEBUG -+ mov %rsp, %rdi -+ mov %r12, %rsi -+ call check_ist_exit -+#endif -+ - /* - * Check whether we need to switch to the per-CPU page tables, in - * case we return to late PV exit code (from an NMI or #MC). -@@ -1091,6 +1098,10 @@ handle_ist_exception: - .L_ist_dispatch_done: - mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) - mov %bl, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) -+ -+ /* This is an IST exit */ -+ mov $1, %r12d -+ - cmpb $TRAP_nmi,UREGS_entry_vector(%rsp) - jne ret_from_intr - --- -2.41.0 - diff --git a/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch b/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch deleted file mode 100644 index 6e00ca6..0000000 --- a/xsa439-0008-x86-spec-ctrl-Issue-VERW-during-IST-exit-to-Xen.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 2e2c3efcfc9f183674a8de6ed954ffbe7188b70d Mon Sep 17 00:00:00 2001 -Message-ID: <2e2c3efcfc9f183674a8de6ed954ffbe7188b70d.1695733540.git.m.a.young@durham.ac.uk> -In-Reply-To: -References: -From: Andrew Cooper -Date: Wed, 13 Sep 2023 13:53:33 +0100 -Subject: [XEN PATCH 08/10] x86/spec-ctrl: Issue VERW during IST exit to Xen - -There is a corner case where e.g. an NMI hitting an exit-to-guest path after -SPEC_CTRL_EXIT_TO_* would have run the entire NMI handler *after* the VERW -flush to scrub potentially sensitive data from uarch buffers. - -In order to compensate, issue VERW when exiting to Xen from an IST entry. - -SPEC_CTRL_EXIT_TO_XEN already has two reads of spec_ctrl_flags off the stack, -and we're about to add a third. Load the field into %ebx, and list the -register as clobbered. - -%r12 has been arranged to be the ist_exit signal, so add this as an input -dependency and use it to identify when to issue a VERW. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 3ee6066bcd737756b0990d417d94eddc0b0d2585) ---- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 20 +++++++++++++++----- - xen/arch/x86/x86_64/entry.S | 2 +- - 2 files changed, 16 insertions(+), 6 deletions(-) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index 66c706496f..28a75796e6 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -357,10 +357,12 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - */ - .macro SPEC_CTRL_EXIT_TO_XEN - /* -- * Requires %r14=stack_end -- * Clobbers %rax, %rcx, %rdx -+ * Requires %r12=ist_exit, %r14=stack_end -+ * Clobbers %rax, %rbx, %rcx, %rdx - */ -- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) -+ movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx -+ -+ testb $SCF_ist_sc_msr, %bl - jz .L\@_skip_sc_msr - - /* -@@ -371,7 +373,7 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - */ - xor %edx, %edx - -- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) -+ testb $SCF_use_shadow, %bl - jz .L\@_skip_sc_msr - - mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax -@@ -380,8 +382,16 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - - .L\@_skip_sc_msr: - -- /* TODO VERW */ -+ test %r12, %r12 -+ jz .L\@_skip_ist_exit -+ -+ /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */ -+ testb $SCF_verw, %bl -+ jz .L\@_skip_verw -+ verw STACK_CPUINFO_FIELD(verw_sel)(%r14) -+.L\@_skip_verw: - -+.L\@_skip_ist_exit: - .endm - - #endif /* __ASSEMBLY__ */ -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 4cebc4fbe3..c12e011b4d 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -680,7 +680,7 @@ UNLIKELY_START(ne, exit_cr3) - UNLIKELY_END(exit_cr3) - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */ -+ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */ - - RESTORE_ALL adj=8 - iretq --- -2.41.0 - diff --git a/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch b/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch deleted file mode 100644 index 5f063b1..0000000 --- a/xsa439-0009-x86-amd-Introduce-is_zen-1-2-_uarch-predicates.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 19ee1e1faa32b79274b3484cb1170a5970f1e602 Mon Sep 17 00:00:00 2001 -Message-ID: <19ee1e1faa32b79274b3484cb1170a5970f1e602.1695733540.git.m.a.young@durham.ac.uk> -In-Reply-To: -References: -From: Andrew Cooper -Date: Fri, 15 Sep 2023 12:13:51 +0100 -Subject: [XEN PATCH 09/10] x86/amd: Introduce is_zen{1,2}_uarch() predicates - -We already have 3 cases using STIBP as a Zen1/2 heuristic, and are about to -introduce a 4th. Wrap the heuristic into a pair of predicates rather than -opencoding it, and the explanation of the heuristic, at each usage site. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit de1d265001397f308c5c3c5d3ffc30e7ef8c0705) ---- - xen/arch/x86/cpu/amd.c | 18 ++++-------------- - xen/arch/x86/include/asm/amd.h | 11 +++++++++++ - 2 files changed, 15 insertions(+), 14 deletions(-) - -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index 1bb3044be1..e94ba5a0e0 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -855,15 +855,13 @@ void amd_set_legacy_ssbd(bool enable) - * non-branch instructions to be ignored. It is to be set unilaterally in - * newer microcode. - * -- * This chickenbit is something unrelated on Zen1, and Zen1 vs Zen2 isn't a -- * simple model number comparison, so use STIBP as a heuristic to separate the -- * two uarches in Fam17h(AMD)/18h(Hygon). -+ * This chickenbit is something unrelated on Zen1. - */ - void amd_init_spectral_chicken(void) - { - uint64_t val, chickenbit = 1 << 1; - -- if (cpu_has_hypervisor || !boot_cpu_has(X86_FEATURE_AMD_STIBP)) -+ if (cpu_has_hypervisor || !is_zen2_uarch()) - return; - - if (rdmsr_safe(MSR_AMD64_DE_CFG2, val) == 0 && !(val & chickenbit)) -@@ -912,11 +910,8 @@ void amd_check_zenbleed(void) - * With the Fam17h check above, most parts getting here are - * Zen1. They're not affected. Assume Zen2 ones making it - * here are affected regardless of microcode version. -- * -- * Zen1 vs Zen2 isn't a simple model number comparison, so use -- * STIBP as a heuristic to distinguish. - */ -- if (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) -+ if (is_zen1_uarch()) - return; - good_rev = ~0U; - break; -@@ -1277,12 +1272,7 @@ static int __init cf_check zen2_c6_errata_check(void) - */ - s_time_t delta; - -- /* -- * Zen1 vs Zen2 isn't a simple model number comparison, so use STIBP as -- * a heuristic to separate the two uarches in Fam17h. -- */ -- if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || -- !boot_cpu_has(X86_FEATURE_AMD_STIBP)) -+ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || !is_zen2_uarch()) - return 0; - - /* -diff --git a/xen/arch/x86/include/asm/amd.h b/xen/arch/x86/include/asm/amd.h -index a975d3de26..82324110ab 100644 ---- a/xen/arch/x86/include/asm/amd.h -+++ b/xen/arch/x86/include/asm/amd.h -@@ -140,6 +140,17 @@ - AMD_MODEL_RANGE(0x11, 0x0, 0x0, 0xff, 0xf), \ - AMD_MODEL_RANGE(0x12, 0x0, 0x0, 0xff, 0xf)) - -+/* -+ * The Zen1 and Zen2 microarchitectures are implemented by AMD (Fam17h) and -+ * Hygon (Fam18h) but without simple model number rules. Instead, use STIBP -+ * as a heuristic that distinguishes the two. -+ * -+ * The caller is required to perform the appropriate vendor/family checks -+ * first. -+ */ -+#define is_zen1_uarch() (!boot_cpu_has(X86_FEATURE_AMD_STIBP)) -+#define is_zen2_uarch() boot_cpu_has(X86_FEATURE_AMD_STIBP) -+ - struct cpuinfo_x86; - int cpu_has_amd_erratum(const struct cpuinfo_x86 *, int, ...); - --- -2.41.0 - diff --git a/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch b/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch deleted file mode 100644 index 0dc6780..0000000 --- a/xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 9ac2f49f5fa3a5159409241d4f74fb0d721dd4c5 Mon Sep 17 00:00:00 2001 -Message-ID: <9ac2f49f5fa3a5159409241d4f74fb0d721dd4c5.1695733540.git.m.a.young@durham.ac.uk> -In-Reply-To: -References: -From: Andrew Cooper -Date: Wed, 30 Aug 2023 20:24:25 +0100 -Subject: [XEN PATCH 10/10] x86/spec-ctrl: Mitigate the Zen1 DIV leakage - -In the Zen1 microarchitecure, there is one divider in the pipeline which -services uops from both threads. In the case of #DE, the latched result from -the previous DIV to execute will be forwarded speculatively. - -This is an interesting covert channel that allows two threads to communicate -without any system calls. In also allows userspace to obtain the result of -the most recent DIV instruction executed (even speculatively) in the core, -which can be from a higher privilege context. - -Scrub the result from the divider by executing a non-faulting divide. This -needs performing on the exit-to-guest paths, and ist_exit-to-Xen. - -Alternatives in IST context is believed safe now that it's done in NMI -context. - -This is XSA-439 / CVE-2023-20588. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit b5926c6ecf05c28ee99c6248c42d691ccbf0c315) ---- - docs/misc/xen-command-line.pandoc | 6 ++- - xen/arch/x86/hvm/svm/entry.S | 1 + - xen/arch/x86/include/asm/cpufeatures.h | 2 +- - xen/arch/x86/include/asm/spec_ctrl_asm.h | 17 +++++++++ - xen/arch/x86/spec_ctrl.c | 48 +++++++++++++++++++++++- - 5 files changed, 71 insertions(+), 3 deletions(-) - -diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc -index d9dae740cc..b92c8f969c 100644 ---- a/docs/misc/xen-command-line.pandoc -+++ b/docs/misc/xen-command-line.pandoc -@@ -2315,7 +2315,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). - > {msr-sc,rsb,md-clear,ibpb-entry}=|{pv,hvm}=, - > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, - > eager-fpu,l1d-flush,branch-harden,srb-lock, --> unpriv-mmio,gds-mit}= ]` -+> unpriv-mmio,gds-mit,div-scrub}= ]` - - Controls for speculative execution sidechannel mitigations. By default, Xen - will pick the most appropriate mitigations based on compiled in support, -@@ -2437,6 +2437,10 @@ has elected not to lock the configuration, Xen will use GDS_CTRL to mitigate - GDS with. Otherwise, Xen will mitigate by disabling AVX, which blocks the use - of the AVX2 Gather instructions. - -+On all hardware, the `div-scrub=` option can be used to force or prevent Xen -+from mitigating the DIV-leakage vulnerability. By default, Xen will mitigate -+DIV-leakage on hardware believed to be vulnerable. -+ - ### sync_console - > `= ` - -diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S -index 981cd82e7c..934f12cf5c 100644 ---- a/xen/arch/x86/hvm/svm/entry.S -+++ b/xen/arch/x86/hvm/svm/entry.S -@@ -74,6 +74,7 @@ __UNLIKELY_END(nsvm_hap) - 1: /* No Spectre v1 concerns. Execution will hit VMRUN imminently. */ - .endm - ALTERNATIVE "", svm_vmentry_spec_ctrl, X86_FEATURE_SC_MSR_HVM -+ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV - - pop %r15 - pop %r14 -diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h -index da0593de85..c3aad21c3b 100644 ---- a/xen/arch/x86/include/asm/cpufeatures.h -+++ b/xen/arch/x86/include/asm/cpufeatures.h -@@ -35,7 +35,7 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM - XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */ - XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */ - XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */ --/* Bits 23 unused. */ -+XEN_CPUFEATURE(SC_DIV, X86_SYNTH(23)) /* DIV scrub needed */ - XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */ - XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */ - XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */ -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index 28a75796e6..f4b8b9d956 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -177,6 +177,19 @@ - .L\@_verw_skip: - .endm - -+.macro DO_SPEC_CTRL_DIV -+/* -+ * Requires nothing -+ * Clobbers %rax -+ * -+ * Issue a DIV for its flushing side effect (Zen1 uarch specific). Any -+ * non-faulting DIV will do; a byte DIV has least latency, and doesn't clobber -+ * %rdx. -+ */ -+ mov $1, %eax -+ div %al -+.endm -+ - .macro DO_SPEC_CTRL_ENTRY maybexen:req - /* - * Requires %rsp=regs (also cpuinfo if !maybexen) -@@ -279,6 +292,8 @@ - ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV - - DO_SPEC_CTRL_COND_VERW -+ -+ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV - .endm - - /* -@@ -391,6 +406,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - verw STACK_CPUINFO_FIELD(verw_sel)(%r14) - .L\@_skip_verw: - -+ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV -+ - .L\@_skip_ist_exit: - .endm - -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 79b98f0fe7..0ff3c895ac 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -79,6 +79,7 @@ static int8_t __initdata opt_srb_lock = -1; - static bool __initdata opt_unpriv_mmio; - static bool __ro_after_init opt_fb_clear_mmio; - static int8_t __initdata opt_gds_mit = -1; -+static int8_t __initdata opt_div_scrub = -1; - - static int __init cf_check parse_spec_ctrl(const char *s) - { -@@ -133,6 +134,7 @@ static int __init cf_check parse_spec_ctrl(const char *s) - opt_srb_lock = 0; - opt_unpriv_mmio = false; - opt_gds_mit = 0; -+ opt_div_scrub = 0; - } - else if ( val > 0 ) - rc = -EINVAL; -@@ -285,6 +287,8 @@ static int __init cf_check parse_spec_ctrl(const char *s) - opt_unpriv_mmio = val; - else if ( (val = parse_boolean("gds-mit", s, ss)) >= 0 ) - opt_gds_mit = val; -+ else if ( (val = parse_boolean("div-scrub", s, ss)) >= 0 ) -+ opt_div_scrub = val; - else - rc = -EINVAL; - -@@ -485,7 +489,7 @@ static void __init print_details(enum ind_thunk thunk) - "\n"); - - /* Settings for Xen's protection, irrespective of guests. */ -- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s\n", -+ printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", - thunk == THUNK_NONE ? "N/A" : - thunk == THUNK_RETPOLINE ? "RETPOLINE" : - thunk == THUNK_LFENCE ? "LFENCE" : -@@ -510,6 +514,7 @@ static void __init print_details(enum ind_thunk thunk) - opt_l1d_flush ? " L1D_FLUSH" : "", - opt_md_clear_pv || opt_md_clear_hvm || - opt_fb_clear_mmio ? " VERW" : "", -+ opt_div_scrub ? " DIV" : "", - opt_branch_harden ? " BRANCH_HARDEN" : ""); - - /* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */ -@@ -967,6 +972,45 @@ static void __init srso_calculations(bool hw_smt_enabled) - setup_force_cpu_cap(X86_FEATURE_SRSO_NO); - } - -+/* -+ * The Div leakage issue is specific to the AMD Zen1 microarchitecure. -+ * -+ * However, there's no $FOO_NO bit defined, so if we're virtualised we have no -+ * hope of spotting the case where we might move to vulnerable hardware. We -+ * also can't make any useful conclusion about SMT-ness. -+ * -+ * Don't check the hypervisor bit, so at least we do the safe thing when -+ * booting on something that looks like a Zen1 CPU. -+ */ -+static bool __init has_div_vuln(void) -+{ -+ if ( !(boot_cpu_data.x86_vendor & -+ (X86_VENDOR_AMD | X86_VENDOR_HYGON)) ) -+ return false; -+ -+ if ( boot_cpu_data.x86 != 0x17 && boot_cpu_data.x86 != 0x18 ) -+ return false; -+ -+ return is_zen1_uarch(); -+} -+ -+static void __init div_calculations(bool hw_smt_enabled) -+{ -+ bool cpu_bug_div = has_div_vuln(); -+ -+ if ( opt_div_scrub == -1 ) -+ opt_div_scrub = cpu_bug_div; -+ -+ if ( opt_div_scrub ) -+ setup_force_cpu_cap(X86_FEATURE_SC_DIV); -+ -+ if ( opt_smt == -1 && !cpu_has_hypervisor && cpu_bug_div && hw_smt_enabled ) -+ warning_add( -+ "Booted on leaky-DIV hardware with SMT/Hyperthreading\n" -+ "enabled. Please assess your configuration and choose an\n" -+ "explicit 'smt=' setting. See XSA-439.\n"); -+} -+ - static void __init ibpb_calculations(void) - { - bool def_ibpb_entry = false; -@@ -1726,6 +1770,8 @@ void __init init_speculation_mitigations(void) - - ibpb_calculations(); - -+ div_calculations(hw_smt_enabled); -+ - /* Check whether Eager FPU should be enabled by default. */ - if ( opt_eager_fpu == -1 ) - opt_eager_fpu = should_use_eager_fpu(); --- -2.41.0 - diff --git a/xsa440-4.17.patch b/xsa440-4.17.patch deleted file mode 100644 index 4941afc..0000000 --- a/xsa440-4.17.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 5d8b3d1ec98e56155d9650d7f4a70cd8ba9dc27d Mon Sep 17 00:00:00 2001 -From: Julien Grall -Date: Fri, 22 Sep 2023 11:32:16 +0100 -Subject: tools/xenstored: domain_entry_fix(): Handle conflicting transaction - -The function domain_entry_fix() will be initially called to check if the -quota is correct before attempt to commit any nodes. So it would be -possible that accounting is temporarily negative. This is the case -in the following sequence: - - 1) Create 50 nodes - 2) Start two transactions - 3) Delete all the nodes in each transaction - 4) Commit the two transactions - -Because the first transaction will have succeed and updated the -accounting, there is no guarantee that 'd->nbentry + num' will still -be above 0. So the assert() would be triggered. -The assert() was introduced in dbef1f748289 ("tools/xenstore: simplify -and fix per domain node accounting") with the assumption that the -value can't be negative. As this is not true revert to the original -check but restricted to the path where we don't update. Take the -opportunity to explain the rationale behind the check. - -This CVE-2023-34323 / XSA-440. - -Reported-by: Stanislav Uschakow -Fixes: dbef1f748289 ("tools/xenstore: simplify and fix per domain node accounting") -Signed-off-by: Julien Grall -Reviewed-by: Juergen Gross - -diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c -index aa86892fed9e..6074df210c6e 100644 ---- a/tools/xenstore/xenstored_domain.c -+++ b/tools/xenstore/xenstored_domain.c -@@ -1094,10 +1094,20 @@ int domain_entry_fix(unsigned int domid, int num, bool update) - } - - cnt = d->nbentry + num; -- assert(cnt >= 0); - -- if (update) -+ if (update) { -+ assert(cnt >= 0); - d->nbentry = cnt; -+ } else if (cnt < 0) { -+ /* -+ * In a transaction when a node is being added/removed AND -+ * the same node has been added/removed outside the -+ * transaction in parallel, the result value may be negative. -+ * This is no problem, as the transaction will fail due to -+ * the resulting conflict. So override 'cnt'. -+ */ -+ cnt = 0; -+ } - - return domid_is_unprivileged(domid) ? cnt : 0; - } diff --git a/xsa442-4.17.patch b/xsa442-4.17.patch deleted file mode 100644 index a78bfdd..0000000 --- a/xsa442-4.17.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 5b2ccb60ff22fbff44dd66214c2956a434ee6271 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Tue, 13 Jun 2023 15:01:05 +0200 -Subject: [PATCH] iommu/amd-vi: flush IOMMU TLB when flushing the DTE -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The caching invalidation guidelines from the AMD-Vi specification (48882—Rev -3.07-PUB—Oct 2022) seem to be misleading on some hardware, as devices will -malfunction (see stale DMA mappings) if some fields of the DTE are updated but -the IOMMU TLB is not flushed. This has been observed in practice on AMD -systems. Due to the lack of guidance from the currently published -specification this patch aims to increase the flushing done in order to prevent -device malfunction. - -In order to fix, issue an INVALIDATE_IOMMU_PAGES command from -amd_iommu_flush_device(), flushing all the address space. Note this requires -callers to be adjusted in order to pass the DomID on the DTE previous to the -modification. - -Some call sites don't provide a valid DomID to amd_iommu_flush_device() in -order to avoid the flush. That's because the device had address translations -disabled and hence the previous DomID on the DTE is not valid. Note the -current logic relies on the entity disabling address translations to also flush -the TLB of the in use DomID. - -Device I/O TLB flushing when ATS are enabled is not covered by the current -change, as ATS usage is not security supported. - -This is XSA-442 / CVE-2023-34326 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/drivers/passthrough/amd/iommu.h | 3 ++- - xen/drivers/passthrough/amd/iommu_cmd.c | 10 +++++++++- - xen/drivers/passthrough/amd/iommu_guest.c | 5 +++-- - xen/drivers/passthrough/amd/iommu_init.c | 6 +++++- - xen/drivers/passthrough/amd/pci_amd_iommu.c | 14 ++++++++++---- - 5 files changed, 29 insertions(+), 9 deletions(-) - -diff --git a/xen/drivers/passthrough/amd/iommu.h b/xen/drivers/passthrough/amd/iommu.h -index 5429ada58ef5..a58be28bf96d 100644 ---- a/xen/drivers/passthrough/amd/iommu.h -+++ b/xen/drivers/passthrough/amd/iommu.h -@@ -283,7 +283,8 @@ void amd_iommu_flush_pages(struct domain *d, unsigned long dfn, - unsigned int order); - void amd_iommu_flush_iotlb(u8 devfn, const struct pci_dev *pdev, - uint64_t gaddr, unsigned int order); --void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf); -+void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf, -+ domid_t domid); - void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf); - void amd_iommu_flush_all_caches(struct amd_iommu *iommu); - -diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c b/xen/drivers/passthrough/amd/iommu_cmd.c -index 40ddf366bb4d..cb28b36abc38 100644 ---- a/xen/drivers/passthrough/amd/iommu_cmd.c -+++ b/xen/drivers/passthrough/amd/iommu_cmd.c -@@ -363,10 +363,18 @@ void amd_iommu_flush_pages(struct domain *d, - _amd_iommu_flush_pages(d, __dfn_to_daddr(dfn), order); - } - --void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf) -+void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf, -+ domid_t domid) - { - invalidate_dev_table_entry(iommu, bdf); - flush_command_buffer(iommu, 0); -+ -+ /* Also invalidate IOMMU TLB entries when flushing the DTE. */ -+ if ( domid != DOMID_INVALID ) -+ { -+ invalidate_iommu_pages(iommu, INV_IOMMU_ALL_PAGES_ADDRESS, domid, 0); -+ flush_command_buffer(iommu, 0); -+ } - } - - void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf) -diff --git a/xen/drivers/passthrough/amd/iommu_guest.c b/xen/drivers/passthrough/amd/iommu_guest.c -index 80a331f546ed..be86bce6fb03 100644 ---- a/xen/drivers/passthrough/amd/iommu_guest.c -+++ b/xen/drivers/passthrough/amd/iommu_guest.c -@@ -385,7 +385,7 @@ static int do_completion_wait(struct domain *d, cmd_entry_t *cmd) - - static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd) - { -- uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id; -+ uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id, prev_domid; - struct amd_iommu_dte *gdte, *mdte, *dte_base; - struct amd_iommu *iommu = NULL; - struct guest_iommu *g_iommu; -@@ -445,13 +445,14 @@ static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd) - req_id = get_dma_requestor_id(iommu->seg, mbdf); - dte_base = iommu->dev_table.buffer; - mdte = &dte_base[req_id]; -+ prev_domid = mdte->domain_id; - - spin_lock_irqsave(&iommu->lock, flags); - dte_set_gcr3_table(mdte, hdom_id, gcr3_mfn << PAGE_SHIFT, gv, glx); - - spin_unlock_irqrestore(&iommu->lock, flags); - -- amd_iommu_flush_device(iommu, req_id); -+ amd_iommu_flush_device(iommu, req_id, prev_domid); - - return 0; - } -diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c -index 166570648d26..101a60ce1794 100644 ---- a/xen/drivers/passthrough/amd/iommu_init.c -+++ b/xen/drivers/passthrough/amd/iommu_init.c -@@ -1547,7 +1547,11 @@ static int cf_check _invalidate_all_devices( - req_id = ivrs_mappings[bdf].dte_requestor_id; - if ( iommu ) - { -- amd_iommu_flush_device(iommu, req_id); -+ /* -+ * IOMMU TLB flush performed separately (see -+ * invalidate_all_domain_pages()). -+ */ -+ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID); - amd_iommu_flush_intremap(iommu, req_id); - } - } -diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c -index 94e37755064b..8641b84712a0 100644 ---- a/xen/drivers/passthrough/amd/pci_amd_iommu.c -+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c -@@ -192,10 +192,13 @@ static int __must_check amd_iommu_setup_domain_device( - - spin_unlock_irqrestore(&iommu->lock, flags); - -- amd_iommu_flush_device(iommu, req_id); -+ /* DTE didn't have DMA translations enabled, do not flush the TLB. */ -+ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID); - } - else if ( dte->pt_root != mfn_x(page_to_mfn(root_pg)) ) - { -+ domid_t prev_domid = dte->domain_id; -+ - /* - * Strictly speaking if the device is the only one with this requestor - * ID, it could be allowed to be re-assigned regardless of unity map -@@ -252,7 +255,7 @@ static int __must_check amd_iommu_setup_domain_device( - - spin_unlock_irqrestore(&iommu->lock, flags); - -- amd_iommu_flush_device(iommu, req_id); -+ amd_iommu_flush_device(iommu, req_id, prev_domid); - } - else - spin_unlock_irqrestore(&iommu->lock, flags); -@@ -421,6 +424,8 @@ static void amd_iommu_disable_domain_device(const struct domain *domain, - spin_lock_irqsave(&iommu->lock, flags); - if ( dte->tv || dte->v ) - { -+ domid_t prev_domid = dte->domain_id; -+ - /* See the comment in amd_iommu_setup_device_table(). */ - dte->int_ctl = IOMMU_DEV_TABLE_INT_CONTROL_ABORTED; - smp_wmb(); -@@ -439,7 +444,7 @@ static void amd_iommu_disable_domain_device(const struct domain *domain, - - spin_unlock_irqrestore(&iommu->lock, flags); - -- amd_iommu_flush_device(iommu, req_id); -+ amd_iommu_flush_device(iommu, req_id, prev_domid); - - AMD_IOMMU_DEBUG("Disable: device id = %#x, " - "domain = %d, paging mode = %d\n", -@@ -610,7 +615,8 @@ static int cf_check amd_iommu_add_device(u8 devfn, struct pci_dev *pdev) - - spin_unlock_irqrestore(&iommu->lock, flags); - -- amd_iommu_flush_device(iommu, bdf); -+ /* DTE didn't have DMA translations enabled, do not flush the TLB. */ -+ amd_iommu_flush_device(iommu, bdf, DOMID_INVALID); - } - - if ( amd_iommu_reserve_domain_unity_map( --- -2.42.0 - diff --git a/xsa443-4.17-01.patch b/xsa443-4.17-01.patch deleted file mode 100644 index d9ca3f8..0000000 --- a/xsa443-4.17-01.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 7e48562bf34e90f907491a0595782d2daa1ff3ad Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Thu, 14 Sep 2023 13:22:50 +0100 -Subject: [PATCH 01/11] libfsimage/xfs: Remove dead code - -xfs_info.agnolog (and related code) and XFS_INO_AGBNO_BITS are dead code -that serve no purpose. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Reviewed-by: Jan Beulich ---- - tools/libfsimage/xfs/fsys_xfs.c | 18 ------------------ - 1 file changed, 18 deletions(-) - -diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c -index d735a88e55f3..2800699f5985 100644 ---- a/tools/libfsimage/xfs/fsys_xfs.c -+++ b/tools/libfsimage/xfs/fsys_xfs.c -@@ -37,7 +37,6 @@ struct xfs_info { - int blklog; - int inopblog; - int agblklog; -- int agnolog; - unsigned int nextents; - xfs_daddr_t next; - xfs_daddr_t daddr; -@@ -65,9 +64,7 @@ static struct xfs_info xfs; - - #define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1)) - #define XFS_INO_OFFSET_BITS xfs.inopblog --#define XFS_INO_AGBNO_BITS xfs.agblklog - #define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog) --#define XFS_INO_AGNO_BITS xfs.agnolog - - static inline xfs_agblock_t - agino2agbno (xfs_agino_t agino) -@@ -149,20 +146,6 @@ xt_len (xfs_bmbt_rec_32_t *r) - return le32(r->l3) & mask32lo(21); - } - --static inline int --xfs_highbit32(xfs_uint32_t v) --{ -- int i; -- -- if (--v) { -- for (i = 0; i < 31; i++, v >>= 1) { -- if (v == 0) -- return i; -- } -- } -- return 0; --} -- - static int - isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len) - { -@@ -472,7 +455,6 @@ xfs_mount (fsi_file_t *ffi, const char *options) - - xfs.inopblog = super.sb_inopblog; - xfs.agblklog = super.sb_agblklog; -- xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount)); - - xfs.btnode_ptr0_off = - ((xfs.bsize - sizeof(xfs_btree_block_t)) / --- -2.42.0 - diff --git a/xsa443-4.17-02.patch b/xsa443-4.17-02.patch deleted file mode 100644 index 0f2edaf..0000000 --- a/xsa443-4.17-02.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c26327795b78c93f6fa6d5d46e34f59dc4046601 Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Thu, 14 Sep 2023 13:22:51 +0100 -Subject: [PATCH 02/11] libfsimage/xfs: Amend mask32lo() to allow the value 32 - -agblklog could plausibly be 32, but that would overflow this shift. -Perform the shift as ULL and cast to u32 at the end instead. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Acked-by: Jan Beulich ---- - tools/libfsimage/xfs/fsys_xfs.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c -index 2800699f5985..4720bb4505c8 100644 ---- a/tools/libfsimage/xfs/fsys_xfs.c -+++ b/tools/libfsimage/xfs/fsys_xfs.c -@@ -60,7 +60,7 @@ static struct xfs_info xfs; - #define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192)) - #define icore (inode->di_core) - --#define mask32lo(n) (((xfs_uint32_t)1 << (n)) - 1) -+#define mask32lo(n) ((xfs_uint32_t)((1ull << (n)) - 1)) - - #define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1)) - #define XFS_INO_OFFSET_BITS xfs.inopblog --- -2.42.0 - diff --git a/xsa443-4.17-03.patch b/xsa443-4.17-03.patch deleted file mode 100644 index b89721a..0000000 --- a/xsa443-4.17-03.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 199f0538bbec052028679a55ea512437170854c9 Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Thu, 14 Sep 2023 13:22:52 +0100 -Subject: [PATCH 03/11] libfsimage/xfs: Sanity-check the superblock during - mounts - -Sanity-check the XFS superblock for wellformedness at the mount handler. -This forces pygrub to abort parsing a potentially malformed filesystem and -ensures the invariants assumed throughout the rest of the code hold. - -Also, derive parameters from previously sanitized parameters where possible -(rather than reading them off the superblock) - -The code doesn't try to avoid overflowing the end of the disk, because -that's an unlikely and benign error. Parameters used in calculations of -xfs_daddr_t (like the root inode index) aren't in critical need of being -sanitized. - -The sanitization of agblklog is basically checking that no obvious -overflows happen on agblklog, and then ensuring agblocks is contained in -the range (2^(sb_agblklog-1), 2^sb_agblklog]. - -This is part of XSA-443 / CVE-2023-34325 - -Reported-by: Ferdinand Nölscher -Signed-off-by: Alejandro Vallejo -Reviewed-by: Jan Beulich ---- - tools/libfsimage/xfs/fsys_xfs.c | 48 ++++++++++++++++++++++++++------- - tools/libfsimage/xfs/xfs.h | 12 +++++++++ - 2 files changed, 50 insertions(+), 10 deletions(-) - -diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c -index 4720bb4505c8..e4eb7e1ee26f 100644 ---- a/tools/libfsimage/xfs/fsys_xfs.c -+++ b/tools/libfsimage/xfs/fsys_xfs.c -@@ -17,6 +17,7 @@ - * along with this program; If not, see . - */ - -+#include - #include - #include "xfs.h" - -@@ -433,29 +434,56 @@ first_dentry (fsi_file_t *ffi, xfs_ino_t *ino) - return next_dentry (ffi, ino); - } - -+static bool -+xfs_sb_is_invalid (const xfs_sb_t *super) -+{ -+ return (le32(super->sb_magicnum) != XFS_SB_MAGIC) -+ || ((le16(super->sb_versionnum) & XFS_SB_VERSION_NUMBITS) != -+ XFS_SB_VERSION_4) -+ || (super->sb_inodelog < XFS_SB_INODELOG_MIN) -+ || (super->sb_inodelog > XFS_SB_INODELOG_MAX) -+ || (super->sb_blocklog < XFS_SB_BLOCKLOG_MIN) -+ || (super->sb_blocklog > XFS_SB_BLOCKLOG_MAX) -+ || (super->sb_blocklog < super->sb_inodelog) -+ || (super->sb_agblklog > XFS_SB_AGBLKLOG_MAX) -+ || ((1ull << super->sb_agblklog) < le32(super->sb_agblocks)) -+ || (((1ull << super->sb_agblklog) >> 1) >= -+ le32(super->sb_agblocks)) -+ || ((super->sb_blocklog + super->sb_dirblklog) >= -+ XFS_SB_DIRBLK_NUMBITS); -+} -+ - static int - xfs_mount (fsi_file_t *ffi, const char *options) - { - xfs_sb_t super; - - if (!devread (ffi, 0, 0, sizeof(super), (char *)&super) -- || (le32(super.sb_magicnum) != XFS_SB_MAGIC) -- || ((le16(super.sb_versionnum) -- & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) { -+ || xfs_sb_is_invalid(&super)) { - return 0; - } - -- xfs.bsize = le32 (super.sb_blocksize); -- xfs.blklog = super.sb_blocklog; -- xfs.bdlog = xfs.blklog - SECTOR_BITS; -+ /* -+ * Not sanitized. It's exclusively used to generate disk addresses, -+ * so it's not important from a security standpoint. -+ */ - xfs.rootino = le64 (super.sb_rootino); -- xfs.isize = le16 (super.sb_inodesize); -- xfs.agblocks = le32 (super.sb_agblocks); -- xfs.dirbsize = xfs.bsize << super.sb_dirblklog; - -- xfs.inopblog = super.sb_inopblog; -+ /* -+ * Sanitized to be consistent with each other, only used to -+ * generate disk addresses, so it's safe -+ */ -+ xfs.agblocks = le32 (super.sb_agblocks); - xfs.agblklog = super.sb_agblklog; - -+ /* Derived from sanitized parameters */ -+ xfs.bsize = 1 << super.sb_blocklog; -+ xfs.blklog = super.sb_blocklog; -+ xfs.bdlog = super.sb_blocklog - SECTOR_BITS; -+ xfs.isize = 1 << super.sb_inodelog; -+ xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog); -+ xfs.inopblog = super.sb_blocklog - super.sb_inodelog; -+ - xfs.btnode_ptr0_off = - ((xfs.bsize - sizeof(xfs_btree_block_t)) / - (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t))) -diff --git a/tools/libfsimage/xfs/xfs.h b/tools/libfsimage/xfs/xfs.h -index 40699281e44d..b87e37d3d7e9 100644 ---- a/tools/libfsimage/xfs/xfs.h -+++ b/tools/libfsimage/xfs/xfs.h -@@ -134,6 +134,18 @@ typedef struct xfs_sb - xfs_uint8_t sb_dummy[7]; /* padding */ - } xfs_sb_t; - -+/* Bound taken from xfs.c in GRUB2. It doesn't exist in the spec */ -+#define XFS_SB_DIRBLK_NUMBITS 27 -+/* Implied by the XFS specification. The minimum block size is 512 octets */ -+#define XFS_SB_BLOCKLOG_MIN 9 -+/* Implied by the XFS specification. The maximum block size is 65536 octets */ -+#define XFS_SB_BLOCKLOG_MAX 16 -+/* Implied by the XFS specification. The minimum inode size is 256 octets */ -+#define XFS_SB_INODELOG_MIN 8 -+/* Implied by the XFS specification. The maximum inode size is 2048 octets */ -+#define XFS_SB_INODELOG_MAX 11 -+/* High bound for sb_agblklog */ -+#define XFS_SB_AGBLKLOG_MAX 32 - - /* those are from xfs_btree.h */ - --- -2.42.0 - diff --git a/xsa443-4.17-04.patch b/xsa443-4.17-04.patch deleted file mode 100644 index dde095e..0000000 --- a/xsa443-4.17-04.patch +++ /dev/null @@ -1,61 +0,0 @@ -From c66fd01277939634c624c8340838682d9d4fd839 Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Thu, 14 Sep 2023 13:22:53 +0100 -Subject: [PATCH 04/11] libfsimage/xfs: Add compile-time check to libfsimage - -Adds the common tools include folder to the -I compile flags -of libfsimage. This allows us to use: - xen-tools/common-macros.h:BUILD_BUG_ON() - -With it, statically assert a sanitized "blocklog - SECTOR_BITS" cannot -underflow. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Reviewed-by: Jan Beulich ---- - tools/libfsimage/common.mk | 2 +- - tools/libfsimage/xfs/fsys_xfs.c | 4 +++- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/tools/libfsimage/common.mk b/tools/libfsimage/common.mk -index 4fc8c6679599..e4336837d045 100644 ---- a/tools/libfsimage/common.mk -+++ b/tools/libfsimage/common.mk -@@ -1,7 +1,7 @@ - include $(XEN_ROOT)/tools/Rules.mk - - FSDIR := $(libdir)/xenfsimage --CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ -DFSIMAGE_FSDIR=\"$(FSDIR)\" -+CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ $(CFLAGS_xeninclude) -DFSIMAGE_FSDIR=\"$(FSDIR)\" - CFLAGS += -D_GNU_SOURCE - LDFLAGS += -L../common/ - -diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c -index e4eb7e1ee26f..4a8dd6f2397b 100644 ---- a/tools/libfsimage/xfs/fsys_xfs.c -+++ b/tools/libfsimage/xfs/fsys_xfs.c -@@ -19,6 +19,7 @@ - - #include - #include -+#include - #include "xfs.h" - - #define MAX_LINK_COUNT 8 -@@ -477,9 +478,10 @@ xfs_mount (fsi_file_t *ffi, const char *options) - xfs.agblklog = super.sb_agblklog; - - /* Derived from sanitized parameters */ -+ BUILD_BUG_ON(XFS_SB_BLOCKLOG_MIN < SECTOR_BITS); -+ xfs.bdlog = super.sb_blocklog - SECTOR_BITS; - xfs.bsize = 1 << super.sb_blocklog; - xfs.blklog = super.sb_blocklog; -- xfs.bdlog = super.sb_blocklog - SECTOR_BITS; - xfs.isize = 1 << super.sb_inodelog; - xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog); - xfs.inopblog = super.sb_blocklog - super.sb_inodelog; --- -2.42.0 - diff --git a/xsa443-4.17-05.patch b/xsa443-4.17-05.patch deleted file mode 100644 index b2f5daa..0000000 --- a/xsa443-4.17-05.patch +++ /dev/null @@ -1,59 +0,0 @@ -From ad5d0db5e68e5d4e79255fa85d9cb0069bb1c5d5 Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Mon, 25 Sep 2023 18:32:21 +0100 -Subject: [PATCH 05/11] tools/pygrub: Remove unnecessary hypercall - -There's a hypercall being issued in order to determine whether PV64 is -supported, but since Xen 4.3 that's strictly true so it's not required. - -Plus, this way we can avoid mapping the privcmd interface altogether in the -depriv pygrub. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Reviewed-by: Andrew Cooper ---- - tools/pygrub/src/pygrub | 12 +----------- - 1 file changed, 1 insertion(+), 11 deletions(-) - -diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub -index ce7ab0eb8cf3..ce4e07d3e823 100755 ---- a/tools/pygrub/src/pygrub -+++ b/tools/pygrub/src/pygrub -@@ -18,7 +18,6 @@ import os, sys, string, struct, tempfile, re, traceback, stat, errno - import copy - import logging - import platform --import xen.lowlevel.xc - - import curses, _curses, curses.textpad, curses.ascii - import getopt -@@ -668,14 +667,6 @@ def run_grub(file, entry, fs, cfg_args): - - return grubcfg - --def supports64bitPVguest(): -- xc = xen.lowlevel.xc.xc() -- caps = xc.xeninfo()['xen_caps'].split(" ") -- for cap in caps: -- if cap == "xen-3.0-x86_64": -- return True -- return False -- - # If nothing has been specified, look for a Solaris domU. If found, perform the - # necessary tweaks. - def sniff_solaris(fs, cfg): -@@ -684,8 +675,7 @@ def sniff_solaris(fs, cfg): - return cfg - - if not cfg["kernel"]: -- if supports64bitPVguest() and \ -- fs.file_exists("/platform/i86xpv/kernel/amd64/unix"): -+ if fs.file_exists("/platform/i86xpv/kernel/amd64/unix"): - cfg["kernel"] = "/platform/i86xpv/kernel/amd64/unix" - cfg["ramdisk"] = "/platform/i86pc/amd64/boot_archive" - elif fs.file_exists("/platform/i86xpv/kernel/unix"): --- -2.42.0 - diff --git a/xsa443-4.17-06.patch b/xsa443-4.17-06.patch deleted file mode 100644 index 22af109..0000000 --- a/xsa443-4.17-06.patch +++ /dev/null @@ -1,65 +0,0 @@ -From d3ceb0b314005a656dd2ca4b2821575a36f8426d Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Mon, 25 Sep 2023 18:32:22 +0100 -Subject: [PATCH 06/11] tools/pygrub: Small refactors - -Small tidy up to ensure output_directory always has a trailing '/' to ease -concatenating paths and that `output` can only be a filename or None. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Acked-by: Andrew Cooper ---- - tools/pygrub/src/pygrub | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub -index ce4e07d3e823..1042c05b8676 100755 ---- a/tools/pygrub/src/pygrub -+++ b/tools/pygrub/src/pygrub -@@ -793,7 +793,7 @@ if __name__ == "__main__": - debug = False - not_really = False - output_format = "sxp" -- output_directory = "/var/run/xen/pygrub" -+ output_directory = "/var/run/xen/pygrub/" - - # what was passed in - incfg = { "kernel": None, "ramdisk": None, "args": "" } -@@ -815,7 +815,8 @@ if __name__ == "__main__": - usage() - sys.exit() - elif o in ("--output",): -- output = a -+ if a != "-": -+ output = a - elif o in ("--kernel",): - incfg["kernel"] = a - elif o in ("--ramdisk",): -@@ -847,12 +848,11 @@ if __name__ == "__main__": - if not os.path.isdir(a): - print("%s is not an existing directory" % a) - sys.exit(1) -- output_directory = a -+ output_directory = a + '/' - - if debug: - logging.basicConfig(level=logging.DEBUG) - -- - try: - os.makedirs(output_directory, 0o700) - except OSError as e: -@@ -861,7 +861,7 @@ if __name__ == "__main__": - else: - raise - -- if output is None or output == "-": -+ if output is None: - fd = sys.stdout.fileno() - else: - fd = os.open(output, os.O_WRONLY) --- -2.42.0 - diff --git a/xsa443-4.17-07.patch b/xsa443-4.17-07.patch deleted file mode 100644 index 94da883..0000000 --- a/xsa443-4.17-07.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 9e80cfecde338cea0db136c2fb5ed78d6081e05f Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Mon, 25 Sep 2023 18:32:23 +0100 -Subject: [PATCH 07/11] tools/pygrub: Open the output files earlier - -This patch allows pygrub to get ahold of every RW file descriptor it needs -early on. A later patch will clamp the filesystem it can access so it can't -obtain any others. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Acked-by: Andrew Cooper ---- - tools/pygrub/src/pygrub | 37 ++++++++++++++++++++++--------------- - 1 file changed, 22 insertions(+), 15 deletions(-) - -diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub -index 1042c05b8676..91e2ec2ab105 100755 ---- a/tools/pygrub/src/pygrub -+++ b/tools/pygrub/src/pygrub -@@ -738,8 +738,7 @@ if __name__ == "__main__": - def usage(): - print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] " %(sys.argv[0],), file=sys.stderr) - -- def copy_from_image(fs, file_to_read, file_type, output_directory, -- not_really): -+ def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really): - if not_really: - if fs.file_exists(file_to_read): - return "<%s:%s>" % (file_type, file_to_read) -@@ -750,21 +749,18 @@ if __name__ == "__main__": - except Exception as e: - print(e, file=sys.stderr) - sys.exit("Error opening %s in guest" % file_to_read) -- (tfd, ret) = tempfile.mkstemp(prefix="boot_"+file_type+".", -- dir=output_directory) - dataoff = 0 - while True: - data = datafile.read(FS_READ_MAX, dataoff) - if len(data) == 0: -- os.close(tfd) -+ os.close(fd_dst) - del datafile -- return ret -+ return - try: -- os.write(tfd, data) -+ os.write(fd_dst, data) - except Exception as e: - print(e, file=sys.stderr) -- os.close(tfd) -- os.unlink(ret) -+ os.unlink(path_dst) - del datafile - sys.exit("Error writing temporary copy of "+file_type) - dataoff += len(data) -@@ -861,6 +857,14 @@ if __name__ == "__main__": - else: - raise - -+ if not_really: -+ fd_kernel = path_kernel = fd_ramdisk = path_ramdisk = None -+ else: -+ (fd_kernel, path_kernel) = tempfile.mkstemp(prefix="boot_kernel.", -+ dir=output_directory) -+ (fd_ramdisk, path_ramdisk) = tempfile.mkstemp(prefix="boot_ramdisk.", -+ dir=output_directory) -+ - if output is None: - fd = sys.stdout.fileno() - else: -@@ -920,20 +924,23 @@ if __name__ == "__main__": - if fs is None: - raise RuntimeError("Unable to find partition containing kernel") - -- bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel", -- output_directory, not_really) -+ copy_from_image(fs, chosencfg["kernel"], "kernel", -+ fd_kernel, path_kernel, not_really) -+ bootcfg["kernel"] = path_kernel - - if chosencfg["ramdisk"]: - try: -- bootcfg["ramdisk"] = copy_from_image(fs, chosencfg["ramdisk"], -- "ramdisk", output_directory, -- not_really) -+ copy_from_image(fs, chosencfg["ramdisk"], "ramdisk", -+ fd_ramdisk, path_ramdisk, not_really) - except: - if not not_really: -- os.unlink(bootcfg["kernel"]) -+ os.unlink(path_kernel) - raise -+ bootcfg["ramdisk"] = path_ramdisk - else: - initrd = None -+ if not not_really: -+ os.unlink(path_ramdisk) - - args = None - if chosencfg["args"]: --- -2.42.0 - diff --git a/xsa443-4.17-08.patch b/xsa443-4.17-08.patch deleted file mode 100644 index bd7de1d..0000000 --- a/xsa443-4.17-08.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 2fb4cdcedd8720f78c4bd44739a5d30dd1a7d9a5 Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Mon, 25 Sep 2023 18:32:24 +0100 -Subject: [PATCH 08/11] tools/libfsimage: Export a new function to preload all - plugins - -This is work required in order to let pygrub operate in highly deprivileged -chroot mode. This patch adds a function that preloads every plugin, hence -ensuring that a on function exit, every shared library is loaded in memory. - -The new "init" function is supposed to be used before depriv, but that's -fine because it's not acting on untrusted data. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Acked-by: Andrew Cooper ---- - tools/libfsimage/common/fsimage_plugin.c | 4 ++-- - tools/libfsimage/common/mapfile-GNU | 1 + - tools/libfsimage/common/mapfile-SunOS | 1 + - tools/libfsimage/common/xenfsimage.h | 8 ++++++++ - tools/pygrub/src/fsimage/fsimage.c | 15 +++++++++++++++ - 5 files changed, 27 insertions(+), 2 deletions(-) - -diff --git a/tools/libfsimage/common/fsimage_plugin.c b/tools/libfsimage/common/fsimage_plugin.c -index de1412b4233a..d0cb9e96a654 100644 ---- a/tools/libfsimage/common/fsimage_plugin.c -+++ b/tools/libfsimage/common/fsimage_plugin.c -@@ -119,7 +119,7 @@ fail: - return (-1); - } - --static int load_plugins(void) -+int fsi_init(void) - { - const char *fsdir = getenv("XEN_FSIMAGE_FSDIR"); - struct dirent *dp = NULL; -@@ -180,7 +180,7 @@ int find_plugin(fsi_t *fsi, const char *path, const char *options) - fsi_plugin_t *fp; - int ret = 0; - -- if (plugins == NULL && (ret = load_plugins()) != 0) -+ if (plugins == NULL && (ret = fsi_init()) != 0) - goto out; - - for (fp = plugins; fp != NULL; fp = fp->fp_next) { -diff --git a/tools/libfsimage/common/mapfile-GNU b/tools/libfsimage/common/mapfile-GNU -index 26d4d7a69ec7..2d54d527d7f5 100644 ---- a/tools/libfsimage/common/mapfile-GNU -+++ b/tools/libfsimage/common/mapfile-GNU -@@ -1,6 +1,7 @@ - VERSION { - libfsimage.so.1.0 { - global: -+ fsi_init; - fsi_open_fsimage; - fsi_close_fsimage; - fsi_file_exists; -diff --git a/tools/libfsimage/common/mapfile-SunOS b/tools/libfsimage/common/mapfile-SunOS -index e99b90b65077..48deedb4252f 100644 ---- a/tools/libfsimage/common/mapfile-SunOS -+++ b/tools/libfsimage/common/mapfile-SunOS -@@ -1,5 +1,6 @@ - libfsimage.so.1.0 { - global: -+ fsi_init; - fsi_open_fsimage; - fsi_close_fsimage; - fsi_file_exists; -diff --git a/tools/libfsimage/common/xenfsimage.h b/tools/libfsimage/common/xenfsimage.h -index 201abd54f23a..341883b2d71a 100644 ---- a/tools/libfsimage/common/xenfsimage.h -+++ b/tools/libfsimage/common/xenfsimage.h -@@ -35,6 +35,14 @@ extern C { - typedef struct fsi fsi_t; - typedef struct fsi_file fsi_file_t; - -+/* -+ * Optional initialization function. If invoked it loads the associated -+ * dynamic libraries for the backends ahead of time. This is required if -+ * the library is to run as part of a highly deprivileged executable, as -+ * the libraries may not be reachable after depriv. -+ */ -+int fsi_init(void); -+ - fsi_t *fsi_open_fsimage(const char *, uint64_t, const char *); - void fsi_close_fsimage(fsi_t *); - -diff --git a/tools/pygrub/src/fsimage/fsimage.c b/tools/pygrub/src/fsimage/fsimage.c -index 2ebbbe35df92..92fbf2851f01 100644 ---- a/tools/pygrub/src/fsimage/fsimage.c -+++ b/tools/pygrub/src/fsimage/fsimage.c -@@ -286,6 +286,15 @@ fsimage_getbootstring(PyObject *o, PyObject *args) - return Py_BuildValue("s", bootstring); - } - -+static PyObject * -+fsimage_init(PyObject *o, PyObject *args) -+{ -+ if (!PyArg_ParseTuple(args, "")) -+ return (NULL); -+ -+ return Py_BuildValue("i", fsi_init()); -+} -+ - PyDoc_STRVAR(fsimage_open__doc__, - "open(name, [offset=off]) - Open the given file as a filesystem image.\n" - "\n" -@@ -297,7 +306,13 @@ PyDoc_STRVAR(fsimage_getbootstring__doc__, - "getbootstring(fs) - Return the boot string needed for this file system " - "or NULL if none is needed.\n"); - -+PyDoc_STRVAR(fsimage_init__doc__, -+ "init() - Loads every dynamic library contained in xenfsimage " -+ "into memory so that it can be used in chrooted environments.\n"); -+ - static struct PyMethodDef fsimage_module_methods[] = { -+ { "init", (PyCFunction)fsimage_init, -+ METH_VARARGS, fsimage_init__doc__ }, - { "open", (PyCFunction)fsimage_open, - METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ }, - { "getbootstring", (PyCFunction)fsimage_getbootstring, --- -2.42.0 - diff --git a/xsa443-4.17-09.patch b/xsa443-4.17-09.patch deleted file mode 100644 index 2e3ebd8..0000000 --- a/xsa443-4.17-09.patch +++ /dev/null @@ -1,307 +0,0 @@ -From 150771ce86a07e469e34941a63c56e2cf242223b Mon Sep 17 00:00:00 2001 -From: Alejandro Vallejo -Date: Mon, 25 Sep 2023 18:32:25 +0100 -Subject: [PATCH 09/11] tools/pygrub: Deprivilege pygrub - -Introduce a --runas= flag to deprivilege pygrub on Linux and *BSDs. It -also implicitly creates a chroot env where it drops a deprivileged forked -process. The chroot itself is cleaned up at the end. - -If the --runas arg is present, then pygrub forks, leaving the child to -deprivilege itself, and waiting for it to complete. When the child exists, -the parent performs cleanup and exits with the same error code. - -This is roughly what the child does: - 1. Initialize libfsimage (this loads every .so in memory so the chroot - can avoid bind-mounting /{,usr}/lib* - 2. Create a temporary empty chroot directory - 3. Mount tmpfs in it - 4. Bind mount the disk inside, because libfsimage expects a path, not a - file descriptor. - 5. Remount the root tmpfs to be stricter (ro,nosuid,nodev) - 6. Set RLIMIT_FSIZE to a sensibly high amount (128 MiB) - 7. Depriv gid, groups and uid - -With this scheme in place, the "output" files are writable (up to -RLIMIT_FSIZE octets) and the exposed filesystem is immutable and contains -the single only file we can't easily get rid of (the disk). - -If running on Linux, the child process also unshares mount, IPC, and -network namespaces before dropping its privileges. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Alejandro Vallejo -Acked-by: Andrew Cooper ---- - tools/pygrub/setup.py | 2 +- - tools/pygrub/src/pygrub | 162 +++++++++++++++++++++++++++++++++++++--- - 2 files changed, 154 insertions(+), 10 deletions(-) - -diff --git a/tools/pygrub/setup.py b/tools/pygrub/setup.py -index 0e4e3d02d372..06b96733d020 100644 ---- a/tools/pygrub/setup.py -+++ b/tools/pygrub/setup.py -@@ -17,7 +17,7 @@ xenfsimage = Extension("xenfsimage", - pkgs = [ 'grub' ] - - setup(name='pygrub', -- version='0.6', -+ version='0.7', - description='Boot loader that looks a lot like grub for Xen', - author='Jeremy Katz', - author_email='katzj@redhat.com', -diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub -index 91e2ec2ab105..7cea496ade08 100755 ---- a/tools/pygrub/src/pygrub -+++ b/tools/pygrub/src/pygrub -@@ -16,8 +16,11 @@ from __future__ import print_function - - import os, sys, string, struct, tempfile, re, traceback, stat, errno - import copy -+import ctypes, ctypes.util - import logging - import platform -+import resource -+import subprocess - - import curses, _curses, curses.textpad, curses.ascii - import getopt -@@ -27,10 +30,135 @@ import grub.GrubConf - import grub.LiloConf - import grub.ExtLinuxConf - --PYGRUB_VER = 0.6 -+PYGRUB_VER = 0.7 - FS_READ_MAX = 1024 * 1024 - SECTOR_SIZE = 512 - -+# Unless provided through the env variable PYGRUB_MAX_FILE_SIZE_MB, then -+# this is the maximum filesize allowed for files written by the depriv -+# pygrub -+LIMIT_FSIZE = 128 << 20 -+ -+CLONE_NEWNS = 0x00020000 # mount namespace -+CLONE_NEWNET = 0x40000000 # network namespace -+CLONE_NEWIPC = 0x08000000 # IPC namespace -+ -+def unshare(flags): -+ if not sys.platform.startswith("linux"): -+ print("skip_unshare reason=not_linux platform=%s", sys.platform, file=sys.stderr) -+ return -+ -+ libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) -+ unshare_prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True) -+ unshare = unshare_prototype(('unshare', libc)) -+ -+ if unshare(flags) < 0: -+ raise OSError(ctypes.get_errno(), os.strerror(ctypes.get_errno())) -+ -+def bind_mount(src, dst, options): -+ open(dst, "a").close() # touch -+ -+ rc = subprocess.call(["mount", "--bind", "-o", options, src, dst]) -+ if rc != 0: -+ raise RuntimeError("bad_mount: src=%s dst=%s opts=%s" % -+ (src, dst, options)) -+ -+def downgrade_rlimits(): -+ # Wipe the authority to use unrequired resources -+ resource.setrlimit(resource.RLIMIT_NPROC, (0, 0)) -+ resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) -+ resource.setrlimit(resource.RLIMIT_MEMLOCK, (0, 0)) -+ -+ # py2's resource module doesn't know about resource.RLIMIT_MSGQUEUE -+ # -+ # TODO: Use resource.RLIMIT_MSGQUEUE after python2 is deprecated -+ if sys.platform.startswith('linux'): -+ RLIMIT_MSGQUEUE = 12 -+ resource.setrlimit(RLIMIT_MSGQUEUE, (0, 0)) -+ -+ # The final look of the filesystem for this process is fully RO, but -+ # note we have some file descriptor already open (notably, kernel and -+ # ramdisk). In order to avoid a compromised pygrub from filling up the -+ # filesystem we set RLIMIT_FSIZE to a high bound, so that the file -+ # write permissions are bound. -+ fsize = LIMIT_FSIZE -+ if "PYGRUB_MAX_FILE_SIZE_MB" in os.environ.keys(): -+ fsize = os.environ["PYGRUB_MAX_FILE_SIZE_MB"] << 20 -+ -+ resource.setrlimit(resource.RLIMIT_FSIZE, (fsize, fsize)) -+ -+def depriv(output_directory, output, device, uid, path_kernel, path_ramdisk): -+ # The only point of this call is to force the loading of libfsimage. -+ # That way, we don't need to bind-mount it into the chroot -+ rc = xenfsimage.init() -+ if rc != 0: -+ os.unlink(path_ramdisk) -+ os.unlink(path_kernel) -+ raise RuntimeError("bad_xenfsimage: rc=%d" % rc) -+ -+ # Create a temporary directory for the chroot -+ chroot = tempfile.mkdtemp(prefix=str(uid)+'-', dir=output_directory) + '/' -+ device_path = '/device' -+ -+ pid = os.fork() -+ if pid: -+ # parent -+ _, rc = os.waitpid(pid, 0) -+ -+ for path in [path_kernel, path_ramdisk]: -+ # If the child didn't write anything, just get rid of it, -+ # otherwise we end up consuming a 0-size file when parsing -+ # systems without a ramdisk that the ultimate caller of pygrub -+ # may just be unaware of -+ if rc != 0 or os.path.getsize(path) == 0: -+ os.unlink(path) -+ -+ # Normally, unshare(CLONE_NEWNS) will ensure this is not required. -+ # However, this syscall doesn't exist in *BSD systems and doesn't -+ # auto-unmount everything on older Linux kernels (At least as of -+ # Linux 4.19, but it seems fixed in 5.15). Either way, -+ # recursively unmount everything if needed. Quietly. -+ with open('/dev/null', 'w') as devnull: -+ subprocess.call(["umount", "-f", chroot + device_path], -+ stdout=devnull, stderr=devnull) -+ subprocess.call(["umount", "-f", chroot], -+ stdout=devnull, stderr=devnull) -+ os.rmdir(chroot) -+ -+ sys.exit(rc) -+ -+ # By unsharing the namespace we're making sure it's all bulk-released -+ # at the end, when the namespaces disappear. This means the kernel does -+ # (almost) all the cleanup for us and the parent just has to remove the -+ # temporary directory. -+ unshare(CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET) -+ -+ # Set sensible limits using the setrlimit interface -+ downgrade_rlimits() -+ -+ # We'll mount tmpfs on the chroot to ensure the deprivileged child -+ # cannot affect the persistent state. It's RW now in order to -+ # bind-mount the device, but note it's remounted RO after that. -+ rc = subprocess.call(["mount", "-t", "tmpfs", "none", chroot]) -+ if rc != 0: -+ raise RuntimeError("mount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot)) -+ -+ # Bind the untrusted device RO -+ bind_mount(device, chroot + device_path, "ro,nosuid,noexec") -+ -+ rc = subprocess.call(["mount", "-t", "tmpfs", "-o", "remount,ro,nosuid,noexec,nodev", "none", chroot]) -+ if rc != 0: -+ raise RuntimeError("remount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot)) -+ -+ # Drop superpowers! -+ os.chroot(chroot) -+ os.chdir('/') -+ os.setgid(uid) -+ os.setgroups([uid]) -+ os.setuid(uid) -+ -+ return device_path -+ - def read_size_roundup(fd, size): - if platform.system() != 'FreeBSD': - return size -@@ -736,7 +864,7 @@ if __name__ == "__main__": - sel = None - - def usage(): -- print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] " %(sys.argv[0],), file=sys.stderr) -+ print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--runas=] [--offset=] " %(sys.argv[0],), file=sys.stderr) - - def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really): - if not_really: -@@ -760,7 +888,8 @@ if __name__ == "__main__": - os.write(fd_dst, data) - except Exception as e: - print(e, file=sys.stderr) -- os.unlink(path_dst) -+ if path_dst: -+ os.unlink(path_dst) - del datafile - sys.exit("Error writing temporary copy of "+file_type) - dataoff += len(data) -@@ -769,7 +898,7 @@ if __name__ == "__main__": - opts, args = getopt.gnu_getopt(sys.argv[1:], 'qilnh::', - ["quiet", "interactive", "list-entries", "not-really", "help", - "output=", "output-format=", "output-directory=", "offset=", -- "entry=", "kernel=", -+ "runas=", "entry=", "kernel=", - "ramdisk=", "args=", "isconfig", "debug"]) - except getopt.GetoptError: - usage() -@@ -790,6 +919,7 @@ if __name__ == "__main__": - not_really = False - output_format = "sxp" - output_directory = "/var/run/xen/pygrub/" -+ uid = None - - # what was passed in - incfg = { "kernel": None, "ramdisk": None, "args": "" } -@@ -813,6 +943,13 @@ if __name__ == "__main__": - elif o in ("--output",): - if a != "-": - output = a -+ elif o in ("--runas",): -+ try: -+ uid = int(a) -+ except ValueError: -+ print("runas value must be an integer user id") -+ usage() -+ sys.exit(1) - elif o in ("--kernel",): - incfg["kernel"] = a - elif o in ("--ramdisk",): -@@ -849,6 +986,10 @@ if __name__ == "__main__": - if debug: - logging.basicConfig(level=logging.DEBUG) - -+ if interactive and uid: -+ print("In order to use --runas, you must also set --entry or -q", file=sys.stderr) -+ sys.exit(1) -+ - try: - os.makedirs(output_directory, 0o700) - except OSError as e: -@@ -870,6 +1011,9 @@ if __name__ == "__main__": - else: - fd = os.open(output, os.O_WRONLY) - -+ if uid: -+ file = depriv(output_directory, output, file, uid, path_kernel, path_ramdisk) -+ - # debug - if isconfig: - chosencfg = run_grub(file, entry, fs, incfg["args"]) -@@ -925,21 +1069,21 @@ if __name__ == "__main__": - raise RuntimeError("Unable to find partition containing kernel") - - copy_from_image(fs, chosencfg["kernel"], "kernel", -- fd_kernel, path_kernel, not_really) -+ fd_kernel, None if uid else path_kernel, not_really) - bootcfg["kernel"] = path_kernel - - if chosencfg["ramdisk"]: - try: - copy_from_image(fs, chosencfg["ramdisk"], "ramdisk", -- fd_ramdisk, path_ramdisk, not_really) -+ fd_ramdisk, None if uid else path_ramdisk, not_really) - except: -- if not not_really: -- os.unlink(path_kernel) -+ if not uid and not not_really: -+ os.unlink(path_kernel) - raise - bootcfg["ramdisk"] = path_ramdisk - else: - initrd = None -- if not not_really: -+ if not uid and not not_really: - os.unlink(path_ramdisk) - - args = None --- -2.42.0 - diff --git a/xsa443-4.17-10.patch b/xsa443-4.17-10.patch deleted file mode 100644 index 7c91f32..0000000 --- a/xsa443-4.17-10.patch +++ /dev/null @@ -1,250 +0,0 @@ -From 698b451473a6d868ca0f60a124fc4f31d81cd7b1 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Mon, 25 Sep 2023 14:30:20 +0200 -Subject: [PATCH 10/11] libxl: add support for running bootloader in restricted - mode -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Much like the device model depriv mode, add the same kind of support for the -bootloader. Such feature allows passing a UID as a parameter for the -bootloader to run as, together with the bootloader itself taking the necessary -actions to isolate. - -Note that the user to run the bootloader as must have the right permissions to -access the guest disk image (in read mode only), and that the bootloader will -be run in non-interactive mode when restricted. - -If enabled bootloader restrict mode will attempt to re-use the user(s) from the -QEMU depriv implementation if no user is provided on the configuration file or -the environment. See docs/features/qemu-deprivilege.pandoc for more -information about how to setup those users. - -Bootloader restrict mode is not enabled by default as it requires certain -setup to be done first (setup of the user(s) to use in restrict mode). - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Anthony PERARD ---- - docs/man/xl.1.pod.in | 33 +++++++++++ - tools/libs/light/libxl_bootloader.c | 89 ++++++++++++++++++++++++++++- - tools/libs/light/libxl_dm.c | 8 +-- - tools/libs/light/libxl_internal.h | 8 +++ - 4 files changed, 131 insertions(+), 7 deletions(-) - -diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in -index 101e14241d1c..4831e122427d 100644 ---- a/docs/man/xl.1.pod.in -+++ b/docs/man/xl.1.pod.in -@@ -1957,6 +1957,39 @@ ignored: - - =back - -+=head1 ENVIRONMENT VARIABLES -+ -+The following environment variables shall affect the execution of xl: -+ -+=over 4 -+ -+=item LIBXL_BOOTLOADER_RESTRICT -+ -+Attempt to restrict the bootloader after startup, to limit the -+consequences of security vulnerabilities due to parsing guest -+owned image files. -+ -+See docs/features/qemu-deprivilege.pandoc for more information -+on how to setup the unprivileged users. -+ -+Note that running the bootloader in restricted mode also implies using -+non-interactive mode, and the disk image must be readable by the -+restricted user. -+ -+Having this variable set is equivalent to enabling the option, even if the -+value is 0. -+ -+=item LIBXL_BOOTLOADER_USER -+ -+When using bootloader_restrict, run the bootloader as this user. If -+not set the default QEMU restrict users will be used. -+ -+NOTE: Each domain MUST have a SEPARATE username. -+ -+See docs/features/qemu-deprivilege.pandoc for more information. -+ -+=back -+ - =head1 SEE ALSO - - The following man pages: -diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c -index 108329b4a5bb..23c0ef3e8935 100644 ---- a/tools/libs/light/libxl_bootloader.c -+++ b/tools/libs/light/libxl_bootloader.c -@@ -14,6 +14,7 @@ - - #include "libxl_osdeps.h" /* must come before any other headers */ - -+#include - #include - #ifdef HAVE_UTMP_H - #include -@@ -42,8 +43,71 @@ static void bootloader_arg(libxl__bootloader_state *bl, const char *arg) - bl->args[bl->nargs++] = arg; - } - --static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, -- const char *bootloader_path) -+static int bootloader_uid(libxl__gc *gc, domid_t guest_domid, -+ const char *user, uid_t *intended_uid) -+{ -+ struct passwd *user_base, user_pwbuf; -+ int rc; -+ -+ if (user) { -+ rc = userlookup_helper_getpwnam(gc, user, &user_pwbuf, &user_base); -+ if (rc) return rc; -+ -+ if (!user_base) { -+ LOGD(ERROR, guest_domid, "Couldn't find user %s", user); -+ return ERROR_INVAL; -+ } -+ -+ *intended_uid = user_base->pw_uid; -+ return 0; -+ } -+ -+ /* Re-use QEMU user range for the bootloader. */ -+ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_RANGE_BASE, -+ &user_pwbuf, &user_base); -+ if (rc) return rc; -+ -+ if (user_base) { -+ struct passwd *user_clash, user_clash_pwbuf; -+ uid_t temp_uid = user_base->pw_uid + guest_domid; -+ -+ rc = userlookup_helper_getpwuid(gc, temp_uid, &user_clash_pwbuf, -+ &user_clash); -+ if (rc) return rc; -+ -+ if (user_clash) { -+ LOGD(ERROR, guest_domid, -+ "wanted to use uid %ld (%s + %d) but that is user %s !", -+ (long)temp_uid, LIBXL_QEMU_USER_RANGE_BASE, -+ guest_domid, user_clash->pw_name); -+ return ERROR_INVAL; -+ } -+ -+ *intended_uid = temp_uid; -+ return 0; -+ } -+ -+ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_SHARED, &user_pwbuf, -+ &user_base); -+ if (rc) return rc; -+ -+ if (user_base) { -+ LOGD(WARN, guest_domid, "Could not find user %s, falling back to %s", -+ LIBXL_QEMU_USER_RANGE_BASE, LIBXL_QEMU_USER_SHARED); -+ *intended_uid = user_base->pw_uid; -+ -+ return 0; -+ } -+ -+ LOGD(ERROR, guest_domid, -+ "Could not find user %s or range base pseudo-user %s, cannot restrict", -+ LIBXL_QEMU_USER_SHARED, LIBXL_QEMU_USER_RANGE_BASE); -+ -+ return ERROR_INVAL; -+} -+ -+static int make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, -+ const char *bootloader_path) - { - const libxl_domain_build_info *info = bl->info; - -@@ -61,6 +125,23 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, - ARG(GCSPRINTF("--ramdisk=%s", info->ramdisk)); - if (info->cmdline && *info->cmdline != '\0') - ARG(GCSPRINTF("--args=%s", info->cmdline)); -+ if (getenv("LIBXL_BOOTLOADER_RESTRICT") || -+ getenv("LIBXL_BOOTLOADER_USER")) { -+ uid_t uid = -1; -+ int rc = bootloader_uid(gc, bl->domid, getenv("LIBXL_BOOTLOADER_USER"), -+ &uid); -+ -+ if (rc) return rc; -+ -+ assert(uid != -1); -+ if (!uid) { -+ LOGD(ERROR, bl->domid, "bootloader restrict UID is 0 (root)!"); -+ return ERROR_INVAL; -+ } -+ LOGD(DEBUG, bl->domid, "using uid %ld", (long)uid); -+ ARG(GCSPRINTF("--runas=%ld", (long)uid)); -+ ARG("--quiet"); -+ } - - ARG(GCSPRINTF("--output=%s", bl->outputpath)); - ARG("--output-format=simple0"); -@@ -79,6 +160,7 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl, - /* Sentinel for execv */ - ARG(NULL); - -+ return 0; - #undef ARG - } - -@@ -443,7 +525,8 @@ static void bootloader_disk_attached_cb(libxl__egc *egc, - bootloader = bltmp; - } - -- make_bootloader_args(gc, bl, bootloader); -+ rc = make_bootloader_args(gc, bl, bootloader); -+ if (rc) goto out; - - bl->openpty.ao = ao; - bl->openpty.callback = bootloader_gotptys; -diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c -index fc264a3a13a6..14b593110f7c 100644 ---- a/tools/libs/light/libxl_dm.c -+++ b/tools/libs/light/libxl_dm.c -@@ -80,10 +80,10 @@ static int libxl__create_qemu_logfile(libxl__gc *gc, char *name) - * On error, return a libxl-style error code. - */ - #define DEFINE_USERLOOKUP_HELPER(NAME,SPEC_TYPE,STRUCTNAME,SYSCONF) \ -- static int userlookup_helper_##NAME(libxl__gc *gc, \ -- SPEC_TYPE spec, \ -- struct STRUCTNAME *resultbuf, \ -- struct STRUCTNAME **out) \ -+ int userlookup_helper_##NAME(libxl__gc *gc, \ -+ SPEC_TYPE spec, \ -+ struct STRUCTNAME *resultbuf, \ -+ struct STRUCTNAME **out) \ - { \ - struct STRUCTNAME *resultp = NULL; \ - char *buf = NULL; \ -diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h -index 7ad38de30e0b..f1e3a9a15b13 100644 ---- a/tools/libs/light/libxl_internal.h -+++ b/tools/libs/light/libxl_internal.h -@@ -4873,6 +4873,14 @@ struct libxl__cpu_policy { - struct xc_msr *msr; - }; - -+struct passwd; -+_hidden int userlookup_helper_getpwnam(libxl__gc*, const char *user, -+ struct passwd *res, -+ struct passwd **out); -+_hidden int userlookup_helper_getpwuid(libxl__gc*, uid_t uid, -+ struct passwd *res, -+ struct passwd **out); -+ - #endif - - /* --- -2.42.0 - diff --git a/xsa443-4.17-11.patch b/xsa443-4.17-11.patch deleted file mode 100644 index 27e6f78..0000000 --- a/xsa443-4.17-11.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 9d480426bfa2c68843ac8395b512e06fbdbcf53e Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Thu, 28 Sep 2023 12:22:35 +0200 -Subject: [PATCH 11/11] libxl: limit bootloader execution in restricted mode -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Introduce a timeout for bootloader execution when running in restricted mode. - -Allow overwriting the default time out with an environment provided value. - -This is part of XSA-443 / CVE-2023-34325 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Anthony PERARD ---- - docs/man/xl.1.pod.in | 8 ++++++ - tools/libs/light/libxl_bootloader.c | 40 +++++++++++++++++++++++++++++ - tools/libs/light/libxl_internal.h | 2 ++ - 3 files changed, 50 insertions(+) - -diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in -index 4831e122427d..c3eb6570ab8b 100644 ---- a/docs/man/xl.1.pod.in -+++ b/docs/man/xl.1.pod.in -@@ -1988,6 +1988,14 @@ NOTE: Each domain MUST have a SEPARATE username. - - See docs/features/qemu-deprivilege.pandoc for more information. - -+=item LIBXL_BOOTLOADER_TIMEOUT -+ -+Timeout in seconds for bootloader execution when running in restricted mode. -+Otherwise the build time default in LIBXL_BOOTLOADER_TIMEOUT will be used. -+ -+If defined the value must be an unsigned integer between 0 and INT_MAX, -+otherwise behavior is undefined. Setting to 0 disables the timeout. -+ - =back - - =head1 SEE ALSO -diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c -index 23c0ef3e8935..ee26d08f3765 100644 ---- a/tools/libs/light/libxl_bootloader.c -+++ b/tools/libs/light/libxl_bootloader.c -@@ -30,6 +30,8 @@ static void bootloader_keystrokes_copyfail(libxl__egc *egc, - libxl__datacopier_state *dc, int rc, int onwrite, int errnoval); - static void bootloader_display_copyfail(libxl__egc *egc, - libxl__datacopier_state *dc, int rc, int onwrite, int errnoval); -+static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev, -+ const struct timeval *requested_abs, int rc); - static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc, - int rc); - static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child, -@@ -297,6 +299,7 @@ void libxl__bootloader_init(libxl__bootloader_state *bl) - bl->ptys[0].master = bl->ptys[0].slave = 0; - bl->ptys[1].master = bl->ptys[1].slave = 0; - libxl__ev_child_init(&bl->child); -+ libxl__ev_time_init(&bl->time); - libxl__domaindeathcheck_init(&bl->deathcheck); - bl->keystrokes.ao = bl->ao; libxl__datacopier_init(&bl->keystrokes); - bl->display.ao = bl->ao; libxl__datacopier_init(&bl->display); -@@ -314,6 +317,7 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl) - libxl__domaindeathcheck_stop(gc,&bl->deathcheck); - libxl__datacopier_kill(&bl->keystrokes); - libxl__datacopier_kill(&bl->display); -+ libxl__ev_time_deregister(gc, &bl->time); - for (i=0; i<2; i++) { - libxl__carefd_close(bl->ptys[i].master); - libxl__carefd_close(bl->ptys[i].slave); -@@ -375,6 +379,7 @@ static void bootloader_stop(libxl__egc *egc, - - libxl__datacopier_kill(&bl->keystrokes); - libxl__datacopier_kill(&bl->display); -+ libxl__ev_time_deregister(gc, &bl->time); - if (libxl__ev_child_inuse(&bl->child)) { - r = kill(bl->child.pid, SIGTERM); - if (r) LOGED(WARN, bl->domid, "%sfailed to kill bootloader [%lu]", -@@ -637,6 +642,25 @@ static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op) - - struct termios termattr; - -+ if (getenv("LIBXL_BOOTLOADER_RESTRICT") || -+ getenv("LIBXL_BOOTLOADER_USER")) { -+ const char *timeout_env = getenv("LIBXL_BOOTLOADER_TIMEOUT"); -+ int timeout = timeout_env ? atoi(timeout_env) -+ : LIBXL_BOOTLOADER_TIMEOUT; -+ -+ if (timeout) { -+ /* Set execution timeout */ -+ rc = libxl__ev_time_register_rel(ao, &bl->time, -+ bootloader_timeout, -+ timeout * 1000); -+ if (rc) { -+ LOGED(ERROR, bl->domid, -+ "unable to register timeout for bootloader execution"); -+ goto out; -+ } -+ } -+ } -+ - pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished); - if (pid == -1) { - rc = ERROR_FAIL; -@@ -702,6 +726,21 @@ static void bootloader_display_copyfail(libxl__egc *egc, - libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, display); - bootloader_copyfail(egc, "bootloader output", bl, 1, rc,onwrite,errnoval); - } -+static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev, -+ const struct timeval *requested_abs, int rc) -+{ -+ libxl__bootloader_state *bl = CONTAINER_OF(ev, *bl, time); -+ STATE_AO_GC(bl->ao); -+ -+ libxl__ev_time_deregister(gc, &bl->time); -+ -+ assert(libxl__ev_child_inuse(&bl->child)); -+ LOGD(ERROR, bl->domid, "killing bootloader because of timeout"); -+ -+ libxl__ev_child_kill_deregister(ao, &bl->child, SIGKILL); -+ -+ bootloader_callback(egc, bl, rc); -+} - - static void bootloader_domaindeath(libxl__egc *egc, - libxl__domaindeathcheck *dc, -@@ -718,6 +757,7 @@ static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child, - STATE_AO_GC(bl->ao); - int rc; - -+ libxl__ev_time_deregister(gc, &bl->time); - libxl__datacopier_kill(&bl->keystrokes); - libxl__datacopier_kill(&bl->display); - -diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h -index f1e3a9a15b13..d05783617ff5 100644 ---- a/tools/libs/light/libxl_internal.h -+++ b/tools/libs/light/libxl_internal.h -@@ -102,6 +102,7 @@ - #define LIBXL_QMP_CMD_TIMEOUT 10 - #define LIBXL_STUBDOM_START_TIMEOUT 30 - #define LIBXL_QEMU_BODGE_TIMEOUT 2 -+#define LIBXL_BOOTLOADER_TIMEOUT 120 - #define LIBXL_XENCONSOLE_LIMIT 1048576 - #define LIBXL_XENCONSOLE_PROTOCOL "vt100" - #define LIBXL_MAXMEM_CONSTANT 1024 -@@ -3744,6 +3745,7 @@ struct libxl__bootloader_state { - libxl__openpty_state openpty; - libxl__openpty_result ptys[2]; /* [0] is for bootloader */ - libxl__ev_child child; -+ libxl__ev_time time; - libxl__domaindeathcheck deathcheck; - int nargs, argsspace; - const char **args; --- -2.42.0 - diff --git a/xsa444-4.17-1.patch b/xsa444-4.17-1.patch deleted file mode 100644 index 5a4b2e5..0000000 --- a/xsa444-4.17-1.patch +++ /dev/null @@ -1,93 +0,0 @@ -From: Andrew Cooper -Subject: x86/svm: Fix asymmetry with AMD DR MASK context switching - -The handling of MSR_DR{0..3}_MASK is asymmetric between PV and HVM guests. - -HVM guests context switch in based on the guest view of DBEXT, whereas PV -guest switch in base on the host capability. Both guest types leave the -context dirty for the next vCPU. - -This leads to the following issue: - - * PV or HVM guest has debugging active (%dr7 + mask) - * Switch-out deactivates %dr7 but leaves other state stale in hardware - * Another HVM guest with masks unavailable has debugging active - * Switch in loads %dr7 but leaves the mask MSRs alone - -Now, the second guest's vCPU is operating in the context of the prior vCPU's -mask MSR, while the environment the vCPU can see says there are no mask MSRs. - -As a stopgap, adjust the HVM path to switch in the masks based on host -capabilities rather than guest visibility (i.e. like the PV path). Adjustment -of the intercepts still needs to be dependent on the guest visibility of -DBEXT. - -This is part of XSA-444 / CVE-2023-34327 - -Fixes: c097f54912d3 ("x86/SVM: support data breakpoint extension registers") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c -index e8f50e7c5ec7..fd32600ae364 100644 ---- a/xen/arch/x86/hvm/svm/svm.c -+++ b/xen/arch/x86/hvm/svm/svm.c -@@ -339,6 +339,10 @@ static void svm_save_dr(struct vcpu *v) - v->arch.hvm.flag_dr_dirty = 0; - vmcb_set_dr_intercepts(vmcb, ~0u); - -+ /* -+ * The guest can only have changed the mask MSRs if we previous dropped -+ * intercepts. Re-read them from hardware. -+ */ - if ( v->domain->arch.cpuid->extd.dbext ) - { - svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_RW); -@@ -370,17 +374,25 @@ static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v) - - ASSERT(v == current); - -- if ( v->domain->arch.cpuid->extd.dbext ) -+ /* -+ * Both the PV and HVM paths leave stale DR_MASK values in hardware on -+ * context-switch-out. If we're activating %dr7 for the guest, we must -+ * sync the DR_MASKs too, whether or not the guest can see them. -+ */ -+ if ( boot_cpu_has(X86_FEATURE_DBEXT) ) - { -- svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE); -- svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE); -- svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE); -- svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE); -- - wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, v->arch.msrs->dr_mask[0]); - wrmsrl(MSR_AMD64_DR1_ADDRESS_MASK, v->arch.msrs->dr_mask[1]); - wrmsrl(MSR_AMD64_DR2_ADDRESS_MASK, v->arch.msrs->dr_mask[2]); - wrmsrl(MSR_AMD64_DR3_ADDRESS_MASK, v->arch.msrs->dr_mask[3]); -+ -+ if ( v->domain->arch.cpuid->extd.dbext ) -+ { -+ svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE); -+ svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE); -+ svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE); -+ svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE); -+ } - } - - write_debugreg(0, v->arch.dr[0]); -diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c -index e65cc6004148..06c4f3868b7a 100644 ---- a/xen/arch/x86/traps.c -+++ b/xen/arch/x86/traps.c -@@ -2281,6 +2281,11 @@ void activate_debugregs(const struct vcpu *curr) - if ( curr->arch.dr7 & DR7_ACTIVE_MASK ) - write_debugreg(7, curr->arch.dr7); - -+ /* -+ * Both the PV and HVM paths leave stale DR_MASK values in hardware on -+ * context-switch-out. If we're activating %dr7 for the guest, we must -+ * sync the DR_MASKs too, whether or not the guest can see them. -+ */ - if ( boot_cpu_has(X86_FEATURE_DBEXT) ) - { - wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, curr->arch.msrs->dr_mask[0]); diff --git a/xsa444-4.17-2.patch b/xsa444-4.17-2.patch deleted file mode 100644 index 2687bd1..0000000 --- a/xsa444-4.17-2.patch +++ /dev/null @@ -1,72 +0,0 @@ -From: Andrew Cooper -Subject: x86/pv: Correct the auditing of guest breakpoint addresses - -The use of access_ok() is buggy, because it permits access to the compat -translation area. 64bit PV guests don't use the XLAT area, but on AMD -hardware, the DBEXT feature allows a breakpoint to match up to a 4G aligned -region, allowing the breakpoint to reach outside of the XLAT area. - -Prior to c/s cda16c1bb223 ("x86: mirror compat argument translation area for -32-bit PV"), the live GDT was within 4G of the XLAT area. - -All together, this allowed a malicious 64bit PV guest on AMD hardware to place -a breakpoint over the live GDT, and trigger a #DB livelock (CVE-2015-8104). - -Introduce breakpoint_addr_ok() and explain why __addr_ok() happens to be an -appropriate check in this case. - -For Xen 4.14 and later, this is a latent bug because the XLAT area has moved -to be on its own with nothing interesting adjacent. For Xen 4.13 and older on -AMD hardware, this fixes a PV-trigger-able DoS. - -This is part of XSA-444 / CVE-2023-34328. - -Fixes: 65e355490817 ("x86/PV: support data breakpoint extension registers") -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/include/asm/debugreg.h b/xen/arch/x86/include/asm/debugreg.h -index c57914efc6e8..cc298265244b 100644 ---- a/xen/arch/x86/include/asm/debugreg.h -+++ b/xen/arch/x86/include/asm/debugreg.h -@@ -77,6 +77,26 @@ - asm volatile ( "mov %%db" #reg ",%0" : "=r" (__val) ); \ - __val; \ - }) -+ -+/* -+ * Architecturally, %dr{0..3} can have any arbitrary value. However, Xen -+ * can't allow the guest to breakpoint the Xen address range, so we limit the -+ * guest to the lower canonical half, or above the Xen range in the higher -+ * canonical half. -+ * -+ * Breakpoint lengths are specified to mask the low order address bits, -+ * meaning all breakpoints are naturally aligned. With %dr7, the widest -+ * breakpoint is 8 bytes. With DBEXT, the widest breakpoint is 4G. Both of -+ * the Xen boundaries have >4G alignment. -+ * -+ * In principle we should account for HYPERVISOR_COMPAT_VIRT_START(d), but -+ * 64bit Xen has never enforced this for compat guests, and there's no problem -+ * (to Xen) if the guest breakpoints it's alias of the M2P. Skipping this -+ * aspect simplifies the logic, and causes us not to reject a migrating guest -+ * which operated fine on prior versions of Xen. -+ */ -+#define breakpoint_addr_ok(a) __addr_ok(a) -+ - long set_debugreg(struct vcpu *, unsigned int reg, unsigned long value); - void activate_debugregs(const struct vcpu *); - -diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c -index aaaf70eb6330..f8636de907ae 100644 ---- a/xen/arch/x86/pv/misc-hypercalls.c -+++ b/xen/arch/x86/pv/misc-hypercalls.c -@@ -72,7 +72,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) - switch ( reg ) - { - case 0 ... 3: -- if ( !access_ok(value, sizeof(long)) ) -+ if ( !breakpoint_addr_ok(value) ) - return -EPERM; - - v->arch.dr[reg] = value; diff --git a/xsa445-4.17.patch b/xsa445-4.17.patch deleted file mode 100644 index db66d7c..0000000 --- a/xsa445-4.17.patch +++ /dev/null @@ -1,63 +0,0 @@ -From a43127d4f1f9a364334fe16b6239c211b35fd238 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Wed, 11 Oct 2023 13:14:21 +0200 -Subject: [PATCH] iommu/amd-vi: use correct level for quarantine domain page - tables -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The current setup of the quarantine page tables assumes that the quarantine -domain (dom_io) has been initialized with an address width of -DEFAULT_DOMAIN_ADDRESS_WIDTH (48). - -However dom_io being a PV domain gets the AMD-Vi IOMMU page tables levels based -on the maximum (hot pluggable) RAM address, and hence on systems with no RAM -above the 512GB mark only 3 page-table levels are configured in the IOMMU. - -On systems without RAM above the 512GB boundary amd_iommu_quarantine_init() -will setup page tables for the scratch page with 4 levels, while the IOMMU will -be configured to use 3 levels only. The page destined to be used as level 1, -and to contain a directory of PTEs ends up being the address in a PTE itself, -and thus level 1 page becomes the leaf page. Without the level mismatch it's -level 0 page that should be the leaf page instead. - -The level 1 page won't be used as such, and hence it's not possible to use it -to gain access to other memory on the system. However that page is not cleared -in amd_iommu_quarantine_init() as part of re-initialization of the device -quarantine page tables, and hence data on the level 1 page can be leaked -between device usages. - -Fix this by making sure the paging levels setup by amd_iommu_quarantine_init() -match the number configured on the IOMMUs. - -Note that IVMD regions are not affected by this issue, as those areas are -mapped taking the configured paging levels into account. - -This is XSA-445 / CVE-2023-46835 - -Fixes: ea38867831da ('x86 / iommu: set up a scratch page in the quarantine domain') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/drivers/passthrough/amd/iommu_map.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/xen/drivers/passthrough/amd/iommu_map.c b/xen/drivers/passthrough/amd/iommu_map.c -index 993bac6f8878..e0f4fe736a8d 100644 ---- a/xen/drivers/passthrough/amd/iommu_map.c -+++ b/xen/drivers/passthrough/amd/iommu_map.c -@@ -837,9 +837,7 @@ static int fill_qpt(union amd_iommu_pte *this, unsigned int level, - int cf_check amd_iommu_quarantine_init(struct pci_dev *pdev, bool scratch_page) - { - struct domain_iommu *hd = dom_iommu(dom_io); -- unsigned long end_gfn = -- 1ul << (DEFAULT_DOMAIN_ADDRESS_WIDTH - PAGE_SHIFT); -- unsigned int level = amd_iommu_get_paging_mode(end_gfn); -+ unsigned int level = hd->arch.amd.paging_mode; - unsigned int req_id = get_dma_requestor_id(pdev->seg, pdev->sbdf.bdf); - const struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg); - int rc; --- -2.42.0 - diff --git a/xsa446.patch b/xsa446.patch deleted file mode 100644 index acf1d0f..0000000 --- a/xsa446.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 80d5aada598c3a800a350003d5d582931545e13c Mon Sep 17 00:00:00 2001 -From: Andrew Cooper -Date: Thu, 26 Oct 2023 14:37:38 +0100 -Subject: [PATCH] x86/spec-ctrl: Remove conditional IRQs-on-ness for INT - $0x80/0x82 paths -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Before speculation defences, some paths in Xen could genuinely get away with -being IRQs-on at entry. But XPTI invalidated this property on most paths, and -attempting to maintain it on the remaining paths was a mistake. - -Fast forward, and DO_SPEC_CTRL_COND_IBPB (protection for AMD BTC/SRSO) is not -IRQ-safe, running with IRQs enabled in some cases. The other actions taken on -these paths happen to be IRQ-safe. - -Make entry_int82() and int80_direct_trap() unconditionally Interrupt Gates -rather than Trap Gates. Remove the conditional re-adjustment of -int80_direct_trap() in smp_prepare_cpus(), and have entry_int82() explicitly -enable interrupts when safe to do so. - -In smp_prepare_cpus(), with the conditional re-adjustment removed, the -clearing of pv_cr3 is the only remaining action gated on XPTI, and it is out -of place anyway, repeating work already done by smp_prepare_boot_cpu(). Drop -the entire if() condition to avoid leaving an incorrect vestigial remnant. - -Also drop comments which make incorrect statements about when its safe to -enable interrupts. - -This is XSA-446 / CVE-2023-46836 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné ---- - xen/arch/x86/pv/traps.c | 4 ++-- - xen/arch/x86/smpboot.c | 14 -------------- - xen/arch/x86/x86_64/compat/entry.S | 2 ++ - xen/arch/x86/x86_64/entry.S | 1 - - 4 files changed, 4 insertions(+), 17 deletions(-) - -diff --git a/xen/arch/x86/pv/traps.c b/xen/arch/x86/pv/traps.c -index 74f333da7e1c..240d1a2db7a3 100644 ---- a/xen/arch/x86/pv/traps.c -+++ b/xen/arch/x86/pv/traps.c -@@ -139,11 +139,11 @@ void __init pv_trap_init(void) - #ifdef CONFIG_PV32 - /* The 32-on-64 hypercall vector is only accessible from ring 1. */ - _set_gate(idt_table + HYPERCALL_VECTOR, -- SYS_DESC_trap_gate, 1, entry_int82); -+ SYS_DESC_irq_gate, 1, entry_int82); - #endif - - /* Fast trap for int80 (faster than taking the #GP-fixup path). */ -- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_trap_gate, 3, -+ _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3, - &int80_direct_trap); - - open_softirq(NMI_SOFTIRQ, nmi_softirq); -diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c -index 3a1a659082c6..4c54ecbc91d7 100644 ---- a/xen/arch/x86/smpboot.c -+++ b/xen/arch/x86/smpboot.c -@@ -1158,20 +1158,6 @@ void __init smp_prepare_cpus(void) - - stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1)); - -- if ( opt_xpti_hwdom || opt_xpti_domu ) -- { -- get_cpu_info()->pv_cr3 = 0; -- --#ifdef CONFIG_PV -- /* -- * All entry points which may need to switch page tables have to start -- * with interrupts off. Re-write what pv_trap_init() has put there. -- */ -- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3, -- &int80_direct_trap); --#endif -- } -- - set_nr_sockets(); - - socket_cpumask = xzalloc_array(cpumask_t *, nr_sockets); -diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S -index bd5abd8040bd..fcc3a721f147 100644 ---- a/xen/arch/x86/x86_64/compat/entry.S -+++ b/xen/arch/x86/x86_64/compat/entry.S -@@ -21,6 +21,8 @@ ENTRY(entry_int82) - SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ - /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ - -+ sti -+ - CR4_PV32_RESTORE - - GET_CURRENT(bx) -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 5ca74f5f62b2..9a7b129aa7e4 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -327,7 +327,6 @@ ENTRY(sysenter_entry) - #ifdef CONFIG_XEN_SHSTK - ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK - #endif -- /* sti could live here when we don't switch page tables below. */ - pushq $FLAT_USER_SS - pushq $0 - pushfq - -base-commit: 7befef87cc9b1bb8ca15d866ce1ecd9165ccb58c -prerequisite-patch-id: 142a87c707411d49e136c3fb76f1b14963ec6dc8 --- -2.30.2 - From 343a901c216405ca8ebe8c7b3ce21eafb7b5c495 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 13 Dec 2023 17:39:02 +0000 Subject: [PATCH 42/99] arm32: The cache may not be properly cleaned/invalidated (take two) [XSA-447, CVE-2023-46837] rebuild for OCaml-5.1.1 --- xen.spec | 9 +++- xsa447.patch | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 xsa447.patch diff --git a/xen.spec b/xen.spec index 07bb3d2..c0bd413 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,7 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch +Patch51: xsa447.patch %if %build_qemutrad @@ -328,6 +329,7 @@ manage Xen virtual machines. %if "%dist" != ".fc38" %patch 50 -p1 %endif +%patch 51 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -934,6 +936,11 @@ fi %endif %changelog +* Wed Dec 13 2023 Michael Young - 4.18.0-2 +- arm32: The cache may not be properly cleaned/invalidated (take two) + [XSA-447, CVE-2023-46837] +- rebuild for OCaml-5.1.1 + * Wed Nov 29 2023 Michael Young - 4.18.0-1 - update to xen-4.18.0 rebase xen.canonicalize.patch and xen.ocaml5.fixes.patch diff --git a/xsa447.patch b/xsa447.patch new file mode 100644 index 0000000..2e26396 --- /dev/null +++ b/xsa447.patch @@ -0,0 +1,117 @@ +From 084c7312fa6c1d4a7fa343efa1d7d73693dafff4 Mon Sep 17 00:00:00 2001 +From: Michal Orzel +Date: Thu, 23 Nov 2023 15:53:02 +0100 +Subject: [PATCH] xen/arm: page: Avoid pointer overflow on cache clean & + invalidate + +On Arm32, after cleaning and invalidating the last dcache line of the top +domheap page i.e. VA = 0xfffff000 (as a result of flushing the page to +RAM), we end up adding the value of a dcache line size to the pointer +once again, which results in a pointer arithmetic overflow (with 64B line +size, operation 0xffffffc0 + 0x40 overflows to 0x0). Such behavior is +undefined and given the wide range of compiler versions we support, it is +difficult to determine what could happen in such scenario. + +Modify clean_and_invalidate_dcache_va_range() as well as +clean_dcache_va_range() and invalidate_dcache_va_range() due to similarity +of handling to prevent pointer arithmetic overflow. Modify the loops to +use an additional variable to store the index of the next cacheline. +Add an assert to prevent passing a region that wraps around which is +illegal and would end up in a page fault anyway (region 0-2MB is +unmapped). Lastly, return early if size passed is 0. + +Note that on Arm64, we don't have this problem given that the max VA +space we support is 48-bits. + +This is XSA-447 / CVE-2023-46837. + +Signed-off-by: Michal Orzel +Reviewed-by: Julien Grall +--- + xen/arch/arm/include/asm/page.h | 35 ++++++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 7 deletions(-) + +diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h +index ebaf5964f114..69f817d1e68a 100644 +--- a/xen/arch/arm/include/asm/page.h ++++ b/xen/arch/arm/include/asm/page.h +@@ -162,6 +162,13 @@ static inline size_t read_dcache_line_bytes(void) + static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + { + size_t cacheline_mask = dcache_line_bytes - 1; ++ unsigned long idx = 0; ++ ++ if ( !size ) ++ return 0; ++ ++ /* Passing a region that wraps around is illegal */ ++ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); + + dsb(sy); /* So the CPU issues all writes to the range */ + +@@ -174,11 +181,11 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + } + + for ( ; size >= dcache_line_bytes; +- p += dcache_line_bytes, size -= dcache_line_bytes ) +- asm volatile (__invalidate_dcache_one(0) : : "r" (p)); ++ idx += dcache_line_bytes, size -= dcache_line_bytes ) ++ asm volatile (__invalidate_dcache_one(0) : : "r" (p + idx)); + + if ( size > 0 ) +- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); ++ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); + + dsb(sy); /* So we know the flushes happen before continuing */ + +@@ -188,14 +195,21 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + static inline int clean_dcache_va_range(const void *p, unsigned long size) + { + size_t cacheline_mask = dcache_line_bytes - 1; ++ unsigned long idx = 0; ++ ++ if ( !size ) ++ return 0; ++ ++ /* Passing a region that wraps around is illegal */ ++ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); + + dsb(sy); /* So the CPU issues all writes to the range */ + size += (uintptr_t)p & cacheline_mask; + size = (size + cacheline_mask) & ~cacheline_mask; + p = (void *)((uintptr_t)p & ~cacheline_mask); + for ( ; size >= dcache_line_bytes; +- p += dcache_line_bytes, size -= dcache_line_bytes ) +- asm volatile (__clean_dcache_one(0) : : "r" (p)); ++ idx += dcache_line_bytes, size -= dcache_line_bytes ) ++ asm volatile (__clean_dcache_one(0) : : "r" (p + idx)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ + return 0; +@@ -205,14 +219,21 @@ static inline int clean_and_invalidate_dcache_va_range + (const void *p, unsigned long size) + { + size_t cacheline_mask = dcache_line_bytes - 1; ++ unsigned long idx = 0; ++ ++ if ( !size ) ++ return 0; ++ ++ /* Passing a region that wraps around is illegal */ ++ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); + + dsb(sy); /* So the CPU issues all writes to the range */ + size += (uintptr_t)p & cacheline_mask; + size = (size + cacheline_mask) & ~cacheline_mask; + p = (void *)((uintptr_t)p & ~cacheline_mask); + for ( ; size >= dcache_line_bytes; +- p += dcache_line_bytes, size -= dcache_line_bytes ) +- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); ++ idx += dcache_line_bytes, size -= dcache_line_bytes ) ++ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ + return 0; +-- +2.40.1 + From 869574bf2f57093775e262e13333ea9396f76b85 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 27 Jan 2024 09:30:44 +0000 Subject: [PATCH 43/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index c0bd413..380064a 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -936,6 +936,9 @@ fi %endif %changelog +* Sat Jan 27 2024 Fedora Release Engineering - 4.18.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Wed Dec 13 2023 Michael Young - 4.18.0-2 - arm32: The cache may not be properly cleaned/invalidated (take two) [XSA-447, CVE-2023-46837] From b644c52cfa0d914d33b9369462074e60faa60320 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sat, 3 Feb 2024 09:47:57 +0000 Subject: [PATCH 44/99] build fixes for gcc14, replace stubs-32.h requirement with glibc32 --- newlib.gcc14.fixes.patch | 388 +++++++++++++++++++++++++++++++++++++++ xen.gcc14.fixes.patch | 24 +++ xen.spec | 13 +- 3 files changed, 422 insertions(+), 3 deletions(-) create mode 100644 newlib.gcc14.fixes.patch create mode 100644 xen.gcc14.fixes.patch diff --git a/newlib.gcc14.fixes.patch b/newlib.gcc14.fixes.patch new file mode 100644 index 0000000..bdb3594 --- /dev/null +++ b/newlib.gcc14.fixes.patch @@ -0,0 +1,388 @@ +--- xen-4.18.0/stubdom/newlib-makedoc.patch.orig 2023-11-16 21:44:21.000000000 +0000 ++++ xen-4.18.0/stubdom/newlib-makedoc.patch 2024-02-01 20:32:40.565785056 +0000 +@@ -33,3 +33,385 @@ + #include + + #define DEF_SIZE 5000 ++--- ++ ++patch makedoc.c for gcc14 build ++ ++--- newlib-1.16.0/newlib/doc/makedoc.c.orig 2007-01-02 16:59:59.000000000 +0000 +++++ newlib-1.16.0/newlib/doc/makedoc.c 2024-02-01 20:26:32.415396758 +0000 ++@@ -63,25 +63,20 @@ ++ ++ ++ ++-static void DEFUN(init_string_with_size,(buffer, size), ++- string_type *buffer AND ++- unsigned int size ) +++static void init_string_with_size (string_type *buffer, unsigned int size) ++ { ++ buffer->write_idx = 0; ++ buffer->size = size; ++ buffer->ptr = malloc(size); ++ } ++ ++-static void DEFUN(init_string,(buffer), ++- string_type *buffer) +++static void init_string (string_type *buffer) ++ { ++ init_string_with_size(buffer, DEF_SIZE); ++ ++ } ++ ++-static int DEFUN(find, (str, what), ++- string_type *str AND ++- char *what) +++static int find (string_type *str, char *what) ++ { ++ unsigned int i; ++ char *p; ++@@ -97,30 +92,24 @@ ++ ++ } ++ ++-static void DEFUN(write_buffer,(buffer), ++- string_type *buffer) +++static void write_buffer (string_type *buffer) ++ { ++ fwrite(buffer->ptr, buffer->write_idx, 1, stdout); ++ } ++ ++ ++-static void DEFUN(delete_string,(buffer), ++- string_type *buffer) +++static void delete_string (string_type *buffer) ++ { ++ free(buffer->ptr); ++ } ++ ++ ++-static char *DEFUN(addr, (buffer, idx), ++- string_type *buffer AND ++- unsigned int idx) +++static char * addr (string_type *buffer, unsigned int idx) ++ { ++ return buffer->ptr + idx; ++ } ++ ++-static char DEFUN(at,(buffer, pos), ++- string_type *buffer AND ++- unsigned int pos) +++static char at (string_type *buffer, unsigned int pos) ++ { ++ if ( pos >= buffer->write_idx) ++ { ++@@ -129,9 +118,7 @@ ++ return buffer->ptr[pos]; ++ } ++ ++-static void DEFUN(catchar,(buffer, ch), ++- string_type *buffer AND ++- char ch) +++static void catchar (string_type *buffer, char ch) ++ { ++ if (buffer->write_idx == buffer->size) ++ { ++@@ -143,9 +130,7 @@ ++ } ++ ++ ++-static void DEFUN(overwrite_string,(dst, src), ++- string_type *dst AND ++- string_type *src) +++static void overwrite_string (string_type *dst, string_type *src) ++ { ++ free(dst->ptr); ++ dst->size = src->size; ++@@ -153,9 +138,7 @@ ++ dst->ptr = src->ptr; ++ } ++ ++-static void DEFUN(catstr,(dst, src), ++- string_type *dst AND ++- string_type *src) +++static void catstr ( string_type *dst, string_type *src) ++ { ++ unsigned int i; ++ for (i = 0; i < src->write_idx; i++) ++@@ -165,9 +148,7 @@ ++ } ++ ++ ++-static void DEFUN(cattext,(buffer, string), ++- string_type *buffer AND ++- char *string) +++static void cattext (string_type *buffer, char *string) ++ { ++ ++ while (*string) ++@@ -177,10 +158,7 @@ ++ } ++ } ++ ++-static void DEFUN(catbuf,(buffer, buf, len), ++- string_type *buffer AND ++- char *buf AND ++- unsigned int len) +++static void catbuf ( string_type *buffer, char *buf, unsigned int len) ++ { ++ ++ while (len--) ++@@ -192,10 +170,7 @@ ++ ++ ++ ++-static unsigned int ++-DEFUN(skip_white_and_stars,(src, idx), ++- string_type *src AND ++- unsigned int idx) +++static unsigned int skip_white_and_stars (string_type *src, unsigned int idx) ++ { ++ while (isspace(at(src,idx)) ++ || (at(src,idx) == '*' && at(src,idx +1) !='/')) ++@@ -216,10 +191,23 @@ ++ stinst_type *pc; ++ stinst_type sstack[STACK]; ++ stinst_type *ssp = &sstack[0]; ++-int istack[STACK]; ++-int *isp = &istack[0]; ++ ++-typedef int *word_type; +++#if defined(__PTRDIFF_TYPE__) +++typedef signed __PTRDIFF_TYPE__ intptr_t; +++typedef unsigned __PTRDIFF_TYPE__ uintptr_t; +++#else +++/* +++ * Fallback to hardcoded values, +++ * should be valid on cpu's with 32bit int/32bit void* +++ */ +++typedef signed long intptr_t; +++typedef unsigned long uintptr_t; +++#endif +++ +++uintptr_t istack[STACK]; +++uintptr_t *isp = &istack[0]; +++ +++typedef uintptr_t *word_type; ++ ++ ++ ++@@ -236,8 +224,7 @@ ++ typedef struct dict_struct dict_type; ++ #define WORD(x) static void x() ++ ++-static void DEFUN(exec,(word), ++- dict_type *word) +++static void exec (dict_type *word) ++ { ++ pc = word->code; ++ while (*pc) ++@@ -267,7 +254,7 @@ ++ { ++ isp++; ++ pc++; ++- *isp = (int)(*pc); +++ *isp = (uintptr_t)(*pc); ++ pc++; ++ ++ } ++@@ -294,10 +281,7 @@ ++ Blank lines are turned into one blank line ++ */ ++ ++-static void ++-DEFUN(remove_noncomments,(src,dst), ++- string_type *src AND ++- string_type *dst) +++static void remove_noncomments (string_type *src, string_type *dst) ++ { ++ unsigned int idx = 0; ++ ++@@ -349,8 +333,7 @@ ++ ++ */ ++ ++-static void ++-DEFUN_VOID(exfunstuff) +++static void exfunstuff (void) ++ { ++ unsigned int openp; ++ unsigned int fname; ++@@ -522,8 +505,7 @@ ++ } ++ ++ /* Mod tos so that only lines with leading dots remain */ ++-static void ++-DEFUN_VOID(outputdots) +++static void (outputdots (void)) ++ { ++ unsigned int idx = 0; ++ string_type out; ++@@ -772,10 +754,7 @@ ++ ++ } ++ /* A command is all upper case,and alone on a line */ ++-static int ++-DEFUN( iscommand,(ptr, idx), ++- string_type *ptr AND ++- unsigned int idx) +++static int iscommand (string_type *ptr, unsigned int idx) ++ { ++ unsigned int len = 0; ++ while (at(ptr,idx)) { ++@@ -797,10 +776,7 @@ ++ } ++ ++ ++-DEFUN(copy_past_newline,(ptr, idx, dst), ++- string_type *ptr AND ++- unsigned int idx AND ++- string_type *dst) +++unsigned int copy_past_newline (string_type *ptr, unsigned int idx, string_type *dst) ++ { ++ while (at(ptr, idx) && at(ptr, idx) != '\n') ++ { ++@@ -1060,10 +1036,7 @@ ++ ++ } ++ ++-char * ++-DEFUN(nextword,(string, word), ++- char *string AND ++- char **word) +++char * nextword (char *string, char **word) ++ { ++ char *word_start; ++ int idx; ++@@ -1138,9 +1111,7 @@ ++ ++ } ++ dict_type *root; ++-dict_type * ++-DEFUN(lookup_word,(word), ++- char *word) +++dict_type * lookup_word (char *word) ++ { ++ dict_type *ptr = root; ++ while (ptr) { ++@@ -1154,7 +1125,7 @@ ++ ++ } ++ ++-static void DEFUN_VOID(perform) +++static int perform (void) ++ { ++ tos = stack; ++ ++@@ -1192,9 +1163,7 @@ ++ } ++ } ++ ++-dict_type * ++-DEFUN(newentry,(word), ++- char *word) +++dict_type * newentry (char *word) ++ { ++ dict_type *new = (dict_type *)malloc(sizeof(dict_type)); ++ new->word = word; ++@@ -1208,10 +1177,7 @@ ++ } ++ ++ ++-unsigned int ++-DEFUN(add_to_definition,(entry, word), ++- dict_type *entry AND ++- stinst_type word) +++unsigned int add_to_definition (dict_type *entry, stinst_type word) ++ { ++ if (entry->code_end == entry->code_length) ++ { ++@@ -1232,9 +1198,7 @@ ++ ++ ++ void ++-DEFUN(add_intrinsic,(name, func), ++- char *name AND ++- void (*func)()) +++add_intrinsic (char *name, void (*func)(void)) ++ { ++ dict_type *new = newentry(name); ++ add_to_definition(new, func); ++@@ -1247,9 +1211,7 @@ ++ ++ } ++ ++-void ++-DEFUN(add_var,(name), ++- char *name) +++void add_var (char *name) ++ { ++ dict_type *new = newentry(name); ++ add_to_definition(new, push_number); ++@@ -1262,8 +1224,7 @@ ++ ++ ++ void ++-DEFUN(compile, (string), ++- char *string) +++compile (char *string) ++ ++ { ++ int jstack[STACK]; ++@@ -1315,11 +1276,11 @@ ++ /* Got a number, embedd the magic push number ++ function */ ++ add_to_definition(ptr, push_number); ++- add_to_definition(ptr, atol(word)); +++ add_to_definition(ptr, (stinst_type)atol(word)); ++ break; ++ default: ++ add_to_definition(ptr, call); ++- add_to_definition(ptr, lookup_word(word)); +++ add_to_definition(ptr, (stinst_type)lookup_word(word)); ++ } ++ ++ string = nextword(string, &word); ++@@ -1336,9 +1297,9 @@ ++ } ++ ++ ++-static void DEFUN_VOID(bang) +++static void bang (void) ++ { ++-*(int *)((isp[0])) = isp[-1]; +++*(uintptr_t *)((isp[0])) = isp[-1]; ++ isp-=2; ++ pc++; ++ ++@@ -1359,9 +1320,7 @@ ++ ++ ++ ++-static void DEFUN(read_in, (str, file), ++- string_type *str AND ++- FILE *file) +++static void read_in (string_type *str, FILE *file) ++ { ++ char buff[10000]; ++ unsigned int r; ++@@ -1378,15 +1337,13 @@ ++ } ++ ++ ++-static void DEFUN_VOID(usage) +++static void usage (void) ++ { ++ fprintf(stderr,"usage: -[d|i|g] file\n"); ++ exit(33); ++ } ++ ++-int DEFUN(main,(ac,av), ++-int ac AND ++-char *av[]) +++int main (int ac, char *av[]) ++ { ++ unsigned int i; ++ diff --git a/xen.gcc14.fixes.patch b/xen.gcc14.fixes.patch new file mode 100644 index 0000000..cc27089 --- /dev/null +++ b/xen.gcc14.fixes.patch @@ -0,0 +1,24 @@ +Work around newlib build problems with gcc14 + +--- xen-4.18.0/stubdom/Makefile.orig 2024-01-15 20:35:36.941740548 +0000 ++++ xen-4.18.0/stubdom/Makefile 2024-01-29 22:29:29.067367523 +0000 +@@ -45,6 +45,7 @@ + NEWLIB_CFLAGS+=-D_I386MACH_ALLOW_HW_INTERRUPTS + STUBDOM_SUPPORTED=1 + endif ++NEWLIB_CFLAGS+=-Wno-error=implicit-function-declaration + + CROSS_ROOT=cross-root-$(GNU_TARGET_ARCH) + CROSS_PREFIX=$(CURDIR)/$(CROSS_ROOT) +--- xen-4.18.0/extras/mini-os/include/posix/sys/mman.h.orig 2022-07-04 09:52:38.000000000 +0100 ++++ xen-4.18.0/extras/mini-os/include/posix/sys/mman.h 2024-02-01 23:00:19.923263409 +0000 +@@ -16,7 +16,7 @@ + + void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) asm("mmap64"); + int munmap(void *start, size_t length); +-static inline mlock(const void *addr, size_t len) { return 0; } +-static inline munlock(const void *addr, size_t len) { return 0; } ++static inline int mlock(const void *addr, size_t len) { return 0; } ++static inline int munlock(const void *addr, size_t len) { return 0; } + + #endif /* _POSIX_SYS_MMAN_H */ diff --git a/xen.spec b/xen.spec index 380064a..350fd29 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -113,6 +113,8 @@ Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch51: xsa447.patch +Patch52: xen.gcc14.fixes.patch +Patch53: newlib.gcc14.fixes.patch %if %build_qemutrad @@ -127,9 +129,9 @@ BuildRequires: dev86 %endif BuildRequires: python3-devel ncurses-devel python3-setuptools BuildRequires: perl-interpreter perl-generators -%ifarch %{ix86} x86_64 +%ifarch x86_64 # so that x86_64 builds pick up glibc32 correctly -BuildRequires: /usr/include/gnu/stubs-32.h +BuildRequires: glibc32 %endif BuildRequires: gettext BuildRequires: gnutls-devel @@ -330,6 +332,8 @@ manage Xen virtual machines. %patch 50 -p1 %endif %patch 51 -p1 +%patch 52 -p1 +%patch 53 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -936,6 +940,9 @@ fi %endif %changelog +* Sat Feb 03 2024 Michael Young - 4.18.0-4 +- build fixes for gcc14, replace stubs-32.h requirement with glibc32 + * Sat Jan 27 2024 Fedora Release Engineering - 4.18.0-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild From 950832bad0fbf2411446da7e84264114fb5b1ef0 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sun, 4 Feb 2024 19:57:54 +0000 Subject: [PATCH 45/99] 2 security updates + drop glibc32 requirement pci: phantom functions assigned to incorrect contexts [XSA-449, CVE-2023-46839] VT-d: Failure to quarantine devices in !HVM build [XSA-450, CVE-2023-46840] --- xen.spec | 17 +++++++--- xsa449.patch | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ xsa450.patch | 59 ++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 xsa449.patch create mode 100644 xsa450.patch diff --git a/xen.spec b/xen.spec index 350fd29..7c58b1a 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -115,6 +115,8 @@ Patch50: xen.ocaml5.fixes.patch Patch51: xsa447.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch +Patch54: xsa449.patch +Patch55: xsa450.patch %if %build_qemutrad @@ -129,10 +131,6 @@ BuildRequires: dev86 %endif BuildRequires: python3-devel ncurses-devel python3-setuptools BuildRequires: perl-interpreter perl-generators -%ifarch x86_64 -# so that x86_64 builds pick up glibc32 correctly -BuildRequires: glibc32 -%endif BuildRequires: gettext BuildRequires: gnutls-devel BuildRequires: openssl-devel @@ -334,6 +332,8 @@ manage Xen virtual machines. %patch 51 -p1 %patch 52 -p1 %patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -940,6 +940,13 @@ fi %endif %changelog +* Sun Feb 04 2024 Michael Young - 4.18.0-5 +- pci: phantom functions assigned to incorrect contexts [XSA-449, + CVE-2023-46839] +- VT-d: Failure to quarantine devices in !HVM build [XSA-450, + CVE-2023-46840] +- the glibc32 doesn't seem to add anything to the build so drop it + * Sat Feb 03 2024 Michael Young - 4.18.0-4 - build fixes for gcc14, replace stubs-32.h requirement with glibc32 diff --git a/xsa449.patch b/xsa449.patch new file mode 100644 index 0000000..80aeac2 --- /dev/null +++ b/xsa449.patch @@ -0,0 +1,89 @@ +From d8b92b21b224126860978e4c604302f3c1e3bf75 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Wed, 13 Dec 2023 15:51:59 +0100 +Subject: [PATCH] pci: fail device assignment if phantom functions cannot be + assigned +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current behavior is that no error is reported if (some) phantom functions +fail to be assigned during device add or assignment, so the operation succeeds +even if some phantom functions are not correctly setup. + +This can lead to devices possibly being successfully assigned to a domU while +some of the device phantom functions are still assigned to dom0. Even when the +device is assigned domIO before being assigned to a domU phantom functions +might fail to be assigned to domIO, and also fail to be assigned to the domU, +leaving them assigned to dom0. + +Since the device can generate requests using the IDs of those phantom +functions, given the scenario above a device in such state would be in control +of a domU, but still capable of generating transactions that use a context ID +targeting dom0 owned memory. + +Modify device assign in order to attempt to deassign the device if phantom +functions failed to be assigned. + +Note that device addition is not modified in the same way, as in that case the +device is assigned to a trusted domain, and hence partial assign can lead to +device malfunction but not a security issue. + +This is XSA-449 / CVE-2023-46839 + +Fixes: 4e9950dc1bd2 ('IOMMU: add phantom function support') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/drivers/passthrough/pci.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c +index 1439d1ef2b26..47c0eee7bdcc 100644 +--- a/xen/drivers/passthrough/pci.c ++++ b/xen/drivers/passthrough/pci.c +@@ -1488,11 +1488,10 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) + + pdev->fault.count = 0; + +- if ( (rc = iommu_call(hd->platform_ops, assign_device, d, devfn, +- pci_to_dev(pdev), flag)) ) +- goto done; ++ rc = iommu_call(hd->platform_ops, assign_device, d, devfn, pci_to_dev(pdev), ++ flag); + +- for ( ; pdev->phantom_stride; rc = 0 ) ++ while ( pdev->phantom_stride && !rc ) + { + devfn += pdev->phantom_stride; + if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) ) +@@ -1503,8 +1502,24 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) + + done: + if ( rc ) +- printk(XENLOG_G_WARNING "%pd: assign (%pp) failed (%d)\n", +- d, &PCI_SBDF(seg, bus, devfn), rc); ++ { ++ printk(XENLOG_G_WARNING "%pd: assign %s(%pp) failed (%d)\n", ++ d, devfn != pdev->devfn ? "phantom function " : "", ++ &PCI_SBDF(seg, bus, devfn), rc); ++ ++ if ( devfn != pdev->devfn && deassign_device(d, seg, bus, pdev->devfn) ) ++ { ++ /* ++ * Device with phantom functions that failed to both assign and ++ * rollback. Mark the device as broken and crash the target domain, ++ * as the state of the functions at this point is unknown and Xen ++ * has no way to assert consistent context assignment among them. ++ */ ++ pdev->broken = true; ++ if ( !is_hardware_domain(d) && d != dom_io ) ++ domain_crash(d); ++ } ++ } + /* The device is assigned to dom_io so mark it as quarantined */ + else if ( d == dom_io ) + pdev->quarantine = true; +-- +2.43.0 + diff --git a/xsa450.patch b/xsa450.patch new file mode 100644 index 0000000..e94933b --- /dev/null +++ b/xsa450.patch @@ -0,0 +1,59 @@ +From: Andrew Cooper +Subject: VT-d: Fix "else" vs "#endif" misplacement + +In domain_pgd_maddr() the "#endif" is misplaced with respect to "else". This +generates incorrect logic when CONFIG_HVM is compiled out, as the "else" body +is executed unconditionally. + +Rework the logic to use IS_ENABLED() instead of explicit #ifdef-ary, as it's +clearer to follow. This in turn involves adjusting p2m_get_pagetable() to +compile when CONFIG_HVM is disabled. + +This is XSA-450 / CVE-2023-46840. + +Reported-by: Reported-by: Teddy Astie +Fixes: 033ff90aa9c1 ("x86/P2M: p2m_{alloc,free}_ptp() and p2m_alloc_table() are HVM-only") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h +index 32f3f394b05a..6ada585eaac2 100644 +--- a/xen/arch/x86/include/asm/p2m.h ++++ b/xen/arch/x86/include/asm/p2m.h +@@ -435,7 +435,14 @@ static inline bool p2m_is_altp2m(const struct p2m_domain *p2m) + return p2m->p2m_class == p2m_alternate; + } + +-#define p2m_get_pagetable(p2m) ((p2m)->phys_table) ++#ifdef CONFIG_HVM ++static inline pagetable_t p2m_get_pagetable(const struct p2m_domain *p2m) ++{ ++ return p2m->phys_table; ++} ++#else ++pagetable_t p2m_get_pagetable(const struct p2m_domain *p2m); ++#endif + + /* + * Ensure any deferred p2m TLB flush has been completed on all VCPUs. +diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c +index 99b642f12ef9..4244855032ee 100644 +--- a/xen/drivers/passthrough/vtd/iommu.c ++++ b/xen/drivers/passthrough/vtd/iommu.c +@@ -438,15 +438,13 @@ static paddr_t domain_pgd_maddr(struct domain *d, paddr_t pgd_maddr, + + if ( pgd_maddr ) + /* nothing */; +-#ifdef CONFIG_HVM +- else if ( iommu_use_hap_pt(d) ) ++ else if ( IS_ENABLED(CONFIG_HVM) && iommu_use_hap_pt(d) ) + { + pagetable_t pgt = p2m_get_pagetable(p2m_get_hostp2m(d)); + + pgd_maddr = pagetable_get_paddr(pgt); + } + else +-#endif + { + if ( !hd->arch.vtd.pgd_maddr ) + { From ef85dabcd352e1c093d9eba10b7e3e01c6059ea3 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 27 Feb 2024 20:02:19 +0000 Subject: [PATCH 46/99] x86: shadow stack vs exceptions from emulation stubs [XSA-451, CVE-2023-46841] (#2266326) --- xen.spec | 8 +- xsa451-4.18.patch | 188 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 xsa451-4.18.patch diff --git a/xen.spec b/xen.spec index 7c58b1a..39fd394 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -117,6 +117,7 @@ Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch Patch54: xsa449.patch Patch55: xsa450.patch +Patch56: xsa451-4.18.patch %if %build_qemutrad @@ -334,6 +335,7 @@ manage Xen virtual machines. %patch 53 -p1 %patch 54 -p1 %patch 55 -p1 +%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -940,6 +942,10 @@ fi %endif %changelog +* Tue Feb 27 2024 Michael Young - 4.18.0-6 +- x86: shadow stack vs exceptions from emulation stubs - [XSA-451, + CVE-2023-46841] (#2266326) + * Sun Feb 04 2024 Michael Young - 4.18.0-5 - pci: phantom functions assigned to incorrect contexts [XSA-449, CVE-2023-46839] diff --git a/xsa451-4.18.patch b/xsa451-4.18.patch new file mode 100644 index 0000000..721f3f3 --- /dev/null +++ b/xsa451-4.18.patch @@ -0,0 +1,188 @@ +From: Jan Beulich +Subject: x86: account for shadow stack in exception-from-stub recovery + +Dealing with exceptions raised from within emulation stubs involves +discarding return address (replaced by exception related information). +Such discarding of course also requires removing the corresponding entry +from the shadow stack. + +Also amend the comment in fixup_exception_return(), to further clarify +why use of ptr[1] can't be an out-of-bounds access. + +While touching do_invalid_op() also add a missing fall-through +annotation. + +This is CVE-2023-46841 / XSA-451. + +Fixes: 209fb9919b50 ("x86/extable: Adjust extable handling to be shadow stack compatible") +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/xen/arch/x86/extable.c ++++ b/xen/arch/x86/extable.c +@@ -86,26 +86,29 @@ search_one_extable(const struct exceptio + } + + unsigned long +-search_exception_table(const struct cpu_user_regs *regs) ++search_exception_table(const struct cpu_user_regs *regs, unsigned long *stub_ra) + { + const struct virtual_region *region = find_text_region(regs->rip); + unsigned long stub = this_cpu(stubs.addr); + + if ( region && region->ex ) ++ { ++ *stub_ra = 0; + return search_one_extable(region->ex, region->ex_end, regs->rip); ++ } + + if ( regs->rip >= stub + STUB_BUF_SIZE / 2 && + regs->rip < stub + STUB_BUF_SIZE && + regs->rsp > (unsigned long)regs && + regs->rsp < (unsigned long)get_cpu_info() ) + { +- unsigned long retptr = *(unsigned long *)regs->rsp; ++ unsigned long retaddr = *(unsigned long *)regs->rsp, fixup; + +- region = find_text_region(retptr); +- retptr = region && region->ex +- ? search_one_extable(region->ex, region->ex_end, retptr) +- : 0; +- if ( retptr ) ++ region = find_text_region(retaddr); ++ fixup = region && region->ex ++ ? search_one_extable(region->ex, region->ex_end, retaddr) ++ : 0; ++ if ( fixup ) + { + /* + * Put trap number and error code on the stack (in place of the +@@ -117,7 +120,8 @@ search_exception_table(const struct cpu_ + }; + + *(unsigned long *)regs->rsp = token.raw; +- return retptr; ++ *stub_ra = retaddr; ++ return fixup; + } + } + +--- a/xen/arch/x86/include/asm/uaccess.h ++++ b/xen/arch/x86/include/asm/uaccess.h +@@ -421,7 +421,8 @@ union stub_exception_token { + unsigned long raw; + }; + +-extern unsigned long search_exception_table(const struct cpu_user_regs *regs); ++extern unsigned long search_exception_table(const struct cpu_user_regs *regs, ++ unsigned long *stub_ra); + extern void sort_exception_tables(void); + extern void sort_exception_table(struct exception_table_entry *start, + const struct exception_table_entry *stop); +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -845,7 +845,7 @@ void do_unhandled_trap(struct cpu_user_r + } + + static void fixup_exception_return(struct cpu_user_regs *regs, +- unsigned long fixup) ++ unsigned long fixup, unsigned long stub_ra) + { + if ( IS_ENABLED(CONFIG_XEN_SHSTK) ) + { +@@ -862,7 +862,8 @@ static void fixup_exception_return(struc + /* + * Search for %rip. The shstk currently looks like this: + * +- * ... [Likely pointed to by SSP] ++ * tok [Supervisor token, == &tok | BUSY, only with FRED inactive] ++ * ... [Pointed to by SSP for most exceptions, empty in IST cases] + * %cs [== regs->cs] + * %rip [== regs->rip] + * SSP [Likely points to 3 slots higher, above %cs] +@@ -880,7 +881,56 @@ static void fixup_exception_return(struc + */ + if ( ptr[0] == regs->rip && ptr[1] == regs->cs ) + { ++ unsigned long primary_shstk = ++ (ssp & ~(STACK_SIZE - 1)) + ++ (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8; ++ + wrss(fixup, ptr); ++ ++ if ( !stub_ra ) ++ goto shstk_done; ++ ++ /* ++ * Stub recovery ought to happen only when the outer context ++ * was on the main shadow stack. We need to also "pop" the ++ * stub's return address from the interrupted context's shadow ++ * stack. That is, ++ * - if we're still on the main stack, we need to move the ++ * entire stack (up to and including the exception frame) ++ * up by one slot, incrementing the original SSP in the ++ * exception frame, ++ * - if we're on an IST stack, we need to increment the ++ * original SSP. ++ */ ++ BUG_ON((ptr[-1] ^ primary_shstk) >> PAGE_SHIFT); ++ ++ if ( (ssp ^ primary_shstk) >> PAGE_SHIFT ) ++ { ++ /* ++ * We're on an IST stack. First make sure the two return ++ * addresses actually match. Then increment the interrupted ++ * context's SSP. ++ */ ++ BUG_ON(stub_ra != *(unsigned long*)ptr[-1]); ++ wrss(ptr[-1] + 8, &ptr[-1]); ++ goto shstk_done; ++ } ++ ++ /* Make sure the two return addresses actually match. */ ++ BUG_ON(stub_ra != ptr[2]); ++ ++ /* Move exception frame, updating SSP there. */ ++ wrss(ptr[1], &ptr[2]); /* %cs */ ++ wrss(ptr[0], &ptr[1]); /* %rip */ ++ wrss(ptr[-1] + 8, &ptr[0]); /* SSP */ ++ ++ /* Move all newer entries. */ ++ while ( --ptr != _p(ssp) ) ++ wrss(ptr[-1], &ptr[0]); ++ ++ /* Finally account for our own stack having shifted up. */ ++ asm volatile ( "incsspd %0" :: "r" (2) ); ++ + goto shstk_done; + } + } +@@ -901,7 +951,8 @@ static void fixup_exception_return(struc + + static bool extable_fixup(struct cpu_user_regs *regs, bool print) + { +- unsigned long fixup = search_exception_table(regs); ++ unsigned long stub_ra = 0; ++ unsigned long fixup = search_exception_table(regs, &stub_ra); + + if ( unlikely(fixup == 0) ) + return false; +@@ -915,7 +966,7 @@ static bool extable_fixup(struct cpu_use + vector_name(regs->entry_vector), regs->error_code, + _p(regs->rip), _p(regs->rip), _p(fixup)); + +- fixup_exception_return(regs, fixup); ++ fixup_exception_return(regs, fixup, stub_ra); + this_cpu(last_extable_addr) = regs->rip; + + return true; +@@ -1183,7 +1234,8 @@ void do_invalid_op(struct cpu_user_regs + { + case BUGFRAME_run_fn: + case BUGFRAME_warn: +- fixup_exception_return(regs, (unsigned long)eip); ++ fixup_exception_return(regs, (unsigned long)eip, 0); ++ fallthrough; + case BUGFRAME_bug: + case BUGFRAME_assert: + return; From 4d6e2c00074f47eab6cf7adaa8d5bbe0b71e6cb9 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 13 Mar 2024 20:26:24 +0000 Subject: [PATCH 47/99] 2 security updates x86: Register File Data Sampling [XSA-452, CVE-2023-28746] GhostRace: Speculative Race Conditions [XSA-453, CVE-2024-2193] --- ...28a2a742069af203e90c613c5c93e23c9755.patch | 47 +++ ...0f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch | 55 +++ ...07f7d51fe49df8bc70f83e49ce06c92e4e54.patch | 51 +++ ...162cafd27f2865a3102a2ec0f386a02ed03d.patch | 99 +++++ xen.spec | 43 +- xsa452-4.18-1.patch | 304 ++++++++++++++ xsa452-4.18-2.patch | 90 +++++ xsa452-4.18-3.patch | 135 +++++++ xsa452-4.18-4.patch | 197 +++++++++ xsa452-4.18-5.patch | 239 +++++++++++ xsa452-4.18-6.patch | 163 ++++++++ xsa452-4.18-7.patch | 307 ++++++++++++++ xsa453-4.18-1.patch | 50 +++ xsa453-4.18-2.patch | 314 ++++++++++++++ xsa453-4.18-3.patch | 113 ++++++ xsa453-4.18-4.patch | 75 ++++ xsa453-4.18-5.patch | 382 ++++++++++++++++++ xsa453-4.18-6.patch | 61 +++ xsa453-4.18-7.patch | 201 +++++++++ 19 files changed, 2925 insertions(+), 1 deletion(-) create mode 100644 xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch create mode 100644 xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch create mode 100644 xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch create mode 100644 xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch create mode 100644 xsa452-4.18-1.patch create mode 100644 xsa452-4.18-2.patch create mode 100644 xsa452-4.18-3.patch create mode 100644 xsa452-4.18-4.patch create mode 100644 xsa452-4.18-5.patch create mode 100644 xsa452-4.18-6.patch create mode 100644 xsa452-4.18-7.patch create mode 100644 xsa453-4.18-1.patch create mode 100644 xsa453-4.18-2.patch create mode 100644 xsa453-4.18-3.patch create mode 100644 xsa453-4.18-4.patch create mode 100644 xsa453-4.18-5.patch create mode 100644 xsa453-4.18-6.patch create mode 100644 xsa453-4.18-7.patch diff --git a/xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch b/xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch new file mode 100644 index 0000000..20acd78 --- /dev/null +++ b/xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch @@ -0,0 +1,47 @@ +From 576528a2a742069af203e90c613c5c93e23c9755 Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Tue, 27 Feb 2024 14:58:40 +0100 +Subject: [PATCH] x86/spec: do not print thunk option selection if not built-in +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Since the thunk built-in enable is printed as part of the "Compiled-in +support:" line, avoid printing anything in "Xen settings:" if the thunk is +disabled at build time. + +Note the BTI-Thunk option printing is also adjusted to print a colon in the +same way the other options on the line do. + +Requested-by: Jan Beulich +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/spec_ctrl.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 74d2136d42..752225faa6 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -504,11 +504,12 @@ static void __init print_details(enum ind_thunk thunk) + "\n"); + + /* Settings for Xen's protection, irrespective of guests. */ +- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", +- thunk == THUNK_NONE ? "N/A" : +- thunk == THUNK_RETPOLINE ? "RETPOLINE" : +- thunk == THUNK_LFENCE ? "LFENCE" : +- thunk == THUNK_JMP ? "JMP" : "?", ++ printk(" Xen settings: %s%sSPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", ++ thunk != THUNK_NONE ? "BTI-Thunk: " : "", ++ thunk == THUNK_NONE ? "" : ++ thunk == THUNK_RETPOLINE ? "RETPOLINE, " : ++ thunk == THUNK_LFENCE ? "LFENCE, " : ++ thunk == THUNK_JMP ? "JMP, " : "?, ", + (!boot_cpu_has(X86_FEATURE_IBRSB) && + !boot_cpu_has(X86_FEATURE_IBRS)) ? "No" : + (default_xen_spec_ctrl & SPEC_CTRL_IBRS) ? "IBRS+" : "IBRS-", +-- +2.30.2 + diff --git a/xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch b/xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch new file mode 100644 index 0000000..a1b9f49 --- /dev/null +++ b/xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch @@ -0,0 +1,55 @@ +From 60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3 Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Mon, 26 Feb 2024 16:06:42 +0100 +Subject: [PATCH] x86/spec: fix BRANCH_HARDEN option to only be set when + build-enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +The current logic to handle the BRANCH_HARDEN option will report it as enabled +even when build-time disabled. Fix this by only allowing the option to be set +when support for it is built into Xen. + +Fixes: 2d6f36daa086 ('x86/nospec: Introduce CONFIG_SPECULATIVE_HARDEN_BRANCH') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/spec_ctrl.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 421fe3f640..503f1c7a37 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -50,7 +50,8 @@ static int8_t __initdata opt_psfd = -1; + int8_t __ro_after_init opt_ibpb_ctxt_switch = -1; + int8_t __read_mostly opt_eager_fpu = -1; + int8_t __read_mostly opt_l1d_flush = -1; +-static bool __initdata opt_branch_harden = true; ++static bool __initdata opt_branch_harden = ++ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH); + + bool __initdata bsp_delay_spec_ctrl; + uint8_t __read_mostly default_xen_spec_ctrl; +@@ -268,7 +269,16 @@ static int __init cf_check parse_spec_ctrl(const char *s) + else if ( (val = parse_boolean("l1d-flush", s, ss)) >= 0 ) + opt_l1d_flush = val; + else if ( (val = parse_boolean("branch-harden", s, ss)) >= 0 ) +- opt_branch_harden = val; ++ { ++ if ( IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH) ) ++ opt_branch_harden = val; ++ else ++ { ++ no_config_param("SPECULATIVE_HARDEN_BRANCH", "spec-ctrl", s, ++ ss); ++ rc = -EINVAL; ++ } ++ } + else if ( (val = parse_boolean("srb-lock", s, ss)) >= 0 ) + opt_srb_lock = val; + else if ( (val = parse_boolean("unpriv-mmio", s, ss)) >= 0 ) +-- +2.30.2 + diff --git a/xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch b/xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch new file mode 100644 index 0000000..a78c792 --- /dev/null +++ b/xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch @@ -0,0 +1,51 @@ +From 6e9507f7d51fe49df8bc70f83e49ce06c92e4e54 Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Tue, 27 Feb 2024 14:57:52 +0100 +Subject: [PATCH] x86/spec: print the built-in SPECULATIVE_HARDEN_* options +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Just like it's done for INDIRECT_THUNK and SHADOW_PAGING. + +Reported-by: Jan Beulich +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/spec_ctrl.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 503f1c7a37..2d17cbe25f 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -476,13 +476,25 @@ static void __init print_details(enum ind_thunk thunk) + (e21a & cpufeat_mask(X86_FEATURE_SBPB)) ? " SBPB" : ""); + + /* Compiled-in support which pertains to mitigations. */ +- if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) ) ++ if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) || ++ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_ARRAY) || ++ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH) || ++ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS) ) + printk(" Compiled-in support:" + #ifdef CONFIG_INDIRECT_THUNK + " INDIRECT_THUNK" + #endif + #ifdef CONFIG_SHADOW_PAGING + " SHADOW_PAGING" ++#endif ++#ifdef CONFIG_SPECULATIVE_HARDEN_ARRAY ++ " HARDEN_ARRAY" ++#endif ++#ifdef CONFIG_SPECULATIVE_HARDEN_BRANCH ++ " HARDEN_BRANCH" ++#endif ++#ifdef CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS ++ " HARDEN_GUEST_ACCESS" + #endif + "\n"); + +-- +2.30.2 + diff --git a/xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch b/xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch new file mode 100644 index 0000000..6043d48 --- /dev/null +++ b/xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch @@ -0,0 +1,99 @@ +From de17162cafd27f2865a3102a2ec0f386a02ed03d Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Thu, 29 Feb 2024 11:26:40 +0000 +Subject: [PATCH] x86/cpu-policy: Allow for levelling of VERW side effects +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +MD_CLEAR and FB_CLEAR need OR-ing across a migrate pool. Allow this, by +having them unconditinally set in max, with the host values reflected in +default. Annotate the bits as having special properies. + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +--- + xen/arch/x86/cpu-policy.c | 24 +++++++++++++++++++++ + xen/arch/x86/include/asm/cpufeature.h | 1 + + xen/include/public/arch-x86/cpufeatureset.h | 4 ++-- + 3 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/xen/arch/x86/cpu-policy.c b/xen/arch/x86/cpu-policy.c +index 609db6946f..2c6f03057b 100644 +--- a/xen/arch/x86/cpu-policy.c ++++ b/xen/arch/x86/cpu-policy.c +@@ -442,6 +442,16 @@ static void __init guest_common_max_feature_adjustments(uint32_t *fs) + __set_bit(X86_FEATURE_RSBA, fs); + __set_bit(X86_FEATURE_RRSBA, fs); + ++ /* ++ * These bits indicate that the VERW instruction may have gained ++ * scrubbing side effects. With pooling, they mean "you might migrate ++ * somewhere where scrubbing is necessary", and may need exposing on ++ * unaffected hardware. This is fine, because the VERW instruction ++ * has been around since the 286. ++ */ ++ __set_bit(X86_FEATURE_MD_CLEAR, fs); ++ __set_bit(X86_FEATURE_FB_CLEAR, fs); ++ + /* + * The Gather Data Sampling microcode mitigation (August 2023) has an + * adverse performance impact on the CLWB instruction on SKX/CLX/CPX. +@@ -486,6 +496,20 @@ static void __init guest_common_default_feature_adjustments(uint32_t *fs) + cpu_has_rdrand && !is_forced_cpu_cap(X86_FEATURE_RDRAND) ) + __clear_bit(X86_FEATURE_RDRAND, fs); + ++ /* ++ * These bits indicate that the VERW instruction may have gained ++ * scrubbing side effects. The max policy has them set for migration ++ * reasons, so reset the default policy back to the host values in ++ * case we're unaffected. ++ */ ++ __clear_bit(X86_FEATURE_MD_CLEAR, fs); ++ if ( cpu_has_md_clear ) ++ __set_bit(X86_FEATURE_MD_CLEAR, fs); ++ ++ __clear_bit(X86_FEATURE_FB_CLEAR, fs); ++ if ( cpu_has_fb_clear ) ++ __set_bit(X86_FEATURE_FB_CLEAR, fs); ++ + /* + * The Gather Data Sampling microcode mitigation (August 2023) has an + * adverse performance impact on the CLWB instruction on SKX/CLX/CPX. +diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h +index be16492c68..ad24d0fa88 100644 +--- a/xen/arch/x86/include/asm/cpufeature.h ++++ b/xen/arch/x86/include/asm/cpufeature.h +@@ -178,6 +178,7 @@ static inline bool boot_cpu_has(unsigned int feat) + #define cpu_has_avx512_4fmaps boot_cpu_has(X86_FEATURE_AVX512_4FMAPS) + #define cpu_has_avx512_vp2intersect boot_cpu_has(X86_FEATURE_AVX512_VP2INTERSECT) + #define cpu_has_srbds_ctrl boot_cpu_has(X86_FEATURE_SRBDS_CTRL) ++#define cpu_has_md_clear boot_cpu_has(X86_FEATURE_MD_CLEAR) + #define cpu_has_rtm_always_abort boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) + #define cpu_has_tsx_force_abort boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT) + #define cpu_has_serialize boot_cpu_has(X86_FEATURE_SERIALIZE) +diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h +index b230d3a690..0374cec3a2 100644 +--- a/xen/include/public/arch-x86/cpufeatureset.h ++++ b/xen/include/public/arch-x86/cpufeatureset.h +@@ -262,7 +262,7 @@ XEN_CPUFEATURE(AVX512_4FMAPS, 9*32+ 3) /*A AVX512 Multiply Accumulation Single + XEN_CPUFEATURE(FSRM, 9*32+ 4) /*A Fast Short REP MOVS */ + XEN_CPUFEATURE(AVX512_VP2INTERSECT, 9*32+8) /*a VP2INTERSECT{D,Q} insns */ + XEN_CPUFEATURE(SRBDS_CTRL, 9*32+ 9) /* MSR_MCU_OPT_CTRL and RNGDS_MITG_DIS. */ +-XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*A VERW clears microarchitectural buffers */ ++XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*!A VERW clears microarchitectural buffers */ + XEN_CPUFEATURE(RTM_ALWAYS_ABORT, 9*32+11) /*! June 2021 TSX defeaturing in microcode. */ + XEN_CPUFEATURE(TSX_FORCE_ABORT, 9*32+13) /* MSR_TSX_FORCE_ABORT.RTM_ABORT */ + XEN_CPUFEATURE(SERIALIZE, 9*32+14) /*A SERIALIZE insn */ +@@ -334,7 +334,7 @@ XEN_CPUFEATURE(DOITM, 16*32+12) /* Data Operand Invariant Timing + XEN_CPUFEATURE(SBDR_SSDP_NO, 16*32+13) /*A No Shared Buffer Data Read or Sideband Stale Data Propagation */ + XEN_CPUFEATURE(FBSDP_NO, 16*32+14) /*A No Fill Buffer Stale Data Propagation */ + XEN_CPUFEATURE(PSDP_NO, 16*32+15) /*A No Primary Stale Data Propagation */ +-XEN_CPUFEATURE(FB_CLEAR, 16*32+17) /*A Fill Buffers cleared by VERW */ ++XEN_CPUFEATURE(FB_CLEAR, 16*32+17) /*!A Fill Buffers cleared by VERW */ + XEN_CPUFEATURE(FB_CLEAR_CTRL, 16*32+18) /* MSR_OPT_CPU_CTRL.FB_CLEAR_DIS */ + XEN_CPUFEATURE(RRSBA, 16*32+19) /*! Restricted RSB Alternative */ + XEN_CPUFEATURE(BHI_NO, 16*32+20) /*A No Branch History Injection */ +-- +2.30.2 + diff --git a/xen.spec b/xen.spec index 39fd394..1236568 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 6%{?dist} +Release: 7%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -118,6 +118,24 @@ Patch53: newlib.gcc14.fixes.patch Patch54: xsa449.patch Patch55: xsa450.patch Patch56: xsa451-4.18.patch +Patch57: xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch +Patch58: xsa452-4.18-1.patch +Patch59: xsa452-4.18-2.patch +Patch60: xsa452-4.18-3.patch +Patch61: xsa452-4.18-4.patch +Patch62: xsa452-4.18-5.patch +Patch63: xsa452-4.18-6.patch +Patch64: xsa452-4.18-7.patch +Patch65: xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch +Patch66: xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch +Patch67: xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch +Patch68: xsa453-4.18-1.patch +Patch69: xsa453-4.18-2.patch +Patch70: xsa453-4.18-3.patch +Patch71: xsa453-4.18-4.patch +Patch72: xsa453-4.18-5.patch +Patch73: xsa453-4.18-6.patch +Patch74: xsa453-4.18-7.patch %if %build_qemutrad @@ -336,6 +354,24 @@ manage Xen virtual machines. %patch 54 -p1 %patch 55 -p1 %patch 56 -p1 +%patch 57 -p1 +%patch 58 -p1 +%patch 59 -p1 +%patch 60 -p1 +%patch 61 -p1 +%patch 62 -p1 +%patch 63 -p1 +%patch 64 -p1 +%patch 65 -p1 +%patch 66 -p1 +%patch 67 -p1 +%patch 68 -p1 +%patch 69 -p1 +%patch 70 -p1 +%patch 71 -p1 +%patch 72 -p1 +%patch 73 -p1 +%patch 74 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -942,6 +978,11 @@ fi %endif %changelog +* Wed Mar 13 2024 Michael Young - 4.18.0-7 +- x86: Register File Data Sampling [XSA-452, CVE-2023-28746] +- GhostRace: Speculative Race Conditions [XSA-453, CVE-2024-2193] +- additional patches so above applies cleanly + * Tue Feb 27 2024 Michael Young - 4.18.0-6 - x86: shadow stack vs exceptions from emulation stubs - [XSA-451, CVE-2023-46841] (#2266326) diff --git a/xsa452-4.18-1.patch b/xsa452-4.18-1.patch new file mode 100644 index 0000000..cae848f --- /dev/null +++ b/xsa452-4.18-1.patch @@ -0,0 +1,304 @@ +From: Andrew Cooper +Subject: x86/entry: Introduce EFRAME_* constants + +restore_all_guest() does a lot of manipulation of the stack after popping the +GPRs, and uses raw %rsp displacements to do so. Also, almost all entrypaths +use raw %rsp displacements prior to pushing GPRs. + +Provide better mnemonics, to aid readability and reduce the chance of errors +when editing. + +No functional change. The resulting binary is identical. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 37541208f119a9c552c6c6c3246ea61be0d44035) + +diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c +index 57b73a4e6214..2fc4d9130a4d 100644 +--- a/xen/arch/x86/x86_64/asm-offsets.c ++++ b/xen/arch/x86/x86_64/asm-offsets.c +@@ -51,6 +51,23 @@ void __dummy__(void) + OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, es); + BLANK(); + ++ /* ++ * EFRAME_* is for the entry/exit logic where %rsp is pointing at ++ * UREGS_error_code and GPRs are still/already guest values. ++ */ ++#define OFFSET_EF(sym, mem) \ ++ DEFINE(sym, offsetof(struct cpu_user_regs, mem) - \ ++ offsetof(struct cpu_user_regs, error_code)) ++ ++ OFFSET_EF(EFRAME_entry_vector, entry_vector); ++ OFFSET_EF(EFRAME_rip, rip); ++ OFFSET_EF(EFRAME_cs, cs); ++ OFFSET_EF(EFRAME_eflags, eflags); ++ OFFSET_EF(EFRAME_rsp, rsp); ++ BLANK(); ++ ++#undef OFFSET_EF ++ + OFFSET(VCPU_processor, struct vcpu, processor); + OFFSET(VCPU_domain, struct vcpu, domain); + OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info_area.map); +diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S +index fcc3a721f147..cb473f08eebd 100644 +--- a/xen/arch/x86/x86_64/compat/entry.S ++++ b/xen/arch/x86/x86_64/compat/entry.S +@@ -15,7 +15,7 @@ ENTRY(entry_int82) + ENDBR64 + ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP + pushq $0 +- movl $HYPERCALL_VECTOR, 4(%rsp) ++ movl $HYPERCALL_VECTOR, EFRAME_entry_vector(%rsp) + SAVE_ALL compat=1 /* DPL1 gate, restricted to 32bit PV guests only. */ + + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 9a7b129aa7e4..968da9d727b1 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -190,15 +190,15 @@ restore_all_guest: + SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ + + RESTORE_ALL +- testw $TRAP_syscall,4(%rsp) ++ testw $TRAP_syscall, EFRAME_entry_vector(%rsp) + jz iret_exit_to_guest + +- movq 24(%rsp),%r11 # RFLAGS ++ mov EFRAME_eflags(%rsp), %r11 + andq $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), %r11 + orq $X86_EFLAGS_IF,%r11 + + /* Don't use SYSRET path if the return address is not canonical. */ +- movq 8(%rsp),%rcx ++ mov EFRAME_rip(%rsp), %rcx + sarq $47,%rcx + incl %ecx + cmpl $1,%ecx +@@ -213,20 +213,20 @@ restore_all_guest: + ALTERNATIVE "", rag_clrssbsy, X86_FEATURE_XEN_SHSTK + #endif + +- movq 8(%rsp), %rcx # RIP +- cmpw $FLAT_USER_CS32,16(%rsp)# CS +- movq 32(%rsp),%rsp # RSP ++ mov EFRAME_rip(%rsp), %rcx ++ cmpw $FLAT_USER_CS32, EFRAME_cs(%rsp) ++ mov EFRAME_rsp(%rsp), %rsp + je 1f + sysretq + 1: sysretl + + ALIGN + .Lrestore_rcx_iret_exit_to_guest: +- movq 8(%rsp), %rcx # RIP ++ mov EFRAME_rip(%rsp), %rcx + /* No special register assumptions. */ + iret_exit_to_guest: +- andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), 24(%rsp) +- orl $X86_EFLAGS_IF,24(%rsp) ++ andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), EFRAME_eflags(%rsp) ++ orl $X86_EFLAGS_IF, EFRAME_eflags(%rsp) + addq $8,%rsp + .Lft0: iretq + _ASM_PRE_EXTABLE(.Lft0, handle_exception) +@@ -257,7 +257,7 @@ ENTRY(lstar_enter) + pushq $FLAT_KERNEL_CS64 + pushq %rcx + pushq $0 +- movl $TRAP_syscall, 4(%rsp) ++ movl $TRAP_syscall, EFRAME_entry_vector(%rsp) + SAVE_ALL + + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ +@@ -294,7 +294,7 @@ ENTRY(cstar_enter) + pushq $FLAT_USER_CS32 + pushq %rcx + pushq $0 +- movl $TRAP_syscall, 4(%rsp) ++ movl $TRAP_syscall, EFRAME_entry_vector(%rsp) + SAVE_ALL + + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ +@@ -335,7 +335,7 @@ GLOBAL(sysenter_eflags_saved) + pushq $3 /* ring 3 null cs */ + pushq $0 /* null rip */ + pushq $0 +- movl $TRAP_syscall, 4(%rsp) ++ movl $TRAP_syscall, EFRAME_entry_vector(%rsp) + SAVE_ALL + + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ +@@ -389,7 +389,7 @@ ENTRY(int80_direct_trap) + ENDBR64 + ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP + pushq $0 +- movl $0x80, 4(%rsp) ++ movl $0x80, EFRAME_entry_vector(%rsp) + SAVE_ALL + + SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ +@@ -649,7 +649,7 @@ ret_from_intr: + .section .init.text, "ax", @progbits + ENTRY(early_page_fault) + ENDBR64 +- movl $X86_EXC_PF, 4(%rsp) ++ movl $X86_EXC_PF, EFRAME_entry_vector(%rsp) + SAVE_ALL + movq %rsp, %rdi + call do_early_page_fault +@@ -716,7 +716,7 @@ ENTRY(common_interrupt) + + ENTRY(entry_PF) + ENDBR64 +- movl $X86_EXC_PF, 4(%rsp) ++ movl $X86_EXC_PF, EFRAME_entry_vector(%rsp) + /* No special register assumptions. */ + GLOBAL(handle_exception) + ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP +@@ -890,90 +890,90 @@ FATAL_exception_with_ints_disabled: + ENTRY(entry_DE) + ENDBR64 + pushq $0 +- movl $X86_EXC_DE, 4(%rsp) ++ movl $X86_EXC_DE, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_MF) + ENDBR64 + pushq $0 +- movl $X86_EXC_MF, 4(%rsp) ++ movl $X86_EXC_MF, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_XM) + ENDBR64 + pushq $0 +- movl $X86_EXC_XM, 4(%rsp) ++ movl $X86_EXC_XM, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_NM) + ENDBR64 + pushq $0 +- movl $X86_EXC_NM, 4(%rsp) ++ movl $X86_EXC_NM, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_DB) + ENDBR64 + pushq $0 +- movl $X86_EXC_DB, 4(%rsp) ++ movl $X86_EXC_DB, EFRAME_entry_vector(%rsp) + jmp handle_ist_exception + + ENTRY(entry_BP) + ENDBR64 + pushq $0 +- movl $X86_EXC_BP, 4(%rsp) ++ movl $X86_EXC_BP, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_OF) + ENDBR64 + pushq $0 +- movl $X86_EXC_OF, 4(%rsp) ++ movl $X86_EXC_OF, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_BR) + ENDBR64 + pushq $0 +- movl $X86_EXC_BR, 4(%rsp) ++ movl $X86_EXC_BR, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_UD) + ENDBR64 + pushq $0 +- movl $X86_EXC_UD, 4(%rsp) ++ movl $X86_EXC_UD, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_TS) + ENDBR64 +- movl $X86_EXC_TS, 4(%rsp) ++ movl $X86_EXC_TS, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_NP) + ENDBR64 +- movl $X86_EXC_NP, 4(%rsp) ++ movl $X86_EXC_NP, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_SS) + ENDBR64 +- movl $X86_EXC_SS, 4(%rsp) ++ movl $X86_EXC_SS, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_GP) + ENDBR64 +- movl $X86_EXC_GP, 4(%rsp) ++ movl $X86_EXC_GP, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_AC) + ENDBR64 +- movl $X86_EXC_AC, 4(%rsp) ++ movl $X86_EXC_AC, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_CP) + ENDBR64 +- movl $X86_EXC_CP, 4(%rsp) ++ movl $X86_EXC_CP, EFRAME_entry_vector(%rsp) + jmp handle_exception + + ENTRY(entry_DF) + ENDBR64 +- movl $X86_EXC_DF, 4(%rsp) ++ movl $X86_EXC_DF, EFRAME_entry_vector(%rsp) + /* Set AC to reduce chance of further SMAP faults */ + ALTERNATIVE "", stac, X86_FEATURE_XEN_SMAP + SAVE_ALL +@@ -998,7 +998,7 @@ ENTRY(entry_DF) + ENTRY(entry_NMI) + ENDBR64 + pushq $0 +- movl $X86_EXC_NMI, 4(%rsp) ++ movl $X86_EXC_NMI, EFRAME_entry_vector(%rsp) + handle_ist_exception: + ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP + SAVE_ALL +@@ -1130,7 +1130,7 @@ handle_ist_exception: + ENTRY(entry_MC) + ENDBR64 + pushq $0 +- movl $X86_EXC_MC, 4(%rsp) ++ movl $X86_EXC_MC, EFRAME_entry_vector(%rsp) + jmp handle_ist_exception + + /* No op trap handler. Required for kexec crash path. */ +@@ -1167,7 +1167,7 @@ autogen_stubs: /* Automatically generated stubs. */ + 1: + ENDBR64 + pushq $0 +- movb $vec,4(%rsp) ++ movb $vec, EFRAME_entry_vector(%rsp) + jmp common_interrupt + + entrypoint 1b +@@ -1181,7 +1181,7 @@ autogen_stubs: /* Automatically generated stubs. */ + test $8,%spl /* 64bit exception frames are 16 byte aligned, but the word */ + jz 2f /* size is 8 bytes. Check whether the processor gave us an */ + pushq $0 /* error code, and insert an empty one if not. */ +-2: movb $vec,4(%rsp) ++2: movb $vec, EFRAME_entry_vector(%rsp) + jmp handle_exception + + entrypoint 1b diff --git a/xsa452-4.18-2.patch b/xsa452-4.18-2.patch new file mode 100644 index 0000000..4535397 --- /dev/null +++ b/xsa452-4.18-2.patch @@ -0,0 +1,90 @@ +From: Andrew Cooper +Subject: x86: Resync intel-family.h from Linux + +From v6.8-rc6 + +Signed-off-by: Andrew Cooper +Acked-by: Jan Beulich +(cherry picked from commit 195e75371b13c4f7ecdf7b5c50aed0d02f2d7ce8) + +diff --git a/xen/arch/x86/include/asm/intel-family.h b/xen/arch/x86/include/asm/intel-family.h +index ffc49151befe..b65e9c46b922 100644 +--- a/xen/arch/x86/include/asm/intel-family.h ++++ b/xen/arch/x86/include/asm/intel-family.h +@@ -26,6 +26,9 @@ + * _G - parts with extra graphics on + * _X - regular server parts + * _D - micro server parts ++ * _N,_P - other mobile parts ++ * _H - premium mobile parts ++ * _S - other client parts + * + * Historical OPTDIFFs: + * +@@ -37,6 +40,9 @@ + * their own names :-( + */ + ++/* Wildcard match for FAM6 so X86_MATCH_INTEL_FAM6_MODEL(ANY) works */ ++#define INTEL_FAM6_ANY X86_MODEL_ANY ++ + #define INTEL_FAM6_CORE_YONAH 0x0E + + #define INTEL_FAM6_CORE2_MEROM 0x0F +@@ -93,8 +99,6 @@ + #define INTEL_FAM6_ICELAKE_L 0x7E /* Sunny Cove */ + #define INTEL_FAM6_ICELAKE_NNPI 0x9D /* Sunny Cove */ + +-#define INTEL_FAM6_LAKEFIELD 0x8A /* Sunny Cove / Tremont */ +- + #define INTEL_FAM6_ROCKETLAKE 0xA7 /* Cypress Cove */ + + #define INTEL_FAM6_TIGERLAKE_L 0x8C /* Willow Cove */ +@@ -102,12 +106,31 @@ + + #define INTEL_FAM6_SAPPHIRERAPIDS_X 0x8F /* Golden Cove */ + ++#define INTEL_FAM6_EMERALDRAPIDS_X 0xCF ++ ++#define INTEL_FAM6_GRANITERAPIDS_X 0xAD ++#define INTEL_FAM6_GRANITERAPIDS_D 0xAE ++ ++/* "Hybrid" Processors (P-Core/E-Core) */ ++ ++#define INTEL_FAM6_LAKEFIELD 0x8A /* Sunny Cove / Tremont */ ++ + #define INTEL_FAM6_ALDERLAKE 0x97 /* Golden Cove / Gracemont */ + #define INTEL_FAM6_ALDERLAKE_L 0x9A /* Golden Cove / Gracemont */ + +-#define INTEL_FAM6_RAPTORLAKE 0xB7 ++#define INTEL_FAM6_RAPTORLAKE 0xB7 /* Raptor Cove / Enhanced Gracemont */ ++#define INTEL_FAM6_RAPTORLAKE_P 0xBA ++#define INTEL_FAM6_RAPTORLAKE_S 0xBF ++ ++#define INTEL_FAM6_METEORLAKE 0xAC ++#define INTEL_FAM6_METEORLAKE_L 0xAA ++ ++#define INTEL_FAM6_ARROWLAKE_H 0xC5 ++#define INTEL_FAM6_ARROWLAKE 0xC6 ++ ++#define INTEL_FAM6_LUNARLAKE_M 0xBD + +-/* "Small Core" Processors (Atom) */ ++/* "Small Core" Processors (Atom/E-Core) */ + + #define INTEL_FAM6_ATOM_BONNELL 0x1C /* Diamondville, Pineview */ + #define INTEL_FAM6_ATOM_BONNELL_MID 0x26 /* Silverthorne, Lincroft */ +@@ -134,6 +157,13 @@ + #define INTEL_FAM6_ATOM_TREMONT 0x96 /* Elkhart Lake */ + #define INTEL_FAM6_ATOM_TREMONT_L 0x9C /* Jasper Lake */ + ++#define INTEL_FAM6_ATOM_GRACEMONT 0xBE /* Alderlake N */ ++ ++#define INTEL_FAM6_ATOM_CRESTMONT_X 0xAF /* Sierra Forest */ ++#define INTEL_FAM6_ATOM_CRESTMONT 0xB6 /* Grand Ridge */ ++ ++#define INTEL_FAM6_ATOM_DARKMONT_X 0xDD /* Clearwater Forest */ ++ + /* Xeon Phi */ + + #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ diff --git a/xsa452-4.18-3.patch b/xsa452-4.18-3.patch new file mode 100644 index 0000000..bc9059c --- /dev/null +++ b/xsa452-4.18-3.patch @@ -0,0 +1,135 @@ +From: Andrew Cooper +Subject: x86/vmx: Perform VERW flushing later in the VMExit path + +Broken out of the following patch because this change is subtle enough on its +own. See it for the rational of why we're moving VERW. + +As for how, extend the trick already used to hold one condition in +flags (RESUME vs LAUNCH) through the POPing of GPRs. + +Move the MOV CR earlier. Intel specify flags to be undefined across it. + +Encode the two conditions we want using SF and PF. See the code comment for +exactly how. + +Leave a comment to explain the lack of any content around +SPEC_CTRL_EXIT_TO_VMX, but leave the block in place. Sods law says if we +delete it, we'll need to reintroduce it. + +This is part of XSA-452 / CVE-2023-28746. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 475fa20b7384464210f42bad7195f87bd6f1c63f) + +diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S +index e3f60d5a82f7..1bead826caa3 100644 +--- a/xen/arch/x86/hvm/vmx/entry.S ++++ b/xen/arch/x86/hvm/vmx/entry.S +@@ -87,17 +87,39 @@ UNLIKELY_END(realmode) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ + /* SPEC_CTRL_EXIT_TO_VMX Req: %rsp=regs/cpuinfo Clob: */ +- DO_SPEC_CTRL_COND_VERW ++ /* ++ * All speculation safety work happens to be elsewhere. VERW is after ++ * popping the GPRs, while restoring the guest MSR_SPEC_CTRL is left ++ * to the MSR load list. ++ */ + + mov VCPU_hvm_guest_cr2(%rbx),%rax ++ mov %rax, %cr2 ++ ++ /* ++ * We need to perform two conditional actions (VERW, and Resume vs ++ * Launch) after popping GPRs. With some cunning, we can encode both ++ * of these in eflags together. ++ * ++ * Parity is only calculated over the bottom byte of the answer, while ++ * Sign is simply the top bit. ++ * ++ * Therefore, the final OR instruction ends up producing: ++ * SF = VCPU_vmx_launched ++ * PF = !SCF_verw ++ */ ++ BUILD_BUG_ON(SCF_verw & ~0xff) ++ movzbl VCPU_vmx_launched(%rbx), %ecx ++ shl $31, %ecx ++ movzbl CPUINFO_spec_ctrl_flags(%rsp), %eax ++ and $SCF_verw, %eax ++ or %eax, %ecx + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp +- mov %rax,%cr2 +- cmpb $0,VCPU_vmx_launched(%rbx) + pop %rbx + pop %r11 + pop %r10 +@@ -108,7 +130,13 @@ UNLIKELY_END(realmode) + pop %rdx + pop %rsi + pop %rdi +- je .Lvmx_launch ++ ++ jpe .L_skip_verw ++ /* VERW clobbers ZF, but preserves all others, including SF. */ ++ verw STK_REL(CPUINFO_verw_sel, CPUINFO_error_code)(%rsp) ++.L_skip_verw: ++ ++ jns .Lvmx_launch + + /*.Lvmx_resume:*/ + VMRESUME +diff --git a/xen/arch/x86/include/asm/asm_defns.h b/xen/arch/x86/include/asm/asm_defns.h +index baaaccb26e17..56ae26e54265 100644 +--- a/xen/arch/x86/include/asm/asm_defns.h ++++ b/xen/arch/x86/include/asm/asm_defns.h +@@ -81,6 +81,14 @@ register unsigned long current_stack_pointer asm("rsp"); + + #ifdef __ASSEMBLY__ + ++.macro BUILD_BUG_ON condstr, cond:vararg ++ .if \cond ++ .error "Condition \"\condstr\" not satisfied" ++ .endif ++.endm ++/* preprocessor macro to make error message more user friendly */ ++#define BUILD_BUG_ON(cond) BUILD_BUG_ON #cond, cond ++ + #ifdef HAVE_AS_QUOTED_SYM + #define SUBSECTION_LBL(tag) \ + .ifndef .L.tag; \ +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index 6cb7c1b9491e..525745a06608 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -152,6 +152,13 @@ + #endif + .endm + ++/* ++ * Helper to improve the readibility of stack dispacements with %rsp in ++ * unusual positions. Both @field and @top_of_stack should be constants from ++ * the same object. @top_of_stack should be where %rsp is currently pointing. ++ */ ++#define STK_REL(field, top_of_stk) ((field) - (top_of_stk)) ++ + .macro DO_SPEC_CTRL_COND_VERW + /* + * Requires %rsp=cpuinfo +diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c +index 2fc4d9130a4d..0d336788989f 100644 +--- a/xen/arch/x86/x86_64/asm-offsets.c ++++ b/xen/arch/x86/x86_64/asm-offsets.c +@@ -135,6 +135,7 @@ void __dummy__(void) + #endif + + OFFSET(CPUINFO_guest_cpu_user_regs, struct cpu_info, guest_cpu_user_regs); ++ OFFSET(CPUINFO_error_code, struct cpu_info, guest_cpu_user_regs.error_code); + OFFSET(CPUINFO_verw_sel, struct cpu_info, verw_sel); + OFFSET(CPUINFO_current_vcpu, struct cpu_info, current_vcpu); + OFFSET(CPUINFO_per_cpu_offset, struct cpu_info, per_cpu_offset); diff --git a/xsa452-4.18-4.patch b/xsa452-4.18-4.patch new file mode 100644 index 0000000..0ccff77 --- /dev/null +++ b/xsa452-4.18-4.patch @@ -0,0 +1,197 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Perform VERW flushing later in exit paths + +On parts vulnerable to RFDS, VERW's side effects are extended to scrub all +non-architectural entries in various Physical Register Files. To remove all +of Xen's values, the VERW must be after popping the GPRs. + +Rework SPEC_CTRL_COND_VERW to default to an CPUINFO_error_code %rsp position, +but with overrides for other contexts. Identify that it clobbers eflags; this +is particularly relevant for the SYSRET path. + +For the IST exit return to Xen, have the main SPEC_CTRL_EXIT_TO_XEN put a +shadow copy of spec_ctrl_flags, as GPRs can't be used at the point we want to +issue the VERW. + +This is part of XSA-452 / CVE-2023-28746. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit 0a666cf2cd99df6faf3eebc81a1fc286e4eca4c7) + +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index 525745a06608..13acebc75dff 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -159,16 +159,23 @@ + */ + #define STK_REL(field, top_of_stk) ((field) - (top_of_stk)) + +-.macro DO_SPEC_CTRL_COND_VERW ++.macro SPEC_CTRL_COND_VERW \ ++ scf=STK_REL(CPUINFO_spec_ctrl_flags, CPUINFO_error_code), \ ++ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_error_code) + /* +- * Requires %rsp=cpuinfo ++ * Requires \scf and \sel as %rsp-relative expressions ++ * Clobbers eflags ++ * ++ * VERW needs to run after guest GPRs have been restored, where only %rsp is ++ * good to use. Default to expecting %rsp pointing at CPUINFO_error_code. ++ * Contexts where this is not true must provide an alternative \scf and \sel. + * + * Issue a VERW for its flushing side effect, if indicated. This is a Spectre + * v1 gadget, but the IRET/VMEntry is serialising. + */ +- testb $SCF_verw, CPUINFO_spec_ctrl_flags(%rsp) ++ testb $SCF_verw, \scf(%rsp) + jz .L\@_verw_skip +- verw CPUINFO_verw_sel(%rsp) ++ verw \sel(%rsp) + .L\@_verw_skip: + .endm + +@@ -286,8 +293,6 @@ + */ + ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV + +- DO_SPEC_CTRL_COND_VERW +- + ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV + .endm + +@@ -367,7 +372,7 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + */ + .macro SPEC_CTRL_EXIT_TO_XEN + /* +- * Requires %r12=ist_exit, %r14=stack_end ++ * Requires %r12=ist_exit, %r14=stack_end, %rsp=regs + * Clobbers %rax, %rbx, %rcx, %rdx + */ + movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx +@@ -395,11 +400,18 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): + test %r12, %r12 + jz .L\@_skip_ist_exit + +- /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */ +- testb $SCF_verw, %bl +- jz .L\@_skip_verw +- verw STACK_CPUINFO_FIELD(verw_sel)(%r14) +-.L\@_skip_verw: ++ /* ++ * Stash SCF and verw_sel above eflags in the case of an IST_exit. The ++ * VERW logic needs to run after guest GPRs have been restored; i.e. where ++ * we cannot use %r12 or %r14 for the purposes they have here. ++ * ++ * When the CPU pushed this exception frame, it zero-extended eflags. ++ * Therefore it is safe for the VERW logic to look at the stashed SCF ++ * outside of the ist_exit condition. Also, this stashing won't influence ++ * any other restore_all_guest() paths. ++ */ ++ or $(__HYPERVISOR_DS32 << 16), %ebx ++ mov %ebx, UREGS_eflags + 4(%rsp) /* EFRAME_shadow_scf/sel */ + + ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV + +diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c +index 0d336788989f..85c7d0c98967 100644 +--- a/xen/arch/x86/x86_64/asm-offsets.c ++++ b/xen/arch/x86/x86_64/asm-offsets.c +@@ -55,14 +55,22 @@ void __dummy__(void) + * EFRAME_* is for the entry/exit logic where %rsp is pointing at + * UREGS_error_code and GPRs are still/already guest values. + */ +-#define OFFSET_EF(sym, mem) \ ++#define OFFSET_EF(sym, mem, ...) \ + DEFINE(sym, offsetof(struct cpu_user_regs, mem) - \ +- offsetof(struct cpu_user_regs, error_code)) ++ offsetof(struct cpu_user_regs, error_code) __VA_ARGS__) + + OFFSET_EF(EFRAME_entry_vector, entry_vector); + OFFSET_EF(EFRAME_rip, rip); + OFFSET_EF(EFRAME_cs, cs); + OFFSET_EF(EFRAME_eflags, eflags); ++ ++ /* ++ * These aren't real fields. They're spare space, used by the IST ++ * exit-to-xen path. ++ */ ++ OFFSET_EF(EFRAME_shadow_scf, eflags, +4); ++ OFFSET_EF(EFRAME_shadow_sel, eflags, +6); ++ + OFFSET_EF(EFRAME_rsp, rsp); + BLANK(); + +@@ -136,6 +144,7 @@ void __dummy__(void) + + OFFSET(CPUINFO_guest_cpu_user_regs, struct cpu_info, guest_cpu_user_regs); + OFFSET(CPUINFO_error_code, struct cpu_info, guest_cpu_user_regs.error_code); ++ OFFSET(CPUINFO_rip, struct cpu_info, guest_cpu_user_regs.rip); + OFFSET(CPUINFO_verw_sel, struct cpu_info, verw_sel); + OFFSET(CPUINFO_current_vcpu, struct cpu_info, current_vcpu); + OFFSET(CPUINFO_per_cpu_offset, struct cpu_info, per_cpu_offset); +diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S +index cb473f08eebd..3bbe3a79a5b7 100644 +--- a/xen/arch/x86/x86_64/compat/entry.S ++++ b/xen/arch/x86/x86_64/compat/entry.S +@@ -161,6 +161,12 @@ ENTRY(compat_restore_all_guest) + SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ + + RESTORE_ALL adj=8 compat=1 ++ ++ /* Account for ev/ec having already been popped off the stack. */ ++ SPEC_CTRL_COND_VERW \ ++ scf=STK_REL(CPUINFO_spec_ctrl_flags, CPUINFO_rip), \ ++ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_rip) ++ + .Lft0: iretq + _ASM_PRE_EXTABLE(.Lft0, handle_exception) + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 968da9d727b1..2c7512130f49 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -214,6 +214,9 @@ restore_all_guest: + #endif + + mov EFRAME_rip(%rsp), %rcx ++ ++ SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */ ++ + cmpw $FLAT_USER_CS32, EFRAME_cs(%rsp) + mov EFRAME_rsp(%rsp), %rsp + je 1f +@@ -227,6 +230,9 @@ restore_all_guest: + iret_exit_to_guest: + andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), EFRAME_eflags(%rsp) + orl $X86_EFLAGS_IF, EFRAME_eflags(%rsp) ++ ++ SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */ ++ + addq $8,%rsp + .Lft0: iretq + _ASM_PRE_EXTABLE(.Lft0, handle_exception) +@@ -679,9 +685,22 @@ UNLIKELY_START(ne, exit_cr3) + UNLIKELY_END(exit_cr3) + + /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ +- SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */ ++ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end %rsp=regs, Clob: abcd */ + + RESTORE_ALL adj=8 ++ ++ /* ++ * When the CPU pushed this exception frame, it zero-extended eflags. ++ * For an IST exit, SPEC_CTRL_EXIT_TO_XEN stashed shadow copies of ++ * spec_ctrl_flags and ver_sel above eflags, as we can't use any GPRs, ++ * and we're at a random place on the stack, not in a CPUFINFO block. ++ * ++ * Account for ev/ec having already been popped off the stack. ++ */ ++ SPEC_CTRL_COND_VERW \ ++ scf=STK_REL(EFRAME_shadow_scf, EFRAME_rip), \ ++ sel=STK_REL(EFRAME_shadow_sel, EFRAME_rip) ++ + iretq + + ENTRY(common_interrupt) diff --git a/xsa452-4.18-5.patch b/xsa452-4.18-5.patch new file mode 100644 index 0000000..d55e454 --- /dev/null +++ b/xsa452-4.18-5.patch @@ -0,0 +1,239 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Rename VERW related options + +VERW is going to be used for a 3rd purpose, and the existing nomenclature +didn't survive the Stale MMIO issues terribly well. + +Rename the command line option from `md-clear=` to `verw=`. This is more +consistent with other options which tend to be named based on what they're +doing, not which feature enumeration they use behind the scenes. Retain +`md-clear=` as a deprecated alias. + +Rename opt_md_clear_{pv,hvm} and opt_fb_clear_mmio to opt_verw_{pv,hvm,mmio}, +which has a side effect of making spec_ctrl_init_domain() rather clearer to +follow. + +No functional change. + +This is part of XSA-452 / CVE-2023-28746. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit f7603ca252e4226739eb3129a5290ee3da3f8ea4) + +diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc +index 582d6741d182..fbf16839249a 100644 +--- a/docs/misc/xen-command-line.pandoc ++++ b/docs/misc/xen-command-line.pandoc +@@ -2370,7 +2370,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). + + ### spec-ctrl (x86) + > `= List of [ , xen=, {pv,hvm}=, +-> {msr-sc,rsb,md-clear,ibpb-entry}=|{pv,hvm}=, ++> {msr-sc,rsb,verw,ibpb-entry}=|{pv,hvm}=, + > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, + > eager-fpu,l1d-flush,branch-harden,srb-lock, + > unpriv-mmio,gds-mit,div-scrub}= ]` +@@ -2395,7 +2395,7 @@ in place for guests to use. + + Use of a positive boolean value for either of these options is invalid. + +-The `pv=`, `hvm=`, `msr-sc=`, `rsb=`, `md-clear=` and `ibpb-entry=` options ++The `pv=`, `hvm=`, `msr-sc=`, `rsb=`, `verw=` and `ibpb-entry=` options + offer fine grained control over the primitives by Xen. These impact Xen's + ability to protect itself, and/or Xen's ability to virtualise support for + guests to use. +@@ -2412,11 +2412,12 @@ guests to use. + guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. + * `rsb=` offers control over whether to overwrite the Return Stack Buffer / + Return Address Stack on entry to Xen and on idle. +-* `md-clear=` offers control over whether to use VERW to flush +- microarchitectural buffers on idle and exit from Xen. *Note: For +- compatibility with development versions of this fix, `mds=` is also accepted +- on Xen 4.12 and earlier as an alias. Consult vendor documentation in +- preference to here.* ++* `verw=` offers control over whether to use VERW for its scrubbing side ++ effects at appropriate privilege transitions. The exact side effects are ++ microarchitecture and microcode specific. *Note: `md-clear=` is accepted as ++ a deprecated alias. For compatibility with development versions of XSA-297, ++ `mds=` is also accepted on Xen 4.12 and earlier as an alias. Consult vendor ++ documentation in preference to here.* + * `ibpb-entry=` offers control over whether IBPB (Indirect Branch Prediction + Barrier) is used on entry to Xen. This is used by default on hardware + vulnerable to Branch Type Confusion, and hardware vulnerable to Speculative +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index a965b6db28ba..c42d8cdc22d6 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -25,8 +25,8 @@ static bool __initdata opt_msr_sc_pv = true; + static bool __initdata opt_msr_sc_hvm = true; + static int8_t __initdata opt_rsb_pv = -1; + static bool __initdata opt_rsb_hvm = true; +-static int8_t __ro_after_init opt_md_clear_pv = -1; +-static int8_t __ro_after_init opt_md_clear_hvm = -1; ++static int8_t __ro_after_init opt_verw_pv = -1; ++static int8_t __ro_after_init opt_verw_hvm = -1; + + static int8_t __ro_after_init opt_ibpb_entry_pv = -1; + static int8_t __ro_after_init opt_ibpb_entry_hvm = -1; +@@ -66,7 +66,7 @@ static bool __initdata cpu_has_bug_mds; /* Any other M{LP,SB,FB}DS combination. + + static int8_t __initdata opt_srb_lock = -1; + static bool __initdata opt_unpriv_mmio; +-static bool __ro_after_init opt_fb_clear_mmio; ++static bool __ro_after_init opt_verw_mmio; + static int8_t __initdata opt_gds_mit = -1; + static int8_t __initdata opt_div_scrub = -1; + +@@ -108,8 +108,8 @@ static int __init cf_check parse_spec_ctrl(const char *s) + disable_common: + opt_rsb_pv = false; + opt_rsb_hvm = false; +- opt_md_clear_pv = 0; +- opt_md_clear_hvm = 0; ++ opt_verw_pv = 0; ++ opt_verw_hvm = 0; + opt_ibpb_entry_pv = 0; + opt_ibpb_entry_hvm = 0; + opt_ibpb_entry_dom0 = false; +@@ -140,14 +140,14 @@ static int __init cf_check parse_spec_ctrl(const char *s) + { + opt_msr_sc_pv = val; + opt_rsb_pv = val; +- opt_md_clear_pv = val; ++ opt_verw_pv = val; + opt_ibpb_entry_pv = val; + } + else if ( (val = parse_boolean("hvm", s, ss)) >= 0 ) + { + opt_msr_sc_hvm = val; + opt_rsb_hvm = val; +- opt_md_clear_hvm = val; ++ opt_verw_hvm = val; + opt_ibpb_entry_hvm = val; + } + else if ( (val = parse_boolean("msr-sc", s, ss)) != -1 ) +@@ -192,21 +192,22 @@ static int __init cf_check parse_spec_ctrl(const char *s) + break; + } + } +- else if ( (val = parse_boolean("md-clear", s, ss)) != -1 ) ++ else if ( (val = parse_boolean("verw", s, ss)) != -1 || ++ (val = parse_boolean("md-clear", s, ss)) != -1 ) + { + switch ( val ) + { + case 0: + case 1: +- opt_md_clear_pv = opt_md_clear_hvm = val; ++ opt_verw_pv = opt_verw_hvm = val; + break; + + case -2: +- s += strlen("md-clear="); ++ s += (*s == 'v') ? strlen("verw=") : strlen("md-clear="); + if ( (val = parse_boolean("pv", s, ss)) >= 0 ) +- opt_md_clear_pv = val; ++ opt_verw_pv = val; + else if ( (val = parse_boolean("hvm", s, ss)) >= 0 ) +- opt_md_clear_hvm = val; ++ opt_verw_hvm = val; + else + default: + rc = -EINVAL; +@@ -528,8 +529,8 @@ static void __init print_details(enum ind_thunk thunk) + opt_srb_lock ? " SRB_LOCK+" : " SRB_LOCK-", + opt_ibpb_ctxt_switch ? " IBPB-ctxt" : "", + opt_l1d_flush ? " L1D_FLUSH" : "", +- opt_md_clear_pv || opt_md_clear_hvm || +- opt_fb_clear_mmio ? " VERW" : "", ++ opt_verw_pv || opt_verw_hvm || ++ opt_verw_mmio ? " VERW" : "", + opt_div_scrub ? " DIV" : "", + opt_branch_harden ? " BRANCH_HARDEN" : ""); + +@@ -550,13 +551,13 @@ static void __init print_details(enum ind_thunk thunk) + boot_cpu_has(X86_FEATURE_SC_RSB_HVM) || + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) || + amd_virt_spec_ctrl || +- opt_eager_fpu || opt_md_clear_hvm) ? "" : " None", ++ opt_eager_fpu || opt_verw_hvm) ? "" : " None", + boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ? " MSR_SPEC_CTRL" : "", + (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || + amd_virt_spec_ctrl) ? " MSR_VIRT_SPEC_CTRL" : "", + boot_cpu_has(X86_FEATURE_SC_RSB_HVM) ? " RSB" : "", + opt_eager_fpu ? " EAGER_FPU" : "", +- opt_md_clear_hvm ? " MD_CLEAR" : "", ++ opt_verw_hvm ? " VERW" : "", + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) ? " IBPB-entry" : ""); + + #endif +@@ -565,11 +566,11 @@ static void __init print_details(enum ind_thunk thunk) + (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || + boot_cpu_has(X86_FEATURE_SC_RSB_PV) || + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) || +- opt_eager_fpu || opt_md_clear_pv) ? "" : " None", ++ opt_eager_fpu || opt_verw_pv) ? "" : " None", + boot_cpu_has(X86_FEATURE_SC_MSR_PV) ? " MSR_SPEC_CTRL" : "", + boot_cpu_has(X86_FEATURE_SC_RSB_PV) ? " RSB" : "", + opt_eager_fpu ? " EAGER_FPU" : "", +- opt_md_clear_pv ? " MD_CLEAR" : "", ++ opt_verw_pv ? " VERW" : "", + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) ? " IBPB-entry" : ""); + + printk(" XPTI (64-bit PV only): Dom0 %s, DomU %s (with%s PCID)\n", +@@ -1502,8 +1503,8 @@ void spec_ctrl_init_domain(struct domain *d) + { + bool pv = is_pv_domain(d); + +- bool verw = ((pv ? opt_md_clear_pv : opt_md_clear_hvm) || +- (opt_fb_clear_mmio && is_iommu_enabled(d))); ++ bool verw = ((pv ? opt_verw_pv : opt_verw_hvm) || ++ (opt_verw_mmio && is_iommu_enabled(d))); + + bool ibpb = ((pv ? opt_ibpb_entry_pv : opt_ibpb_entry_hvm) && + (d->domain_id != 0 || opt_ibpb_entry_dom0)); +@@ -1866,19 +1867,20 @@ void __init init_speculation_mitigations(void) + * the return-to-guest path. + */ + if ( opt_unpriv_mmio ) +- opt_fb_clear_mmio = cpu_has_fb_clear; ++ opt_verw_mmio = cpu_has_fb_clear; + + /* + * By default, enable PV and HVM mitigations on MDS-vulnerable hardware. + * This will only be a token effort for MLPDS/MFBDS when HT is enabled, + * but it is somewhat better than nothing. + */ +- if ( opt_md_clear_pv == -1 ) +- opt_md_clear_pv = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && +- boot_cpu_has(X86_FEATURE_MD_CLEAR)); +- if ( opt_md_clear_hvm == -1 ) +- opt_md_clear_hvm = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && +- boot_cpu_has(X86_FEATURE_MD_CLEAR)); ++ if ( opt_verw_pv == -1 ) ++ opt_verw_pv = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && ++ cpu_has_md_clear); ++ ++ if ( opt_verw_hvm == -1 ) ++ opt_verw_hvm = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && ++ cpu_has_md_clear); + + /* + * Enable MDS/MMIO defences as applicable. The Idle blocks need using if +@@ -1891,12 +1893,12 @@ void __init init_speculation_mitigations(void) + * MDS mitigations. L1D_FLUSH is not safe for MMIO mitigations.) + * + * After calculating the appropriate idle setting, simplify +- * opt_md_clear_hvm to mean just "should we VERW on the way into HVM ++ * opt_verw_hvm to mean just "should we VERW on the way into HVM + * guests", so spec_ctrl_init_domain() can calculate suitable settings. + */ +- if ( opt_md_clear_pv || opt_md_clear_hvm || opt_fb_clear_mmio ) ++ if ( opt_verw_pv || opt_verw_hvm || opt_verw_mmio ) + setup_force_cpu_cap(X86_FEATURE_SC_VERW_IDLE); +- opt_md_clear_hvm &= !cpu_has_skip_l1dfl && !opt_l1d_flush; ++ opt_verw_hvm &= !cpu_has_skip_l1dfl && !opt_l1d_flush; + + /* + * Warn the user if they are on MLPDS/MFBDS-vulnerable hardware with HT diff --git a/xsa452-4.18-6.patch b/xsa452-4.18-6.patch new file mode 100644 index 0000000..422dc62 --- /dev/null +++ b/xsa452-4.18-6.patch @@ -0,0 +1,163 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: VERW-handling adjustments + +... before we add yet more complexity to this logic. Mostly expanded +comments, but with three minor changes. + +1) Introduce cpu_has_useful_md_clear to simplify later logic in this patch and + future ones. + +2) We only ever need SC_VERW_IDLE when SMT is active. If SMT isn't active, + then there's no re-partition of pipeline resources based on thread-idleness + to worry about. + +3) The logic to adjust HVM VERW based on L1D_FLUSH is unmaintainable and, as + it turns out, wrong. SKIP_L1DFL is just a hint bit, whereas opt_l1d_flush + is the relevant decision of whether to use L1D_FLUSH based on + susceptibility and user preference. + + Rewrite the logic so it can be followed, and incorporate the fact that when + FB_CLEAR is visible, L1D_FLUSH isn't a safe substitution. + +This is part of XSA-452 / CVE-2023-28746. + +Signed-off-by: Andrew Cooper +Acked-by: Jan Beulich +(cherry picked from commit 1eb91a8a06230b4b64228c9a380194f8cfe6c5e2) + +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index c42d8cdc22d6..a4afcd8570e2 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -1519,7 +1519,7 @@ void __init init_speculation_mitigations(void) + { + enum ind_thunk thunk = THUNK_DEFAULT; + bool has_spec_ctrl, ibrs = false, hw_smt_enabled; +- bool cpu_has_bug_taa, retpoline_safe; ++ bool cpu_has_bug_taa, cpu_has_useful_md_clear, retpoline_safe; + + hw_smt_enabled = check_smt_enabled(); + +@@ -1855,50 +1855,97 @@ void __init init_speculation_mitigations(void) + "enabled. Please assess your configuration and choose an\n" + "explicit 'smt=' setting. See XSA-273.\n"); + ++ /* ++ * A brief summary of VERW-related changes. ++ * ++ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/intel-analysis-microarchitectural-data-sampling.html ++ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html ++ * ++ * Relevant ucodes: ++ * ++ * - May 2019, for MDS. Introduces the MD_CLEAR CPUID bit and VERW side ++ * effects to scrub Store/Load/Fill buffers as applicable. MD_CLEAR ++ * exists architecturally, even when the side effects have been removed. ++ * ++ * Use VERW to scrub on return-to-guest. Parts with L1D_FLUSH to ++ * mitigate L1TF have the same side effect, so no need to do both. ++ * ++ * Various Atoms suffer from Store-buffer sampling only. Store buffers ++ * are statically partitioned between non-idle threads, so scrubbing is ++ * wanted when going idle too. ++ * ++ * Load ports and Fill buffers are competitively shared between threads. ++ * SMT must be disabled for VERW scrubbing to be fully effective. ++ * ++ * - November 2019, for TAA. Extended VERW side effects to TSX-enabled ++ * MDS_NO parts. ++ * ++ * - February 2022, for Client TSX de-feature. Removed VERW side effects ++ * from Client CPUs only. ++ * ++ * - May 2022, for MMIO Stale Data. (Re)introduced Fill Buffer scrubbing ++ * on all MMIO-affected parts which didn't already have it for MDS ++ * reasons, enumerating FB_CLEAR on those parts only. ++ * ++ * If FB_CLEAR is enumerated, L1D_FLUSH does not have the same scrubbing ++ * side effects as VERW and cannot be used in its place. ++ */ + mds_calculations(); + + /* +- * Parts which enumerate FB_CLEAR are those which are post-MDS_NO and have +- * reintroduced the VERW fill buffer flushing side effect because of a +- * susceptibility to FBSDP. ++ * Parts which enumerate FB_CLEAR are those with now-updated microcode ++ * which weren't susceptible to the original MFBDS (and therefore didn't ++ * have Fill Buffer scrubbing side effects to begin with, or were Client ++ * MDS_NO non-TAA_NO parts where the scrubbing was removed), but have had ++ * the scrubbing reintroduced because of a susceptibility to FBSDP. + * + * If unprivileged guests have (or will have) MMIO mappings, we can + * mitigate cross-domain leakage of fill buffer data by issuing VERW on +- * the return-to-guest path. ++ * the return-to-guest path. This is only a token effort if SMT is ++ * active. + */ + if ( opt_unpriv_mmio ) + opt_verw_mmio = cpu_has_fb_clear; + + /* +- * By default, enable PV and HVM mitigations on MDS-vulnerable hardware. +- * This will only be a token effort for MLPDS/MFBDS when HT is enabled, +- * but it is somewhat better than nothing. ++ * MD_CLEAR is enumerated architecturally forevermore, even after the ++ * scrubbing side effects have been removed. Create ourselves an version ++ * which expressed whether we think MD_CLEAR is having any useful side ++ * effect. ++ */ ++ cpu_has_useful_md_clear = (cpu_has_md_clear && ++ (cpu_has_bug_mds || cpu_has_bug_msbds_only)); ++ ++ /* ++ * By default, use VERW scrubbing on applicable hardware, if we think it's ++ * going to have an effect. This will only be a token effort for ++ * MLPDS/MFBDS when SMT is enabled. + */ + if ( opt_verw_pv == -1 ) +- opt_verw_pv = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && +- cpu_has_md_clear); ++ opt_verw_pv = cpu_has_useful_md_clear; + + if ( opt_verw_hvm == -1 ) +- opt_verw_hvm = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && +- cpu_has_md_clear); ++ opt_verw_hvm = cpu_has_useful_md_clear; + + /* +- * Enable MDS/MMIO defences as applicable. The Idle blocks need using if +- * either the PV or HVM MDS defences are used, or if we may give MMIO +- * access to untrusted guests. +- * +- * HVM is more complicated. The MD_CLEAR microcode extends L1D_FLUSH with +- * equivalent semantics to avoid needing to perform both flushes on the +- * HVM path. Therefore, we don't need VERW in addition to L1D_FLUSH (for +- * MDS mitigations. L1D_FLUSH is not safe for MMIO mitigations.) +- * +- * After calculating the appropriate idle setting, simplify +- * opt_verw_hvm to mean just "should we VERW on the way into HVM +- * guests", so spec_ctrl_init_domain() can calculate suitable settings. ++ * If SMT is active, and we're protecting against MDS or MMIO stale data, ++ * we need to scrub before going idle as well as on return to guest. ++ * Various pipeline resources are repartitioned amongst non-idle threads. + */ +- if ( opt_verw_pv || opt_verw_hvm || opt_verw_mmio ) ++ if ( ((cpu_has_useful_md_clear && (opt_verw_pv || opt_verw_hvm)) || ++ opt_verw_mmio) && hw_smt_enabled ) + setup_force_cpu_cap(X86_FEATURE_SC_VERW_IDLE); +- opt_verw_hvm &= !cpu_has_skip_l1dfl && !opt_l1d_flush; ++ ++ /* ++ * After calculating the appropriate idle setting, simplify opt_verw_hvm ++ * to mean just "should we VERW on the way into HVM guests", so ++ * spec_ctrl_init_domain() can calculate suitable settings. ++ * ++ * It is only safe to use L1D_FLUSH in place of VERW when MD_CLEAR is the ++ * only *_CLEAR we can see. ++ */ ++ if ( opt_l1d_flush && cpu_has_md_clear && !cpu_has_fb_clear ) ++ opt_verw_hvm = false; + + /* + * Warn the user if they are on MLPDS/MFBDS-vulnerable hardware with HT diff --git a/xsa452-4.18-7.patch b/xsa452-4.18-7.patch new file mode 100644 index 0000000..a252db0 --- /dev/null +++ b/xsa452-4.18-7.patch @@ -0,0 +1,307 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Mitigation Register File Data Sampling + +RFDS affects Atom cores, also branded E-cores, between the Goldmont and +Gracemont microarchitectures. This includes Alder Lake and Raptor Lake hybrid +clien systems which have a mix of Gracemont and other types of cores. + +Two new bits have been defined; RFDS_CLEAR to indicate VERW has more side +effets, and RFDS_NO to incidate that the system is unaffected. Plenty of +unaffected CPUs won't be getting RFDS_NO retrofitted in microcode, so we +synthesise it. Alder Lake and Raptor Lake Xeon-E's are unaffected due to +their platform configuration, and we must use the Hybrid CPUID bit to +distinguish them from their non-Xeon counterparts. + +Like MD_CLEAR and FB_CLEAR, RFDS_CLEAR needs OR-ing across a resource pool, so +set it in the max policies and reflect the host setting in default. + +This is part of XSA-452 / CVE-2023-28746. + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich +(cherry picked from commit fb5b6f6744713410c74cfc12b7176c108e3c9a31) + +diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c +index 7370f1b56ef9..52e451a806c1 100644 +--- a/tools/misc/xen-cpuid.c ++++ b/tools/misc/xen-cpuid.c +@@ -172,7 +172,7 @@ static const char *const str_7d0[32] = + [ 8] = "avx512-vp2intersect", [ 9] = "srbds-ctrl", + [10] = "md-clear", [11] = "rtm-always-abort", + /* 12 */ [13] = "tsx-force-abort", +- [14] = "serialize", ++ [14] = "serialize", [15] = "hybrid", + [16] = "tsxldtrk", + [18] = "pconfig", + [20] = "cet-ibt", +@@ -245,7 +245,8 @@ static const char *const str_m10Al[32] = + [20] = "bhi-no", [21] = "xapic-status", + /* 22 */ [23] = "ovrclk-status", + [24] = "pbrsb-no", [25] = "gds-ctrl", +- [26] = "gds-no", ++ [26] = "gds-no", [27] = "rfds-no", ++ [28] = "rfds-clear", + }; + + static const char *const str_m10Ah[32] = +diff --git a/xen/arch/x86/cpu-policy.c b/xen/arch/x86/cpu-policy.c +index c7c5e99b7b4c..12e621b97de6 100644 +--- a/xen/arch/x86/cpu-policy.c ++++ b/xen/arch/x86/cpu-policy.c +@@ -451,6 +451,7 @@ static void __init guest_common_max_feature_adjustments(uint32_t *fs) + */ + __set_bit(X86_FEATURE_MD_CLEAR, fs); + __set_bit(X86_FEATURE_FB_CLEAR, fs); ++ __set_bit(X86_FEATURE_RFDS_CLEAR, fs); + + /* + * The Gather Data Sampling microcode mitigation (August 2023) has an +@@ -500,6 +501,10 @@ static void __init guest_common_default_feature_adjustments(uint32_t *fs) + if ( cpu_has_fb_clear ) + __set_bit(X86_FEATURE_FB_CLEAR, fs); + ++ __clear_bit(X86_FEATURE_RFDS_CLEAR, fs); ++ if ( cpu_has_rfds_clear ) ++ __set_bit(X86_FEATURE_RFDS_CLEAR, fs); ++ + /* + * The Gather Data Sampling microcode mitigation (August 2023) has an + * adverse performance impact on the CLWB instruction on SKX/CLX/CPX. +diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h +index 76ef2aeb1de6..3c57f55de075 100644 +--- a/xen/arch/x86/include/asm/cpufeature.h ++++ b/xen/arch/x86/include/asm/cpufeature.h +@@ -181,6 +181,7 @@ static inline bool boot_cpu_has(unsigned int feat) + #define cpu_has_rtm_always_abort boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) + #define cpu_has_tsx_force_abort boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT) + #define cpu_has_serialize boot_cpu_has(X86_FEATURE_SERIALIZE) ++#define cpu_has_hybrid boot_cpu_has(X86_FEATURE_HYBRID) + #define cpu_has_avx512_fp16 boot_cpu_has(X86_FEATURE_AVX512_FP16) + #define cpu_has_arch_caps boot_cpu_has(X86_FEATURE_ARCH_CAPS) + +@@ -208,6 +209,8 @@ static inline bool boot_cpu_has(unsigned int feat) + #define cpu_has_rrsba boot_cpu_has(X86_FEATURE_RRSBA) + #define cpu_has_gds_ctrl boot_cpu_has(X86_FEATURE_GDS_CTRL) + #define cpu_has_gds_no boot_cpu_has(X86_FEATURE_GDS_NO) ++#define cpu_has_rfds_no boot_cpu_has(X86_FEATURE_RFDS_NO) ++#define cpu_has_rfds_clear boot_cpu_has(X86_FEATURE_RFDS_CLEAR) + + /* Synthesized. */ + #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) +diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h +index 82a81bd0a232..85ef28a612e0 100644 +--- a/xen/arch/x86/include/asm/msr-index.h ++++ b/xen/arch/x86/include/asm/msr-index.h +@@ -89,6 +89,8 @@ + #define ARCH_CAPS_PBRSB_NO (_AC(1, ULL) << 24) + #define ARCH_CAPS_GDS_CTRL (_AC(1, ULL) << 25) + #define ARCH_CAPS_GDS_NO (_AC(1, ULL) << 26) ++#define ARCH_CAPS_RFDS_NO (_AC(1, ULL) << 27) ++#define ARCH_CAPS_RFDS_CLEAR (_AC(1, ULL) << 28) + + #define MSR_FLUSH_CMD 0x0000010b + #define FLUSH_CMD_L1D (_AC(1, ULL) << 0) +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index a4afcd8570e2..8165379fed94 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -435,7 +436,7 @@ static void __init print_details(enum ind_thunk thunk) + * Hardware read-only information, stating immunity to certain issues, or + * suggestions of which mitigation to use. + */ +- printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", ++ printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + (caps & ARCH_CAPS_RDCL_NO) ? " RDCL_NO" : "", + (caps & ARCH_CAPS_EIBRS) ? " EIBRS" : "", + (caps & ARCH_CAPS_RSBA) ? " RSBA" : "", +@@ -451,6 +452,7 @@ static void __init print_details(enum ind_thunk thunk) + (caps & ARCH_CAPS_FB_CLEAR) ? " FB_CLEAR" : "", + (caps & ARCH_CAPS_PBRSB_NO) ? " PBRSB_NO" : "", + (caps & ARCH_CAPS_GDS_NO) ? " GDS_NO" : "", ++ (caps & ARCH_CAPS_RFDS_NO) ? " RFDS_NO" : "", + (e8b & cpufeat_mask(X86_FEATURE_IBRS_ALWAYS)) ? " IBRS_ALWAYS" : "", + (e8b & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS)) ? " STIBP_ALWAYS" : "", + (e8b & cpufeat_mask(X86_FEATURE_IBRS_FAST)) ? " IBRS_FAST" : "", +@@ -461,7 +463,7 @@ static void __init print_details(enum ind_thunk thunk) + (e21a & cpufeat_mask(X86_FEATURE_SRSO_NO)) ? " SRSO_NO" : ""); + + /* Hardware features which need driving to mitigate issues. */ +- printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s%s\n", ++ printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + (e8b & cpufeat_mask(X86_FEATURE_IBPB)) || + (_7d0 & cpufeat_mask(X86_FEATURE_IBRSB)) ? " IBPB" : "", + (e8b & cpufeat_mask(X86_FEATURE_IBRS)) || +@@ -479,6 +481,7 @@ static void __init print_details(enum ind_thunk thunk) + (caps & ARCH_CAPS_TSX_CTRL) ? " TSX_CTRL" : "", + (caps & ARCH_CAPS_FB_CLEAR_CTRL) ? " FB_CLEAR_CTRL" : "", + (caps & ARCH_CAPS_GDS_CTRL) ? " GDS_CTRL" : "", ++ (caps & ARCH_CAPS_RFDS_CLEAR) ? " RFDS_CLEAR" : "", + (e21a & cpufeat_mask(X86_FEATURE_SBPB)) ? " SBPB" : ""); + + /* Compiled-in support which pertains to mitigations. */ +@@ -1347,6 +1350,83 @@ static __init void mds_calculations(void) + } + } + ++/* ++ * Register File Data Sampling affects Atom cores from the Goldmont to ++ * Gracemont microarchitectures. The March 2024 microcode adds RFDS_NO to ++ * some but not all unaffected parts, and RFDS_CLEAR to affected parts still ++ * in support. ++ * ++ * Alder Lake and Raptor Lake client CPUs have a mix of P cores ++ * (Golden/Raptor Cove, not vulnerable) and E cores (Gracemont, ++ * vulnerable), and both enumerate RFDS_CLEAR. ++ * ++ * Both exist in a Xeon SKU, which has the E cores (Gracemont) disabled by ++ * platform configuration, and enumerate RFDS_NO. ++ * ++ * With older parts, or with out-of-date microcode, synthesise RFDS_NO when ++ * safe to do so. ++ * ++ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/register-file-data-sampling.html ++ */ ++static void __init rfds_calculations(void) ++{ ++ /* RFDS is only known to affect Intel Family 6 processors at this time. */ ++ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || ++ boot_cpu_data.x86 != 6 ) ++ return; ++ ++ /* ++ * If RFDS_NO or RFDS_CLEAR are visible, we've either got suitable ++ * microcode, or an RFDS-aware hypervisor is levelling us in a pool. ++ */ ++ if ( cpu_has_rfds_no || cpu_has_rfds_clear ) ++ return; ++ ++ /* If we're virtualised, don't attempt to synthesise RFDS_NO. */ ++ if ( cpu_has_hypervisor ) ++ return; ++ ++ /* ++ * Not all CPUs are expected to get a microcode update enumerating one of ++ * RFDS_{NO,CLEAR}, or we might have out-of-date microcode. ++ */ ++ switch ( boot_cpu_data.x86_model ) ++ { ++ case INTEL_FAM6_ALDERLAKE: ++ case INTEL_FAM6_RAPTORLAKE: ++ /* ++ * Alder Lake and Raptor Lake might be a client SKU (with the ++ * Gracemont cores active, and therefore vulnerable) or might be a ++ * server SKU (with the Gracemont cores disabled, and therefore not ++ * vulnerable). ++ * ++ * See if the CPU identifies as hybrid to distinguish the two cases. ++ */ ++ if ( !cpu_has_hybrid ) ++ break; ++ fallthrough; ++ case INTEL_FAM6_ALDERLAKE_L: ++ case INTEL_FAM6_RAPTORLAKE_P: ++ case INTEL_FAM6_RAPTORLAKE_S: ++ ++ case INTEL_FAM6_ATOM_GOLDMONT: /* Apollo Lake */ ++ case INTEL_FAM6_ATOM_GOLDMONT_D: /* Denverton */ ++ case INTEL_FAM6_ATOM_GOLDMONT_PLUS: /* Gemini Lake */ ++ case INTEL_FAM6_ATOM_TREMONT_D: /* Snow Ridge / Parker Ridge */ ++ case INTEL_FAM6_ATOM_TREMONT: /* Elkhart Lake */ ++ case INTEL_FAM6_ATOM_TREMONT_L: /* Jasper Lake */ ++ case INTEL_FAM6_ATOM_GRACEMONT: /* Alder Lake N */ ++ return; ++ } ++ ++ /* ++ * We appear to be on an unaffected CPU which didn't enumerate RFDS_NO, ++ * perhaps because of it's age or because of out-of-date microcode. ++ * Synthesise it. ++ */ ++ setup_force_cpu_cap(X86_FEATURE_RFDS_NO); ++} ++ + static bool __init cpu_has_gds(void) + { + /* +@@ -1860,6 +1940,7 @@ void __init init_speculation_mitigations(void) + * + * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/intel-analysis-microarchitectural-data-sampling.html + * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html ++ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/register-file-data-sampling.html + * + * Relevant ucodes: + * +@@ -1889,8 +1970,12 @@ void __init init_speculation_mitigations(void) + * + * If FB_CLEAR is enumerated, L1D_FLUSH does not have the same scrubbing + * side effects as VERW and cannot be used in its place. ++ * ++ * - March 2023, for RFDS. Enumerate RFDS_CLEAR to mean that VERW now ++ * scrubs non-architectural entries from certain register files. + */ + mds_calculations(); ++ rfds_calculations(); + + /* + * Parts which enumerate FB_CLEAR are those with now-updated microcode +@@ -1922,15 +2007,19 @@ void __init init_speculation_mitigations(void) + * MLPDS/MFBDS when SMT is enabled. + */ + if ( opt_verw_pv == -1 ) +- opt_verw_pv = cpu_has_useful_md_clear; ++ opt_verw_pv = cpu_has_useful_md_clear || cpu_has_rfds_clear; + + if ( opt_verw_hvm == -1 ) +- opt_verw_hvm = cpu_has_useful_md_clear; ++ opt_verw_hvm = cpu_has_useful_md_clear || cpu_has_rfds_clear; + + /* + * If SMT is active, and we're protecting against MDS or MMIO stale data, + * we need to scrub before going idle as well as on return to guest. + * Various pipeline resources are repartitioned amongst non-idle threads. ++ * ++ * We don't need to scrub on idle for RFDS. There are no affected cores ++ * which support SMT, despite there being affected cores in hybrid systems ++ * which have SMT elsewhere in the platform. + */ + if ( ((cpu_has_useful_md_clear && (opt_verw_pv || opt_verw_hvm)) || + opt_verw_mmio) && hw_smt_enabled ) +@@ -1944,7 +2033,8 @@ void __init init_speculation_mitigations(void) + * It is only safe to use L1D_FLUSH in place of VERW when MD_CLEAR is the + * only *_CLEAR we can see. + */ +- if ( opt_l1d_flush && cpu_has_md_clear && !cpu_has_fb_clear ) ++ if ( opt_l1d_flush && cpu_has_md_clear && !cpu_has_fb_clear && ++ !cpu_has_rfds_clear ) + opt_verw_hvm = false; + + /* +diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h +index 337aaa9c770b..8e17ef670fff 100644 +--- a/xen/include/public/arch-x86/cpufeatureset.h ++++ b/xen/include/public/arch-x86/cpufeatureset.h +@@ -266,6 +266,7 @@ XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*!A VERW clears microarchitectural buffe + XEN_CPUFEATURE(RTM_ALWAYS_ABORT, 9*32+11) /*! June 2021 TSX defeaturing in microcode. */ + XEN_CPUFEATURE(TSX_FORCE_ABORT, 9*32+13) /* MSR_TSX_FORCE_ABORT.RTM_ABORT */ + XEN_CPUFEATURE(SERIALIZE, 9*32+14) /*A SERIALIZE insn */ ++XEN_CPUFEATURE(HYBRID, 9*32+15) /* Heterogeneous platform */ + XEN_CPUFEATURE(TSXLDTRK, 9*32+16) /*a TSX load tracking suspend/resume insns */ + XEN_CPUFEATURE(CET_IBT, 9*32+20) /* CET - Indirect Branch Tracking */ + XEN_CPUFEATURE(AVX512_FP16, 9*32+23) /*A AVX512 FP16 instructions */ +@@ -338,6 +339,8 @@ XEN_CPUFEATURE(OVRCLK_STATUS, 16*32+23) /* MSR_OVERCLOCKING_STATUS */ + XEN_CPUFEATURE(PBRSB_NO, 16*32+24) /*A No Post-Barrier RSB predictions */ + XEN_CPUFEATURE(GDS_CTRL, 16*32+25) /* MCU_OPT_CTRL.GDS_MIT_{DIS,LOCK} */ + XEN_CPUFEATURE(GDS_NO, 16*32+26) /*A No Gather Data Sampling */ ++XEN_CPUFEATURE(RFDS_NO, 16*32+27) /*A No Register File Data Sampling */ ++XEN_CPUFEATURE(RFDS_CLEAR, 16*32+28) /*!A Register File(s) cleared by VERW */ + + /* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 */ + diff --git a/xsa453-4.18-1.patch b/xsa453-4.18-1.patch new file mode 100644 index 0000000..a3c0f05 --- /dev/null +++ b/xsa453-4.18-1.patch @@ -0,0 +1,50 @@ +From: Andrew Cooper +Subject: xen: Swap order of actions in the FREE*() macros + +Wherever possible, it is a good idea to NULL out the visible reference to an +object prior to freeing it. The FREE*() macros already collect together both +parts, making it easy to adjust. + +This has a marginal code generation improvement, as some of the calls to the +free() function can be tailcall optimised. + +No functional change. + +Signed-off-by: Andrew Cooper +Acked-by: Jan Beulich +(cherry picked from commit c4f427ec879e7c0df6d44d02561e8bee838a293e) + +diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h +index 8b9618609f77..8bc5f4249d1b 100644 +--- a/xen/include/xen/mm.h ++++ b/xen/include/xen/mm.h +@@ -91,8 +91,9 @@ bool scrub_free_pages(void); + + /* Free an allocation, and zero the pointer to it. */ + #define FREE_XENHEAP_PAGES(p, o) do { \ +- free_xenheap_pages(p, o); \ ++ void *_ptr_ = (p); \ + (p) = NULL; \ ++ free_xenheap_pages(_ptr_, o); \ + } while ( false ) + #define FREE_XENHEAP_PAGE(p) FREE_XENHEAP_PAGES(p, 0) + +diff --git a/xen/include/xen/xmalloc.h b/xen/include/xen/xmalloc.h +index 16979a117c6a..d857298011c1 100644 +--- a/xen/include/xen/xmalloc.h ++++ b/xen/include/xen/xmalloc.h +@@ -66,9 +66,10 @@ + extern void xfree(void *); + + /* Free an allocation, and zero the pointer to it. */ +-#define XFREE(p) do { \ +- xfree(p); \ +- (p) = NULL; \ ++#define XFREE(p) do { \ ++ void *_ptr_ = (p); \ ++ (p) = NULL; \ ++ xfree(_ptr_); \ + } while ( false ) + + /* Underlying functions */ + diff --git a/xsa453-4.18-2.patch b/xsa453-4.18-2.patch new file mode 100644 index 0000000..01a7e05 --- /dev/null +++ b/xsa453-4.18-2.patch @@ -0,0 +1,314 @@ +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Subject: x86/spinlock: introduce support for blocking speculation into + critical regions + +Introduce a new Kconfig option to block speculation into lock protected +critical regions. The Kconfig option is enabled by default, but the mitigation +won't be engaged unless it's explicitly enabled in the command line using +`spec-ctrl=lock-harden`. + +Convert the spinlock acquire macros into always-inline functions, and introduce +a speculation barrier after the lock has been taken. Note the speculation +barrier is not placed inside the implementation of the spin lock functions, as +to prevent speculation from falling through the call to the lock functions +resulting in the barrier also being skipped. + +trylock variants are protected using a construct akin to the existing +evaluate_nospec(). + +This patch only implements the speculation barrier for x86. + +Note spin locks are the only locking primitive taken care in this change, +further locking primitives will be adjusted by separate changes. + +This is part of XSA-453 / CVE-2024-2193 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +(cherry picked from commit 7ef0084418e188d05f338c3e028fbbe8b6924afa) + +diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc +index fbf16839249a..3f9f9167182f 100644 +--- a/docs/misc/xen-command-line.pandoc ++++ b/docs/misc/xen-command-line.pandoc +@@ -2373,7 +2373,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). + > {msr-sc,rsb,verw,ibpb-entry}=|{pv,hvm}=, + > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, + > eager-fpu,l1d-flush,branch-harden,srb-lock, +-> unpriv-mmio,gds-mit,div-scrub}= ]` ++> unpriv-mmio,gds-mit,div-scrub,lock-harden}= ]` + + Controls for speculative execution sidechannel mitigations. By default, Xen + will pick the most appropriate mitigations based on compiled in support, +@@ -2500,6 +2500,11 @@ On all hardware, the `div-scrub=` option can be used to force or prevent Xen + from mitigating the DIV-leakage vulnerability. By default, Xen will mitigate + DIV-leakage on hardware believed to be vulnerable. + ++If Xen is compiled with `CONFIG_SPECULATIVE_HARDEN_LOCK`, the `lock-harden=` ++boolean can be used to force or prevent Xen from using speculation barriers to ++protect lock critical regions. This mitigation won't be engaged by default, ++and needs to be explicitly enabled on the command line. ++ + ### sync_console + > `= ` + +diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h +index c3aad21c3b43..7e8221fd85dd 100644 +--- a/xen/arch/x86/include/asm/cpufeatures.h ++++ b/xen/arch/x86/include/asm/cpufeatures.h +@@ -24,7 +24,7 @@ XEN_CPUFEATURE(APERFMPERF, X86_SYNTH( 8)) /* APERFMPERF */ + XEN_CPUFEATURE(MFENCE_RDTSC, X86_SYNTH( 9)) /* MFENCE synchronizes RDTSC */ + XEN_CPUFEATURE(XEN_SMEP, X86_SYNTH(10)) /* SMEP gets used by Xen itself */ + XEN_CPUFEATURE(XEN_SMAP, X86_SYNTH(11)) /* SMAP gets used by Xen itself */ +-/* Bit 12 unused. */ ++XEN_CPUFEATURE(SC_NO_LOCK_HARDEN, X86_SYNTH(12)) /* (Disable) Lock critical region hardening */ + XEN_CPUFEATURE(IND_THUNK_LFENCE, X86_SYNTH(13)) /* Use IND_THUNK_LFENCE */ + XEN_CPUFEATURE(IND_THUNK_JMP, X86_SYNTH(14)) /* Use IND_THUNK_JMP */ + XEN_CPUFEATURE(SC_NO_BRANCH_HARDEN, X86_SYNTH(15)) /* (Disable) Conditional branch hardening */ +diff --git a/xen/arch/x86/include/asm/nospec.h b/xen/arch/x86/include/asm/nospec.h +index 7150e76b87fb..0725839e1982 100644 +--- a/xen/arch/x86/include/asm/nospec.h ++++ b/xen/arch/x86/include/asm/nospec.h +@@ -38,6 +38,32 @@ static always_inline void block_speculation(void) + barrier_nospec_true(); + } + ++static always_inline void arch_block_lock_speculation(void) ++{ ++ alternative("lfence", "", X86_FEATURE_SC_NO_LOCK_HARDEN); ++} ++ ++/* Allow to insert a read memory barrier into conditionals */ ++static always_inline bool barrier_lock_true(void) ++{ ++ alternative("lfence #nospec-true", "", X86_FEATURE_SC_NO_LOCK_HARDEN); ++ return true; ++} ++ ++static always_inline bool barrier_lock_false(void) ++{ ++ alternative("lfence #nospec-false", "", X86_FEATURE_SC_NO_LOCK_HARDEN); ++ return false; ++} ++ ++static always_inline bool arch_lock_evaluate_nospec(bool condition) ++{ ++ if ( condition ) ++ return barrier_lock_true(); ++ else ++ return barrier_lock_false(); ++} ++ + #endif /* _ASM_X86_NOSPEC_H */ + + /* +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 8165379fed94..5dfc4ed69ec5 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -53,6 +53,7 @@ int8_t __read_mostly opt_eager_fpu = -1; + int8_t __read_mostly opt_l1d_flush = -1; + static bool __initdata opt_branch_harden = + IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH); ++static bool __initdata opt_lock_harden; + + bool __initdata bsp_delay_spec_ctrl; + uint8_t __read_mostly default_xen_spec_ctrl; +@@ -121,6 +122,7 @@ static int __init cf_check parse_spec_ctrl(const char *s) + opt_ssbd = false; + opt_l1d_flush = 0; + opt_branch_harden = false; ++ opt_lock_harden = false; + opt_srb_lock = 0; + opt_unpriv_mmio = false; + opt_gds_mit = 0; +@@ -286,6 +288,16 @@ static int __init cf_check parse_spec_ctrl(const char *s) + rc = -EINVAL; + } + } ++ else if ( (val = parse_boolean("lock-harden", s, ss)) >= 0 ) ++ { ++ if ( IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_LOCK) ) ++ opt_lock_harden = val; ++ else ++ { ++ no_config_param("SPECULATIVE_HARDEN_LOCK", "spec-ctrl", s, ss); ++ rc = -EINVAL; ++ } ++ } + else if ( (val = parse_boolean("srb-lock", s, ss)) >= 0 ) + opt_srb_lock = val; + else if ( (val = parse_boolean("unpriv-mmio", s, ss)) >= 0 ) +@@ -488,7 +500,8 @@ static void __init print_details(enum ind_thunk thunk) + if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) || + IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_ARRAY) || + IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH) || +- IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS) ) ++ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS) || ++ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_LOCK) ) + printk(" Compiled-in support:" + #ifdef CONFIG_INDIRECT_THUNK + " INDIRECT_THUNK" +@@ -504,11 +517,14 @@ static void __init print_details(enum ind_thunk thunk) + #endif + #ifdef CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS + " HARDEN_GUEST_ACCESS" ++#endif ++#ifdef CONFIG_SPECULATIVE_HARDEN_LOCK ++ " HARDEN_LOCK" + #endif + "\n"); + + /* Settings for Xen's protection, irrespective of guests. */ +- printk(" Xen settings: %s%sSPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", ++ printk(" Xen settings: %s%sSPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s%s\n", + thunk != THUNK_NONE ? "BTI-Thunk: " : "", + thunk == THUNK_NONE ? "" : + thunk == THUNK_RETPOLINE ? "RETPOLINE, " : +@@ -535,7 +551,8 @@ static void __init print_details(enum ind_thunk thunk) + opt_verw_pv || opt_verw_hvm || + opt_verw_mmio ? " VERW" : "", + opt_div_scrub ? " DIV" : "", +- opt_branch_harden ? " BRANCH_HARDEN" : ""); ++ opt_branch_harden ? " BRANCH_HARDEN" : "", ++ opt_lock_harden ? " LOCK_HARDEN" : ""); + + /* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */ + if ( cpu_has_bug_l1tf || opt_pv_l1tf_hwdom || opt_pv_l1tf_domu ) +@@ -1918,6 +1935,9 @@ void __init init_speculation_mitigations(void) + if ( !opt_branch_harden ) + setup_force_cpu_cap(X86_FEATURE_SC_NO_BRANCH_HARDEN); + ++ if ( !opt_lock_harden ) ++ setup_force_cpu_cap(X86_FEATURE_SC_NO_LOCK_HARDEN); ++ + /* + * We do not disable HT by default on affected hardware. + * +diff --git a/xen/common/Kconfig b/xen/common/Kconfig +index 4d6fe051641d..3361a6d89257 100644 +--- a/xen/common/Kconfig ++++ b/xen/common/Kconfig +@@ -188,6 +188,23 @@ config SPECULATIVE_HARDEN_GUEST_ACCESS + + If unsure, say Y. + ++config SPECULATIVE_HARDEN_LOCK ++ bool "Speculative lock context hardening" ++ default y ++ depends on X86 ++ help ++ Contemporary processors may use speculative execution as a ++ performance optimisation, but this can potentially be abused by an ++ attacker to leak data via speculative sidechannels. ++ ++ One source of data leakage is via speculative accesses to lock ++ critical regions. ++ ++ This option is disabled by default at run time, and needs to be ++ enabled on the command line. ++ ++ If unsure, say Y. ++ + endmenu + + config DIT_DEFAULT +diff --git a/xen/include/xen/nospec.h b/xen/include/xen/nospec.h +index 76255bc46efe..455284640396 100644 +--- a/xen/include/xen/nospec.h ++++ b/xen/include/xen/nospec.h +@@ -70,6 +70,21 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, + #define array_access_nospec(array, index) \ + (array)[array_index_nospec(index, ARRAY_SIZE(array))] + ++static always_inline void block_lock_speculation(void) ++{ ++#ifdef CONFIG_SPECULATIVE_HARDEN_LOCK ++ arch_block_lock_speculation(); ++#endif ++} ++ ++static always_inline bool lock_evaluate_nospec(bool condition) ++{ ++#ifdef CONFIG_SPECULATIVE_HARDEN_LOCK ++ return arch_lock_evaluate_nospec(condition); ++#endif ++ return condition; ++} ++ + #endif /* XEN_NOSPEC_H */ + + /* +diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h +index e7a1c1aa8988..28fce5615e5c 100644 +--- a/xen/include/xen/spinlock.h ++++ b/xen/include/xen/spinlock.h +@@ -1,6 +1,7 @@ + #ifndef __SPINLOCK_H__ + #define __SPINLOCK_H__ + ++#include + #include + #include + +@@ -195,13 +196,30 @@ int _spin_trylock_recursive(spinlock_t *lock); + void _spin_lock_recursive(spinlock_t *lock); + void _spin_unlock_recursive(spinlock_t *lock); + +-#define spin_lock(l) _spin_lock(l) +-#define spin_lock_cb(l, c, d) _spin_lock_cb(l, c, d) +-#define spin_lock_irq(l) _spin_lock_irq(l) ++static always_inline void spin_lock(spinlock_t *l) ++{ ++ _spin_lock(l); ++ block_lock_speculation(); ++} ++ ++static always_inline void spin_lock_cb(spinlock_t *l, void (*c)(void *data), ++ void *d) ++{ ++ _spin_lock_cb(l, c, d); ++ block_lock_speculation(); ++} ++ ++static always_inline void spin_lock_irq(spinlock_t *l) ++{ ++ _spin_lock_irq(l); ++ block_lock_speculation(); ++} ++ + #define spin_lock_irqsave(l, f) \ + ({ \ + BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \ + ((f) = _spin_lock_irqsave(l)); \ ++ block_lock_speculation(); \ + }) + + #define spin_unlock(l) _spin_unlock(l) +@@ -209,7 +227,7 @@ void _spin_unlock_recursive(spinlock_t *lock); + #define spin_unlock_irqrestore(l, f) _spin_unlock_irqrestore(l, f) + + #define spin_is_locked(l) _spin_is_locked(l) +-#define spin_trylock(l) _spin_trylock(l) ++#define spin_trylock(l) lock_evaluate_nospec(_spin_trylock(l)) + + #define spin_trylock_irqsave(lock, flags) \ + ({ \ +@@ -230,8 +248,15 @@ void _spin_unlock_recursive(spinlock_t *lock); + * are any critical regions that cannot form part of such a set, they can use + * standard spin_[un]lock(). + */ +-#define spin_trylock_recursive(l) _spin_trylock_recursive(l) +-#define spin_lock_recursive(l) _spin_lock_recursive(l) ++#define spin_trylock_recursive(l) \ ++ lock_evaluate_nospec(_spin_trylock_recursive(l)) ++ ++static always_inline void spin_lock_recursive(spinlock_t *l) ++{ ++ _spin_lock_recursive(l); ++ block_lock_speculation(); ++} ++ + #define spin_unlock_recursive(l) _spin_unlock_recursive(l) + + #endif /* __SPINLOCK_H__ */ diff --git a/xsa453-4.18-3.patch b/xsa453-4.18-3.patch new file mode 100644 index 0000000..ecaff41 --- /dev/null +++ b/xsa453-4.18-3.patch @@ -0,0 +1,113 @@ +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Subject: rwlock: introduce support for blocking speculation into critical + regions + +Introduce inline wrappers as required and add direct calls to +block_lock_speculation() in order to prevent speculation into the rwlock +protected critical regions. + +Note the rwlock primitives are adjusted to use the non speculation safe variants +of the spinlock handlers, as a speculation barrier is added in the rwlock +calling wrappers. + +trylock variants are protected by using lock_evaluate_nospec(). + +This is part of XSA-453 / CVE-2024-2193 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +(cherry picked from commit a1fb15f61692b1fa9945fc51f55471ace49cdd59) + +diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c +index 18224a4bb5d6..290602936df6 100644 +--- a/xen/common/rwlock.c ++++ b/xen/common/rwlock.c +@@ -34,8 +34,11 @@ void queue_read_lock_slowpath(rwlock_t *lock) + + /* + * Put the reader into the wait queue. ++ * ++ * Use the speculation unsafe helper, as it's the caller responsibility to ++ * issue a speculation barrier if required. + */ +- spin_lock(&lock->lock); ++ _spin_lock(&lock->lock); + + /* + * At the head of the wait queue now, wait until the writer state +@@ -66,8 +69,13 @@ void queue_write_lock_slowpath(rwlock_t *lock) + { + u32 cnts; + +- /* Put the writer into the wait queue. */ +- spin_lock(&lock->lock); ++ /* ++ * Put the writer into the wait queue. ++ * ++ * Use the speculation unsafe helper, as it's the caller responsibility to ++ * issue a speculation barrier if required. ++ */ ++ _spin_lock(&lock->lock); + + /* Try to acquire the lock directly if no reader is present. */ + if ( !atomic_read(&lock->cnts) && +diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h +index e0d2b41c5c7e..9a0d3ec23847 100644 +--- a/xen/include/xen/rwlock.h ++++ b/xen/include/xen/rwlock.h +@@ -259,27 +259,49 @@ static inline int _rw_is_write_locked(const rwlock_t *lock) + return (atomic_read(&lock->cnts) & _QW_WMASK) == _QW_LOCKED; + } + +-#define read_lock(l) _read_lock(l) +-#define read_lock_irq(l) _read_lock_irq(l) ++static always_inline void read_lock(rwlock_t *l) ++{ ++ _read_lock(l); ++ block_lock_speculation(); ++} ++ ++static always_inline void read_lock_irq(rwlock_t *l) ++{ ++ _read_lock_irq(l); ++ block_lock_speculation(); ++} ++ + #define read_lock_irqsave(l, f) \ + ({ \ + BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \ + ((f) = _read_lock_irqsave(l)); \ ++ block_lock_speculation(); \ + }) + + #define read_unlock(l) _read_unlock(l) + #define read_unlock_irq(l) _read_unlock_irq(l) + #define read_unlock_irqrestore(l, f) _read_unlock_irqrestore(l, f) +-#define read_trylock(l) _read_trylock(l) ++#define read_trylock(l) lock_evaluate_nospec(_read_trylock(l)) ++ ++static always_inline void write_lock(rwlock_t *l) ++{ ++ _write_lock(l); ++ block_lock_speculation(); ++} ++ ++static always_inline void write_lock_irq(rwlock_t *l) ++{ ++ _write_lock_irq(l); ++ block_lock_speculation(); ++} + +-#define write_lock(l) _write_lock(l) +-#define write_lock_irq(l) _write_lock_irq(l) + #define write_lock_irqsave(l, f) \ + ({ \ + BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \ + ((f) = _write_lock_irqsave(l)); \ ++ block_lock_speculation(); \ + }) +-#define write_trylock(l) _write_trylock(l) ++#define write_trylock(l) lock_evaluate_nospec(_write_trylock(l)) + + #define write_unlock(l) _write_unlock(l) + #define write_unlock_irq(l) _write_unlock_irq(l) diff --git a/xsa453-4.18-4.patch b/xsa453-4.18-4.patch new file mode 100644 index 0000000..a3c6b3c --- /dev/null +++ b/xsa453-4.18-4.patch @@ -0,0 +1,75 @@ +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Subject: percpu-rwlock: introduce support for blocking speculation into + critical regions + +Add direct calls to block_lock_speculation() where required in order to prevent +speculation into the lock protected critical regions. Also convert +_percpu_read_lock() from inline to always_inline. + +Note that _percpu_write_lock() has been modified the use the non speculation +safe of the locking primites, as a speculation is added unconditionally by the +calling wrapper. + +This is part of XSA-453 / CVE-2024-2193 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +(cherry picked from commit f218daf6d3a3b847736d37c6a6b76031a0d08441) + +diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c +index 290602936df6..f5a249bcc240 100644 +--- a/xen/common/rwlock.c ++++ b/xen/common/rwlock.c +@@ -129,8 +129,12 @@ void _percpu_write_lock(percpu_rwlock_t **per_cpudata, + /* + * First take the write lock to protect against other writers or slow + * path readers. ++ * ++ * Note we use the speculation unsafe variant of write_lock(), as the ++ * calling wrapper already adds a speculation barrier after the lock has ++ * been taken. + */ +- write_lock(&percpu_rwlock->rwlock); ++ _write_lock(&percpu_rwlock->rwlock); + + /* Now set the global variable so that readers start using read_lock. */ + percpu_rwlock->writer_activating = 1; +diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h +index 9a0d3ec23847..9e35ee2edf8f 100644 +--- a/xen/include/xen/rwlock.h ++++ b/xen/include/xen/rwlock.h +@@ -338,8 +338,8 @@ static inline void _percpu_rwlock_owner_check(percpu_rwlock_t **per_cpudata, + #define percpu_rwlock_resource_init(l, owner) \ + (*(l) = (percpu_rwlock_t)PERCPU_RW_LOCK_UNLOCKED(&get_per_cpu_var(owner))) + +-static inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata, +- percpu_rwlock_t *percpu_rwlock) ++static always_inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata, ++ percpu_rwlock_t *percpu_rwlock) + { + /* Validate the correct per_cpudata variable has been provided. */ + _percpu_rwlock_owner_check(per_cpudata, percpu_rwlock); +@@ -374,6 +374,8 @@ static inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata, + } + else + { ++ /* Other branch already has a speculation barrier in read_lock(). */ ++ block_lock_speculation(); + /* All other paths have implicit check_lock() calls via read_lock(). */ + check_lock(&percpu_rwlock->rwlock.lock.debug, false); + } +@@ -430,8 +432,12 @@ static inline void _percpu_write_unlock(percpu_rwlock_t **per_cpudata, + _percpu_read_lock(&get_per_cpu_var(percpu), lock) + #define percpu_read_unlock(percpu, lock) \ + _percpu_read_unlock(&get_per_cpu_var(percpu), lock) +-#define percpu_write_lock(percpu, lock) \ +- _percpu_write_lock(&get_per_cpu_var(percpu), lock) ++ ++#define percpu_write_lock(percpu, lock) \ ++({ \ ++ _percpu_write_lock(&get_per_cpu_var(percpu), lock); \ ++ block_lock_speculation(); \ ++}) + #define percpu_write_unlock(percpu, lock) \ + _percpu_write_unlock(&get_per_cpu_var(percpu), lock) + diff --git a/xsa453-4.18-5.patch b/xsa453-4.18-5.patch new file mode 100644 index 0000000..aab46e3 --- /dev/null +++ b/xsa453-4.18-5.patch @@ -0,0 +1,382 @@ +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Subject: locking: attempt to ensure lock wrappers are always inline + +In order to prevent the locking speculation barriers from being inside of +`call`ed functions that could be speculatively bypassed. + +While there also add an extra locking barrier to _mm_write_lock() in the branch +taken when the lock is already held. + +Note some functions are switched to use the unsafe variants (without speculation +barrier) of the locking primitives, but a speculation barrier is always added +to the exposed public lock wrapping helper. That's the case with +sched_spin_lock_double() or pcidevs_lock() for example. + +This is part of XSA-453 / CVE-2024-2193 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +(cherry picked from commit 197ecd838a2aaf959a469df3696d4559c4f8b762) + +diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c +index 8f53e88d6706..e1d6845a2844 100644 +--- a/xen/arch/x86/hvm/vpt.c ++++ b/xen/arch/x86/hvm/vpt.c +@@ -150,7 +150,7 @@ static int pt_irq_masked(struct periodic_time *pt) + * pt->vcpu field, because another thread holding the pt_migrate lock + * may already be spinning waiting for your vcpu lock. + */ +-static void pt_vcpu_lock(struct vcpu *v) ++static always_inline void pt_vcpu_lock(struct vcpu *v) + { + spin_lock(&v->arch.hvm.tm_lock); + } +@@ -169,9 +169,13 @@ static void pt_vcpu_unlock(struct vcpu *v) + * need to take an additional lock that protects against pt->vcpu + * changing. + */ +-static void pt_lock(struct periodic_time *pt) ++static always_inline void pt_lock(struct periodic_time *pt) + { +- read_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate); ++ /* ++ * Use the speculation unsafe variant for the first lock, as the following ++ * lock taking helper already includes a speculation barrier. ++ */ ++ _read_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate); + spin_lock(&pt->vcpu->arch.hvm.tm_lock); + } + +diff --git a/xen/arch/x86/include/asm/irq.h b/xen/arch/x86/include/asm/irq.h +index a87af47ece22..465ab39bb041 100644 +--- a/xen/arch/x86/include/asm/irq.h ++++ b/xen/arch/x86/include/asm/irq.h +@@ -174,6 +174,7 @@ void cf_check irq_complete_move(struct irq_desc *desc); + + extern struct irq_desc *irq_desc; + ++/* Not speculation safe, only used for AP bringup. */ + void lock_vector_lock(void); + void unlock_vector_lock(void); + +diff --git a/xen/arch/x86/mm/mm-locks.h b/xen/arch/x86/mm/mm-locks.h +index 5a3f96fbaadd..5ec080c02fd8 100644 +--- a/xen/arch/x86/mm/mm-locks.h ++++ b/xen/arch/x86/mm/mm-locks.h +@@ -74,8 +74,8 @@ static inline void _set_lock_level(int l) + this_cpu(mm_lock_level) = l; + } + +-static inline void _mm_lock(const struct domain *d, mm_lock_t *l, +- const char *func, int level, int rec) ++static always_inline void _mm_lock(const struct domain *d, mm_lock_t *l, ++ const char *func, int level, int rec) + { + if ( !((mm_locked_by_me(l)) && rec) ) + _check_lock_level(d, level); +@@ -125,8 +125,8 @@ static inline int mm_write_locked_by_me(mm_rwlock_t *l) + return (l->locker == get_processor_id()); + } + +-static inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l, +- const char *func, int level) ++static always_inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l, ++ const char *func, int level) + { + if ( !mm_write_locked_by_me(l) ) + { +@@ -137,6 +137,8 @@ static inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l, + l->unlock_level = _get_lock_level(); + _set_lock_level(_lock_level(d, level)); + } ++ else ++ block_speculation(); + l->recurse_count++; + } + +@@ -150,8 +152,8 @@ static inline void mm_write_unlock(mm_rwlock_t *l) + percpu_write_unlock(p2m_percpu_rwlock, &l->lock); + } + +-static inline void _mm_read_lock(const struct domain *d, mm_rwlock_t *l, +- int level) ++static always_inline void _mm_read_lock(const struct domain *d, mm_rwlock_t *l, ++ int level) + { + _check_lock_level(d, level); + percpu_read_lock(p2m_percpu_rwlock, &l->lock); +@@ -166,15 +168,15 @@ static inline void mm_read_unlock(mm_rwlock_t *l) + + /* This wrapper uses the line number to express the locking order below */ + #define declare_mm_lock(name) \ +- static inline void mm_lock_##name(const struct domain *d, mm_lock_t *l, \ +- const char *func, int rec) \ ++ static always_inline void mm_lock_##name( \ ++ const struct domain *d, mm_lock_t *l, const char *func, int rec) \ + { _mm_lock(d, l, func, MM_LOCK_ORDER_##name, rec); } + #define declare_mm_rwlock(name) \ +- static inline void mm_write_lock_##name(const struct domain *d, \ +- mm_rwlock_t *l, const char *func) \ ++ static always_inline void mm_write_lock_##name( \ ++ const struct domain *d, mm_rwlock_t *l, const char *func) \ + { _mm_write_lock(d, l, func, MM_LOCK_ORDER_##name); } \ +- static inline void mm_read_lock_##name(const struct domain *d, \ +- mm_rwlock_t *l) \ ++ static always_inline void mm_read_lock_##name(const struct domain *d, \ ++ mm_rwlock_t *l) \ + { _mm_read_lock(d, l, MM_LOCK_ORDER_##name); } + /* These capture the name of the calling function */ + #define mm_lock(name, d, l) mm_lock_##name(d, l, __func__, 0) +@@ -309,7 +311,7 @@ declare_mm_lock(altp2mlist) + #define MM_LOCK_ORDER_altp2m 40 + declare_mm_rwlock(altp2m); + +-static inline void p2m_lock(struct p2m_domain *p) ++static always_inline void p2m_lock(struct p2m_domain *p) + { + if ( p2m_is_altp2m(p) ) + mm_write_lock(altp2m, p->domain, &p->lock); +diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c +index 9969eb45fa8c..9be67b63ce3e 100644 +--- a/xen/arch/x86/mm/p2m-pod.c ++++ b/xen/arch/x86/mm/p2m-pod.c +@@ -24,7 +24,7 @@ + #define superpage_aligned(_x) (((_x)&(SUPERPAGE_PAGES-1))==0) + + /* Enforce lock ordering when grabbing the "external" page_alloc lock */ +-static inline void lock_page_alloc(struct p2m_domain *p2m) ++static always_inline void lock_page_alloc(struct p2m_domain *p2m) + { + page_alloc_mm_pre_lock(p2m->domain); + spin_lock(&(p2m->domain->page_alloc_lock)); +diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c +index a7a004a08429..66f924a7b091 100644 +--- a/xen/common/event_channel.c ++++ b/xen/common/event_channel.c +@@ -45,7 +45,7 @@ + * just assume the event channel is free or unbound at the moment when the + * evtchn_read_trylock() returns false. + */ +-static inline void evtchn_write_lock(struct evtchn *evtchn) ++static always_inline void evtchn_write_lock(struct evtchn *evtchn) + { + write_lock(&evtchn->lock); + +@@ -351,7 +351,8 @@ int evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc, evtchn_port_t port) + return rc; + } + +-static void double_evtchn_lock(struct evtchn *lchn, struct evtchn *rchn) ++static always_inline void double_evtchn_lock(struct evtchn *lchn, ++ struct evtchn *rchn) + { + ASSERT(lchn != rchn); + +diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c +index 89b7811c51c3..934924cbda66 100644 +--- a/xen/common/grant_table.c ++++ b/xen/common/grant_table.c +@@ -403,7 +403,7 @@ static inline void act_set_gfn(struct active_grant_entry *act, gfn_t gfn) + + static DEFINE_PERCPU_RWLOCK_GLOBAL(grant_rwlock); + +-static inline void grant_read_lock(struct grant_table *gt) ++static always_inline void grant_read_lock(struct grant_table *gt) + { + percpu_read_lock(grant_rwlock, >->lock); + } +@@ -413,7 +413,7 @@ static inline void grant_read_unlock(struct grant_table *gt) + percpu_read_unlock(grant_rwlock, >->lock); + } + +-static inline void grant_write_lock(struct grant_table *gt) ++static always_inline void grant_write_lock(struct grant_table *gt) + { + percpu_write_lock(grant_rwlock, >->lock); + } +@@ -450,7 +450,7 @@ nr_active_grant_frames(struct grant_table *gt) + return num_act_frames_from_sha_frames(nr_grant_frames(gt)); + } + +-static inline struct active_grant_entry * ++static always_inline struct active_grant_entry * + active_entry_acquire(struct grant_table *t, grant_ref_t e) + { + struct active_grant_entry *act; +diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c +index 901782bbb416..34ad39b9ad0b 100644 +--- a/xen/common/sched/core.c ++++ b/xen/common/sched/core.c +@@ -348,23 +348,28 @@ uint64_t get_cpu_idle_time(unsigned int cpu) + * This avoids dead- or live-locks when this code is running on both + * cpus at the same time. + */ +-static void sched_spin_lock_double(spinlock_t *lock1, spinlock_t *lock2, +- unsigned long *flags) ++static always_inline void sched_spin_lock_double( ++ spinlock_t *lock1, spinlock_t *lock2, unsigned long *flags) + { ++ /* ++ * In order to avoid extra overhead, use the locking primitives without the ++ * speculation barrier, and introduce a single barrier here. ++ */ + if ( lock1 == lock2 ) + { +- spin_lock_irqsave(lock1, *flags); ++ *flags = _spin_lock_irqsave(lock1); + } + else if ( lock1 < lock2 ) + { +- spin_lock_irqsave(lock1, *flags); +- spin_lock(lock2); ++ *flags = _spin_lock_irqsave(lock1); ++ _spin_lock(lock2); + } + else + { +- spin_lock_irqsave(lock2, *flags); +- spin_lock(lock1); ++ *flags = _spin_lock_irqsave(lock2); ++ _spin_lock(lock1); + } ++ block_lock_speculation(); + } + + static void sched_spin_unlock_double(spinlock_t *lock1, spinlock_t *lock2, +diff --git a/xen/common/sched/private.h b/xen/common/sched/private.h +index c516976c3740..3b97f1576782 100644 +--- a/xen/common/sched/private.h ++++ b/xen/common/sched/private.h +@@ -207,8 +207,24 @@ DECLARE_PER_CPU(cpumask_t, cpumask_scratch); + #define cpumask_scratch (&this_cpu(cpumask_scratch)) + #define cpumask_scratch_cpu(c) (&per_cpu(cpumask_scratch, c)) + ++/* ++ * Deal with _spin_lock_irqsave() returning the flags value instead of storing ++ * it in a passed parameter. ++ */ ++#define _sched_spinlock0(lock, irq) _spin_lock##irq(lock) ++#define _sched_spinlock1(lock, irq, arg) ({ \ ++ BUILD_BUG_ON(sizeof(arg) != sizeof(unsigned long)); \ ++ (arg) = _spin_lock##irq(lock); \ ++}) ++ ++#define _sched_spinlock__(nr) _sched_spinlock ## nr ++#define _sched_spinlock_(nr) _sched_spinlock__(nr) ++#define _sched_spinlock(lock, irq, args...) \ ++ _sched_spinlock_(count_args(args))(lock, irq, ## args) ++ + #define sched_lock(kind, param, cpu, irq, arg...) \ +-static inline spinlock_t *kind##_schedule_lock##irq(param EXTRA_TYPE(arg)) \ ++static always_inline spinlock_t \ ++*kind##_schedule_lock##irq(param EXTRA_TYPE(arg)) \ + { \ + for ( ; ; ) \ + { \ +@@ -220,10 +236,16 @@ static inline spinlock_t *kind##_schedule_lock##irq(param EXTRA_TYPE(arg)) \ + * \ + * It may also be the case that v->processor may change but the \ + * lock may be the same; this will succeed in that case. \ ++ * \ ++ * Use the speculation unsafe locking helper, there's a speculation \ ++ * barrier before returning to the caller. \ + */ \ +- spin_lock##irq(lock, ## arg); \ ++ _sched_spinlock(lock, irq, ## arg); \ + if ( likely(lock == get_sched_res(cpu)->schedule_lock) ) \ ++ { \ ++ block_lock_speculation(); \ + return lock; \ ++ } \ + spin_unlock##irq(lock, ## arg); \ + } \ + } +diff --git a/xen/common/timer.c b/xen/common/timer.c +index 0fddfa74879e..38eb5fd20d36 100644 +--- a/xen/common/timer.c ++++ b/xen/common/timer.c +@@ -239,7 +239,7 @@ static inline void deactivate_timer(struct timer *timer) + list_add(&timer->inactive, &per_cpu(timers, timer->cpu).inactive); + } + +-static inline bool_t timer_lock(struct timer *timer) ++static inline bool_t timer_lock_unsafe(struct timer *timer) + { + unsigned int cpu; + +@@ -253,7 +253,8 @@ static inline bool_t timer_lock(struct timer *timer) + rcu_read_unlock(&timer_cpu_read_lock); + return 0; + } +- spin_lock(&per_cpu(timers, cpu).lock); ++ /* Use the speculation unsafe variant, the wrapper has the barrier. */ ++ _spin_lock(&per_cpu(timers, cpu).lock); + if ( likely(timer->cpu == cpu) ) + break; + spin_unlock(&per_cpu(timers, cpu).lock); +@@ -266,8 +267,9 @@ static inline bool_t timer_lock(struct timer *timer) + #define timer_lock_irqsave(t, flags) ({ \ + bool_t __x; \ + local_irq_save(flags); \ +- if ( !(__x = timer_lock(t)) ) \ ++ if ( !(__x = timer_lock_unsafe(t)) ) \ + local_irq_restore(flags); \ ++ block_lock_speculation(); \ + __x; \ + }) + +diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c +index e99837b6e141..2a1e7ee89a5d 100644 +--- a/xen/drivers/passthrough/pci.c ++++ b/xen/drivers/passthrough/pci.c +@@ -52,9 +52,10 @@ struct pci_seg { + + static spinlock_t _pcidevs_lock = SPIN_LOCK_UNLOCKED; + +-void pcidevs_lock(void) ++/* Do not use, as it has no speculation barrier, use pcidevs_lock() instead. */ ++void pcidevs_lock_unsafe(void) + { +- spin_lock_recursive(&_pcidevs_lock); ++ _spin_lock_recursive(&_pcidevs_lock); + } + + void pcidevs_unlock(void) +diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h +index 8e509e078475..f1472ea1ebe5 100644 +--- a/xen/include/xen/event.h ++++ b/xen/include/xen/event.h +@@ -114,12 +114,12 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); + #define bucket_from_port(d, p) \ + ((group_from_port(d, p))[((p) % EVTCHNS_PER_GROUP) / EVTCHNS_PER_BUCKET]) + +-static inline void evtchn_read_lock(struct evtchn *evtchn) ++static always_inline void evtchn_read_lock(struct evtchn *evtchn) + { + read_lock(&evtchn->lock); + } + +-static inline bool evtchn_read_trylock(struct evtchn *evtchn) ++static always_inline bool evtchn_read_trylock(struct evtchn *evtchn) + { + return read_trylock(&evtchn->lock); + } +diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h +index 251b8761a8e9..a71bed36be29 100644 +--- a/xen/include/xen/pci.h ++++ b/xen/include/xen/pci.h +@@ -155,8 +155,12 @@ struct pci_dev { + * devices, it also sync the access to the msi capability that is not + * interrupt handling related (the mask bit register). + */ +- +-void pcidevs_lock(void); ++void pcidevs_lock_unsafe(void); ++static always_inline void pcidevs_lock(void) ++{ ++ pcidevs_lock_unsafe(); ++ block_lock_speculation(); ++} + void pcidevs_unlock(void); + bool __must_check pcidevs_locked(void); + diff --git a/xsa453-4.18-6.patch b/xsa453-4.18-6.patch new file mode 100644 index 0000000..e8104c5 --- /dev/null +++ b/xsa453-4.18-6.patch @@ -0,0 +1,61 @@ +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Subject: x86/mm: add speculation barriers to open coded locks + +Add a speculation barrier to the clearly identified open-coded lock taking +functions. + +Note that the memory sharing page_lock() replacement (_page_lock()) is left +as-is, as the code is experimental and not security supported. + +This is part of XSA-453 / CVE-2024-2193 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +(cherry picked from commit 42a572a38e22a97d86a4b648a22597628d5b42e4) + +diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h +index 05dfe35502c8..d1b1fee99b7d 100644 +--- a/xen/arch/x86/include/asm/mm.h ++++ b/xen/arch/x86/include/asm/mm.h +@@ -399,7 +399,9 @@ const struct platform_bad_page *get_platform_badpages(unsigned int *array_size); + * The use of PGT_locked in mem_sharing does not collide, since mem_sharing is + * only supported for hvm guests, which do not have PV PTEs updated. + */ +-int page_lock(struct page_info *page); ++int page_lock_unsafe(struct page_info *page); ++#define page_lock(pg) lock_evaluate_nospec(page_lock_unsafe(pg)) ++ + void page_unlock(struct page_info *page); + + void put_page_type(struct page_info *page); +diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c +index ab0acbfea6e5..000fd0fb558b 100644 +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -2017,7 +2017,7 @@ static inline bool current_locked_page_ne_check(struct page_info *page) { + #define current_locked_page_ne_check(x) true + #endif + +-int page_lock(struct page_info *page) ++int page_lock_unsafe(struct page_info *page) + { + unsigned long x, nx; + +@@ -2078,7 +2078,7 @@ void page_unlock(struct page_info *page) + * l3t_lock(), so to avoid deadlock we must avoid grabbing them in + * reverse order. + */ +-static void l3t_lock(struct page_info *page) ++static always_inline void l3t_lock(struct page_info *page) + { + unsigned long x, nx; + +@@ -2087,6 +2087,8 @@ static void l3t_lock(struct page_info *page) + cpu_relax(); + nx = x | PGT_locked; + } while ( cmpxchg(&page->u.inuse.type_info, x, nx) != x ); ++ ++ block_lock_speculation(); + } + + static void l3t_unlock(struct page_info *page) diff --git a/xsa453-4.18-7.patch b/xsa453-4.18-7.patch new file mode 100644 index 0000000..48f0bf9 --- /dev/null +++ b/xsa453-4.18-7.patch @@ -0,0 +1,201 @@ +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Subject: x86: protect conditional lock taking from speculative execution + +Conditionally taken locks that use the pattern: + +if ( lock ) + spin_lock(...); + +Need an else branch in order to issue an speculation barrier in the else case, +just like it's done in case the lock needs to be acquired. + +eval_nospec() could be used on the condition itself, but that would result in a +double barrier on the branch where the lock is taken. + +Introduce a new pair of helpers, {gfn,spin}_lock_if() that can be used to +conditionally take a lock in a speculation safe way. + +This is part of XSA-453 / CVE-2024-2193 + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +(cherry picked from commit 03cf7ca23e0e876075954c558485b267b7d02406) + +diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c +index 000fd0fb558b..45bfbc2522f7 100644 +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -5007,8 +5007,7 @@ static l3_pgentry_t *virt_to_xen_l3e(unsigned long v) + if ( !l3t ) + return NULL; + UNMAP_DOMAIN_PAGE(l3t); +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) ) + { + l4_pgentry_t l4e = l4e_from_mfn(l3mfn, __PAGE_HYPERVISOR); +@@ -5045,8 +5044,7 @@ static l2_pgentry_t *virt_to_xen_l2e(unsigned long v) + return NULL; + } + UNMAP_DOMAIN_PAGE(l2t); +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) + { + l3e_write(pl3e, l3e_from_mfn(l2mfn, __PAGE_HYPERVISOR)); +@@ -5084,8 +5082,7 @@ l1_pgentry_t *virt_to_xen_l1e(unsigned long v) + return NULL; + } + UNMAP_DOMAIN_PAGE(l1t); +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) + { + l2e_write(pl2e, l2e_from_mfn(l1mfn, __PAGE_HYPERVISOR)); +@@ -5116,6 +5113,8 @@ l1_pgentry_t *virt_to_xen_l1e(unsigned long v) + do { \ + if ( locking ) \ + l3t_lock(page); \ ++ else \ ++ block_lock_speculation(); \ + } while ( false ) + + #define L3T_UNLOCK(page) \ +@@ -5331,8 +5330,7 @@ int map_pages_to_xen( + if ( l3e_get_flags(ol3e) & _PAGE_GLOBAL ) + flush_flags |= FLUSH_TLB_GLOBAL; + +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) && + (l3e_get_flags(*pl3e) & _PAGE_PSE) ) + { +@@ -5436,8 +5434,7 @@ int map_pages_to_xen( + if ( l2e_get_flags(*pl2e) & _PAGE_GLOBAL ) + flush_flags |= FLUSH_TLB_GLOBAL; + +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( (l2e_get_flags(*pl2e) & _PAGE_PRESENT) && + (l2e_get_flags(*pl2e) & _PAGE_PSE) ) + { +@@ -5478,8 +5475,7 @@ int map_pages_to_xen( + unsigned long base_mfn; + const l1_pgentry_t *l1t; + +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + + ol2e = *pl2e; + /* +@@ -5533,8 +5529,7 @@ int map_pages_to_xen( + unsigned long base_mfn; + const l2_pgentry_t *l2t; + +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + + ol3e = *pl3e; + /* +@@ -5678,8 +5673,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) + l3e_get_flags(*pl3e))); + UNMAP_DOMAIN_PAGE(l2t); + +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) && + (l3e_get_flags(*pl3e) & _PAGE_PSE) ) + { +@@ -5738,8 +5732,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) + l2e_get_flags(*pl2e) & ~_PAGE_PSE)); + UNMAP_DOMAIN_PAGE(l1t); + +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + if ( (l2e_get_flags(*pl2e) & _PAGE_PRESENT) && + (l2e_get_flags(*pl2e) & _PAGE_PSE) ) + { +@@ -5783,8 +5776,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) + */ + if ( (nf & _PAGE_PRESENT) || ((v != e) && (l1_table_offset(v) != 0)) ) + continue; +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + + /* + * L2E may be already cleared, or set to a superpage, by +@@ -5831,8 +5823,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) + if ( (nf & _PAGE_PRESENT) || + ((v != e) && (l2_table_offset(v) + l1_table_offset(v) != 0)) ) + continue; +- if ( locking ) +- spin_lock(&map_pgdir_lock); ++ spin_lock_if(locking, &map_pgdir_lock); + + /* + * L3E may be already cleared, or set to a superpage, by +diff --git a/xen/arch/x86/mm/mm-locks.h b/xen/arch/x86/mm/mm-locks.h +index 5ec080c02fd8..b4960fb90eff 100644 +--- a/xen/arch/x86/mm/mm-locks.h ++++ b/xen/arch/x86/mm/mm-locks.h +@@ -335,6 +335,15 @@ static inline void p2m_unlock(struct p2m_domain *p) + #define p2m_locked_by_me(p) mm_write_locked_by_me(&(p)->lock) + #define gfn_locked_by_me(p,g) p2m_locked_by_me(p) + ++static always_inline void gfn_lock_if(bool condition, struct p2m_domain *p2m, ++ gfn_t gfn, unsigned int order) ++{ ++ if ( condition ) ++ gfn_lock(p2m, gfn, order); ++ else ++ block_lock_speculation(); ++} ++ + /* PoD lock (per-p2m-table) + * + * Protects private PoD data structs: entry and cache +diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c +index 0983bd71d9a9..22ab1d606e8a 100644 +--- a/xen/arch/x86/mm/p2m.c ++++ b/xen/arch/x86/mm/p2m.c +@@ -280,9 +280,8 @@ mfn_t p2m_get_gfn_type_access(struct p2m_domain *p2m, gfn_t gfn, + if ( q & P2M_UNSHARE ) + q |= P2M_ALLOC; + +- if ( locked ) +- /* Grab the lock here, don't release until put_gfn */ +- gfn_lock(p2m, gfn, 0); ++ /* Grab the lock here, don't release until put_gfn */ ++ gfn_lock_if(locked, p2m, gfn, 0); + + mfn = p2m->get_entry(p2m, gfn, t, a, q, page_order, NULL); + +diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h +index 28fce5615e5c..c830df3430a3 100644 +--- a/xen/include/xen/spinlock.h ++++ b/xen/include/xen/spinlock.h +@@ -222,6 +222,14 @@ static always_inline void spin_lock_irq(spinlock_t *l) + block_lock_speculation(); \ + }) + ++/* Conditionally take a spinlock in a speculation safe way. */ ++static always_inline void spin_lock_if(bool condition, spinlock_t *l) ++{ ++ if ( condition ) ++ _spin_lock(l); ++ block_lock_speculation(); ++} ++ + #define spin_unlock(l) _spin_unlock(l) + #define spin_unlock_irq(l) _spin_unlock_irq(l) + #define spin_unlock_irqrestore(l, f) _spin_unlock_irqrestore(l, f) From 81b1db8227e9e4377fab84deb03ed078c2b7f943 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 20 Mar 2024 19:12:09 +0000 Subject: [PATCH 48/99] update to xen-4.18.1 --- .gitignore | 2 +- sources | 2 +- xen.gcc12.fixes.patch | 2 +- ...28a2a742069af203e90c613c5c93e23c9755.patch | 47 --- ...0f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch | 55 --- ...07f7d51fe49df8bc70f83e49ce06c92e4e54.patch | 51 --- ...162cafd27f2865a3102a2ec0f386a02ed03d.patch | 99 ----- xen.spec | 53 +-- xsa447.patch | 117 ------ xsa449.patch | 89 ---- xsa450.patch | 59 --- xsa451-4.18.patch | 188 --------- xsa452-4.18-1.patch | 304 -------------- xsa452-4.18-2.patch | 90 ----- xsa452-4.18-3.patch | 135 ------- xsa452-4.18-4.patch | 197 --------- xsa452-4.18-5.patch | 239 ----------- xsa452-4.18-6.patch | 163 -------- xsa452-4.18-7.patch | 307 -------------- xsa453-4.18-1.patch | 50 --- xsa453-4.18-2.patch | 314 -------------- xsa453-4.18-3.patch | 113 ------ xsa453-4.18-4.patch | 75 ---- xsa453-4.18-5.patch | 382 ------------------ xsa453-4.18-6.patch | 61 --- xsa453-4.18-7.patch | 201 --------- 26 files changed, 10 insertions(+), 3385 deletions(-) delete mode 100644 xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch delete mode 100644 xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch delete mode 100644 xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch delete mode 100644 xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch delete mode 100644 xsa447.patch delete mode 100644 xsa449.patch delete mode 100644 xsa450.patch delete mode 100644 xsa451-4.18.patch delete mode 100644 xsa452-4.18-1.patch delete mode 100644 xsa452-4.18-2.patch delete mode 100644 xsa452-4.18-3.patch delete mode 100644 xsa452-4.18-4.patch delete mode 100644 xsa452-4.18-5.patch delete mode 100644 xsa452-4.18-6.patch delete mode 100644 xsa452-4.18-7.patch delete mode 100644 xsa453-4.18-1.patch delete mode 100644 xsa453-4.18-2.patch delete mode 100644 xsa453-4.18-3.patch delete mode 100644 xsa453-4.18-4.patch delete mode 100644 xsa453-4.18-5.patch delete mode 100644 xsa453-4.18-6.patch delete mode 100644 xsa453-4.18-7.patch diff --git a/.gitignore b/.gitignore index 7c63a9b..97a51c2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.18.0.tar.gz +/xen-4.18.1.tar.gz diff --git a/sources b/sources index 1aaa8a6..8d4dabc 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.18.0.tar.gz) = 4cc9fd155144045a173c5f8ecc45f149817f1034eec618cb6f8b0494ef2fb5b95c4c60cf0bf4bec4bef8a622c35b6a3cb7dedc38e6d95e726f1611c73ddb3273 +SHA512 (xen-4.18.1.tar.gz) = 6d67c177a31dae6979c111498f65cff2a7a792299cc72e658ae9f926468c14092807de94b6e269849fafdb6ed5a9d076400ecde0c4fec3b2b4bdb5f5ef39fcbb diff --git a/xen.gcc12.fixes.patch b/xen.gcc12.fixes.patch index 66d13b1..b35440f 100644 --- a/xen.gcc12.fixes.patch +++ b/xen.gcc12.fixes.patch @@ -1,7 +1,7 @@ --- xen-4.16.0/Config.mk.orig 2021-11-30 11:42:42.000000000 +0000 +++ xen-4.16.0/Config.mk 2022-01-24 20:25:16.687125822 +0000 @@ -186,6 +186,7 @@ - $(call cc-option-add,CFLAGS,CC,-Wdeclaration-after-statement) + $(call cc-option-add,CFLAGS,CC,-Wno-unused-but-set-variable) $(call cc-option-add,CFLAGS,CC,-Wno-unused-local-typedefs) +$(call cc-option-add,CFLAGS,CC,-Wno-error=array-bounds) diff --git a/xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch b/xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch deleted file mode 100644 index 20acd78..0000000 --- a/xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 576528a2a742069af203e90c613c5c93e23c9755 Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= -Date: Tue, 27 Feb 2024 14:58:40 +0100 -Subject: [PATCH] x86/spec: do not print thunk option selection if not built-in -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Since the thunk built-in enable is printed as part of the "Compiled-in -support:" line, avoid printing anything in "Xen settings:" if the thunk is -disabled at build time. - -Note the BTI-Thunk option printing is also adjusted to print a colon in the -same way the other options on the line do. - -Requested-by: Jan Beulich -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/spec_ctrl.c | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 74d2136d42..752225faa6 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -504,11 +504,12 @@ static void __init print_details(enum ind_thunk thunk) - "\n"); - - /* Settings for Xen's protection, irrespective of guests. */ -- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", -- thunk == THUNK_NONE ? "N/A" : -- thunk == THUNK_RETPOLINE ? "RETPOLINE" : -- thunk == THUNK_LFENCE ? "LFENCE" : -- thunk == THUNK_JMP ? "JMP" : "?", -+ printk(" Xen settings: %s%sSPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", -+ thunk != THUNK_NONE ? "BTI-Thunk: " : "", -+ thunk == THUNK_NONE ? "" : -+ thunk == THUNK_RETPOLINE ? "RETPOLINE, " : -+ thunk == THUNK_LFENCE ? "LFENCE, " : -+ thunk == THUNK_JMP ? "JMP, " : "?, ", - (!boot_cpu_has(X86_FEATURE_IBRSB) && - !boot_cpu_has(X86_FEATURE_IBRS)) ? "No" : - (default_xen_spec_ctrl & SPEC_CTRL_IBRS) ? "IBRS+" : "IBRS-", --- -2.30.2 - diff --git a/xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch b/xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch deleted file mode 100644 index a1b9f49..0000000 --- a/xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3 Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= -Date: Mon, 26 Feb 2024 16:06:42 +0100 -Subject: [PATCH] x86/spec: fix BRANCH_HARDEN option to only be set when - build-enabled -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -The current logic to handle the BRANCH_HARDEN option will report it as enabled -even when build-time disabled. Fix this by only allowing the option to be set -when support for it is built into Xen. - -Fixes: 2d6f36daa086 ('x86/nospec: Introduce CONFIG_SPECULATIVE_HARDEN_BRANCH') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/spec_ctrl.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 421fe3f640..503f1c7a37 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -50,7 +50,8 @@ static int8_t __initdata opt_psfd = -1; - int8_t __ro_after_init opt_ibpb_ctxt_switch = -1; - int8_t __read_mostly opt_eager_fpu = -1; - int8_t __read_mostly opt_l1d_flush = -1; --static bool __initdata opt_branch_harden = true; -+static bool __initdata opt_branch_harden = -+ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH); - - bool __initdata bsp_delay_spec_ctrl; - uint8_t __read_mostly default_xen_spec_ctrl; -@@ -268,7 +269,16 @@ static int __init cf_check parse_spec_ctrl(const char *s) - else if ( (val = parse_boolean("l1d-flush", s, ss)) >= 0 ) - opt_l1d_flush = val; - else if ( (val = parse_boolean("branch-harden", s, ss)) >= 0 ) -- opt_branch_harden = val; -+ { -+ if ( IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH) ) -+ opt_branch_harden = val; -+ else -+ { -+ no_config_param("SPECULATIVE_HARDEN_BRANCH", "spec-ctrl", s, -+ ss); -+ rc = -EINVAL; -+ } -+ } - else if ( (val = parse_boolean("srb-lock", s, ss)) >= 0 ) - opt_srb_lock = val; - else if ( (val = parse_boolean("unpriv-mmio", s, ss)) >= 0 ) --- -2.30.2 - diff --git a/xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch b/xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch deleted file mode 100644 index a78c792..0000000 --- a/xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 6e9507f7d51fe49df8bc70f83e49ce06c92e4e54 Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= -Date: Tue, 27 Feb 2024 14:57:52 +0100 -Subject: [PATCH] x86/spec: print the built-in SPECULATIVE_HARDEN_* options -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Just like it's done for INDIRECT_THUNK and SHADOW_PAGING. - -Reported-by: Jan Beulich -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/spec_ctrl.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 503f1c7a37..2d17cbe25f 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -476,13 +476,25 @@ static void __init print_details(enum ind_thunk thunk) - (e21a & cpufeat_mask(X86_FEATURE_SBPB)) ? " SBPB" : ""); - - /* Compiled-in support which pertains to mitigations. */ -- if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) ) -+ if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) || -+ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_ARRAY) || -+ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH) || -+ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS) ) - printk(" Compiled-in support:" - #ifdef CONFIG_INDIRECT_THUNK - " INDIRECT_THUNK" - #endif - #ifdef CONFIG_SHADOW_PAGING - " SHADOW_PAGING" -+#endif -+#ifdef CONFIG_SPECULATIVE_HARDEN_ARRAY -+ " HARDEN_ARRAY" -+#endif -+#ifdef CONFIG_SPECULATIVE_HARDEN_BRANCH -+ " HARDEN_BRANCH" -+#endif -+#ifdef CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS -+ " HARDEN_GUEST_ACCESS" - #endif - "\n"); - --- -2.30.2 - diff --git a/xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch b/xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch deleted file mode 100644 index 6043d48..0000000 --- a/xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch +++ /dev/null @@ -1,99 +0,0 @@ -From de17162cafd27f2865a3102a2ec0f386a02ed03d Mon Sep 17 00:00:00 2001 -From: Andrew Cooper -Date: Thu, 29 Feb 2024 11:26:40 +0000 -Subject: [PATCH] x86/cpu-policy: Allow for levelling of VERW side effects -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -MD_CLEAR and FB_CLEAR need OR-ing across a migrate pool. Allow this, by -having them unconditinally set in max, with the host values reflected in -default. Annotate the bits as having special properies. - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné ---- - xen/arch/x86/cpu-policy.c | 24 +++++++++++++++++++++ - xen/arch/x86/include/asm/cpufeature.h | 1 + - xen/include/public/arch-x86/cpufeatureset.h | 4 ++-- - 3 files changed, 27 insertions(+), 2 deletions(-) - -diff --git a/xen/arch/x86/cpu-policy.c b/xen/arch/x86/cpu-policy.c -index 609db6946f..2c6f03057b 100644 ---- a/xen/arch/x86/cpu-policy.c -+++ b/xen/arch/x86/cpu-policy.c -@@ -442,6 +442,16 @@ static void __init guest_common_max_feature_adjustments(uint32_t *fs) - __set_bit(X86_FEATURE_RSBA, fs); - __set_bit(X86_FEATURE_RRSBA, fs); - -+ /* -+ * These bits indicate that the VERW instruction may have gained -+ * scrubbing side effects. With pooling, they mean "you might migrate -+ * somewhere where scrubbing is necessary", and may need exposing on -+ * unaffected hardware. This is fine, because the VERW instruction -+ * has been around since the 286. -+ */ -+ __set_bit(X86_FEATURE_MD_CLEAR, fs); -+ __set_bit(X86_FEATURE_FB_CLEAR, fs); -+ - /* - * The Gather Data Sampling microcode mitigation (August 2023) has an - * adverse performance impact on the CLWB instruction on SKX/CLX/CPX. -@@ -486,6 +496,20 @@ static void __init guest_common_default_feature_adjustments(uint32_t *fs) - cpu_has_rdrand && !is_forced_cpu_cap(X86_FEATURE_RDRAND) ) - __clear_bit(X86_FEATURE_RDRAND, fs); - -+ /* -+ * These bits indicate that the VERW instruction may have gained -+ * scrubbing side effects. The max policy has them set for migration -+ * reasons, so reset the default policy back to the host values in -+ * case we're unaffected. -+ */ -+ __clear_bit(X86_FEATURE_MD_CLEAR, fs); -+ if ( cpu_has_md_clear ) -+ __set_bit(X86_FEATURE_MD_CLEAR, fs); -+ -+ __clear_bit(X86_FEATURE_FB_CLEAR, fs); -+ if ( cpu_has_fb_clear ) -+ __set_bit(X86_FEATURE_FB_CLEAR, fs); -+ - /* - * The Gather Data Sampling microcode mitigation (August 2023) has an - * adverse performance impact on the CLWB instruction on SKX/CLX/CPX. -diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h -index be16492c68..ad24d0fa88 100644 ---- a/xen/arch/x86/include/asm/cpufeature.h -+++ b/xen/arch/x86/include/asm/cpufeature.h -@@ -178,6 +178,7 @@ static inline bool boot_cpu_has(unsigned int feat) - #define cpu_has_avx512_4fmaps boot_cpu_has(X86_FEATURE_AVX512_4FMAPS) - #define cpu_has_avx512_vp2intersect boot_cpu_has(X86_FEATURE_AVX512_VP2INTERSECT) - #define cpu_has_srbds_ctrl boot_cpu_has(X86_FEATURE_SRBDS_CTRL) -+#define cpu_has_md_clear boot_cpu_has(X86_FEATURE_MD_CLEAR) - #define cpu_has_rtm_always_abort boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) - #define cpu_has_tsx_force_abort boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT) - #define cpu_has_serialize boot_cpu_has(X86_FEATURE_SERIALIZE) -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index b230d3a690..0374cec3a2 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -262,7 +262,7 @@ XEN_CPUFEATURE(AVX512_4FMAPS, 9*32+ 3) /*A AVX512 Multiply Accumulation Single - XEN_CPUFEATURE(FSRM, 9*32+ 4) /*A Fast Short REP MOVS */ - XEN_CPUFEATURE(AVX512_VP2INTERSECT, 9*32+8) /*a VP2INTERSECT{D,Q} insns */ - XEN_CPUFEATURE(SRBDS_CTRL, 9*32+ 9) /* MSR_MCU_OPT_CTRL and RNGDS_MITG_DIS. */ --XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*A VERW clears microarchitectural buffers */ -+XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*!A VERW clears microarchitectural buffers */ - XEN_CPUFEATURE(RTM_ALWAYS_ABORT, 9*32+11) /*! June 2021 TSX defeaturing in microcode. */ - XEN_CPUFEATURE(TSX_FORCE_ABORT, 9*32+13) /* MSR_TSX_FORCE_ABORT.RTM_ABORT */ - XEN_CPUFEATURE(SERIALIZE, 9*32+14) /*A SERIALIZE insn */ -@@ -334,7 +334,7 @@ XEN_CPUFEATURE(DOITM, 16*32+12) /* Data Operand Invariant Timing - XEN_CPUFEATURE(SBDR_SSDP_NO, 16*32+13) /*A No Shared Buffer Data Read or Sideband Stale Data Propagation */ - XEN_CPUFEATURE(FBSDP_NO, 16*32+14) /*A No Fill Buffer Stale Data Propagation */ - XEN_CPUFEATURE(PSDP_NO, 16*32+15) /*A No Primary Stale Data Propagation */ --XEN_CPUFEATURE(FB_CLEAR, 16*32+17) /*A Fill Buffers cleared by VERW */ -+XEN_CPUFEATURE(FB_CLEAR, 16*32+17) /*!A Fill Buffers cleared by VERW */ - XEN_CPUFEATURE(FB_CLEAR_CTRL, 16*32+18) /* MSR_OPT_CPU_CTRL.FB_CLEAR_DIS */ - XEN_CPUFEATURE(RRSBA, 16*32+19) /*! Restricted RSB Alternative */ - XEN_CPUFEATURE(BHI_NO, 16*32+20) /*A No Branch History Injection */ --- -2.30.2 - diff --git a/xen.spec b/xen.spec index 1236568..06a5573 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.18.0 -Release: 7%{?dist} +Version: 4.18.1 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,30 +112,8 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch -Patch51: xsa447.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch -Patch54: xsa449.patch -Patch55: xsa450.patch -Patch56: xsa451-4.18.patch -Patch57: xen.git-de17162cafd27f2865a3102a2ec0f386a02ed03d.patch -Patch58: xsa452-4.18-1.patch -Patch59: xsa452-4.18-2.patch -Patch60: xsa452-4.18-3.patch -Patch61: xsa452-4.18-4.patch -Patch62: xsa452-4.18-5.patch -Patch63: xsa452-4.18-6.patch -Patch64: xsa452-4.18-7.patch -Patch65: xen.git-60e00f77a5cc671d30c5ef3318f5b8e9b74e4aa3.patch -Patch66: xen.git-6e9507f7d51fe49df8bc70f83e49ce06c92e4e54.patch -Patch67: xen.git-576528a2a742069af203e90c613c5c93e23c9755.patch -Patch68: xsa453-4.18-1.patch -Patch69: xsa453-4.18-2.patch -Patch70: xsa453-4.18-3.patch -Patch71: xsa453-4.18-4.patch -Patch72: xsa453-4.18-5.patch -Patch73: xsa453-4.18-6.patch -Patch74: xsa453-4.18-7.patch %if %build_qemutrad @@ -348,30 +326,8 @@ manage Xen virtual machines. %if "%dist" != ".fc38" %patch 50 -p1 %endif -%patch 51 -p1 %patch 52 -p1 %patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 -%patch 57 -p1 -%patch 58 -p1 -%patch 59 -p1 -%patch 60 -p1 -%patch 61 -p1 -%patch 62 -p1 -%patch 63 -p1 -%patch 64 -p1 -%patch 65 -p1 -%patch 66 -p1 -%patch 67 -p1 -%patch 68 -p1 -%patch 69 -p1 -%patch 70 -p1 -%patch 71 -p1 -%patch 72 -p1 -%patch 73 -p1 -%patch 74 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -978,6 +934,11 @@ fi %endif %changelog +* Wed Mar 20 2024 Michael Young - 4.18.1-1 +- update to xen-4.18.1 + rebase xen.gcc12.fixes.patch + remove patches now included or superceded upstream + * Wed Mar 13 2024 Michael Young - 4.18.0-7 - x86: Register File Data Sampling [XSA-452, CVE-2023-28746] - GhostRace: Speculative Race Conditions [XSA-453, CVE-2024-2193] diff --git a/xsa447.patch b/xsa447.patch deleted file mode 100644 index 2e26396..0000000 --- a/xsa447.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 084c7312fa6c1d4a7fa343efa1d7d73693dafff4 Mon Sep 17 00:00:00 2001 -From: Michal Orzel -Date: Thu, 23 Nov 2023 15:53:02 +0100 -Subject: [PATCH] xen/arm: page: Avoid pointer overflow on cache clean & - invalidate - -On Arm32, after cleaning and invalidating the last dcache line of the top -domheap page i.e. VA = 0xfffff000 (as a result of flushing the page to -RAM), we end up adding the value of a dcache line size to the pointer -once again, which results in a pointer arithmetic overflow (with 64B line -size, operation 0xffffffc0 + 0x40 overflows to 0x0). Such behavior is -undefined and given the wide range of compiler versions we support, it is -difficult to determine what could happen in such scenario. - -Modify clean_and_invalidate_dcache_va_range() as well as -clean_dcache_va_range() and invalidate_dcache_va_range() due to similarity -of handling to prevent pointer arithmetic overflow. Modify the loops to -use an additional variable to store the index of the next cacheline. -Add an assert to prevent passing a region that wraps around which is -illegal and would end up in a page fault anyway (region 0-2MB is -unmapped). Lastly, return early if size passed is 0. - -Note that on Arm64, we don't have this problem given that the max VA -space we support is 48-bits. - -This is XSA-447 / CVE-2023-46837. - -Signed-off-by: Michal Orzel -Reviewed-by: Julien Grall ---- - xen/arch/arm/include/asm/page.h | 35 ++++++++++++++++++++++++++------- - 1 file changed, 28 insertions(+), 7 deletions(-) - -diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h -index ebaf5964f114..69f817d1e68a 100644 ---- a/xen/arch/arm/include/asm/page.h -+++ b/xen/arch/arm/include/asm/page.h -@@ -162,6 +162,13 @@ static inline size_t read_dcache_line_bytes(void) - static inline int invalidate_dcache_va_range(const void *p, unsigned long size) - { - size_t cacheline_mask = dcache_line_bytes - 1; -+ unsigned long idx = 0; -+ -+ if ( !size ) -+ return 0; -+ -+ /* Passing a region that wraps around is illegal */ -+ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); - - dsb(sy); /* So the CPU issues all writes to the range */ - -@@ -174,11 +181,11 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) - } - - for ( ; size >= dcache_line_bytes; -- p += dcache_line_bytes, size -= dcache_line_bytes ) -- asm volatile (__invalidate_dcache_one(0) : : "r" (p)); -+ idx += dcache_line_bytes, size -= dcache_line_bytes ) -+ asm volatile (__invalidate_dcache_one(0) : : "r" (p + idx)); - - if ( size > 0 ) -- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); -+ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); - - dsb(sy); /* So we know the flushes happen before continuing */ - -@@ -188,14 +195,21 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) - static inline int clean_dcache_va_range(const void *p, unsigned long size) - { - size_t cacheline_mask = dcache_line_bytes - 1; -+ unsigned long idx = 0; -+ -+ if ( !size ) -+ return 0; -+ -+ /* Passing a region that wraps around is illegal */ -+ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); - - dsb(sy); /* So the CPU issues all writes to the range */ - size += (uintptr_t)p & cacheline_mask; - size = (size + cacheline_mask) & ~cacheline_mask; - p = (void *)((uintptr_t)p & ~cacheline_mask); - for ( ; size >= dcache_line_bytes; -- p += dcache_line_bytes, size -= dcache_line_bytes ) -- asm volatile (__clean_dcache_one(0) : : "r" (p)); -+ idx += dcache_line_bytes, size -= dcache_line_bytes ) -+ asm volatile (__clean_dcache_one(0) : : "r" (p + idx)); - dsb(sy); /* So we know the flushes happen before continuing */ - /* ARM callers assume that dcache_* functions cannot fail. */ - return 0; -@@ -205,14 +219,21 @@ static inline int clean_and_invalidate_dcache_va_range - (const void *p, unsigned long size) - { - size_t cacheline_mask = dcache_line_bytes - 1; -+ unsigned long idx = 0; -+ -+ if ( !size ) -+ return 0; -+ -+ /* Passing a region that wraps around is illegal */ -+ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); - - dsb(sy); /* So the CPU issues all writes to the range */ - size += (uintptr_t)p & cacheline_mask; - size = (size + cacheline_mask) & ~cacheline_mask; - p = (void *)((uintptr_t)p & ~cacheline_mask); - for ( ; size >= dcache_line_bytes; -- p += dcache_line_bytes, size -= dcache_line_bytes ) -- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); -+ idx += dcache_line_bytes, size -= dcache_line_bytes ) -+ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); - dsb(sy); /* So we know the flushes happen before continuing */ - /* ARM callers assume that dcache_* functions cannot fail. */ - return 0; --- -2.40.1 - diff --git a/xsa449.patch b/xsa449.patch deleted file mode 100644 index 80aeac2..0000000 --- a/xsa449.patch +++ /dev/null @@ -1,89 +0,0 @@ -From d8b92b21b224126860978e4c604302f3c1e3bf75 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Wed, 13 Dec 2023 15:51:59 +0100 -Subject: [PATCH] pci: fail device assignment if phantom functions cannot be - assigned -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The current behavior is that no error is reported if (some) phantom functions -fail to be assigned during device add or assignment, so the operation succeeds -even if some phantom functions are not correctly setup. - -This can lead to devices possibly being successfully assigned to a domU while -some of the device phantom functions are still assigned to dom0. Even when the -device is assigned domIO before being assigned to a domU phantom functions -might fail to be assigned to domIO, and also fail to be assigned to the domU, -leaving them assigned to dom0. - -Since the device can generate requests using the IDs of those phantom -functions, given the scenario above a device in such state would be in control -of a domU, but still capable of generating transactions that use a context ID -targeting dom0 owned memory. - -Modify device assign in order to attempt to deassign the device if phantom -functions failed to be assigned. - -Note that device addition is not modified in the same way, as in that case the -device is assigned to a trusted domain, and hence partial assign can lead to -device malfunction but not a security issue. - -This is XSA-449 / CVE-2023-46839 - -Fixes: 4e9950dc1bd2 ('IOMMU: add phantom function support') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/drivers/passthrough/pci.c | 27 +++++++++++++++++++++------ - 1 file changed, 21 insertions(+), 6 deletions(-) - -diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c -index 1439d1ef2b26..47c0eee7bdcc 100644 ---- a/xen/drivers/passthrough/pci.c -+++ b/xen/drivers/passthrough/pci.c -@@ -1488,11 +1488,10 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) - - pdev->fault.count = 0; - -- if ( (rc = iommu_call(hd->platform_ops, assign_device, d, devfn, -- pci_to_dev(pdev), flag)) ) -- goto done; -+ rc = iommu_call(hd->platform_ops, assign_device, d, devfn, pci_to_dev(pdev), -+ flag); - -- for ( ; pdev->phantom_stride; rc = 0 ) -+ while ( pdev->phantom_stride && !rc ) - { - devfn += pdev->phantom_stride; - if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) ) -@@ -1503,8 +1502,24 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) - - done: - if ( rc ) -- printk(XENLOG_G_WARNING "%pd: assign (%pp) failed (%d)\n", -- d, &PCI_SBDF(seg, bus, devfn), rc); -+ { -+ printk(XENLOG_G_WARNING "%pd: assign %s(%pp) failed (%d)\n", -+ d, devfn != pdev->devfn ? "phantom function " : "", -+ &PCI_SBDF(seg, bus, devfn), rc); -+ -+ if ( devfn != pdev->devfn && deassign_device(d, seg, bus, pdev->devfn) ) -+ { -+ /* -+ * Device with phantom functions that failed to both assign and -+ * rollback. Mark the device as broken and crash the target domain, -+ * as the state of the functions at this point is unknown and Xen -+ * has no way to assert consistent context assignment among them. -+ */ -+ pdev->broken = true; -+ if ( !is_hardware_domain(d) && d != dom_io ) -+ domain_crash(d); -+ } -+ } - /* The device is assigned to dom_io so mark it as quarantined */ - else if ( d == dom_io ) - pdev->quarantine = true; --- -2.43.0 - diff --git a/xsa450.patch b/xsa450.patch deleted file mode 100644 index e94933b..0000000 --- a/xsa450.patch +++ /dev/null @@ -1,59 +0,0 @@ -From: Andrew Cooper -Subject: VT-d: Fix "else" vs "#endif" misplacement - -In domain_pgd_maddr() the "#endif" is misplaced with respect to "else". This -generates incorrect logic when CONFIG_HVM is compiled out, as the "else" body -is executed unconditionally. - -Rework the logic to use IS_ENABLED() instead of explicit #ifdef-ary, as it's -clearer to follow. This in turn involves adjusting p2m_get_pagetable() to -compile when CONFIG_HVM is disabled. - -This is XSA-450 / CVE-2023-46840. - -Reported-by: Reported-by: Teddy Astie -Fixes: 033ff90aa9c1 ("x86/P2M: p2m_{alloc,free}_ptp() and p2m_alloc_table() are HVM-only") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h -index 32f3f394b05a..6ada585eaac2 100644 ---- a/xen/arch/x86/include/asm/p2m.h -+++ b/xen/arch/x86/include/asm/p2m.h -@@ -435,7 +435,14 @@ static inline bool p2m_is_altp2m(const struct p2m_domain *p2m) - return p2m->p2m_class == p2m_alternate; - } - --#define p2m_get_pagetable(p2m) ((p2m)->phys_table) -+#ifdef CONFIG_HVM -+static inline pagetable_t p2m_get_pagetable(const struct p2m_domain *p2m) -+{ -+ return p2m->phys_table; -+} -+#else -+pagetable_t p2m_get_pagetable(const struct p2m_domain *p2m); -+#endif - - /* - * Ensure any deferred p2m TLB flush has been completed on all VCPUs. -diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c -index 99b642f12ef9..4244855032ee 100644 ---- a/xen/drivers/passthrough/vtd/iommu.c -+++ b/xen/drivers/passthrough/vtd/iommu.c -@@ -438,15 +438,13 @@ static paddr_t domain_pgd_maddr(struct domain *d, paddr_t pgd_maddr, - - if ( pgd_maddr ) - /* nothing */; --#ifdef CONFIG_HVM -- else if ( iommu_use_hap_pt(d) ) -+ else if ( IS_ENABLED(CONFIG_HVM) && iommu_use_hap_pt(d) ) - { - pagetable_t pgt = p2m_get_pagetable(p2m_get_hostp2m(d)); - - pgd_maddr = pagetable_get_paddr(pgt); - } - else --#endif - { - if ( !hd->arch.vtd.pgd_maddr ) - { diff --git a/xsa451-4.18.patch b/xsa451-4.18.patch deleted file mode 100644 index 721f3f3..0000000 --- a/xsa451-4.18.patch +++ /dev/null @@ -1,188 +0,0 @@ -From: Jan Beulich -Subject: x86: account for shadow stack in exception-from-stub recovery - -Dealing with exceptions raised from within emulation stubs involves -discarding return address (replaced by exception related information). -Such discarding of course also requires removing the corresponding entry -from the shadow stack. - -Also amend the comment in fixup_exception_return(), to further clarify -why use of ptr[1] can't be an out-of-bounds access. - -While touching do_invalid_op() also add a missing fall-through -annotation. - -This is CVE-2023-46841 / XSA-451. - -Fixes: 209fb9919b50 ("x86/extable: Adjust extable handling to be shadow stack compatible") -Signed-off-by: Jan Beulich -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/extable.c -+++ b/xen/arch/x86/extable.c -@@ -86,26 +86,29 @@ search_one_extable(const struct exceptio - } - - unsigned long --search_exception_table(const struct cpu_user_regs *regs) -+search_exception_table(const struct cpu_user_regs *regs, unsigned long *stub_ra) - { - const struct virtual_region *region = find_text_region(regs->rip); - unsigned long stub = this_cpu(stubs.addr); - - if ( region && region->ex ) -+ { -+ *stub_ra = 0; - return search_one_extable(region->ex, region->ex_end, regs->rip); -+ } - - if ( regs->rip >= stub + STUB_BUF_SIZE / 2 && - regs->rip < stub + STUB_BUF_SIZE && - regs->rsp > (unsigned long)regs && - regs->rsp < (unsigned long)get_cpu_info() ) - { -- unsigned long retptr = *(unsigned long *)regs->rsp; -+ unsigned long retaddr = *(unsigned long *)regs->rsp, fixup; - -- region = find_text_region(retptr); -- retptr = region && region->ex -- ? search_one_extable(region->ex, region->ex_end, retptr) -- : 0; -- if ( retptr ) -+ region = find_text_region(retaddr); -+ fixup = region && region->ex -+ ? search_one_extable(region->ex, region->ex_end, retaddr) -+ : 0; -+ if ( fixup ) - { - /* - * Put trap number and error code on the stack (in place of the -@@ -117,7 +120,8 @@ search_exception_table(const struct cpu_ - }; - - *(unsigned long *)regs->rsp = token.raw; -- return retptr; -+ *stub_ra = retaddr; -+ return fixup; - } - } - ---- a/xen/arch/x86/include/asm/uaccess.h -+++ b/xen/arch/x86/include/asm/uaccess.h -@@ -421,7 +421,8 @@ union stub_exception_token { - unsigned long raw; - }; - --extern unsigned long search_exception_table(const struct cpu_user_regs *regs); -+extern unsigned long search_exception_table(const struct cpu_user_regs *regs, -+ unsigned long *stub_ra); - extern void sort_exception_tables(void); - extern void sort_exception_table(struct exception_table_entry *start, - const struct exception_table_entry *stop); ---- a/xen/arch/x86/traps.c -+++ b/xen/arch/x86/traps.c -@@ -845,7 +845,7 @@ void do_unhandled_trap(struct cpu_user_r - } - - static void fixup_exception_return(struct cpu_user_regs *regs, -- unsigned long fixup) -+ unsigned long fixup, unsigned long stub_ra) - { - if ( IS_ENABLED(CONFIG_XEN_SHSTK) ) - { -@@ -862,7 +862,8 @@ static void fixup_exception_return(struc - /* - * Search for %rip. The shstk currently looks like this: - * -- * ... [Likely pointed to by SSP] -+ * tok [Supervisor token, == &tok | BUSY, only with FRED inactive] -+ * ... [Pointed to by SSP for most exceptions, empty in IST cases] - * %cs [== regs->cs] - * %rip [== regs->rip] - * SSP [Likely points to 3 slots higher, above %cs] -@@ -880,7 +881,56 @@ static void fixup_exception_return(struc - */ - if ( ptr[0] == regs->rip && ptr[1] == regs->cs ) - { -+ unsigned long primary_shstk = -+ (ssp & ~(STACK_SIZE - 1)) + -+ (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8; -+ - wrss(fixup, ptr); -+ -+ if ( !stub_ra ) -+ goto shstk_done; -+ -+ /* -+ * Stub recovery ought to happen only when the outer context -+ * was on the main shadow stack. We need to also "pop" the -+ * stub's return address from the interrupted context's shadow -+ * stack. That is, -+ * - if we're still on the main stack, we need to move the -+ * entire stack (up to and including the exception frame) -+ * up by one slot, incrementing the original SSP in the -+ * exception frame, -+ * - if we're on an IST stack, we need to increment the -+ * original SSP. -+ */ -+ BUG_ON((ptr[-1] ^ primary_shstk) >> PAGE_SHIFT); -+ -+ if ( (ssp ^ primary_shstk) >> PAGE_SHIFT ) -+ { -+ /* -+ * We're on an IST stack. First make sure the two return -+ * addresses actually match. Then increment the interrupted -+ * context's SSP. -+ */ -+ BUG_ON(stub_ra != *(unsigned long*)ptr[-1]); -+ wrss(ptr[-1] + 8, &ptr[-1]); -+ goto shstk_done; -+ } -+ -+ /* Make sure the two return addresses actually match. */ -+ BUG_ON(stub_ra != ptr[2]); -+ -+ /* Move exception frame, updating SSP there. */ -+ wrss(ptr[1], &ptr[2]); /* %cs */ -+ wrss(ptr[0], &ptr[1]); /* %rip */ -+ wrss(ptr[-1] + 8, &ptr[0]); /* SSP */ -+ -+ /* Move all newer entries. */ -+ while ( --ptr != _p(ssp) ) -+ wrss(ptr[-1], &ptr[0]); -+ -+ /* Finally account for our own stack having shifted up. */ -+ asm volatile ( "incsspd %0" :: "r" (2) ); -+ - goto shstk_done; - } - } -@@ -901,7 +951,8 @@ static void fixup_exception_return(struc - - static bool extable_fixup(struct cpu_user_regs *regs, bool print) - { -- unsigned long fixup = search_exception_table(regs); -+ unsigned long stub_ra = 0; -+ unsigned long fixup = search_exception_table(regs, &stub_ra); - - if ( unlikely(fixup == 0) ) - return false; -@@ -915,7 +966,7 @@ static bool extable_fixup(struct cpu_use - vector_name(regs->entry_vector), regs->error_code, - _p(regs->rip), _p(regs->rip), _p(fixup)); - -- fixup_exception_return(regs, fixup); -+ fixup_exception_return(regs, fixup, stub_ra); - this_cpu(last_extable_addr) = regs->rip; - - return true; -@@ -1183,7 +1234,8 @@ void do_invalid_op(struct cpu_user_regs - { - case BUGFRAME_run_fn: - case BUGFRAME_warn: -- fixup_exception_return(regs, (unsigned long)eip); -+ fixup_exception_return(regs, (unsigned long)eip, 0); -+ fallthrough; - case BUGFRAME_bug: - case BUGFRAME_assert: - return; diff --git a/xsa452-4.18-1.patch b/xsa452-4.18-1.patch deleted file mode 100644 index cae848f..0000000 --- a/xsa452-4.18-1.patch +++ /dev/null @@ -1,304 +0,0 @@ -From: Andrew Cooper -Subject: x86/entry: Introduce EFRAME_* constants - -restore_all_guest() does a lot of manipulation of the stack after popping the -GPRs, and uses raw %rsp displacements to do so. Also, almost all entrypaths -use raw %rsp displacements prior to pushing GPRs. - -Provide better mnemonics, to aid readability and reduce the chance of errors -when editing. - -No functional change. The resulting binary is identical. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 37541208f119a9c552c6c6c3246ea61be0d44035) - -diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c -index 57b73a4e6214..2fc4d9130a4d 100644 ---- a/xen/arch/x86/x86_64/asm-offsets.c -+++ b/xen/arch/x86/x86_64/asm-offsets.c -@@ -51,6 +51,23 @@ void __dummy__(void) - OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, es); - BLANK(); - -+ /* -+ * EFRAME_* is for the entry/exit logic where %rsp is pointing at -+ * UREGS_error_code and GPRs are still/already guest values. -+ */ -+#define OFFSET_EF(sym, mem) \ -+ DEFINE(sym, offsetof(struct cpu_user_regs, mem) - \ -+ offsetof(struct cpu_user_regs, error_code)) -+ -+ OFFSET_EF(EFRAME_entry_vector, entry_vector); -+ OFFSET_EF(EFRAME_rip, rip); -+ OFFSET_EF(EFRAME_cs, cs); -+ OFFSET_EF(EFRAME_eflags, eflags); -+ OFFSET_EF(EFRAME_rsp, rsp); -+ BLANK(); -+ -+#undef OFFSET_EF -+ - OFFSET(VCPU_processor, struct vcpu, processor); - OFFSET(VCPU_domain, struct vcpu, domain); - OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info_area.map); -diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S -index fcc3a721f147..cb473f08eebd 100644 ---- a/xen/arch/x86/x86_64/compat/entry.S -+++ b/xen/arch/x86/x86_64/compat/entry.S -@@ -15,7 +15,7 @@ ENTRY(entry_int82) - ENDBR64 - ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP - pushq $0 -- movl $HYPERCALL_VECTOR, 4(%rsp) -+ movl $HYPERCALL_VECTOR, EFRAME_entry_vector(%rsp) - SAVE_ALL compat=1 /* DPL1 gate, restricted to 32bit PV guests only. */ - - SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 9a7b129aa7e4..968da9d727b1 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -190,15 +190,15 @@ restore_all_guest: - SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ - - RESTORE_ALL -- testw $TRAP_syscall,4(%rsp) -+ testw $TRAP_syscall, EFRAME_entry_vector(%rsp) - jz iret_exit_to_guest - -- movq 24(%rsp),%r11 # RFLAGS -+ mov EFRAME_eflags(%rsp), %r11 - andq $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), %r11 - orq $X86_EFLAGS_IF,%r11 - - /* Don't use SYSRET path if the return address is not canonical. */ -- movq 8(%rsp),%rcx -+ mov EFRAME_rip(%rsp), %rcx - sarq $47,%rcx - incl %ecx - cmpl $1,%ecx -@@ -213,20 +213,20 @@ restore_all_guest: - ALTERNATIVE "", rag_clrssbsy, X86_FEATURE_XEN_SHSTK - #endif - -- movq 8(%rsp), %rcx # RIP -- cmpw $FLAT_USER_CS32,16(%rsp)# CS -- movq 32(%rsp),%rsp # RSP -+ mov EFRAME_rip(%rsp), %rcx -+ cmpw $FLAT_USER_CS32, EFRAME_cs(%rsp) -+ mov EFRAME_rsp(%rsp), %rsp - je 1f - sysretq - 1: sysretl - - ALIGN - .Lrestore_rcx_iret_exit_to_guest: -- movq 8(%rsp), %rcx # RIP -+ mov EFRAME_rip(%rsp), %rcx - /* No special register assumptions. */ - iret_exit_to_guest: -- andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), 24(%rsp) -- orl $X86_EFLAGS_IF,24(%rsp) -+ andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), EFRAME_eflags(%rsp) -+ orl $X86_EFLAGS_IF, EFRAME_eflags(%rsp) - addq $8,%rsp - .Lft0: iretq - _ASM_PRE_EXTABLE(.Lft0, handle_exception) -@@ -257,7 +257,7 @@ ENTRY(lstar_enter) - pushq $FLAT_KERNEL_CS64 - pushq %rcx - pushq $0 -- movl $TRAP_syscall, 4(%rsp) -+ movl $TRAP_syscall, EFRAME_entry_vector(%rsp) - SAVE_ALL - - SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ -@@ -294,7 +294,7 @@ ENTRY(cstar_enter) - pushq $FLAT_USER_CS32 - pushq %rcx - pushq $0 -- movl $TRAP_syscall, 4(%rsp) -+ movl $TRAP_syscall, EFRAME_entry_vector(%rsp) - SAVE_ALL - - SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ -@@ -335,7 +335,7 @@ GLOBAL(sysenter_eflags_saved) - pushq $3 /* ring 3 null cs */ - pushq $0 /* null rip */ - pushq $0 -- movl $TRAP_syscall, 4(%rsp) -+ movl $TRAP_syscall, EFRAME_entry_vector(%rsp) - SAVE_ALL - - SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ -@@ -389,7 +389,7 @@ ENTRY(int80_direct_trap) - ENDBR64 - ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP - pushq $0 -- movl $0x80, 4(%rsp) -+ movl $0x80, EFRAME_entry_vector(%rsp) - SAVE_ALL - - SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ -@@ -649,7 +649,7 @@ ret_from_intr: - .section .init.text, "ax", @progbits - ENTRY(early_page_fault) - ENDBR64 -- movl $X86_EXC_PF, 4(%rsp) -+ movl $X86_EXC_PF, EFRAME_entry_vector(%rsp) - SAVE_ALL - movq %rsp, %rdi - call do_early_page_fault -@@ -716,7 +716,7 @@ ENTRY(common_interrupt) - - ENTRY(entry_PF) - ENDBR64 -- movl $X86_EXC_PF, 4(%rsp) -+ movl $X86_EXC_PF, EFRAME_entry_vector(%rsp) - /* No special register assumptions. */ - GLOBAL(handle_exception) - ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP -@@ -890,90 +890,90 @@ FATAL_exception_with_ints_disabled: - ENTRY(entry_DE) - ENDBR64 - pushq $0 -- movl $X86_EXC_DE, 4(%rsp) -+ movl $X86_EXC_DE, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_MF) - ENDBR64 - pushq $0 -- movl $X86_EXC_MF, 4(%rsp) -+ movl $X86_EXC_MF, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_XM) - ENDBR64 - pushq $0 -- movl $X86_EXC_XM, 4(%rsp) -+ movl $X86_EXC_XM, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_NM) - ENDBR64 - pushq $0 -- movl $X86_EXC_NM, 4(%rsp) -+ movl $X86_EXC_NM, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_DB) - ENDBR64 - pushq $0 -- movl $X86_EXC_DB, 4(%rsp) -+ movl $X86_EXC_DB, EFRAME_entry_vector(%rsp) - jmp handle_ist_exception - - ENTRY(entry_BP) - ENDBR64 - pushq $0 -- movl $X86_EXC_BP, 4(%rsp) -+ movl $X86_EXC_BP, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_OF) - ENDBR64 - pushq $0 -- movl $X86_EXC_OF, 4(%rsp) -+ movl $X86_EXC_OF, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_BR) - ENDBR64 - pushq $0 -- movl $X86_EXC_BR, 4(%rsp) -+ movl $X86_EXC_BR, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_UD) - ENDBR64 - pushq $0 -- movl $X86_EXC_UD, 4(%rsp) -+ movl $X86_EXC_UD, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_TS) - ENDBR64 -- movl $X86_EXC_TS, 4(%rsp) -+ movl $X86_EXC_TS, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_NP) - ENDBR64 -- movl $X86_EXC_NP, 4(%rsp) -+ movl $X86_EXC_NP, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_SS) - ENDBR64 -- movl $X86_EXC_SS, 4(%rsp) -+ movl $X86_EXC_SS, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_GP) - ENDBR64 -- movl $X86_EXC_GP, 4(%rsp) -+ movl $X86_EXC_GP, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_AC) - ENDBR64 -- movl $X86_EXC_AC, 4(%rsp) -+ movl $X86_EXC_AC, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_CP) - ENDBR64 -- movl $X86_EXC_CP, 4(%rsp) -+ movl $X86_EXC_CP, EFRAME_entry_vector(%rsp) - jmp handle_exception - - ENTRY(entry_DF) - ENDBR64 -- movl $X86_EXC_DF, 4(%rsp) -+ movl $X86_EXC_DF, EFRAME_entry_vector(%rsp) - /* Set AC to reduce chance of further SMAP faults */ - ALTERNATIVE "", stac, X86_FEATURE_XEN_SMAP - SAVE_ALL -@@ -998,7 +998,7 @@ ENTRY(entry_DF) - ENTRY(entry_NMI) - ENDBR64 - pushq $0 -- movl $X86_EXC_NMI, 4(%rsp) -+ movl $X86_EXC_NMI, EFRAME_entry_vector(%rsp) - handle_ist_exception: - ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP - SAVE_ALL -@@ -1130,7 +1130,7 @@ handle_ist_exception: - ENTRY(entry_MC) - ENDBR64 - pushq $0 -- movl $X86_EXC_MC, 4(%rsp) -+ movl $X86_EXC_MC, EFRAME_entry_vector(%rsp) - jmp handle_ist_exception - - /* No op trap handler. Required for kexec crash path. */ -@@ -1167,7 +1167,7 @@ autogen_stubs: /* Automatically generated stubs. */ - 1: - ENDBR64 - pushq $0 -- movb $vec,4(%rsp) -+ movb $vec, EFRAME_entry_vector(%rsp) - jmp common_interrupt - - entrypoint 1b -@@ -1181,7 +1181,7 @@ autogen_stubs: /* Automatically generated stubs. */ - test $8,%spl /* 64bit exception frames are 16 byte aligned, but the word */ - jz 2f /* size is 8 bytes. Check whether the processor gave us an */ - pushq $0 /* error code, and insert an empty one if not. */ --2: movb $vec,4(%rsp) -+2: movb $vec, EFRAME_entry_vector(%rsp) - jmp handle_exception - - entrypoint 1b diff --git a/xsa452-4.18-2.patch b/xsa452-4.18-2.patch deleted file mode 100644 index 4535397..0000000 --- a/xsa452-4.18-2.patch +++ /dev/null @@ -1,90 +0,0 @@ -From: Andrew Cooper -Subject: x86: Resync intel-family.h from Linux - -From v6.8-rc6 - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich -(cherry picked from commit 195e75371b13c4f7ecdf7b5c50aed0d02f2d7ce8) - -diff --git a/xen/arch/x86/include/asm/intel-family.h b/xen/arch/x86/include/asm/intel-family.h -index ffc49151befe..b65e9c46b922 100644 ---- a/xen/arch/x86/include/asm/intel-family.h -+++ b/xen/arch/x86/include/asm/intel-family.h -@@ -26,6 +26,9 @@ - * _G - parts with extra graphics on - * _X - regular server parts - * _D - micro server parts -+ * _N,_P - other mobile parts -+ * _H - premium mobile parts -+ * _S - other client parts - * - * Historical OPTDIFFs: - * -@@ -37,6 +40,9 @@ - * their own names :-( - */ - -+/* Wildcard match for FAM6 so X86_MATCH_INTEL_FAM6_MODEL(ANY) works */ -+#define INTEL_FAM6_ANY X86_MODEL_ANY -+ - #define INTEL_FAM6_CORE_YONAH 0x0E - - #define INTEL_FAM6_CORE2_MEROM 0x0F -@@ -93,8 +99,6 @@ - #define INTEL_FAM6_ICELAKE_L 0x7E /* Sunny Cove */ - #define INTEL_FAM6_ICELAKE_NNPI 0x9D /* Sunny Cove */ - --#define INTEL_FAM6_LAKEFIELD 0x8A /* Sunny Cove / Tremont */ -- - #define INTEL_FAM6_ROCKETLAKE 0xA7 /* Cypress Cove */ - - #define INTEL_FAM6_TIGERLAKE_L 0x8C /* Willow Cove */ -@@ -102,12 +106,31 @@ - - #define INTEL_FAM6_SAPPHIRERAPIDS_X 0x8F /* Golden Cove */ - -+#define INTEL_FAM6_EMERALDRAPIDS_X 0xCF -+ -+#define INTEL_FAM6_GRANITERAPIDS_X 0xAD -+#define INTEL_FAM6_GRANITERAPIDS_D 0xAE -+ -+/* "Hybrid" Processors (P-Core/E-Core) */ -+ -+#define INTEL_FAM6_LAKEFIELD 0x8A /* Sunny Cove / Tremont */ -+ - #define INTEL_FAM6_ALDERLAKE 0x97 /* Golden Cove / Gracemont */ - #define INTEL_FAM6_ALDERLAKE_L 0x9A /* Golden Cove / Gracemont */ - --#define INTEL_FAM6_RAPTORLAKE 0xB7 -+#define INTEL_FAM6_RAPTORLAKE 0xB7 /* Raptor Cove / Enhanced Gracemont */ -+#define INTEL_FAM6_RAPTORLAKE_P 0xBA -+#define INTEL_FAM6_RAPTORLAKE_S 0xBF -+ -+#define INTEL_FAM6_METEORLAKE 0xAC -+#define INTEL_FAM6_METEORLAKE_L 0xAA -+ -+#define INTEL_FAM6_ARROWLAKE_H 0xC5 -+#define INTEL_FAM6_ARROWLAKE 0xC6 -+ -+#define INTEL_FAM6_LUNARLAKE_M 0xBD - --/* "Small Core" Processors (Atom) */ -+/* "Small Core" Processors (Atom/E-Core) */ - - #define INTEL_FAM6_ATOM_BONNELL 0x1C /* Diamondville, Pineview */ - #define INTEL_FAM6_ATOM_BONNELL_MID 0x26 /* Silverthorne, Lincroft */ -@@ -134,6 +157,13 @@ - #define INTEL_FAM6_ATOM_TREMONT 0x96 /* Elkhart Lake */ - #define INTEL_FAM6_ATOM_TREMONT_L 0x9C /* Jasper Lake */ - -+#define INTEL_FAM6_ATOM_GRACEMONT 0xBE /* Alderlake N */ -+ -+#define INTEL_FAM6_ATOM_CRESTMONT_X 0xAF /* Sierra Forest */ -+#define INTEL_FAM6_ATOM_CRESTMONT 0xB6 /* Grand Ridge */ -+ -+#define INTEL_FAM6_ATOM_DARKMONT_X 0xDD /* Clearwater Forest */ -+ - /* Xeon Phi */ - - #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ diff --git a/xsa452-4.18-3.patch b/xsa452-4.18-3.patch deleted file mode 100644 index bc9059c..0000000 --- a/xsa452-4.18-3.patch +++ /dev/null @@ -1,135 +0,0 @@ -From: Andrew Cooper -Subject: x86/vmx: Perform VERW flushing later in the VMExit path - -Broken out of the following patch because this change is subtle enough on its -own. See it for the rational of why we're moving VERW. - -As for how, extend the trick already used to hold one condition in -flags (RESUME vs LAUNCH) through the POPing of GPRs. - -Move the MOV CR earlier. Intel specify flags to be undefined across it. - -Encode the two conditions we want using SF and PF. See the code comment for -exactly how. - -Leave a comment to explain the lack of any content around -SPEC_CTRL_EXIT_TO_VMX, but leave the block in place. Sods law says if we -delete it, we'll need to reintroduce it. - -This is part of XSA-452 / CVE-2023-28746. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 475fa20b7384464210f42bad7195f87bd6f1c63f) - -diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S -index e3f60d5a82f7..1bead826caa3 100644 ---- a/xen/arch/x86/hvm/vmx/entry.S -+++ b/xen/arch/x86/hvm/vmx/entry.S -@@ -87,17 +87,39 @@ UNLIKELY_END(realmode) - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ - /* SPEC_CTRL_EXIT_TO_VMX Req: %rsp=regs/cpuinfo Clob: */ -- DO_SPEC_CTRL_COND_VERW -+ /* -+ * All speculation safety work happens to be elsewhere. VERW is after -+ * popping the GPRs, while restoring the guest MSR_SPEC_CTRL is left -+ * to the MSR load list. -+ */ - - mov VCPU_hvm_guest_cr2(%rbx),%rax -+ mov %rax, %cr2 -+ -+ /* -+ * We need to perform two conditional actions (VERW, and Resume vs -+ * Launch) after popping GPRs. With some cunning, we can encode both -+ * of these in eflags together. -+ * -+ * Parity is only calculated over the bottom byte of the answer, while -+ * Sign is simply the top bit. -+ * -+ * Therefore, the final OR instruction ends up producing: -+ * SF = VCPU_vmx_launched -+ * PF = !SCF_verw -+ */ -+ BUILD_BUG_ON(SCF_verw & ~0xff) -+ movzbl VCPU_vmx_launched(%rbx), %ecx -+ shl $31, %ecx -+ movzbl CPUINFO_spec_ctrl_flags(%rsp), %eax -+ and $SCF_verw, %eax -+ or %eax, %ecx - - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbp -- mov %rax,%cr2 -- cmpb $0,VCPU_vmx_launched(%rbx) - pop %rbx - pop %r11 - pop %r10 -@@ -108,7 +130,13 @@ UNLIKELY_END(realmode) - pop %rdx - pop %rsi - pop %rdi -- je .Lvmx_launch -+ -+ jpe .L_skip_verw -+ /* VERW clobbers ZF, but preserves all others, including SF. */ -+ verw STK_REL(CPUINFO_verw_sel, CPUINFO_error_code)(%rsp) -+.L_skip_verw: -+ -+ jns .Lvmx_launch - - /*.Lvmx_resume:*/ - VMRESUME -diff --git a/xen/arch/x86/include/asm/asm_defns.h b/xen/arch/x86/include/asm/asm_defns.h -index baaaccb26e17..56ae26e54265 100644 ---- a/xen/arch/x86/include/asm/asm_defns.h -+++ b/xen/arch/x86/include/asm/asm_defns.h -@@ -81,6 +81,14 @@ register unsigned long current_stack_pointer asm("rsp"); - - #ifdef __ASSEMBLY__ - -+.macro BUILD_BUG_ON condstr, cond:vararg -+ .if \cond -+ .error "Condition \"\condstr\" not satisfied" -+ .endif -+.endm -+/* preprocessor macro to make error message more user friendly */ -+#define BUILD_BUG_ON(cond) BUILD_BUG_ON #cond, cond -+ - #ifdef HAVE_AS_QUOTED_SYM - #define SUBSECTION_LBL(tag) \ - .ifndef .L.tag; \ -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index 6cb7c1b9491e..525745a06608 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -152,6 +152,13 @@ - #endif - .endm - -+/* -+ * Helper to improve the readibility of stack dispacements with %rsp in -+ * unusual positions. Both @field and @top_of_stack should be constants from -+ * the same object. @top_of_stack should be where %rsp is currently pointing. -+ */ -+#define STK_REL(field, top_of_stk) ((field) - (top_of_stk)) -+ - .macro DO_SPEC_CTRL_COND_VERW - /* - * Requires %rsp=cpuinfo -diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c -index 2fc4d9130a4d..0d336788989f 100644 ---- a/xen/arch/x86/x86_64/asm-offsets.c -+++ b/xen/arch/x86/x86_64/asm-offsets.c -@@ -135,6 +135,7 @@ void __dummy__(void) - #endif - - OFFSET(CPUINFO_guest_cpu_user_regs, struct cpu_info, guest_cpu_user_regs); -+ OFFSET(CPUINFO_error_code, struct cpu_info, guest_cpu_user_regs.error_code); - OFFSET(CPUINFO_verw_sel, struct cpu_info, verw_sel); - OFFSET(CPUINFO_current_vcpu, struct cpu_info, current_vcpu); - OFFSET(CPUINFO_per_cpu_offset, struct cpu_info, per_cpu_offset); diff --git a/xsa452-4.18-4.patch b/xsa452-4.18-4.patch deleted file mode 100644 index 0ccff77..0000000 --- a/xsa452-4.18-4.patch +++ /dev/null @@ -1,197 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Perform VERW flushing later in exit paths - -On parts vulnerable to RFDS, VERW's side effects are extended to scrub all -non-architectural entries in various Physical Register Files. To remove all -of Xen's values, the VERW must be after popping the GPRs. - -Rework SPEC_CTRL_COND_VERW to default to an CPUINFO_error_code %rsp position, -but with overrides for other contexts. Identify that it clobbers eflags; this -is particularly relevant for the SYSRET path. - -For the IST exit return to Xen, have the main SPEC_CTRL_EXIT_TO_XEN put a -shadow copy of spec_ctrl_flags, as GPRs can't be used at the point we want to -issue the VERW. - -This is part of XSA-452 / CVE-2023-28746. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit 0a666cf2cd99df6faf3eebc81a1fc286e4eca4c7) - -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index 525745a06608..13acebc75dff 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -159,16 +159,23 @@ - */ - #define STK_REL(field, top_of_stk) ((field) - (top_of_stk)) - --.macro DO_SPEC_CTRL_COND_VERW -+.macro SPEC_CTRL_COND_VERW \ -+ scf=STK_REL(CPUINFO_spec_ctrl_flags, CPUINFO_error_code), \ -+ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_error_code) - /* -- * Requires %rsp=cpuinfo -+ * Requires \scf and \sel as %rsp-relative expressions -+ * Clobbers eflags -+ * -+ * VERW needs to run after guest GPRs have been restored, where only %rsp is -+ * good to use. Default to expecting %rsp pointing at CPUINFO_error_code. -+ * Contexts where this is not true must provide an alternative \scf and \sel. - * - * Issue a VERW for its flushing side effect, if indicated. This is a Spectre - * v1 gadget, but the IRET/VMEntry is serialising. - */ -- testb $SCF_verw, CPUINFO_spec_ctrl_flags(%rsp) -+ testb $SCF_verw, \scf(%rsp) - jz .L\@_verw_skip -- verw CPUINFO_verw_sel(%rsp) -+ verw \sel(%rsp) - .L\@_verw_skip: - .endm - -@@ -286,8 +293,6 @@ - */ - ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV - -- DO_SPEC_CTRL_COND_VERW -- - ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV - .endm - -@@ -367,7 +372,7 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - */ - .macro SPEC_CTRL_EXIT_TO_XEN - /* -- * Requires %r12=ist_exit, %r14=stack_end -+ * Requires %r12=ist_exit, %r14=stack_end, %rsp=regs - * Clobbers %rax, %rbx, %rcx, %rdx - */ - movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx -@@ -395,11 +400,18 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - test %r12, %r12 - jz .L\@_skip_ist_exit - -- /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */ -- testb $SCF_verw, %bl -- jz .L\@_skip_verw -- verw STACK_CPUINFO_FIELD(verw_sel)(%r14) --.L\@_skip_verw: -+ /* -+ * Stash SCF and verw_sel above eflags in the case of an IST_exit. The -+ * VERW logic needs to run after guest GPRs have been restored; i.e. where -+ * we cannot use %r12 or %r14 for the purposes they have here. -+ * -+ * When the CPU pushed this exception frame, it zero-extended eflags. -+ * Therefore it is safe for the VERW logic to look at the stashed SCF -+ * outside of the ist_exit condition. Also, this stashing won't influence -+ * any other restore_all_guest() paths. -+ */ -+ or $(__HYPERVISOR_DS32 << 16), %ebx -+ mov %ebx, UREGS_eflags + 4(%rsp) /* EFRAME_shadow_scf/sel */ - - ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV - -diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c -index 0d336788989f..85c7d0c98967 100644 ---- a/xen/arch/x86/x86_64/asm-offsets.c -+++ b/xen/arch/x86/x86_64/asm-offsets.c -@@ -55,14 +55,22 @@ void __dummy__(void) - * EFRAME_* is for the entry/exit logic where %rsp is pointing at - * UREGS_error_code and GPRs are still/already guest values. - */ --#define OFFSET_EF(sym, mem) \ -+#define OFFSET_EF(sym, mem, ...) \ - DEFINE(sym, offsetof(struct cpu_user_regs, mem) - \ -- offsetof(struct cpu_user_regs, error_code)) -+ offsetof(struct cpu_user_regs, error_code) __VA_ARGS__) - - OFFSET_EF(EFRAME_entry_vector, entry_vector); - OFFSET_EF(EFRAME_rip, rip); - OFFSET_EF(EFRAME_cs, cs); - OFFSET_EF(EFRAME_eflags, eflags); -+ -+ /* -+ * These aren't real fields. They're spare space, used by the IST -+ * exit-to-xen path. -+ */ -+ OFFSET_EF(EFRAME_shadow_scf, eflags, +4); -+ OFFSET_EF(EFRAME_shadow_sel, eflags, +6); -+ - OFFSET_EF(EFRAME_rsp, rsp); - BLANK(); - -@@ -136,6 +144,7 @@ void __dummy__(void) - - OFFSET(CPUINFO_guest_cpu_user_regs, struct cpu_info, guest_cpu_user_regs); - OFFSET(CPUINFO_error_code, struct cpu_info, guest_cpu_user_regs.error_code); -+ OFFSET(CPUINFO_rip, struct cpu_info, guest_cpu_user_regs.rip); - OFFSET(CPUINFO_verw_sel, struct cpu_info, verw_sel); - OFFSET(CPUINFO_current_vcpu, struct cpu_info, current_vcpu); - OFFSET(CPUINFO_per_cpu_offset, struct cpu_info, per_cpu_offset); -diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S -index cb473f08eebd..3bbe3a79a5b7 100644 ---- a/xen/arch/x86/x86_64/compat/entry.S -+++ b/xen/arch/x86/x86_64/compat/entry.S -@@ -161,6 +161,12 @@ ENTRY(compat_restore_all_guest) - SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ - - RESTORE_ALL adj=8 compat=1 -+ -+ /* Account for ev/ec having already been popped off the stack. */ -+ SPEC_CTRL_COND_VERW \ -+ scf=STK_REL(CPUINFO_spec_ctrl_flags, CPUINFO_rip), \ -+ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_rip) -+ - .Lft0: iretq - _ASM_PRE_EXTABLE(.Lft0, handle_exception) - -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 968da9d727b1..2c7512130f49 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -214,6 +214,9 @@ restore_all_guest: - #endif - - mov EFRAME_rip(%rsp), %rcx -+ -+ SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */ -+ - cmpw $FLAT_USER_CS32, EFRAME_cs(%rsp) - mov EFRAME_rsp(%rsp), %rsp - je 1f -@@ -227,6 +230,9 @@ restore_all_guest: - iret_exit_to_guest: - andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), EFRAME_eflags(%rsp) - orl $X86_EFLAGS_IF, EFRAME_eflags(%rsp) -+ -+ SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */ -+ - addq $8,%rsp - .Lft0: iretq - _ASM_PRE_EXTABLE(.Lft0, handle_exception) -@@ -679,9 +685,22 @@ UNLIKELY_START(ne, exit_cr3) - UNLIKELY_END(exit_cr3) - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */ -+ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end %rsp=regs, Clob: abcd */ - - RESTORE_ALL adj=8 -+ -+ /* -+ * When the CPU pushed this exception frame, it zero-extended eflags. -+ * For an IST exit, SPEC_CTRL_EXIT_TO_XEN stashed shadow copies of -+ * spec_ctrl_flags and ver_sel above eflags, as we can't use any GPRs, -+ * and we're at a random place on the stack, not in a CPUFINFO block. -+ * -+ * Account for ev/ec having already been popped off the stack. -+ */ -+ SPEC_CTRL_COND_VERW \ -+ scf=STK_REL(EFRAME_shadow_scf, EFRAME_rip), \ -+ sel=STK_REL(EFRAME_shadow_sel, EFRAME_rip) -+ - iretq - - ENTRY(common_interrupt) diff --git a/xsa452-4.18-5.patch b/xsa452-4.18-5.patch deleted file mode 100644 index d55e454..0000000 --- a/xsa452-4.18-5.patch +++ /dev/null @@ -1,239 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Rename VERW related options - -VERW is going to be used for a 3rd purpose, and the existing nomenclature -didn't survive the Stale MMIO issues terribly well. - -Rename the command line option from `md-clear=` to `verw=`. This is more -consistent with other options which tend to be named based on what they're -doing, not which feature enumeration they use behind the scenes. Retain -`md-clear=` as a deprecated alias. - -Rename opt_md_clear_{pv,hvm} and opt_fb_clear_mmio to opt_verw_{pv,hvm,mmio}, -which has a side effect of making spec_ctrl_init_domain() rather clearer to -follow. - -No functional change. - -This is part of XSA-452 / CVE-2023-28746. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit f7603ca252e4226739eb3129a5290ee3da3f8ea4) - -diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc -index 582d6741d182..fbf16839249a 100644 ---- a/docs/misc/xen-command-line.pandoc -+++ b/docs/misc/xen-command-line.pandoc -@@ -2370,7 +2370,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). - - ### spec-ctrl (x86) - > `= List of [ , xen=, {pv,hvm}=, --> {msr-sc,rsb,md-clear,ibpb-entry}=|{pv,hvm}=, -+> {msr-sc,rsb,verw,ibpb-entry}=|{pv,hvm}=, - > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, - > eager-fpu,l1d-flush,branch-harden,srb-lock, - > unpriv-mmio,gds-mit,div-scrub}= ]` -@@ -2395,7 +2395,7 @@ in place for guests to use. - - Use of a positive boolean value for either of these options is invalid. - --The `pv=`, `hvm=`, `msr-sc=`, `rsb=`, `md-clear=` and `ibpb-entry=` options -+The `pv=`, `hvm=`, `msr-sc=`, `rsb=`, `verw=` and `ibpb-entry=` options - offer fine grained control over the primitives by Xen. These impact Xen's - ability to protect itself, and/or Xen's ability to virtualise support for - guests to use. -@@ -2412,11 +2412,12 @@ guests to use. - guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. - * `rsb=` offers control over whether to overwrite the Return Stack Buffer / - Return Address Stack on entry to Xen and on idle. --* `md-clear=` offers control over whether to use VERW to flush -- microarchitectural buffers on idle and exit from Xen. *Note: For -- compatibility with development versions of this fix, `mds=` is also accepted -- on Xen 4.12 and earlier as an alias. Consult vendor documentation in -- preference to here.* -+* `verw=` offers control over whether to use VERW for its scrubbing side -+ effects at appropriate privilege transitions. The exact side effects are -+ microarchitecture and microcode specific. *Note: `md-clear=` is accepted as -+ a deprecated alias. For compatibility with development versions of XSA-297, -+ `mds=` is also accepted on Xen 4.12 and earlier as an alias. Consult vendor -+ documentation in preference to here.* - * `ibpb-entry=` offers control over whether IBPB (Indirect Branch Prediction - Barrier) is used on entry to Xen. This is used by default on hardware - vulnerable to Branch Type Confusion, and hardware vulnerable to Speculative -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index a965b6db28ba..c42d8cdc22d6 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -25,8 +25,8 @@ static bool __initdata opt_msr_sc_pv = true; - static bool __initdata opt_msr_sc_hvm = true; - static int8_t __initdata opt_rsb_pv = -1; - static bool __initdata opt_rsb_hvm = true; --static int8_t __ro_after_init opt_md_clear_pv = -1; --static int8_t __ro_after_init opt_md_clear_hvm = -1; -+static int8_t __ro_after_init opt_verw_pv = -1; -+static int8_t __ro_after_init opt_verw_hvm = -1; - - static int8_t __ro_after_init opt_ibpb_entry_pv = -1; - static int8_t __ro_after_init opt_ibpb_entry_hvm = -1; -@@ -66,7 +66,7 @@ static bool __initdata cpu_has_bug_mds; /* Any other M{LP,SB,FB}DS combination. - - static int8_t __initdata opt_srb_lock = -1; - static bool __initdata opt_unpriv_mmio; --static bool __ro_after_init opt_fb_clear_mmio; -+static bool __ro_after_init opt_verw_mmio; - static int8_t __initdata opt_gds_mit = -1; - static int8_t __initdata opt_div_scrub = -1; - -@@ -108,8 +108,8 @@ static int __init cf_check parse_spec_ctrl(const char *s) - disable_common: - opt_rsb_pv = false; - opt_rsb_hvm = false; -- opt_md_clear_pv = 0; -- opt_md_clear_hvm = 0; -+ opt_verw_pv = 0; -+ opt_verw_hvm = 0; - opt_ibpb_entry_pv = 0; - opt_ibpb_entry_hvm = 0; - opt_ibpb_entry_dom0 = false; -@@ -140,14 +140,14 @@ static int __init cf_check parse_spec_ctrl(const char *s) - { - opt_msr_sc_pv = val; - opt_rsb_pv = val; -- opt_md_clear_pv = val; -+ opt_verw_pv = val; - opt_ibpb_entry_pv = val; - } - else if ( (val = parse_boolean("hvm", s, ss)) >= 0 ) - { - opt_msr_sc_hvm = val; - opt_rsb_hvm = val; -- opt_md_clear_hvm = val; -+ opt_verw_hvm = val; - opt_ibpb_entry_hvm = val; - } - else if ( (val = parse_boolean("msr-sc", s, ss)) != -1 ) -@@ -192,21 +192,22 @@ static int __init cf_check parse_spec_ctrl(const char *s) - break; - } - } -- else if ( (val = parse_boolean("md-clear", s, ss)) != -1 ) -+ else if ( (val = parse_boolean("verw", s, ss)) != -1 || -+ (val = parse_boolean("md-clear", s, ss)) != -1 ) - { - switch ( val ) - { - case 0: - case 1: -- opt_md_clear_pv = opt_md_clear_hvm = val; -+ opt_verw_pv = opt_verw_hvm = val; - break; - - case -2: -- s += strlen("md-clear="); -+ s += (*s == 'v') ? strlen("verw=") : strlen("md-clear="); - if ( (val = parse_boolean("pv", s, ss)) >= 0 ) -- opt_md_clear_pv = val; -+ opt_verw_pv = val; - else if ( (val = parse_boolean("hvm", s, ss)) >= 0 ) -- opt_md_clear_hvm = val; -+ opt_verw_hvm = val; - else - default: - rc = -EINVAL; -@@ -528,8 +529,8 @@ static void __init print_details(enum ind_thunk thunk) - opt_srb_lock ? " SRB_LOCK+" : " SRB_LOCK-", - opt_ibpb_ctxt_switch ? " IBPB-ctxt" : "", - opt_l1d_flush ? " L1D_FLUSH" : "", -- opt_md_clear_pv || opt_md_clear_hvm || -- opt_fb_clear_mmio ? " VERW" : "", -+ opt_verw_pv || opt_verw_hvm || -+ opt_verw_mmio ? " VERW" : "", - opt_div_scrub ? " DIV" : "", - opt_branch_harden ? " BRANCH_HARDEN" : ""); - -@@ -550,13 +551,13 @@ static void __init print_details(enum ind_thunk thunk) - boot_cpu_has(X86_FEATURE_SC_RSB_HVM) || - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) || - amd_virt_spec_ctrl || -- opt_eager_fpu || opt_md_clear_hvm) ? "" : " None", -+ opt_eager_fpu || opt_verw_hvm) ? "" : " None", - boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ? " MSR_SPEC_CTRL" : "", - (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || - amd_virt_spec_ctrl) ? " MSR_VIRT_SPEC_CTRL" : "", - boot_cpu_has(X86_FEATURE_SC_RSB_HVM) ? " RSB" : "", - opt_eager_fpu ? " EAGER_FPU" : "", -- opt_md_clear_hvm ? " MD_CLEAR" : "", -+ opt_verw_hvm ? " VERW" : "", - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) ? " IBPB-entry" : ""); - - #endif -@@ -565,11 +566,11 @@ static void __init print_details(enum ind_thunk thunk) - (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || - boot_cpu_has(X86_FEATURE_SC_RSB_PV) || - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) || -- opt_eager_fpu || opt_md_clear_pv) ? "" : " None", -+ opt_eager_fpu || opt_verw_pv) ? "" : " None", - boot_cpu_has(X86_FEATURE_SC_MSR_PV) ? " MSR_SPEC_CTRL" : "", - boot_cpu_has(X86_FEATURE_SC_RSB_PV) ? " RSB" : "", - opt_eager_fpu ? " EAGER_FPU" : "", -- opt_md_clear_pv ? " MD_CLEAR" : "", -+ opt_verw_pv ? " VERW" : "", - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) ? " IBPB-entry" : ""); - - printk(" XPTI (64-bit PV only): Dom0 %s, DomU %s (with%s PCID)\n", -@@ -1502,8 +1503,8 @@ void spec_ctrl_init_domain(struct domain *d) - { - bool pv = is_pv_domain(d); - -- bool verw = ((pv ? opt_md_clear_pv : opt_md_clear_hvm) || -- (opt_fb_clear_mmio && is_iommu_enabled(d))); -+ bool verw = ((pv ? opt_verw_pv : opt_verw_hvm) || -+ (opt_verw_mmio && is_iommu_enabled(d))); - - bool ibpb = ((pv ? opt_ibpb_entry_pv : opt_ibpb_entry_hvm) && - (d->domain_id != 0 || opt_ibpb_entry_dom0)); -@@ -1866,19 +1867,20 @@ void __init init_speculation_mitigations(void) - * the return-to-guest path. - */ - if ( opt_unpriv_mmio ) -- opt_fb_clear_mmio = cpu_has_fb_clear; -+ opt_verw_mmio = cpu_has_fb_clear; - - /* - * By default, enable PV and HVM mitigations on MDS-vulnerable hardware. - * This will only be a token effort for MLPDS/MFBDS when HT is enabled, - * but it is somewhat better than nothing. - */ -- if ( opt_md_clear_pv == -1 ) -- opt_md_clear_pv = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && -- boot_cpu_has(X86_FEATURE_MD_CLEAR)); -- if ( opt_md_clear_hvm == -1 ) -- opt_md_clear_hvm = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && -- boot_cpu_has(X86_FEATURE_MD_CLEAR)); -+ if ( opt_verw_pv == -1 ) -+ opt_verw_pv = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && -+ cpu_has_md_clear); -+ -+ if ( opt_verw_hvm == -1 ) -+ opt_verw_hvm = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && -+ cpu_has_md_clear); - - /* - * Enable MDS/MMIO defences as applicable. The Idle blocks need using if -@@ -1891,12 +1893,12 @@ void __init init_speculation_mitigations(void) - * MDS mitigations. L1D_FLUSH is not safe for MMIO mitigations.) - * - * After calculating the appropriate idle setting, simplify -- * opt_md_clear_hvm to mean just "should we VERW on the way into HVM -+ * opt_verw_hvm to mean just "should we VERW on the way into HVM - * guests", so spec_ctrl_init_domain() can calculate suitable settings. - */ -- if ( opt_md_clear_pv || opt_md_clear_hvm || opt_fb_clear_mmio ) -+ if ( opt_verw_pv || opt_verw_hvm || opt_verw_mmio ) - setup_force_cpu_cap(X86_FEATURE_SC_VERW_IDLE); -- opt_md_clear_hvm &= !cpu_has_skip_l1dfl && !opt_l1d_flush; -+ opt_verw_hvm &= !cpu_has_skip_l1dfl && !opt_l1d_flush; - - /* - * Warn the user if they are on MLPDS/MFBDS-vulnerable hardware with HT diff --git a/xsa452-4.18-6.patch b/xsa452-4.18-6.patch deleted file mode 100644 index 422dc62..0000000 --- a/xsa452-4.18-6.patch +++ /dev/null @@ -1,163 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: VERW-handling adjustments - -... before we add yet more complexity to this logic. Mostly expanded -comments, but with three minor changes. - -1) Introduce cpu_has_useful_md_clear to simplify later logic in this patch and - future ones. - -2) We only ever need SC_VERW_IDLE when SMT is active. If SMT isn't active, - then there's no re-partition of pipeline resources based on thread-idleness - to worry about. - -3) The logic to adjust HVM VERW based on L1D_FLUSH is unmaintainable and, as - it turns out, wrong. SKIP_L1DFL is just a hint bit, whereas opt_l1d_flush - is the relevant decision of whether to use L1D_FLUSH based on - susceptibility and user preference. - - Rewrite the logic so it can be followed, and incorporate the fact that when - FB_CLEAR is visible, L1D_FLUSH isn't a safe substitution. - -This is part of XSA-452 / CVE-2023-28746. - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich -(cherry picked from commit 1eb91a8a06230b4b64228c9a380194f8cfe6c5e2) - -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index c42d8cdc22d6..a4afcd8570e2 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -1519,7 +1519,7 @@ void __init init_speculation_mitigations(void) - { - enum ind_thunk thunk = THUNK_DEFAULT; - bool has_spec_ctrl, ibrs = false, hw_smt_enabled; -- bool cpu_has_bug_taa, retpoline_safe; -+ bool cpu_has_bug_taa, cpu_has_useful_md_clear, retpoline_safe; - - hw_smt_enabled = check_smt_enabled(); - -@@ -1855,50 +1855,97 @@ void __init init_speculation_mitigations(void) - "enabled. Please assess your configuration and choose an\n" - "explicit 'smt=' setting. See XSA-273.\n"); - -+ /* -+ * A brief summary of VERW-related changes. -+ * -+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/intel-analysis-microarchitectural-data-sampling.html -+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html -+ * -+ * Relevant ucodes: -+ * -+ * - May 2019, for MDS. Introduces the MD_CLEAR CPUID bit and VERW side -+ * effects to scrub Store/Load/Fill buffers as applicable. MD_CLEAR -+ * exists architecturally, even when the side effects have been removed. -+ * -+ * Use VERW to scrub on return-to-guest. Parts with L1D_FLUSH to -+ * mitigate L1TF have the same side effect, so no need to do both. -+ * -+ * Various Atoms suffer from Store-buffer sampling only. Store buffers -+ * are statically partitioned between non-idle threads, so scrubbing is -+ * wanted when going idle too. -+ * -+ * Load ports and Fill buffers are competitively shared between threads. -+ * SMT must be disabled for VERW scrubbing to be fully effective. -+ * -+ * - November 2019, for TAA. Extended VERW side effects to TSX-enabled -+ * MDS_NO parts. -+ * -+ * - February 2022, for Client TSX de-feature. Removed VERW side effects -+ * from Client CPUs only. -+ * -+ * - May 2022, for MMIO Stale Data. (Re)introduced Fill Buffer scrubbing -+ * on all MMIO-affected parts which didn't already have it for MDS -+ * reasons, enumerating FB_CLEAR on those parts only. -+ * -+ * If FB_CLEAR is enumerated, L1D_FLUSH does not have the same scrubbing -+ * side effects as VERW and cannot be used in its place. -+ */ - mds_calculations(); - - /* -- * Parts which enumerate FB_CLEAR are those which are post-MDS_NO and have -- * reintroduced the VERW fill buffer flushing side effect because of a -- * susceptibility to FBSDP. -+ * Parts which enumerate FB_CLEAR are those with now-updated microcode -+ * which weren't susceptible to the original MFBDS (and therefore didn't -+ * have Fill Buffer scrubbing side effects to begin with, or were Client -+ * MDS_NO non-TAA_NO parts where the scrubbing was removed), but have had -+ * the scrubbing reintroduced because of a susceptibility to FBSDP. - * - * If unprivileged guests have (or will have) MMIO mappings, we can - * mitigate cross-domain leakage of fill buffer data by issuing VERW on -- * the return-to-guest path. -+ * the return-to-guest path. This is only a token effort if SMT is -+ * active. - */ - if ( opt_unpriv_mmio ) - opt_verw_mmio = cpu_has_fb_clear; - - /* -- * By default, enable PV and HVM mitigations on MDS-vulnerable hardware. -- * This will only be a token effort for MLPDS/MFBDS when HT is enabled, -- * but it is somewhat better than nothing. -+ * MD_CLEAR is enumerated architecturally forevermore, even after the -+ * scrubbing side effects have been removed. Create ourselves an version -+ * which expressed whether we think MD_CLEAR is having any useful side -+ * effect. -+ */ -+ cpu_has_useful_md_clear = (cpu_has_md_clear && -+ (cpu_has_bug_mds || cpu_has_bug_msbds_only)); -+ -+ /* -+ * By default, use VERW scrubbing on applicable hardware, if we think it's -+ * going to have an effect. This will only be a token effort for -+ * MLPDS/MFBDS when SMT is enabled. - */ - if ( opt_verw_pv == -1 ) -- opt_verw_pv = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && -- cpu_has_md_clear); -+ opt_verw_pv = cpu_has_useful_md_clear; - - if ( opt_verw_hvm == -1 ) -- opt_verw_hvm = ((cpu_has_bug_mds || cpu_has_bug_msbds_only) && -- cpu_has_md_clear); -+ opt_verw_hvm = cpu_has_useful_md_clear; - - /* -- * Enable MDS/MMIO defences as applicable. The Idle blocks need using if -- * either the PV or HVM MDS defences are used, or if we may give MMIO -- * access to untrusted guests. -- * -- * HVM is more complicated. The MD_CLEAR microcode extends L1D_FLUSH with -- * equivalent semantics to avoid needing to perform both flushes on the -- * HVM path. Therefore, we don't need VERW in addition to L1D_FLUSH (for -- * MDS mitigations. L1D_FLUSH is not safe for MMIO mitigations.) -- * -- * After calculating the appropriate idle setting, simplify -- * opt_verw_hvm to mean just "should we VERW on the way into HVM -- * guests", so spec_ctrl_init_domain() can calculate suitable settings. -+ * If SMT is active, and we're protecting against MDS or MMIO stale data, -+ * we need to scrub before going idle as well as on return to guest. -+ * Various pipeline resources are repartitioned amongst non-idle threads. - */ -- if ( opt_verw_pv || opt_verw_hvm || opt_verw_mmio ) -+ if ( ((cpu_has_useful_md_clear && (opt_verw_pv || opt_verw_hvm)) || -+ opt_verw_mmio) && hw_smt_enabled ) - setup_force_cpu_cap(X86_FEATURE_SC_VERW_IDLE); -- opt_verw_hvm &= !cpu_has_skip_l1dfl && !opt_l1d_flush; -+ -+ /* -+ * After calculating the appropriate idle setting, simplify opt_verw_hvm -+ * to mean just "should we VERW on the way into HVM guests", so -+ * spec_ctrl_init_domain() can calculate suitable settings. -+ * -+ * It is only safe to use L1D_FLUSH in place of VERW when MD_CLEAR is the -+ * only *_CLEAR we can see. -+ */ -+ if ( opt_l1d_flush && cpu_has_md_clear && !cpu_has_fb_clear ) -+ opt_verw_hvm = false; - - /* - * Warn the user if they are on MLPDS/MFBDS-vulnerable hardware with HT diff --git a/xsa452-4.18-7.patch b/xsa452-4.18-7.patch deleted file mode 100644 index a252db0..0000000 --- a/xsa452-4.18-7.patch +++ /dev/null @@ -1,307 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Mitigation Register File Data Sampling - -RFDS affects Atom cores, also branded E-cores, between the Goldmont and -Gracemont microarchitectures. This includes Alder Lake and Raptor Lake hybrid -clien systems which have a mix of Gracemont and other types of cores. - -Two new bits have been defined; RFDS_CLEAR to indicate VERW has more side -effets, and RFDS_NO to incidate that the system is unaffected. Plenty of -unaffected CPUs won't be getting RFDS_NO retrofitted in microcode, so we -synthesise it. Alder Lake and Raptor Lake Xeon-E's are unaffected due to -their platform configuration, and we must use the Hybrid CPUID bit to -distinguish them from their non-Xeon counterparts. - -Like MD_CLEAR and FB_CLEAR, RFDS_CLEAR needs OR-ing across a resource pool, so -set it in the max policies and reflect the host setting in default. - -This is part of XSA-452 / CVE-2023-28746. - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich -(cherry picked from commit fb5b6f6744713410c74cfc12b7176c108e3c9a31) - -diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c -index 7370f1b56ef9..52e451a806c1 100644 ---- a/tools/misc/xen-cpuid.c -+++ b/tools/misc/xen-cpuid.c -@@ -172,7 +172,7 @@ static const char *const str_7d0[32] = - [ 8] = "avx512-vp2intersect", [ 9] = "srbds-ctrl", - [10] = "md-clear", [11] = "rtm-always-abort", - /* 12 */ [13] = "tsx-force-abort", -- [14] = "serialize", -+ [14] = "serialize", [15] = "hybrid", - [16] = "tsxldtrk", - [18] = "pconfig", - [20] = "cet-ibt", -@@ -245,7 +245,8 @@ static const char *const str_m10Al[32] = - [20] = "bhi-no", [21] = "xapic-status", - /* 22 */ [23] = "ovrclk-status", - [24] = "pbrsb-no", [25] = "gds-ctrl", -- [26] = "gds-no", -+ [26] = "gds-no", [27] = "rfds-no", -+ [28] = "rfds-clear", - }; - - static const char *const str_m10Ah[32] = -diff --git a/xen/arch/x86/cpu-policy.c b/xen/arch/x86/cpu-policy.c -index c7c5e99b7b4c..12e621b97de6 100644 ---- a/xen/arch/x86/cpu-policy.c -+++ b/xen/arch/x86/cpu-policy.c -@@ -451,6 +451,7 @@ static void __init guest_common_max_feature_adjustments(uint32_t *fs) - */ - __set_bit(X86_FEATURE_MD_CLEAR, fs); - __set_bit(X86_FEATURE_FB_CLEAR, fs); -+ __set_bit(X86_FEATURE_RFDS_CLEAR, fs); - - /* - * The Gather Data Sampling microcode mitigation (August 2023) has an -@@ -500,6 +501,10 @@ static void __init guest_common_default_feature_adjustments(uint32_t *fs) - if ( cpu_has_fb_clear ) - __set_bit(X86_FEATURE_FB_CLEAR, fs); - -+ __clear_bit(X86_FEATURE_RFDS_CLEAR, fs); -+ if ( cpu_has_rfds_clear ) -+ __set_bit(X86_FEATURE_RFDS_CLEAR, fs); -+ - /* - * The Gather Data Sampling microcode mitigation (August 2023) has an - * adverse performance impact on the CLWB instruction on SKX/CLX/CPX. -diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h -index 76ef2aeb1de6..3c57f55de075 100644 ---- a/xen/arch/x86/include/asm/cpufeature.h -+++ b/xen/arch/x86/include/asm/cpufeature.h -@@ -181,6 +181,7 @@ static inline bool boot_cpu_has(unsigned int feat) - #define cpu_has_rtm_always_abort boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) - #define cpu_has_tsx_force_abort boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT) - #define cpu_has_serialize boot_cpu_has(X86_FEATURE_SERIALIZE) -+#define cpu_has_hybrid boot_cpu_has(X86_FEATURE_HYBRID) - #define cpu_has_avx512_fp16 boot_cpu_has(X86_FEATURE_AVX512_FP16) - #define cpu_has_arch_caps boot_cpu_has(X86_FEATURE_ARCH_CAPS) - -@@ -208,6 +209,8 @@ static inline bool boot_cpu_has(unsigned int feat) - #define cpu_has_rrsba boot_cpu_has(X86_FEATURE_RRSBA) - #define cpu_has_gds_ctrl boot_cpu_has(X86_FEATURE_GDS_CTRL) - #define cpu_has_gds_no boot_cpu_has(X86_FEATURE_GDS_NO) -+#define cpu_has_rfds_no boot_cpu_has(X86_FEATURE_RFDS_NO) -+#define cpu_has_rfds_clear boot_cpu_has(X86_FEATURE_RFDS_CLEAR) - - /* Synthesized. */ - #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) -diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h -index 82a81bd0a232..85ef28a612e0 100644 ---- a/xen/arch/x86/include/asm/msr-index.h -+++ b/xen/arch/x86/include/asm/msr-index.h -@@ -89,6 +89,8 @@ - #define ARCH_CAPS_PBRSB_NO (_AC(1, ULL) << 24) - #define ARCH_CAPS_GDS_CTRL (_AC(1, ULL) << 25) - #define ARCH_CAPS_GDS_NO (_AC(1, ULL) << 26) -+#define ARCH_CAPS_RFDS_NO (_AC(1, ULL) << 27) -+#define ARCH_CAPS_RFDS_CLEAR (_AC(1, ULL) << 28) - - #define MSR_FLUSH_CMD 0x0000010b - #define FLUSH_CMD_L1D (_AC(1, ULL) << 0) -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index a4afcd8570e2..8165379fed94 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -12,6 +12,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -435,7 +436,7 @@ static void __init print_details(enum ind_thunk thunk) - * Hardware read-only information, stating immunity to certain issues, or - * suggestions of which mitigation to use. - */ -- printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", -+ printk(" Hardware hints:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (caps & ARCH_CAPS_RDCL_NO) ? " RDCL_NO" : "", - (caps & ARCH_CAPS_EIBRS) ? " EIBRS" : "", - (caps & ARCH_CAPS_RSBA) ? " RSBA" : "", -@@ -451,6 +452,7 @@ static void __init print_details(enum ind_thunk thunk) - (caps & ARCH_CAPS_FB_CLEAR) ? " FB_CLEAR" : "", - (caps & ARCH_CAPS_PBRSB_NO) ? " PBRSB_NO" : "", - (caps & ARCH_CAPS_GDS_NO) ? " GDS_NO" : "", -+ (caps & ARCH_CAPS_RFDS_NO) ? " RFDS_NO" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS_ALWAYS)) ? " IBRS_ALWAYS" : "", - (e8b & cpufeat_mask(X86_FEATURE_STIBP_ALWAYS)) ? " STIBP_ALWAYS" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS_FAST)) ? " IBRS_FAST" : "", -@@ -461,7 +463,7 @@ static void __init print_details(enum ind_thunk thunk) - (e21a & cpufeat_mask(X86_FEATURE_SRSO_NO)) ? " SRSO_NO" : ""); - - /* Hardware features which need driving to mitigate issues. */ -- printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s%s\n", -+ printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (e8b & cpufeat_mask(X86_FEATURE_IBPB)) || - (_7d0 & cpufeat_mask(X86_FEATURE_IBRSB)) ? " IBPB" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBRS)) || -@@ -479,6 +481,7 @@ static void __init print_details(enum ind_thunk thunk) - (caps & ARCH_CAPS_TSX_CTRL) ? " TSX_CTRL" : "", - (caps & ARCH_CAPS_FB_CLEAR_CTRL) ? " FB_CLEAR_CTRL" : "", - (caps & ARCH_CAPS_GDS_CTRL) ? " GDS_CTRL" : "", -+ (caps & ARCH_CAPS_RFDS_CLEAR) ? " RFDS_CLEAR" : "", - (e21a & cpufeat_mask(X86_FEATURE_SBPB)) ? " SBPB" : ""); - - /* Compiled-in support which pertains to mitigations. */ -@@ -1347,6 +1350,83 @@ static __init void mds_calculations(void) - } - } - -+/* -+ * Register File Data Sampling affects Atom cores from the Goldmont to -+ * Gracemont microarchitectures. The March 2024 microcode adds RFDS_NO to -+ * some but not all unaffected parts, and RFDS_CLEAR to affected parts still -+ * in support. -+ * -+ * Alder Lake and Raptor Lake client CPUs have a mix of P cores -+ * (Golden/Raptor Cove, not vulnerable) and E cores (Gracemont, -+ * vulnerable), and both enumerate RFDS_CLEAR. -+ * -+ * Both exist in a Xeon SKU, which has the E cores (Gracemont) disabled by -+ * platform configuration, and enumerate RFDS_NO. -+ * -+ * With older parts, or with out-of-date microcode, synthesise RFDS_NO when -+ * safe to do so. -+ * -+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/register-file-data-sampling.html -+ */ -+static void __init rfds_calculations(void) -+{ -+ /* RFDS is only known to affect Intel Family 6 processors at this time. */ -+ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || -+ boot_cpu_data.x86 != 6 ) -+ return; -+ -+ /* -+ * If RFDS_NO or RFDS_CLEAR are visible, we've either got suitable -+ * microcode, or an RFDS-aware hypervisor is levelling us in a pool. -+ */ -+ if ( cpu_has_rfds_no || cpu_has_rfds_clear ) -+ return; -+ -+ /* If we're virtualised, don't attempt to synthesise RFDS_NO. */ -+ if ( cpu_has_hypervisor ) -+ return; -+ -+ /* -+ * Not all CPUs are expected to get a microcode update enumerating one of -+ * RFDS_{NO,CLEAR}, or we might have out-of-date microcode. -+ */ -+ switch ( boot_cpu_data.x86_model ) -+ { -+ case INTEL_FAM6_ALDERLAKE: -+ case INTEL_FAM6_RAPTORLAKE: -+ /* -+ * Alder Lake and Raptor Lake might be a client SKU (with the -+ * Gracemont cores active, and therefore vulnerable) or might be a -+ * server SKU (with the Gracemont cores disabled, and therefore not -+ * vulnerable). -+ * -+ * See if the CPU identifies as hybrid to distinguish the two cases. -+ */ -+ if ( !cpu_has_hybrid ) -+ break; -+ fallthrough; -+ case INTEL_FAM6_ALDERLAKE_L: -+ case INTEL_FAM6_RAPTORLAKE_P: -+ case INTEL_FAM6_RAPTORLAKE_S: -+ -+ case INTEL_FAM6_ATOM_GOLDMONT: /* Apollo Lake */ -+ case INTEL_FAM6_ATOM_GOLDMONT_D: /* Denverton */ -+ case INTEL_FAM6_ATOM_GOLDMONT_PLUS: /* Gemini Lake */ -+ case INTEL_FAM6_ATOM_TREMONT_D: /* Snow Ridge / Parker Ridge */ -+ case INTEL_FAM6_ATOM_TREMONT: /* Elkhart Lake */ -+ case INTEL_FAM6_ATOM_TREMONT_L: /* Jasper Lake */ -+ case INTEL_FAM6_ATOM_GRACEMONT: /* Alder Lake N */ -+ return; -+ } -+ -+ /* -+ * We appear to be on an unaffected CPU which didn't enumerate RFDS_NO, -+ * perhaps because of it's age or because of out-of-date microcode. -+ * Synthesise it. -+ */ -+ setup_force_cpu_cap(X86_FEATURE_RFDS_NO); -+} -+ - static bool __init cpu_has_gds(void) - { - /* -@@ -1860,6 +1940,7 @@ void __init init_speculation_mitigations(void) - * - * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/intel-analysis-microarchitectural-data-sampling.html - * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html -+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/register-file-data-sampling.html - * - * Relevant ucodes: - * -@@ -1889,8 +1970,12 @@ void __init init_speculation_mitigations(void) - * - * If FB_CLEAR is enumerated, L1D_FLUSH does not have the same scrubbing - * side effects as VERW and cannot be used in its place. -+ * -+ * - March 2023, for RFDS. Enumerate RFDS_CLEAR to mean that VERW now -+ * scrubs non-architectural entries from certain register files. - */ - mds_calculations(); -+ rfds_calculations(); - - /* - * Parts which enumerate FB_CLEAR are those with now-updated microcode -@@ -1922,15 +2007,19 @@ void __init init_speculation_mitigations(void) - * MLPDS/MFBDS when SMT is enabled. - */ - if ( opt_verw_pv == -1 ) -- opt_verw_pv = cpu_has_useful_md_clear; -+ opt_verw_pv = cpu_has_useful_md_clear || cpu_has_rfds_clear; - - if ( opt_verw_hvm == -1 ) -- opt_verw_hvm = cpu_has_useful_md_clear; -+ opt_verw_hvm = cpu_has_useful_md_clear || cpu_has_rfds_clear; - - /* - * If SMT is active, and we're protecting against MDS or MMIO stale data, - * we need to scrub before going idle as well as on return to guest. - * Various pipeline resources are repartitioned amongst non-idle threads. -+ * -+ * We don't need to scrub on idle for RFDS. There are no affected cores -+ * which support SMT, despite there being affected cores in hybrid systems -+ * which have SMT elsewhere in the platform. - */ - if ( ((cpu_has_useful_md_clear && (opt_verw_pv || opt_verw_hvm)) || - opt_verw_mmio) && hw_smt_enabled ) -@@ -1944,7 +2033,8 @@ void __init init_speculation_mitigations(void) - * It is only safe to use L1D_FLUSH in place of VERW when MD_CLEAR is the - * only *_CLEAR we can see. - */ -- if ( opt_l1d_flush && cpu_has_md_clear && !cpu_has_fb_clear ) -+ if ( opt_l1d_flush && cpu_has_md_clear && !cpu_has_fb_clear && -+ !cpu_has_rfds_clear ) - opt_verw_hvm = false; - - /* -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index 337aaa9c770b..8e17ef670fff 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -266,6 +266,7 @@ XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*!A VERW clears microarchitectural buffe - XEN_CPUFEATURE(RTM_ALWAYS_ABORT, 9*32+11) /*! June 2021 TSX defeaturing in microcode. */ - XEN_CPUFEATURE(TSX_FORCE_ABORT, 9*32+13) /* MSR_TSX_FORCE_ABORT.RTM_ABORT */ - XEN_CPUFEATURE(SERIALIZE, 9*32+14) /*A SERIALIZE insn */ -+XEN_CPUFEATURE(HYBRID, 9*32+15) /* Heterogeneous platform */ - XEN_CPUFEATURE(TSXLDTRK, 9*32+16) /*a TSX load tracking suspend/resume insns */ - XEN_CPUFEATURE(CET_IBT, 9*32+20) /* CET - Indirect Branch Tracking */ - XEN_CPUFEATURE(AVX512_FP16, 9*32+23) /*A AVX512 FP16 instructions */ -@@ -338,6 +339,8 @@ XEN_CPUFEATURE(OVRCLK_STATUS, 16*32+23) /* MSR_OVERCLOCKING_STATUS */ - XEN_CPUFEATURE(PBRSB_NO, 16*32+24) /*A No Post-Barrier RSB predictions */ - XEN_CPUFEATURE(GDS_CTRL, 16*32+25) /* MCU_OPT_CTRL.GDS_MIT_{DIS,LOCK} */ - XEN_CPUFEATURE(GDS_NO, 16*32+26) /*A No Gather Data Sampling */ -+XEN_CPUFEATURE(RFDS_NO, 16*32+27) /*A No Register File Data Sampling */ -+XEN_CPUFEATURE(RFDS_CLEAR, 16*32+28) /*!A Register File(s) cleared by VERW */ - - /* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 */ - diff --git a/xsa453-4.18-1.patch b/xsa453-4.18-1.patch deleted file mode 100644 index a3c0f05..0000000 --- a/xsa453-4.18-1.patch +++ /dev/null @@ -1,50 +0,0 @@ -From: Andrew Cooper -Subject: xen: Swap order of actions in the FREE*() macros - -Wherever possible, it is a good idea to NULL out the visible reference to an -object prior to freeing it. The FREE*() macros already collect together both -parts, making it easy to adjust. - -This has a marginal code generation improvement, as some of the calls to the -free() function can be tailcall optimised. - -No functional change. - -Signed-off-by: Andrew Cooper -Acked-by: Jan Beulich -(cherry picked from commit c4f427ec879e7c0df6d44d02561e8bee838a293e) - -diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h -index 8b9618609f77..8bc5f4249d1b 100644 ---- a/xen/include/xen/mm.h -+++ b/xen/include/xen/mm.h -@@ -91,8 +91,9 @@ bool scrub_free_pages(void); - - /* Free an allocation, and zero the pointer to it. */ - #define FREE_XENHEAP_PAGES(p, o) do { \ -- free_xenheap_pages(p, o); \ -+ void *_ptr_ = (p); \ - (p) = NULL; \ -+ free_xenheap_pages(_ptr_, o); \ - } while ( false ) - #define FREE_XENHEAP_PAGE(p) FREE_XENHEAP_PAGES(p, 0) - -diff --git a/xen/include/xen/xmalloc.h b/xen/include/xen/xmalloc.h -index 16979a117c6a..d857298011c1 100644 ---- a/xen/include/xen/xmalloc.h -+++ b/xen/include/xen/xmalloc.h -@@ -66,9 +66,10 @@ - extern void xfree(void *); - - /* Free an allocation, and zero the pointer to it. */ --#define XFREE(p) do { \ -- xfree(p); \ -- (p) = NULL; \ -+#define XFREE(p) do { \ -+ void *_ptr_ = (p); \ -+ (p) = NULL; \ -+ xfree(_ptr_); \ - } while ( false ) - - /* Underlying functions */ - diff --git a/xsa453-4.18-2.patch b/xsa453-4.18-2.patch deleted file mode 100644 index 01a7e05..0000000 --- a/xsa453-4.18-2.patch +++ /dev/null @@ -1,314 +0,0 @@ -From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= -Subject: x86/spinlock: introduce support for blocking speculation into - critical regions - -Introduce a new Kconfig option to block speculation into lock protected -critical regions. The Kconfig option is enabled by default, but the mitigation -won't be engaged unless it's explicitly enabled in the command line using -`spec-ctrl=lock-harden`. - -Convert the spinlock acquire macros into always-inline functions, and introduce -a speculation barrier after the lock has been taken. Note the speculation -barrier is not placed inside the implementation of the spin lock functions, as -to prevent speculation from falling through the call to the lock functions -resulting in the barrier also being skipped. - -trylock variants are protected using a construct akin to the existing -evaluate_nospec(). - -This patch only implements the speculation barrier for x86. - -Note spin locks are the only locking primitive taken care in this change, -further locking primitives will be adjusted by separate changes. - -This is part of XSA-453 / CVE-2024-2193 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -(cherry picked from commit 7ef0084418e188d05f338c3e028fbbe8b6924afa) - -diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc -index fbf16839249a..3f9f9167182f 100644 ---- a/docs/misc/xen-command-line.pandoc -+++ b/docs/misc/xen-command-line.pandoc -@@ -2373,7 +2373,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`). - > {msr-sc,rsb,verw,ibpb-entry}=|{pv,hvm}=, - > bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd, - > eager-fpu,l1d-flush,branch-harden,srb-lock, --> unpriv-mmio,gds-mit,div-scrub}= ]` -+> unpriv-mmio,gds-mit,div-scrub,lock-harden}= ]` - - Controls for speculative execution sidechannel mitigations. By default, Xen - will pick the most appropriate mitigations based on compiled in support, -@@ -2500,6 +2500,11 @@ On all hardware, the `div-scrub=` option can be used to force or prevent Xen - from mitigating the DIV-leakage vulnerability. By default, Xen will mitigate - DIV-leakage on hardware believed to be vulnerable. - -+If Xen is compiled with `CONFIG_SPECULATIVE_HARDEN_LOCK`, the `lock-harden=` -+boolean can be used to force or prevent Xen from using speculation barriers to -+protect lock critical regions. This mitigation won't be engaged by default, -+and needs to be explicitly enabled on the command line. -+ - ### sync_console - > `= ` - -diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h -index c3aad21c3b43..7e8221fd85dd 100644 ---- a/xen/arch/x86/include/asm/cpufeatures.h -+++ b/xen/arch/x86/include/asm/cpufeatures.h -@@ -24,7 +24,7 @@ XEN_CPUFEATURE(APERFMPERF, X86_SYNTH( 8)) /* APERFMPERF */ - XEN_CPUFEATURE(MFENCE_RDTSC, X86_SYNTH( 9)) /* MFENCE synchronizes RDTSC */ - XEN_CPUFEATURE(XEN_SMEP, X86_SYNTH(10)) /* SMEP gets used by Xen itself */ - XEN_CPUFEATURE(XEN_SMAP, X86_SYNTH(11)) /* SMAP gets used by Xen itself */ --/* Bit 12 unused. */ -+XEN_CPUFEATURE(SC_NO_LOCK_HARDEN, X86_SYNTH(12)) /* (Disable) Lock critical region hardening */ - XEN_CPUFEATURE(IND_THUNK_LFENCE, X86_SYNTH(13)) /* Use IND_THUNK_LFENCE */ - XEN_CPUFEATURE(IND_THUNK_JMP, X86_SYNTH(14)) /* Use IND_THUNK_JMP */ - XEN_CPUFEATURE(SC_NO_BRANCH_HARDEN, X86_SYNTH(15)) /* (Disable) Conditional branch hardening */ -diff --git a/xen/arch/x86/include/asm/nospec.h b/xen/arch/x86/include/asm/nospec.h -index 7150e76b87fb..0725839e1982 100644 ---- a/xen/arch/x86/include/asm/nospec.h -+++ b/xen/arch/x86/include/asm/nospec.h -@@ -38,6 +38,32 @@ static always_inline void block_speculation(void) - barrier_nospec_true(); - } - -+static always_inline void arch_block_lock_speculation(void) -+{ -+ alternative("lfence", "", X86_FEATURE_SC_NO_LOCK_HARDEN); -+} -+ -+/* Allow to insert a read memory barrier into conditionals */ -+static always_inline bool barrier_lock_true(void) -+{ -+ alternative("lfence #nospec-true", "", X86_FEATURE_SC_NO_LOCK_HARDEN); -+ return true; -+} -+ -+static always_inline bool barrier_lock_false(void) -+{ -+ alternative("lfence #nospec-false", "", X86_FEATURE_SC_NO_LOCK_HARDEN); -+ return false; -+} -+ -+static always_inline bool arch_lock_evaluate_nospec(bool condition) -+{ -+ if ( condition ) -+ return barrier_lock_true(); -+ else -+ return barrier_lock_false(); -+} -+ - #endif /* _ASM_X86_NOSPEC_H */ - - /* -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 8165379fed94..5dfc4ed69ec5 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -53,6 +53,7 @@ int8_t __read_mostly opt_eager_fpu = -1; - int8_t __read_mostly opt_l1d_flush = -1; - static bool __initdata opt_branch_harden = - IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH); -+static bool __initdata opt_lock_harden; - - bool __initdata bsp_delay_spec_ctrl; - uint8_t __read_mostly default_xen_spec_ctrl; -@@ -121,6 +122,7 @@ static int __init cf_check parse_spec_ctrl(const char *s) - opt_ssbd = false; - opt_l1d_flush = 0; - opt_branch_harden = false; -+ opt_lock_harden = false; - opt_srb_lock = 0; - opt_unpriv_mmio = false; - opt_gds_mit = 0; -@@ -286,6 +288,16 @@ static int __init cf_check parse_spec_ctrl(const char *s) - rc = -EINVAL; - } - } -+ else if ( (val = parse_boolean("lock-harden", s, ss)) >= 0 ) -+ { -+ if ( IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_LOCK) ) -+ opt_lock_harden = val; -+ else -+ { -+ no_config_param("SPECULATIVE_HARDEN_LOCK", "spec-ctrl", s, ss); -+ rc = -EINVAL; -+ } -+ } - else if ( (val = parse_boolean("srb-lock", s, ss)) >= 0 ) - opt_srb_lock = val; - else if ( (val = parse_boolean("unpriv-mmio", s, ss)) >= 0 ) -@@ -488,7 +500,8 @@ static void __init print_details(enum ind_thunk thunk) - if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) || - IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_ARRAY) || - IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_BRANCH) || -- IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS) ) -+ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS) || -+ IS_ENABLED(CONFIG_SPECULATIVE_HARDEN_LOCK) ) - printk(" Compiled-in support:" - #ifdef CONFIG_INDIRECT_THUNK - " INDIRECT_THUNK" -@@ -504,11 +517,14 @@ static void __init print_details(enum ind_thunk thunk) - #endif - #ifdef CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS - " HARDEN_GUEST_ACCESS" -+#endif -+#ifdef CONFIG_SPECULATIVE_HARDEN_LOCK -+ " HARDEN_LOCK" - #endif - "\n"); - - /* Settings for Xen's protection, irrespective of guests. */ -- printk(" Xen settings: %s%sSPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n", -+ printk(" Xen settings: %s%sSPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s%s\n", - thunk != THUNK_NONE ? "BTI-Thunk: " : "", - thunk == THUNK_NONE ? "" : - thunk == THUNK_RETPOLINE ? "RETPOLINE, " : -@@ -535,7 +551,8 @@ static void __init print_details(enum ind_thunk thunk) - opt_verw_pv || opt_verw_hvm || - opt_verw_mmio ? " VERW" : "", - opt_div_scrub ? " DIV" : "", -- opt_branch_harden ? " BRANCH_HARDEN" : ""); -+ opt_branch_harden ? " BRANCH_HARDEN" : "", -+ opt_lock_harden ? " LOCK_HARDEN" : ""); - - /* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */ - if ( cpu_has_bug_l1tf || opt_pv_l1tf_hwdom || opt_pv_l1tf_domu ) -@@ -1918,6 +1935,9 @@ void __init init_speculation_mitigations(void) - if ( !opt_branch_harden ) - setup_force_cpu_cap(X86_FEATURE_SC_NO_BRANCH_HARDEN); - -+ if ( !opt_lock_harden ) -+ setup_force_cpu_cap(X86_FEATURE_SC_NO_LOCK_HARDEN); -+ - /* - * We do not disable HT by default on affected hardware. - * -diff --git a/xen/common/Kconfig b/xen/common/Kconfig -index 4d6fe051641d..3361a6d89257 100644 ---- a/xen/common/Kconfig -+++ b/xen/common/Kconfig -@@ -188,6 +188,23 @@ config SPECULATIVE_HARDEN_GUEST_ACCESS - - If unsure, say Y. - -+config SPECULATIVE_HARDEN_LOCK -+ bool "Speculative lock context hardening" -+ default y -+ depends on X86 -+ help -+ Contemporary processors may use speculative execution as a -+ performance optimisation, but this can potentially be abused by an -+ attacker to leak data via speculative sidechannels. -+ -+ One source of data leakage is via speculative accesses to lock -+ critical regions. -+ -+ This option is disabled by default at run time, and needs to be -+ enabled on the command line. -+ -+ If unsure, say Y. -+ - endmenu - - config DIT_DEFAULT -diff --git a/xen/include/xen/nospec.h b/xen/include/xen/nospec.h -index 76255bc46efe..455284640396 100644 ---- a/xen/include/xen/nospec.h -+++ b/xen/include/xen/nospec.h -@@ -70,6 +70,21 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, - #define array_access_nospec(array, index) \ - (array)[array_index_nospec(index, ARRAY_SIZE(array))] - -+static always_inline void block_lock_speculation(void) -+{ -+#ifdef CONFIG_SPECULATIVE_HARDEN_LOCK -+ arch_block_lock_speculation(); -+#endif -+} -+ -+static always_inline bool lock_evaluate_nospec(bool condition) -+{ -+#ifdef CONFIG_SPECULATIVE_HARDEN_LOCK -+ return arch_lock_evaluate_nospec(condition); -+#endif -+ return condition; -+} -+ - #endif /* XEN_NOSPEC_H */ - - /* -diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h -index e7a1c1aa8988..28fce5615e5c 100644 ---- a/xen/include/xen/spinlock.h -+++ b/xen/include/xen/spinlock.h -@@ -1,6 +1,7 @@ - #ifndef __SPINLOCK_H__ - #define __SPINLOCK_H__ - -+#include - #include - #include - -@@ -195,13 +196,30 @@ int _spin_trylock_recursive(spinlock_t *lock); - void _spin_lock_recursive(spinlock_t *lock); - void _spin_unlock_recursive(spinlock_t *lock); - --#define spin_lock(l) _spin_lock(l) --#define spin_lock_cb(l, c, d) _spin_lock_cb(l, c, d) --#define spin_lock_irq(l) _spin_lock_irq(l) -+static always_inline void spin_lock(spinlock_t *l) -+{ -+ _spin_lock(l); -+ block_lock_speculation(); -+} -+ -+static always_inline void spin_lock_cb(spinlock_t *l, void (*c)(void *data), -+ void *d) -+{ -+ _spin_lock_cb(l, c, d); -+ block_lock_speculation(); -+} -+ -+static always_inline void spin_lock_irq(spinlock_t *l) -+{ -+ _spin_lock_irq(l); -+ block_lock_speculation(); -+} -+ - #define spin_lock_irqsave(l, f) \ - ({ \ - BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \ - ((f) = _spin_lock_irqsave(l)); \ -+ block_lock_speculation(); \ - }) - - #define spin_unlock(l) _spin_unlock(l) -@@ -209,7 +227,7 @@ void _spin_unlock_recursive(spinlock_t *lock); - #define spin_unlock_irqrestore(l, f) _spin_unlock_irqrestore(l, f) - - #define spin_is_locked(l) _spin_is_locked(l) --#define spin_trylock(l) _spin_trylock(l) -+#define spin_trylock(l) lock_evaluate_nospec(_spin_trylock(l)) - - #define spin_trylock_irqsave(lock, flags) \ - ({ \ -@@ -230,8 +248,15 @@ void _spin_unlock_recursive(spinlock_t *lock); - * are any critical regions that cannot form part of such a set, they can use - * standard spin_[un]lock(). - */ --#define spin_trylock_recursive(l) _spin_trylock_recursive(l) --#define spin_lock_recursive(l) _spin_lock_recursive(l) -+#define spin_trylock_recursive(l) \ -+ lock_evaluate_nospec(_spin_trylock_recursive(l)) -+ -+static always_inline void spin_lock_recursive(spinlock_t *l) -+{ -+ _spin_lock_recursive(l); -+ block_lock_speculation(); -+} -+ - #define spin_unlock_recursive(l) _spin_unlock_recursive(l) - - #endif /* __SPINLOCK_H__ */ diff --git a/xsa453-4.18-3.patch b/xsa453-4.18-3.patch deleted file mode 100644 index ecaff41..0000000 --- a/xsa453-4.18-3.patch +++ /dev/null @@ -1,113 +0,0 @@ -From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= -Subject: rwlock: introduce support for blocking speculation into critical - regions - -Introduce inline wrappers as required and add direct calls to -block_lock_speculation() in order to prevent speculation into the rwlock -protected critical regions. - -Note the rwlock primitives are adjusted to use the non speculation safe variants -of the spinlock handlers, as a speculation barrier is added in the rwlock -calling wrappers. - -trylock variants are protected by using lock_evaluate_nospec(). - -This is part of XSA-453 / CVE-2024-2193 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -(cherry picked from commit a1fb15f61692b1fa9945fc51f55471ace49cdd59) - -diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c -index 18224a4bb5d6..290602936df6 100644 ---- a/xen/common/rwlock.c -+++ b/xen/common/rwlock.c -@@ -34,8 +34,11 @@ void queue_read_lock_slowpath(rwlock_t *lock) - - /* - * Put the reader into the wait queue. -+ * -+ * Use the speculation unsafe helper, as it's the caller responsibility to -+ * issue a speculation barrier if required. - */ -- spin_lock(&lock->lock); -+ _spin_lock(&lock->lock); - - /* - * At the head of the wait queue now, wait until the writer state -@@ -66,8 +69,13 @@ void queue_write_lock_slowpath(rwlock_t *lock) - { - u32 cnts; - -- /* Put the writer into the wait queue. */ -- spin_lock(&lock->lock); -+ /* -+ * Put the writer into the wait queue. -+ * -+ * Use the speculation unsafe helper, as it's the caller responsibility to -+ * issue a speculation barrier if required. -+ */ -+ _spin_lock(&lock->lock); - - /* Try to acquire the lock directly if no reader is present. */ - if ( !atomic_read(&lock->cnts) && -diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h -index e0d2b41c5c7e..9a0d3ec23847 100644 ---- a/xen/include/xen/rwlock.h -+++ b/xen/include/xen/rwlock.h -@@ -259,27 +259,49 @@ static inline int _rw_is_write_locked(const rwlock_t *lock) - return (atomic_read(&lock->cnts) & _QW_WMASK) == _QW_LOCKED; - } - --#define read_lock(l) _read_lock(l) --#define read_lock_irq(l) _read_lock_irq(l) -+static always_inline void read_lock(rwlock_t *l) -+{ -+ _read_lock(l); -+ block_lock_speculation(); -+} -+ -+static always_inline void read_lock_irq(rwlock_t *l) -+{ -+ _read_lock_irq(l); -+ block_lock_speculation(); -+} -+ - #define read_lock_irqsave(l, f) \ - ({ \ - BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \ - ((f) = _read_lock_irqsave(l)); \ -+ block_lock_speculation(); \ - }) - - #define read_unlock(l) _read_unlock(l) - #define read_unlock_irq(l) _read_unlock_irq(l) - #define read_unlock_irqrestore(l, f) _read_unlock_irqrestore(l, f) --#define read_trylock(l) _read_trylock(l) -+#define read_trylock(l) lock_evaluate_nospec(_read_trylock(l)) -+ -+static always_inline void write_lock(rwlock_t *l) -+{ -+ _write_lock(l); -+ block_lock_speculation(); -+} -+ -+static always_inline void write_lock_irq(rwlock_t *l) -+{ -+ _write_lock_irq(l); -+ block_lock_speculation(); -+} - --#define write_lock(l) _write_lock(l) --#define write_lock_irq(l) _write_lock_irq(l) - #define write_lock_irqsave(l, f) \ - ({ \ - BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \ - ((f) = _write_lock_irqsave(l)); \ -+ block_lock_speculation(); \ - }) --#define write_trylock(l) _write_trylock(l) -+#define write_trylock(l) lock_evaluate_nospec(_write_trylock(l)) - - #define write_unlock(l) _write_unlock(l) - #define write_unlock_irq(l) _write_unlock_irq(l) diff --git a/xsa453-4.18-4.patch b/xsa453-4.18-4.patch deleted file mode 100644 index a3c6b3c..0000000 --- a/xsa453-4.18-4.patch +++ /dev/null @@ -1,75 +0,0 @@ -From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= -Subject: percpu-rwlock: introduce support for blocking speculation into - critical regions - -Add direct calls to block_lock_speculation() where required in order to prevent -speculation into the lock protected critical regions. Also convert -_percpu_read_lock() from inline to always_inline. - -Note that _percpu_write_lock() has been modified the use the non speculation -safe of the locking primites, as a speculation is added unconditionally by the -calling wrapper. - -This is part of XSA-453 / CVE-2024-2193 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -(cherry picked from commit f218daf6d3a3b847736d37c6a6b76031a0d08441) - -diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c -index 290602936df6..f5a249bcc240 100644 ---- a/xen/common/rwlock.c -+++ b/xen/common/rwlock.c -@@ -129,8 +129,12 @@ void _percpu_write_lock(percpu_rwlock_t **per_cpudata, - /* - * First take the write lock to protect against other writers or slow - * path readers. -+ * -+ * Note we use the speculation unsafe variant of write_lock(), as the -+ * calling wrapper already adds a speculation barrier after the lock has -+ * been taken. - */ -- write_lock(&percpu_rwlock->rwlock); -+ _write_lock(&percpu_rwlock->rwlock); - - /* Now set the global variable so that readers start using read_lock. */ - percpu_rwlock->writer_activating = 1; -diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h -index 9a0d3ec23847..9e35ee2edf8f 100644 ---- a/xen/include/xen/rwlock.h -+++ b/xen/include/xen/rwlock.h -@@ -338,8 +338,8 @@ static inline void _percpu_rwlock_owner_check(percpu_rwlock_t **per_cpudata, - #define percpu_rwlock_resource_init(l, owner) \ - (*(l) = (percpu_rwlock_t)PERCPU_RW_LOCK_UNLOCKED(&get_per_cpu_var(owner))) - --static inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata, -- percpu_rwlock_t *percpu_rwlock) -+static always_inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata, -+ percpu_rwlock_t *percpu_rwlock) - { - /* Validate the correct per_cpudata variable has been provided. */ - _percpu_rwlock_owner_check(per_cpudata, percpu_rwlock); -@@ -374,6 +374,8 @@ static inline void _percpu_read_lock(percpu_rwlock_t **per_cpudata, - } - else - { -+ /* Other branch already has a speculation barrier in read_lock(). */ -+ block_lock_speculation(); - /* All other paths have implicit check_lock() calls via read_lock(). */ - check_lock(&percpu_rwlock->rwlock.lock.debug, false); - } -@@ -430,8 +432,12 @@ static inline void _percpu_write_unlock(percpu_rwlock_t **per_cpudata, - _percpu_read_lock(&get_per_cpu_var(percpu), lock) - #define percpu_read_unlock(percpu, lock) \ - _percpu_read_unlock(&get_per_cpu_var(percpu), lock) --#define percpu_write_lock(percpu, lock) \ -- _percpu_write_lock(&get_per_cpu_var(percpu), lock) -+ -+#define percpu_write_lock(percpu, lock) \ -+({ \ -+ _percpu_write_lock(&get_per_cpu_var(percpu), lock); \ -+ block_lock_speculation(); \ -+}) - #define percpu_write_unlock(percpu, lock) \ - _percpu_write_unlock(&get_per_cpu_var(percpu), lock) - diff --git a/xsa453-4.18-5.patch b/xsa453-4.18-5.patch deleted file mode 100644 index aab46e3..0000000 --- a/xsa453-4.18-5.patch +++ /dev/null @@ -1,382 +0,0 @@ -From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= -Subject: locking: attempt to ensure lock wrappers are always inline - -In order to prevent the locking speculation barriers from being inside of -`call`ed functions that could be speculatively bypassed. - -While there also add an extra locking barrier to _mm_write_lock() in the branch -taken when the lock is already held. - -Note some functions are switched to use the unsafe variants (without speculation -barrier) of the locking primitives, but a speculation barrier is always added -to the exposed public lock wrapping helper. That's the case with -sched_spin_lock_double() or pcidevs_lock() for example. - -This is part of XSA-453 / CVE-2024-2193 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -(cherry picked from commit 197ecd838a2aaf959a469df3696d4559c4f8b762) - -diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c -index 8f53e88d6706..e1d6845a2844 100644 ---- a/xen/arch/x86/hvm/vpt.c -+++ b/xen/arch/x86/hvm/vpt.c -@@ -150,7 +150,7 @@ static int pt_irq_masked(struct periodic_time *pt) - * pt->vcpu field, because another thread holding the pt_migrate lock - * may already be spinning waiting for your vcpu lock. - */ --static void pt_vcpu_lock(struct vcpu *v) -+static always_inline void pt_vcpu_lock(struct vcpu *v) - { - spin_lock(&v->arch.hvm.tm_lock); - } -@@ -169,9 +169,13 @@ static void pt_vcpu_unlock(struct vcpu *v) - * need to take an additional lock that protects against pt->vcpu - * changing. - */ --static void pt_lock(struct periodic_time *pt) -+static always_inline void pt_lock(struct periodic_time *pt) - { -- read_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate); -+ /* -+ * Use the speculation unsafe variant for the first lock, as the following -+ * lock taking helper already includes a speculation barrier. -+ */ -+ _read_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate); - spin_lock(&pt->vcpu->arch.hvm.tm_lock); - } - -diff --git a/xen/arch/x86/include/asm/irq.h b/xen/arch/x86/include/asm/irq.h -index a87af47ece22..465ab39bb041 100644 ---- a/xen/arch/x86/include/asm/irq.h -+++ b/xen/arch/x86/include/asm/irq.h -@@ -174,6 +174,7 @@ void cf_check irq_complete_move(struct irq_desc *desc); - - extern struct irq_desc *irq_desc; - -+/* Not speculation safe, only used for AP bringup. */ - void lock_vector_lock(void); - void unlock_vector_lock(void); - -diff --git a/xen/arch/x86/mm/mm-locks.h b/xen/arch/x86/mm/mm-locks.h -index 5a3f96fbaadd..5ec080c02fd8 100644 ---- a/xen/arch/x86/mm/mm-locks.h -+++ b/xen/arch/x86/mm/mm-locks.h -@@ -74,8 +74,8 @@ static inline void _set_lock_level(int l) - this_cpu(mm_lock_level) = l; - } - --static inline void _mm_lock(const struct domain *d, mm_lock_t *l, -- const char *func, int level, int rec) -+static always_inline void _mm_lock(const struct domain *d, mm_lock_t *l, -+ const char *func, int level, int rec) - { - if ( !((mm_locked_by_me(l)) && rec) ) - _check_lock_level(d, level); -@@ -125,8 +125,8 @@ static inline int mm_write_locked_by_me(mm_rwlock_t *l) - return (l->locker == get_processor_id()); - } - --static inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l, -- const char *func, int level) -+static always_inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l, -+ const char *func, int level) - { - if ( !mm_write_locked_by_me(l) ) - { -@@ -137,6 +137,8 @@ static inline void _mm_write_lock(const struct domain *d, mm_rwlock_t *l, - l->unlock_level = _get_lock_level(); - _set_lock_level(_lock_level(d, level)); - } -+ else -+ block_speculation(); - l->recurse_count++; - } - -@@ -150,8 +152,8 @@ static inline void mm_write_unlock(mm_rwlock_t *l) - percpu_write_unlock(p2m_percpu_rwlock, &l->lock); - } - --static inline void _mm_read_lock(const struct domain *d, mm_rwlock_t *l, -- int level) -+static always_inline void _mm_read_lock(const struct domain *d, mm_rwlock_t *l, -+ int level) - { - _check_lock_level(d, level); - percpu_read_lock(p2m_percpu_rwlock, &l->lock); -@@ -166,15 +168,15 @@ static inline void mm_read_unlock(mm_rwlock_t *l) - - /* This wrapper uses the line number to express the locking order below */ - #define declare_mm_lock(name) \ -- static inline void mm_lock_##name(const struct domain *d, mm_lock_t *l, \ -- const char *func, int rec) \ -+ static always_inline void mm_lock_##name( \ -+ const struct domain *d, mm_lock_t *l, const char *func, int rec) \ - { _mm_lock(d, l, func, MM_LOCK_ORDER_##name, rec); } - #define declare_mm_rwlock(name) \ -- static inline void mm_write_lock_##name(const struct domain *d, \ -- mm_rwlock_t *l, const char *func) \ -+ static always_inline void mm_write_lock_##name( \ -+ const struct domain *d, mm_rwlock_t *l, const char *func) \ - { _mm_write_lock(d, l, func, MM_LOCK_ORDER_##name); } \ -- static inline void mm_read_lock_##name(const struct domain *d, \ -- mm_rwlock_t *l) \ -+ static always_inline void mm_read_lock_##name(const struct domain *d, \ -+ mm_rwlock_t *l) \ - { _mm_read_lock(d, l, MM_LOCK_ORDER_##name); } - /* These capture the name of the calling function */ - #define mm_lock(name, d, l) mm_lock_##name(d, l, __func__, 0) -@@ -309,7 +311,7 @@ declare_mm_lock(altp2mlist) - #define MM_LOCK_ORDER_altp2m 40 - declare_mm_rwlock(altp2m); - --static inline void p2m_lock(struct p2m_domain *p) -+static always_inline void p2m_lock(struct p2m_domain *p) - { - if ( p2m_is_altp2m(p) ) - mm_write_lock(altp2m, p->domain, &p->lock); -diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c -index 9969eb45fa8c..9be67b63ce3e 100644 ---- a/xen/arch/x86/mm/p2m-pod.c -+++ b/xen/arch/x86/mm/p2m-pod.c -@@ -24,7 +24,7 @@ - #define superpage_aligned(_x) (((_x)&(SUPERPAGE_PAGES-1))==0) - - /* Enforce lock ordering when grabbing the "external" page_alloc lock */ --static inline void lock_page_alloc(struct p2m_domain *p2m) -+static always_inline void lock_page_alloc(struct p2m_domain *p2m) - { - page_alloc_mm_pre_lock(p2m->domain); - spin_lock(&(p2m->domain->page_alloc_lock)); -diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c -index a7a004a08429..66f924a7b091 100644 ---- a/xen/common/event_channel.c -+++ b/xen/common/event_channel.c -@@ -45,7 +45,7 @@ - * just assume the event channel is free or unbound at the moment when the - * evtchn_read_trylock() returns false. - */ --static inline void evtchn_write_lock(struct evtchn *evtchn) -+static always_inline void evtchn_write_lock(struct evtchn *evtchn) - { - write_lock(&evtchn->lock); - -@@ -351,7 +351,8 @@ int evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc, evtchn_port_t port) - return rc; - } - --static void double_evtchn_lock(struct evtchn *lchn, struct evtchn *rchn) -+static always_inline void double_evtchn_lock(struct evtchn *lchn, -+ struct evtchn *rchn) - { - ASSERT(lchn != rchn); - -diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c -index 89b7811c51c3..934924cbda66 100644 ---- a/xen/common/grant_table.c -+++ b/xen/common/grant_table.c -@@ -403,7 +403,7 @@ static inline void act_set_gfn(struct active_grant_entry *act, gfn_t gfn) - - static DEFINE_PERCPU_RWLOCK_GLOBAL(grant_rwlock); - --static inline void grant_read_lock(struct grant_table *gt) -+static always_inline void grant_read_lock(struct grant_table *gt) - { - percpu_read_lock(grant_rwlock, >->lock); - } -@@ -413,7 +413,7 @@ static inline void grant_read_unlock(struct grant_table *gt) - percpu_read_unlock(grant_rwlock, >->lock); - } - --static inline void grant_write_lock(struct grant_table *gt) -+static always_inline void grant_write_lock(struct grant_table *gt) - { - percpu_write_lock(grant_rwlock, >->lock); - } -@@ -450,7 +450,7 @@ nr_active_grant_frames(struct grant_table *gt) - return num_act_frames_from_sha_frames(nr_grant_frames(gt)); - } - --static inline struct active_grant_entry * -+static always_inline struct active_grant_entry * - active_entry_acquire(struct grant_table *t, grant_ref_t e) - { - struct active_grant_entry *act; -diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c -index 901782bbb416..34ad39b9ad0b 100644 ---- a/xen/common/sched/core.c -+++ b/xen/common/sched/core.c -@@ -348,23 +348,28 @@ uint64_t get_cpu_idle_time(unsigned int cpu) - * This avoids dead- or live-locks when this code is running on both - * cpus at the same time. - */ --static void sched_spin_lock_double(spinlock_t *lock1, spinlock_t *lock2, -- unsigned long *flags) -+static always_inline void sched_spin_lock_double( -+ spinlock_t *lock1, spinlock_t *lock2, unsigned long *flags) - { -+ /* -+ * In order to avoid extra overhead, use the locking primitives without the -+ * speculation barrier, and introduce a single barrier here. -+ */ - if ( lock1 == lock2 ) - { -- spin_lock_irqsave(lock1, *flags); -+ *flags = _spin_lock_irqsave(lock1); - } - else if ( lock1 < lock2 ) - { -- spin_lock_irqsave(lock1, *flags); -- spin_lock(lock2); -+ *flags = _spin_lock_irqsave(lock1); -+ _spin_lock(lock2); - } - else - { -- spin_lock_irqsave(lock2, *flags); -- spin_lock(lock1); -+ *flags = _spin_lock_irqsave(lock2); -+ _spin_lock(lock1); - } -+ block_lock_speculation(); - } - - static void sched_spin_unlock_double(spinlock_t *lock1, spinlock_t *lock2, -diff --git a/xen/common/sched/private.h b/xen/common/sched/private.h -index c516976c3740..3b97f1576782 100644 ---- a/xen/common/sched/private.h -+++ b/xen/common/sched/private.h -@@ -207,8 +207,24 @@ DECLARE_PER_CPU(cpumask_t, cpumask_scratch); - #define cpumask_scratch (&this_cpu(cpumask_scratch)) - #define cpumask_scratch_cpu(c) (&per_cpu(cpumask_scratch, c)) - -+/* -+ * Deal with _spin_lock_irqsave() returning the flags value instead of storing -+ * it in a passed parameter. -+ */ -+#define _sched_spinlock0(lock, irq) _spin_lock##irq(lock) -+#define _sched_spinlock1(lock, irq, arg) ({ \ -+ BUILD_BUG_ON(sizeof(arg) != sizeof(unsigned long)); \ -+ (arg) = _spin_lock##irq(lock); \ -+}) -+ -+#define _sched_spinlock__(nr) _sched_spinlock ## nr -+#define _sched_spinlock_(nr) _sched_spinlock__(nr) -+#define _sched_spinlock(lock, irq, args...) \ -+ _sched_spinlock_(count_args(args))(lock, irq, ## args) -+ - #define sched_lock(kind, param, cpu, irq, arg...) \ --static inline spinlock_t *kind##_schedule_lock##irq(param EXTRA_TYPE(arg)) \ -+static always_inline spinlock_t \ -+*kind##_schedule_lock##irq(param EXTRA_TYPE(arg)) \ - { \ - for ( ; ; ) \ - { \ -@@ -220,10 +236,16 @@ static inline spinlock_t *kind##_schedule_lock##irq(param EXTRA_TYPE(arg)) \ - * \ - * It may also be the case that v->processor may change but the \ - * lock may be the same; this will succeed in that case. \ -+ * \ -+ * Use the speculation unsafe locking helper, there's a speculation \ -+ * barrier before returning to the caller. \ - */ \ -- spin_lock##irq(lock, ## arg); \ -+ _sched_spinlock(lock, irq, ## arg); \ - if ( likely(lock == get_sched_res(cpu)->schedule_lock) ) \ -+ { \ -+ block_lock_speculation(); \ - return lock; \ -+ } \ - spin_unlock##irq(lock, ## arg); \ - } \ - } -diff --git a/xen/common/timer.c b/xen/common/timer.c -index 0fddfa74879e..38eb5fd20d36 100644 ---- a/xen/common/timer.c -+++ b/xen/common/timer.c -@@ -239,7 +239,7 @@ static inline void deactivate_timer(struct timer *timer) - list_add(&timer->inactive, &per_cpu(timers, timer->cpu).inactive); - } - --static inline bool_t timer_lock(struct timer *timer) -+static inline bool_t timer_lock_unsafe(struct timer *timer) - { - unsigned int cpu; - -@@ -253,7 +253,8 @@ static inline bool_t timer_lock(struct timer *timer) - rcu_read_unlock(&timer_cpu_read_lock); - return 0; - } -- spin_lock(&per_cpu(timers, cpu).lock); -+ /* Use the speculation unsafe variant, the wrapper has the barrier. */ -+ _spin_lock(&per_cpu(timers, cpu).lock); - if ( likely(timer->cpu == cpu) ) - break; - spin_unlock(&per_cpu(timers, cpu).lock); -@@ -266,8 +267,9 @@ static inline bool_t timer_lock(struct timer *timer) - #define timer_lock_irqsave(t, flags) ({ \ - bool_t __x; \ - local_irq_save(flags); \ -- if ( !(__x = timer_lock(t)) ) \ -+ if ( !(__x = timer_lock_unsafe(t)) ) \ - local_irq_restore(flags); \ -+ block_lock_speculation(); \ - __x; \ - }) - -diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c -index e99837b6e141..2a1e7ee89a5d 100644 ---- a/xen/drivers/passthrough/pci.c -+++ b/xen/drivers/passthrough/pci.c -@@ -52,9 +52,10 @@ struct pci_seg { - - static spinlock_t _pcidevs_lock = SPIN_LOCK_UNLOCKED; - --void pcidevs_lock(void) -+/* Do not use, as it has no speculation barrier, use pcidevs_lock() instead. */ -+void pcidevs_lock_unsafe(void) - { -- spin_lock_recursive(&_pcidevs_lock); -+ _spin_lock_recursive(&_pcidevs_lock); - } - - void pcidevs_unlock(void) -diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h -index 8e509e078475..f1472ea1ebe5 100644 ---- a/xen/include/xen/event.h -+++ b/xen/include/xen/event.h -@@ -114,12 +114,12 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); - #define bucket_from_port(d, p) \ - ((group_from_port(d, p))[((p) % EVTCHNS_PER_GROUP) / EVTCHNS_PER_BUCKET]) - --static inline void evtchn_read_lock(struct evtchn *evtchn) -+static always_inline void evtchn_read_lock(struct evtchn *evtchn) - { - read_lock(&evtchn->lock); - } - --static inline bool evtchn_read_trylock(struct evtchn *evtchn) -+static always_inline bool evtchn_read_trylock(struct evtchn *evtchn) - { - return read_trylock(&evtchn->lock); - } -diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h -index 251b8761a8e9..a71bed36be29 100644 ---- a/xen/include/xen/pci.h -+++ b/xen/include/xen/pci.h -@@ -155,8 +155,12 @@ struct pci_dev { - * devices, it also sync the access to the msi capability that is not - * interrupt handling related (the mask bit register). - */ -- --void pcidevs_lock(void); -+void pcidevs_lock_unsafe(void); -+static always_inline void pcidevs_lock(void) -+{ -+ pcidevs_lock_unsafe(); -+ block_lock_speculation(); -+} - void pcidevs_unlock(void); - bool __must_check pcidevs_locked(void); - diff --git a/xsa453-4.18-6.patch b/xsa453-4.18-6.patch deleted file mode 100644 index e8104c5..0000000 --- a/xsa453-4.18-6.patch +++ /dev/null @@ -1,61 +0,0 @@ -From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= -Subject: x86/mm: add speculation barriers to open coded locks - -Add a speculation barrier to the clearly identified open-coded lock taking -functions. - -Note that the memory sharing page_lock() replacement (_page_lock()) is left -as-is, as the code is experimental and not security supported. - -This is part of XSA-453 / CVE-2024-2193 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -(cherry picked from commit 42a572a38e22a97d86a4b648a22597628d5b42e4) - -diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h -index 05dfe35502c8..d1b1fee99b7d 100644 ---- a/xen/arch/x86/include/asm/mm.h -+++ b/xen/arch/x86/include/asm/mm.h -@@ -399,7 +399,9 @@ const struct platform_bad_page *get_platform_badpages(unsigned int *array_size); - * The use of PGT_locked in mem_sharing does not collide, since mem_sharing is - * only supported for hvm guests, which do not have PV PTEs updated. - */ --int page_lock(struct page_info *page); -+int page_lock_unsafe(struct page_info *page); -+#define page_lock(pg) lock_evaluate_nospec(page_lock_unsafe(pg)) -+ - void page_unlock(struct page_info *page); - - void put_page_type(struct page_info *page); -diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c -index ab0acbfea6e5..000fd0fb558b 100644 ---- a/xen/arch/x86/mm.c -+++ b/xen/arch/x86/mm.c -@@ -2017,7 +2017,7 @@ static inline bool current_locked_page_ne_check(struct page_info *page) { - #define current_locked_page_ne_check(x) true - #endif - --int page_lock(struct page_info *page) -+int page_lock_unsafe(struct page_info *page) - { - unsigned long x, nx; - -@@ -2078,7 +2078,7 @@ void page_unlock(struct page_info *page) - * l3t_lock(), so to avoid deadlock we must avoid grabbing them in - * reverse order. - */ --static void l3t_lock(struct page_info *page) -+static always_inline void l3t_lock(struct page_info *page) - { - unsigned long x, nx; - -@@ -2087,6 +2087,8 @@ static void l3t_lock(struct page_info *page) - cpu_relax(); - nx = x | PGT_locked; - } while ( cmpxchg(&page->u.inuse.type_info, x, nx) != x ); -+ -+ block_lock_speculation(); - } - - static void l3t_unlock(struct page_info *page) diff --git a/xsa453-4.18-7.patch b/xsa453-4.18-7.patch deleted file mode 100644 index 48f0bf9..0000000 --- a/xsa453-4.18-7.patch +++ /dev/null @@ -1,201 +0,0 @@ -From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= -Subject: x86: protect conditional lock taking from speculative execution - -Conditionally taken locks that use the pattern: - -if ( lock ) - spin_lock(...); - -Need an else branch in order to issue an speculation barrier in the else case, -just like it's done in case the lock needs to be acquired. - -eval_nospec() could be used on the condition itself, but that would result in a -double barrier on the branch where the lock is taken. - -Introduce a new pair of helpers, {gfn,spin}_lock_if() that can be used to -conditionally take a lock in a speculation safe way. - -This is part of XSA-453 / CVE-2024-2193 - -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -(cherry picked from commit 03cf7ca23e0e876075954c558485b267b7d02406) - -diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c -index 000fd0fb558b..45bfbc2522f7 100644 ---- a/xen/arch/x86/mm.c -+++ b/xen/arch/x86/mm.c -@@ -5007,8 +5007,7 @@ static l3_pgentry_t *virt_to_xen_l3e(unsigned long v) - if ( !l3t ) - return NULL; - UNMAP_DOMAIN_PAGE(l3t); -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) ) - { - l4_pgentry_t l4e = l4e_from_mfn(l3mfn, __PAGE_HYPERVISOR); -@@ -5045,8 +5044,7 @@ static l2_pgentry_t *virt_to_xen_l2e(unsigned long v) - return NULL; - } - UNMAP_DOMAIN_PAGE(l2t); -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) - { - l3e_write(pl3e, l3e_from_mfn(l2mfn, __PAGE_HYPERVISOR)); -@@ -5084,8 +5082,7 @@ l1_pgentry_t *virt_to_xen_l1e(unsigned long v) - return NULL; - } - UNMAP_DOMAIN_PAGE(l1t); -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) - { - l2e_write(pl2e, l2e_from_mfn(l1mfn, __PAGE_HYPERVISOR)); -@@ -5116,6 +5113,8 @@ l1_pgentry_t *virt_to_xen_l1e(unsigned long v) - do { \ - if ( locking ) \ - l3t_lock(page); \ -+ else \ -+ block_lock_speculation(); \ - } while ( false ) - - #define L3T_UNLOCK(page) \ -@@ -5331,8 +5330,7 @@ int map_pages_to_xen( - if ( l3e_get_flags(ol3e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) && - (l3e_get_flags(*pl3e) & _PAGE_PSE) ) - { -@@ -5436,8 +5434,7 @@ int map_pages_to_xen( - if ( l2e_get_flags(*pl2e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( (l2e_get_flags(*pl2e) & _PAGE_PRESENT) && - (l2e_get_flags(*pl2e) & _PAGE_PSE) ) - { -@@ -5478,8 +5475,7 @@ int map_pages_to_xen( - unsigned long base_mfn; - const l1_pgentry_t *l1t; - -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - - ol2e = *pl2e; - /* -@@ -5533,8 +5529,7 @@ int map_pages_to_xen( - unsigned long base_mfn; - const l2_pgentry_t *l2t; - -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - - ol3e = *pl3e; - /* -@@ -5678,8 +5673,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) - l3e_get_flags(*pl3e))); - UNMAP_DOMAIN_PAGE(l2t); - -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( (l3e_get_flags(*pl3e) & _PAGE_PRESENT) && - (l3e_get_flags(*pl3e) & _PAGE_PSE) ) - { -@@ -5738,8 +5732,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) - l2e_get_flags(*pl2e) & ~_PAGE_PSE)); - UNMAP_DOMAIN_PAGE(l1t); - -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - if ( (l2e_get_flags(*pl2e) & _PAGE_PRESENT) && - (l2e_get_flags(*pl2e) & _PAGE_PSE) ) - { -@@ -5783,8 +5776,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) - */ - if ( (nf & _PAGE_PRESENT) || ((v != e) && (l1_table_offset(v) != 0)) ) - continue; -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - - /* - * L2E may be already cleared, or set to a superpage, by -@@ -5831,8 +5823,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf) - if ( (nf & _PAGE_PRESENT) || - ((v != e) && (l2_table_offset(v) + l1_table_offset(v) != 0)) ) - continue; -- if ( locking ) -- spin_lock(&map_pgdir_lock); -+ spin_lock_if(locking, &map_pgdir_lock); - - /* - * L3E may be already cleared, or set to a superpage, by -diff --git a/xen/arch/x86/mm/mm-locks.h b/xen/arch/x86/mm/mm-locks.h -index 5ec080c02fd8..b4960fb90eff 100644 ---- a/xen/arch/x86/mm/mm-locks.h -+++ b/xen/arch/x86/mm/mm-locks.h -@@ -335,6 +335,15 @@ static inline void p2m_unlock(struct p2m_domain *p) - #define p2m_locked_by_me(p) mm_write_locked_by_me(&(p)->lock) - #define gfn_locked_by_me(p,g) p2m_locked_by_me(p) - -+static always_inline void gfn_lock_if(bool condition, struct p2m_domain *p2m, -+ gfn_t gfn, unsigned int order) -+{ -+ if ( condition ) -+ gfn_lock(p2m, gfn, order); -+ else -+ block_lock_speculation(); -+} -+ - /* PoD lock (per-p2m-table) - * - * Protects private PoD data structs: entry and cache -diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c -index 0983bd71d9a9..22ab1d606e8a 100644 ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -280,9 +280,8 @@ mfn_t p2m_get_gfn_type_access(struct p2m_domain *p2m, gfn_t gfn, - if ( q & P2M_UNSHARE ) - q |= P2M_ALLOC; - -- if ( locked ) -- /* Grab the lock here, don't release until put_gfn */ -- gfn_lock(p2m, gfn, 0); -+ /* Grab the lock here, don't release until put_gfn */ -+ gfn_lock_if(locked, p2m, gfn, 0); - - mfn = p2m->get_entry(p2m, gfn, t, a, q, page_order, NULL); - -diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h -index 28fce5615e5c..c830df3430a3 100644 ---- a/xen/include/xen/spinlock.h -+++ b/xen/include/xen/spinlock.h -@@ -222,6 +222,14 @@ static always_inline void spin_lock_irq(spinlock_t *l) - block_lock_speculation(); \ - }) - -+/* Conditionally take a spinlock in a speculation safe way. */ -+static always_inline void spin_lock_if(bool condition, spinlock_t *l) -+{ -+ if ( condition ) -+ _spin_lock(l); -+ block_lock_speculation(); -+} -+ - #define spin_unlock(l) _spin_unlock(l) - #define spin_unlock_irq(l) _spin_unlock_irq(l) - #define spin_unlock_irqrestore(l, f) _spin_unlock_irqrestore(l, f) From 4dc6f761c8795bd7201c191fec3d30030c63184c Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 9 Apr 2024 19:25:08 +0100 Subject: [PATCH 49/99] 2 security updates x86 HVM hypercalls may trigger Xen bug check [XSA-454, CVE-2023-46842] x86: Incorrect logic for BTC/SRSO mitigations [XSA-455, CVE-2024-31142] --- xen.spec | 12 ++++++- xsa454-4.18-1.patch | 88 +++++++++++++++++++++++++++++++++++++++++++++ xsa454-4.18-2.patch | 68 +++++++++++++++++++++++++++++++++++ xsa455.patch | 41 +++++++++++++++++++++ 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 xsa454-4.18-1.patch create mode 100644 xsa454-4.18-2.patch create mode 100644 xsa455.patch diff --git a/xen.spec b/xen.spec index 06a5573..6a7c0c6 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.1 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -114,6 +114,9 @@ Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch +Patch54: xsa454-4.18-1.patch +Patch55: xsa454-4.18-2.patch +Patch56: xsa455.patch %if %build_qemutrad @@ -328,6 +331,9 @@ manage Xen virtual machines. %endif %patch 52 -p1 %patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 +%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -934,6 +940,10 @@ fi %endif %changelog +* Tue Apr 09 2024 Michael Young - 4.18.1-2 +- x86 HVM hypercalls may trigger Xen bug check [XSA-454, CVE-2023-46842] +- x86: Incorrect logic for BTC/SRSO mitigations [XSA-455, CVE-2024-31142] + * Wed Mar 20 2024 Michael Young - 4.18.1-1 - update to xen-4.18.1 rebase xen.gcc12.fixes.patch diff --git a/xsa454-4.18-1.patch b/xsa454-4.18-1.patch new file mode 100644 index 0000000..3655cc4 --- /dev/null +++ b/xsa454-4.18-1.patch @@ -0,0 +1,88 @@ +From: Jan Beulich +Subject: x86/HVM: clear upper halves of GPRs upon entry from 32-bit code + +Hypercalls in particular can be the subject of continuations, and logic +there checks updated state against incoming register values. If the +guest manufactured a suitable argument register with a non-zero upper +half before entering compatibility mode and issuing a hypercall from +there, checks in hypercall_xlat_continuation() might trip. + +Since for HVM we want to also be sure to not hit a corner case in the +emulator, initiate the clipping right from the top of +{svm,vmx}_vmexit_handler(). Also rename the invoked function, as it no +longer does only invalidation of fields. + +Note that architecturally the upper halves of registers are undefined +after a switch between compatibility and 64-bit mode (either direction). +Hence once having entered compatibility mode, the guest can't assume +the upper half of any register to retain its value. + +This is part of XSA-454 / CVE-2023-46842. + +Fixes: b8a7efe8528a ("Enable compatibility mode operation for HYPERVISOR_memory_op") +Reported-by: Manuel Andreas +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/hvm/svm/svm.c ++++ b/xen/arch/x86/hvm/svm/svm.c +@@ -2603,7 +2603,8 @@ void svm_vmexit_handler(void) + regs->rsp = vmcb->rsp; + regs->rflags = vmcb->rflags; + +- hvm_invalidate_regs_fields(regs); ++ hvm_sanitize_regs_fields( ++ regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l)); + + if ( paging_mode_hap(v->domain) ) + v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb); +--- a/xen/arch/x86/hvm/vmx/vmx.c ++++ b/xen/arch/x86/hvm/vmx/vmx.c +@@ -4041,6 +4041,7 @@ static void undo_nmis_unblocked_by_iret( + void vmx_vmexit_handler(struct cpu_user_regs *regs) + { + unsigned long exit_qualification, exit_reason, idtv_info, intr_info = 0; ++ unsigned long cs_ar_bytes = 0; + unsigned int vector = 0; + struct vcpu *v = current; + struct domain *currd = v->domain; +@@ -4049,7 +4050,10 @@ void vmx_vmexit_handler(struct cpu_user_ + __vmread(GUEST_RSP, ®s->rsp); + __vmread(GUEST_RFLAGS, ®s->rflags); + +- hvm_invalidate_regs_fields(regs); ++ if ( hvm_long_mode_active(v) ) ++ __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes); ++ ++ hvm_sanitize_regs_fields(regs, !(cs_ar_bytes & X86_SEG_AR_CS_LM_ACTIVE)); + + if ( paging_mode_hap(v->domain) ) + { +--- a/xen/arch/x86/include/asm/hvm/hvm.h ++++ b/xen/arch/x86/include/asm/hvm/hvm.h +@@ -579,8 +579,24 @@ static inline unsigned int hvm_get_insn_ + ? alternative_call(hvm_funcs.get_insn_bytes, v, buf) : 0); + } + +-static inline void hvm_invalidate_regs_fields(struct cpu_user_regs *regs) ++static inline void hvm_sanitize_regs_fields(struct cpu_user_regs *regs, ++ bool compat) + { ++ if ( compat ) ++ { ++ /* Clear GPR upper halves, to counteract guests playing games. */ ++ regs->rbp = regs->ebp; ++ regs->rbx = regs->ebx; ++ regs->rax = regs->eax; ++ regs->rcx = regs->ecx; ++ regs->rdx = regs->edx; ++ regs->rsi = regs->esi; ++ regs->rdi = regs->edi; ++ regs->rip = regs->eip; ++ regs->rflags = regs->eflags; ++ regs->rsp = regs->esp; ++ } ++ + #ifndef NDEBUG + regs->error_code = 0xbeef; + regs->entry_vector = 0xbeef; diff --git a/xsa454-4.18-2.patch b/xsa454-4.18-2.patch new file mode 100644 index 0000000..ff8c350 --- /dev/null +++ b/xsa454-4.18-2.patch @@ -0,0 +1,68 @@ +From: Bjoern Doebel +Subject: hypercall_xlat_continuation: Replace BUG_ON with domain_crash + +Instead of crashing the host in case of unexpected hypercall parameters, +resort to only crashing the calling domain. + +This is part of XSA-454 / CVE-2023-46842. + +Fixes: b8a7efe8528a ("Enable compatibility mode operation for HYPERVISOR_memory_op") +Reported-by: Manuel Andreas +Signed-off-by: Bjoern Doebel +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/hypercall.c ++++ b/xen/arch/x86/hypercall.c +@@ -140,8 +140,10 @@ int hypercall_xlat_continuation(unsigned + cval = va_arg(args, unsigned int); + if ( cval == nval ) + mask &= ~1U; +- else +- BUG_ON(nval == (unsigned int)nval); ++ else if ( nval == (unsigned int)nval ) ++ domain_crash(current->domain, ++ "multicall (op %lu) bogus continuation arg%u (%#lx)\n", ++ mcs->call.op, i, nval); + } + else if ( id && *id == i ) + { +@@ -153,8 +155,10 @@ int hypercall_xlat_continuation(unsigned + mcs->call.args[i] = cval; + ++rc; + } +- else +- BUG_ON(mcs->call.args[i] != (unsigned int)mcs->call.args[i]); ++ else if ( mcs->call.args[i] != (unsigned int)mcs->call.args[i] ) ++ domain_crash(current->domain, ++ "multicall (op %lu) bad continuation arg%u (%#lx)\n", ++ mcs->call.op, i, mcs->call.args[i]); + } + } + else +@@ -180,8 +184,10 @@ int hypercall_xlat_continuation(unsigned + cval = va_arg(args, unsigned int); + if ( cval == nval ) + mask &= ~1U; +- else +- BUG_ON(nval == (unsigned int)nval); ++ else if ( nval == (unsigned int)nval ) ++ domain_crash(current->domain, ++ "hypercall (op %u) bogus continuation arg%u (%#lx)\n", ++ regs->eax, i, nval); + } + else if ( id && *id == i ) + { +@@ -193,8 +199,10 @@ int hypercall_xlat_continuation(unsigned + *reg = cval; + ++rc; + } +- else +- BUG_ON(*reg != (unsigned int)*reg); ++ else if ( *reg != (unsigned int)*reg ) ++ domain_crash(current->domain, ++ "hypercall (op %u) bad continuation arg%u (%#lx)\n", ++ regs->eax, i, *reg); + } + } + diff --git a/xsa455.patch b/xsa455.patch new file mode 100644 index 0000000..637d21f --- /dev/null +++ b/xsa455.patch @@ -0,0 +1,41 @@ +From 5bc561024f81371ff267edae73ae4a768b2f7a91 Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Tue, 26 Mar 2024 22:47:25 +0000 +Subject: x86/spec-ctrl: Fix BTC/SRSO mitigations + +We were looking for SCF_entry_ibpb in the wrong variable in the top-of-stack +block, and xen_spec_ctrl won't have had bit 5 set because Xen doesn't +understand SPEC_CTRL_RRSBA_DIS_U yet. + +This is XSA-455 / CVE-2024-31142. + +Fixes: 53a570b28569 ("x86/spec-ctrl: Support IBPB-on-entry") +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S +index 60b0b00ed0af..071b3997b1c0 100644 +--- a/xen/arch/x86/hvm/svm/entry.S ++++ b/xen/arch/x86/hvm/svm/entry.S +@@ -101,7 +101,7 @@ __UNLIKELY_END(nsvm_hap) + /* SPEC_CTRL_ENTRY_FROM_SVM Req: %rsp=regs/cpuinfo, %rdx=0 Clob: acd */ + + .macro svm_vmexit_cond_ibpb +- testb $SCF_entry_ibpb, CPUINFO_xen_spec_ctrl(%rsp) ++ testb $SCF_entry_ibpb, CPUINFO_spec_ctrl_flags(%rsp) + jz .L_skip_ibpb + + mov $MSR_PRED_CMD, %ecx +diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h +index 629518cc6925..c19b39d8c200 100644 +--- a/xen/arch/x86/include/asm/spec_ctrl_asm.h ++++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h +@@ -90,7 +90,7 @@ + jz .L\@_skip + testb $3, UREGS_cs(%rsp) + .else +- testb $SCF_entry_ibpb, CPUINFO_xen_spec_ctrl(%rsp) ++ testb $SCF_entry_ibpb, CPUINFO_spec_ctrl_flags(%rsp) + .endif + jz .L\@_skip + From c762409b331479c95fbc74ce9e43931e97f3af17 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 9 Apr 2024 21:43:30 +0100 Subject: [PATCH 50/99] x86: Native Branch History Injection [XSA-456, CVE-2024-2201] update to xen 4.18.2, remove patches now included upstream --- .gitignore | 2 +- sources | 2 +- xen.spec | 14 ++++---- xsa454-4.18-1.patch | 88 --------------------------------------------- xsa454-4.18-2.patch | 68 ----------------------------------- xsa455.patch | 41 --------------------- 6 files changed, 8 insertions(+), 207 deletions(-) delete mode 100644 xsa454-4.18-1.patch delete mode 100644 xsa454-4.18-2.patch delete mode 100644 xsa455.patch diff --git a/.gitignore b/.gitignore index 97a51c2..439b7c0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.18.1.tar.gz +/xen-4.18.2.tar.gz diff --git a/sources b/sources index 8d4dabc..5b1c173 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.18.1.tar.gz) = 6d67c177a31dae6979c111498f65cff2a7a792299cc72e658ae9f926468c14092807de94b6e269849fafdb6ed5a9d076400ecde0c4fec3b2b4bdb5f5ef39fcbb +SHA512 (xen-4.18.2.tar.gz) = c5feb450155883b5d2e7f43b05a64e7215b661b7d2f438d8f5a0896bd57283379ee11ca8e2e7a1d8787813cc6f1a260253fcb8688ed7d61a2bfb636db1626941 diff --git a/xen.spec b/xen.spec index 6a7c0c6..6441674 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.18.1 -Release: 2%{?dist} +Version: 4.18.2 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -114,9 +114,6 @@ Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch -Patch54: xsa454-4.18-1.patch -Patch55: xsa454-4.18-2.patch -Patch56: xsa455.patch %if %build_qemutrad @@ -331,9 +328,6 @@ manage Xen virtual machines. %endif %patch 52 -p1 %patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -940,6 +934,10 @@ fi %endif %changelog +* Tue Apr 09 2024 Michael Young - 4.18.2-1 +- x86: Native Branch History Injection [XSA-456, CVE-2024-2201] +- update to xen 4.18.2, remove patches now included upstream + * Tue Apr 09 2024 Michael Young - 4.18.1-2 - x86 HVM hypercalls may trigger Xen bug check [XSA-454, CVE-2023-46842] - x86: Incorrect logic for BTC/SRSO mitigations [XSA-455, CVE-2024-31142] diff --git a/xsa454-4.18-1.patch b/xsa454-4.18-1.patch deleted file mode 100644 index 3655cc4..0000000 --- a/xsa454-4.18-1.patch +++ /dev/null @@ -1,88 +0,0 @@ -From: Jan Beulich -Subject: x86/HVM: clear upper halves of GPRs upon entry from 32-bit code - -Hypercalls in particular can be the subject of continuations, and logic -there checks updated state against incoming register values. If the -guest manufactured a suitable argument register with a non-zero upper -half before entering compatibility mode and issuing a hypercall from -there, checks in hypercall_xlat_continuation() might trip. - -Since for HVM we want to also be sure to not hit a corner case in the -emulator, initiate the clipping right from the top of -{svm,vmx}_vmexit_handler(). Also rename the invoked function, as it no -longer does only invalidation of fields. - -Note that architecturally the upper halves of registers are undefined -after a switch between compatibility and 64-bit mode (either direction). -Hence once having entered compatibility mode, the guest can't assume -the upper half of any register to retain its value. - -This is part of XSA-454 / CVE-2023-46842. - -Fixes: b8a7efe8528a ("Enable compatibility mode operation for HYPERVISOR_memory_op") -Reported-by: Manuel Andreas -Signed-off-by: Jan Beulich -Reviewed-by: Roger Pau Monné - ---- a/xen/arch/x86/hvm/svm/svm.c -+++ b/xen/arch/x86/hvm/svm/svm.c -@@ -2603,7 +2603,8 @@ void svm_vmexit_handler(void) - regs->rsp = vmcb->rsp; - regs->rflags = vmcb->rflags; - -- hvm_invalidate_regs_fields(regs); -+ hvm_sanitize_regs_fields( -+ regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l)); - - if ( paging_mode_hap(v->domain) ) - v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb); ---- a/xen/arch/x86/hvm/vmx/vmx.c -+++ b/xen/arch/x86/hvm/vmx/vmx.c -@@ -4041,6 +4041,7 @@ static void undo_nmis_unblocked_by_iret( - void vmx_vmexit_handler(struct cpu_user_regs *regs) - { - unsigned long exit_qualification, exit_reason, idtv_info, intr_info = 0; -+ unsigned long cs_ar_bytes = 0; - unsigned int vector = 0; - struct vcpu *v = current; - struct domain *currd = v->domain; -@@ -4049,7 +4050,10 @@ void vmx_vmexit_handler(struct cpu_user_ - __vmread(GUEST_RSP, ®s->rsp); - __vmread(GUEST_RFLAGS, ®s->rflags); - -- hvm_invalidate_regs_fields(regs); -+ if ( hvm_long_mode_active(v) ) -+ __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes); -+ -+ hvm_sanitize_regs_fields(regs, !(cs_ar_bytes & X86_SEG_AR_CS_LM_ACTIVE)); - - if ( paging_mode_hap(v->domain) ) - { ---- a/xen/arch/x86/include/asm/hvm/hvm.h -+++ b/xen/arch/x86/include/asm/hvm/hvm.h -@@ -579,8 +579,24 @@ static inline unsigned int hvm_get_insn_ - ? alternative_call(hvm_funcs.get_insn_bytes, v, buf) : 0); - } - --static inline void hvm_invalidate_regs_fields(struct cpu_user_regs *regs) -+static inline void hvm_sanitize_regs_fields(struct cpu_user_regs *regs, -+ bool compat) - { -+ if ( compat ) -+ { -+ /* Clear GPR upper halves, to counteract guests playing games. */ -+ regs->rbp = regs->ebp; -+ regs->rbx = regs->ebx; -+ regs->rax = regs->eax; -+ regs->rcx = regs->ecx; -+ regs->rdx = regs->edx; -+ regs->rsi = regs->esi; -+ regs->rdi = regs->edi; -+ regs->rip = regs->eip; -+ regs->rflags = regs->eflags; -+ regs->rsp = regs->esp; -+ } -+ - #ifndef NDEBUG - regs->error_code = 0xbeef; - regs->entry_vector = 0xbeef; diff --git a/xsa454-4.18-2.patch b/xsa454-4.18-2.patch deleted file mode 100644 index ff8c350..0000000 --- a/xsa454-4.18-2.patch +++ /dev/null @@ -1,68 +0,0 @@ -From: Bjoern Doebel -Subject: hypercall_xlat_continuation: Replace BUG_ON with domain_crash - -Instead of crashing the host in case of unexpected hypercall parameters, -resort to only crashing the calling domain. - -This is part of XSA-454 / CVE-2023-46842. - -Fixes: b8a7efe8528a ("Enable compatibility mode operation for HYPERVISOR_memory_op") -Reported-by: Manuel Andreas -Signed-off-by: Bjoern Doebel -Signed-off-by: Jan Beulich -Reviewed-by: Roger Pau Monné - ---- a/xen/arch/x86/hypercall.c -+++ b/xen/arch/x86/hypercall.c -@@ -140,8 +140,10 @@ int hypercall_xlat_continuation(unsigned - cval = va_arg(args, unsigned int); - if ( cval == nval ) - mask &= ~1U; -- else -- BUG_ON(nval == (unsigned int)nval); -+ else if ( nval == (unsigned int)nval ) -+ domain_crash(current->domain, -+ "multicall (op %lu) bogus continuation arg%u (%#lx)\n", -+ mcs->call.op, i, nval); - } - else if ( id && *id == i ) - { -@@ -153,8 +155,10 @@ int hypercall_xlat_continuation(unsigned - mcs->call.args[i] = cval; - ++rc; - } -- else -- BUG_ON(mcs->call.args[i] != (unsigned int)mcs->call.args[i]); -+ else if ( mcs->call.args[i] != (unsigned int)mcs->call.args[i] ) -+ domain_crash(current->domain, -+ "multicall (op %lu) bad continuation arg%u (%#lx)\n", -+ mcs->call.op, i, mcs->call.args[i]); - } - } - else -@@ -180,8 +184,10 @@ int hypercall_xlat_continuation(unsigned - cval = va_arg(args, unsigned int); - if ( cval == nval ) - mask &= ~1U; -- else -- BUG_ON(nval == (unsigned int)nval); -+ else if ( nval == (unsigned int)nval ) -+ domain_crash(current->domain, -+ "hypercall (op %u) bogus continuation arg%u (%#lx)\n", -+ regs->eax, i, nval); - } - else if ( id && *id == i ) - { -@@ -193,8 +199,10 @@ int hypercall_xlat_continuation(unsigned - *reg = cval; - ++rc; - } -- else -- BUG_ON(*reg != (unsigned int)*reg); -+ else if ( *reg != (unsigned int)*reg ) -+ domain_crash(current->domain, -+ "hypercall (op %u) bad continuation arg%u (%#lx)\n", -+ regs->eax, i, *reg); - } - } - diff --git a/xsa455.patch b/xsa455.patch deleted file mode 100644 index 637d21f..0000000 --- a/xsa455.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 5bc561024f81371ff267edae73ae4a768b2f7a91 Mon Sep 17 00:00:00 2001 -From: Andrew Cooper -Date: Tue, 26 Mar 2024 22:47:25 +0000 -Subject: x86/spec-ctrl: Fix BTC/SRSO mitigations - -We were looking for SCF_entry_ibpb in the wrong variable in the top-of-stack -block, and xen_spec_ctrl won't have had bit 5 set because Xen doesn't -understand SPEC_CTRL_RRSBA_DIS_U yet. - -This is XSA-455 / CVE-2024-31142. - -Fixes: 53a570b28569 ("x86/spec-ctrl: Support IBPB-on-entry") -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S -index 60b0b00ed0af..071b3997b1c0 100644 ---- a/xen/arch/x86/hvm/svm/entry.S -+++ b/xen/arch/x86/hvm/svm/entry.S -@@ -101,7 +101,7 @@ __UNLIKELY_END(nsvm_hap) - /* SPEC_CTRL_ENTRY_FROM_SVM Req: %rsp=regs/cpuinfo, %rdx=0 Clob: acd */ - - .macro svm_vmexit_cond_ibpb -- testb $SCF_entry_ibpb, CPUINFO_xen_spec_ctrl(%rsp) -+ testb $SCF_entry_ibpb, CPUINFO_spec_ctrl_flags(%rsp) - jz .L_skip_ibpb - - mov $MSR_PRED_CMD, %ecx -diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h -index 629518cc6925..c19b39d8c200 100644 ---- a/xen/arch/x86/include/asm/spec_ctrl_asm.h -+++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h -@@ -90,7 +90,7 @@ - jz .L\@_skip - testb $3, UREGS_cs(%rsp) - .else -- testb $SCF_entry_ibpb, CPUINFO_xen_spec_ctrl(%rsp) -+ testb $SCF_entry_ibpb, CPUINFO_spec_ctrl_flags(%rsp) - .endif - jz .L\@_skip - From 254a3095373afd2c8943e633fdc9e54e8b3a5ea4 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 3 Jun 2024 21:39:12 +0100 Subject: [PATCH 51/99] x86: Native Branch History Injection [XSA-456 version 3, CVE-2024-2201] --- ...7dca70d64c35c86e5d503f67366ebe2b9138.patch | 69 +++++++++++++++++ ...302c33b117aa9a417056db241aefc840c2f0.patch | 32 ++++++++ ...b0b98b53140102031ceca0611f22190227fd.patch | 49 ++++++++++++ ...9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch | 56 ++++++++++++++ ...59767c82d833ebecdf8106e96482b04f3c40.patch | 36 +++++++++ ...1d9cb96041a84a24857a6464628240deed4f.patch | 75 +++++++++++++++++++ xen.spec | 17 ++++- 7 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch create mode 100644 xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch create mode 100644 xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch create mode 100644 xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch create mode 100644 xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch create mode 100644 xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch diff --git a/xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch b/xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch new file mode 100644 index 0000000..fbaac26 --- /dev/null +++ b/xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch @@ -0,0 +1,69 @@ +From 0b0c7dca70d64c35c86e5d503f67366ebe2b9138 Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Mon, 29 Apr 2024 09:37:04 +0200 +Subject: [PATCH] x86/spec: fix reporting of BHB clearing usage from guest + entry points +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Reporting whether the BHB clearing on entry is done for the different domains +types based on cpu_has_bhb_seq is unhelpful, as that variable signals whether +there's a BHB clearing sequence selected, but that alone doesn't imply that +such sequence is used from the PV and/or HVM entry points. + +Instead use opt_bhb_entry_{pv,hvm} which do signal whether BHB clearing is +performed on entry from PV/HVM. + +Fixes: 689ad48ce9cf ('x86/spec-ctrl: Wire up the Native-BHI software sequences') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +Reviewed-by: Andrew Cooper +master commit: 049ab0b2c9f1f5edb54b505fef0bc575787dafe9 +master date: 2024-04-25 16:35:56 +0200 +--- + xen/arch/x86/spec_ctrl.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index ba4349a024..8c67d6256a 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -634,7 +634,7 @@ static void __init print_details(enum ind_thunk thunk) + (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || + boot_cpu_has(X86_FEATURE_SC_RSB_HVM) || + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) || +- cpu_has_bhb_seq || amd_virt_spec_ctrl || ++ opt_bhb_entry_hvm || amd_virt_spec_ctrl || + opt_eager_fpu || opt_verw_hvm) ? "" : " None", + boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ? " MSR_SPEC_CTRL" : "", + (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || +@@ -643,7 +643,7 @@ static void __init print_details(enum ind_thunk thunk) + opt_eager_fpu ? " EAGER_FPU" : "", + opt_verw_hvm ? " VERW" : "", + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) ? " IBPB-entry" : "", +- cpu_has_bhb_seq ? " BHB-entry" : ""); ++ opt_bhb_entry_hvm ? " BHB-entry" : ""); + + #endif + #ifdef CONFIG_PV +@@ -651,14 +651,14 @@ static void __init print_details(enum ind_thunk thunk) + (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || + boot_cpu_has(X86_FEATURE_SC_RSB_PV) || + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) || +- cpu_has_bhb_seq || ++ opt_bhb_entry_pv || + opt_eager_fpu || opt_verw_pv) ? "" : " None", + boot_cpu_has(X86_FEATURE_SC_MSR_PV) ? " MSR_SPEC_CTRL" : "", + boot_cpu_has(X86_FEATURE_SC_RSB_PV) ? " RSB" : "", + opt_eager_fpu ? " EAGER_FPU" : "", + opt_verw_pv ? " VERW" : "", + boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) ? " IBPB-entry" : "", +- cpu_has_bhb_seq ? " BHB-entry" : ""); ++ opt_bhb_entry_pv ? " BHB-entry" : ""); + + printk(" XPTI (64-bit PV only): Dom0 %s, DomU %s (with%s PCID)\n", + opt_xpti_hwdom ? "enabled" : "disabled", +-- +2.30.2 + diff --git a/xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch b/xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch new file mode 100644 index 0000000..4f4ba17 --- /dev/null +++ b/xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch @@ -0,0 +1,32 @@ +From 2d38302c33b117aa9a417056db241aefc840c2f0 Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Tue, 9 Apr 2024 21:39:51 +0100 +Subject: [PATCH] x86/entry: Fix build with older toolchains + +Binutils older than 2.29 doesn't know INCSSPD. + +Fixes: 8e186f98ce0e ("x86: Use indirect calls in reset-stack infrastructure") +Signed-off-by: Andrew Cooper +Reviewed-by: Stefano Stabellini +(cherry picked from commit a9fa82500818a8d8ce5f2843f1577bd2c29d088e) +--- + xen/arch/x86/x86_64/entry.S | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index ad7dd3b23b..054fcb225f 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -643,7 +643,9 @@ ENTRY(continue_pv_domain) + * JMPed to. Drop the return address. + */ + add $8, %rsp ++#ifdef CONFIG_XEN_SHSTK + ALTERNATIVE "", "mov $2, %eax; incsspd %eax", X86_FEATURE_XEN_SHSTK ++#endif + + call check_wakeup_from_wait + ret_from_intr: +-- +2.30.2 + diff --git a/xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch b/xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch new file mode 100644 index 0000000..371ebe1 --- /dev/null +++ b/xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch @@ -0,0 +1,49 @@ +From 8bdcb0b98b53140102031ceca0611f22190227fd Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Mon, 29 Apr 2024 09:35:21 +0200 +Subject: [PATCH] altcall: fix __alt_call_maybe_initdata so it's safe for + livepatch +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Setting alternative call variables as __init is not safe for use with +livepatch, as livepatches can rightfully introduce new alternative calls to +structures marked as __alt_call_maybe_initdata (possibly just indirectly due to +replacing existing functions that use those). Attempting to resolve those +alternative calls then results in page faults as the variable that holds the +function pointer address has been freed. + +When livepatch is supported use the __ro_after_init attribute instead of +__initdata for __alt_call_maybe_initdata. + +Fixes: f26bb285949b ('xen: Implement xen/alternative-call.h for use in common code') +Signed-off-by: Roger Pau Monné +Reviewed-by: Andrew Cooper +master commit: af4cd0a6a61cdb03bc1afca9478b05b0c9703599 +master date: 2024-04-11 18:51:36 +0100 +--- + xen/include/xen/alternative-call.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/xen/include/xen/alternative-call.h b/xen/include/xen/alternative-call.h +index 5c6b9a562b..10f7d7637e 100644 +--- a/xen/include/xen/alternative-call.h ++++ b/xen/include/xen/alternative-call.h +@@ -50,7 +50,12 @@ + + #include + +-#define __alt_call_maybe_initdata __initdata ++#ifdef CONFIG_LIVEPATCH ++/* Must keep for livepatches to resolve alternative calls. */ ++# define __alt_call_maybe_initdata __ro_after_init ++#else ++# define __alt_call_maybe_initdata __initdata ++#endif + + #else + +-- +2.30.2 + diff --git a/xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch b/xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch new file mode 100644 index 0000000..af34479 --- /dev/null +++ b/xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch @@ -0,0 +1,56 @@ +From af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41 Mon Sep 17 00:00:00 2001 +From: Ross Lagerwall +Date: Mon, 29 Apr 2024 09:36:04 +0200 +Subject: [PATCH] x86/rtc: Avoid UIP flag being set for longer than expected + +In a test, OVMF reported an error initializing the RTC without +indicating the precise nature of the error. The only plausible +explanation I can find is as follows: + +As part of the initialization, OVMF reads register C and then reads +register A repatedly until the UIP flag is not set. If this takes longer +than 100 ms, OVMF fails and reports an error. This may happen with the +following sequence of events: + +At guest time=0s, rtc_init() calls check_update_timer() which schedules +update_timer for t=(1 - 244us). + +At t=1s, the update_timer function happens to have been called >= 244us +late. In the timer callback, it sets the UIP flag and schedules +update_timer2 for t=1s. + +Before update_timer2 runs, the guest reads register C which calls +check_update_timer(). check_update_timer() stops the scheduled +update_timer2 and since the guest time is now outside of the update +cycle, it schedules update_timer for t=(2 - 244us). + +The UIP flag will therefore be set for a whole second from t=1 to t=2 +while the guest repeatedly reads register A waiting for the UIP flag to +clear. Fix it by clearing the UIP flag when scheduling update_timer. + +I was able to reproduce this issue with a synthetic test and this +resolves the issue. + +Signed-off-by: Ross Lagerwall +Reviewed-by: Jan Beulich +master commit: 43a07069863b419433dee12c9b58c1f7ce70aa97 +master date: 2024-04-23 14:09:18 +0200 +--- + xen/arch/x86/hvm/rtc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c +index 206b4296e9..4839374352 100644 +--- a/xen/arch/x86/hvm/rtc.c ++++ b/xen/arch/x86/hvm/rtc.c +@@ -202,6 +202,7 @@ static void check_update_timer(RTCState *s) + } + else + { ++ s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP; + next_update_time = (USEC_PER_SEC - guest_usec - 244) * NS_PER_USEC; + expire_time = NOW() + next_update_time; + s->next_update_time = expire_time; +-- +2.30.2 + diff --git a/xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch b/xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch new file mode 100644 index 0000000..c27b537 --- /dev/null +++ b/xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch @@ -0,0 +1,36 @@ +From eb7059767c82d833ebecdf8106e96482b04f3c40 Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Mon, 29 Apr 2024 09:36:37 +0200 +Subject: [PATCH] x86/MTRR: correct inadvertently inverted WC check +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +The ! clearly got lost by mistake. + +Fixes: e9e0eb30d4d6 ("x86/MTRR: avoid several indirect calls") +Reported-by: Marek Marczykowski-Górecki +Signed-off-by: Jan Beulich +Acked-by: Roger Pau Monné +master commit: 77e25f0e30ddd11e043e6fce84bf108ce7de5b6f +master date: 2024-04-23 14:13:48 +0200 +--- + xen/arch/x86/cpu/mtrr/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xen/arch/x86/cpu/mtrr/main.c b/xen/arch/x86/cpu/mtrr/main.c +index 55a4da54a7..90b235f57e 100644 +--- a/xen/arch/x86/cpu/mtrr/main.c ++++ b/xen/arch/x86/cpu/mtrr/main.c +@@ -316,7 +316,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, + } + + /* If the type is WC, check that this processor supports it */ +- if ((type == X86_MT_WC) && mtrr_have_wrcomb()) { ++ if ((type == X86_MT_WC) && !mtrr_have_wrcomb()) { + printk(KERN_WARNING + "mtrr: your processor doesn't support write-combining\n"); + return -EOPNOTSUPP; +-- +2.30.2 + diff --git a/xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch b/xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch new file mode 100644 index 0000000..475a03d --- /dev/null +++ b/xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch @@ -0,0 +1,75 @@ +From f0ff1d9cb96041a84a24857a6464628240deed4f Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Mon, 29 Apr 2024 09:37:29 +0200 +Subject: [PATCH] x86/spec: adjust logic that elides lfence +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +It's currently too restrictive by just checking whether there's a BHB clearing +sequence selected. It should instead check whether BHB clearing is used on +entry from PV or HVM specifically. + +Switch to use opt_bhb_entry_{pv,hvm} instead, and then remove cpu_has_bhb_seq +since it no longer has any users. + +Reported-by: Jan Beulich +Fixes: 954c983abcee ('x86/spec-ctrl: Software BHB-clearing sequences') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +Reviewed-by: Andrew Cooper +master commit: 656ae8f1091bcefec9c46ec3ea3ac2118742d4f6 +master date: 2024-04-25 16:37:01 +0200 +--- + xen/arch/x86/include/asm/cpufeature.h | 3 --- + xen/arch/x86/spec_ctrl.c | 6 +++--- + 2 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h +index 7a312c485e..3c57f55de0 100644 +--- a/xen/arch/x86/include/asm/cpufeature.h ++++ b/xen/arch/x86/include/asm/cpufeature.h +@@ -228,9 +228,6 @@ static inline bool boot_cpu_has(unsigned int feat) + #define cpu_bug_fpu_ptrs boot_cpu_has(X86_BUG_FPU_PTRS) + #define cpu_bug_null_seg boot_cpu_has(X86_BUG_NULL_SEG) + +-#define cpu_has_bhb_seq (boot_cpu_has(X86_SPEC_BHB_TSX) || \ +- boot_cpu_has(X86_SPEC_BHB_LOOPS)) +- + enum _cache_type { + CACHE_TYPE_NULL = 0, + CACHE_TYPE_DATA = 1, +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 8c67d6256a..12c19b7eca 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -2328,7 +2328,7 @@ void __init init_speculation_mitigations(void) + * unconditional WRMSR. If we do have it, or we're not using any + * prior conditional block, then it's safe to drop the LFENCE. + */ +- if ( !cpu_has_bhb_seq && ++ if ( !opt_bhb_entry_pv && + (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || + !boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV)) ) + setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_PV); +@@ -2344,7 +2344,7 @@ void __init init_speculation_mitigations(void) + * active in the block that is skipped when interrupting guest + * context, then it's safe to drop the LFENCE. + */ +- if ( !cpu_has_bhb_seq && ++ if ( !opt_bhb_entry_pv && + (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || + (!boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) && + !boot_cpu_has(X86_FEATURE_SC_RSB_PV))) ) +@@ -2356,7 +2356,7 @@ void __init init_speculation_mitigations(void) + * A BHB sequence, if used, is the only conditional action, so if we + * don't have it, we don't need the safety LFENCE. + */ +- if ( !cpu_has_bhb_seq ) ++ if ( !opt_bhb_entry_hvm ) + setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_VMX); + } + +-- +2.30.2 + diff --git a/xen.spec b/xen.spec index 6441674..a499993 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.2 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -114,6 +114,12 @@ Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch +Patch54: xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch +Patch55: xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch +Patch56: xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch +Patch57: xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch +Patch58: xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch +Patch59: xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch %if %build_qemutrad @@ -328,6 +334,12 @@ manage Xen virtual machines. %endif %patch 52 -p1 %patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 +%patch 56 -p1 +%patch 57 -p1 +%patch 58 -p1 +%patch 59 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -934,6 +946,9 @@ fi %endif %changelog +* Mon Jun 03 2024 Michael Young - 4.18.2-2 +- x86: Native Branch History Injection [XSA-456 version 3, CVE-2024-2201] + * Tue Apr 09 2024 Michael Young - 4.18.2-1 - x86: Native Branch History Injection [XSA-456, CVE-2024-2201] - update to xen 4.18.2, remove patches now included upstream From bac467190c3e7b9b6aee771ca6366689c9a56a10 Mon Sep 17 00:00:00 2001 From: Python Maint Date: Fri, 7 Jun 2024 09:52:18 +0200 Subject: [PATCH 52/99] Rebuilt for Python 3.13 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index a499993..fb843ec 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.2 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -946,6 +946,9 @@ fi %endif %changelog +* Fri Jun 07 2024 Python Maint - 4.18.2-3 +- Rebuilt for Python 3.13 + * Mon Jun 03 2024 Michael Young - 4.18.2-2 - x86: Native Branch History Injection [XSA-456 version 3, CVE-2024-2201] From 269fa36c52b4ef61cfd7886f28588807775d4501 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 16 Jul 2024 21:23:30 +0100 Subject: [PATCH 53/99] double unlock in x86 guest IRQ handling [XSA-458, CVE-2024-31143] --- xen.spec | 7 ++++++- xsa458.patch | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 xsa458.patch diff --git a/xen.spec b/xen.spec index fb843ec..2782f96 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.2 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -120,6 +120,7 @@ Patch56: xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch Patch57: xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch Patch58: xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch Patch59: xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch +Patch60: xsa458.patch %if %build_qemutrad @@ -340,6 +341,7 @@ manage Xen virtual machines. %patch 57 -p1 %patch 58 -p1 %patch 59 -p1 +%patch 60 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -946,6 +948,9 @@ fi %endif %changelog +* Tue Jul 16 2024 Michael Young - 4.18.2-4 +- double unlock in x86 guest IRQ handling [XSA-458, CVE-2024-31143] + * Fri Jun 07 2024 Python Maint - 4.18.2-3 - Rebuilt for Python 3.13 diff --git a/xsa458.patch b/xsa458.patch new file mode 100644 index 0000000..8be0a90 --- /dev/null +++ b/xsa458.patch @@ -0,0 +1,38 @@ +From: Jan Beulich +Subject: x86/IRQ: avoid double unlock in map_domain_pirq() + +Forever since its introduction the main loop in the function dealing +with multi-vector MSI had error exit points ("break") with different +properties: In one case no IRQ descriptor lock is being held. +Nevertheless the subsequent error cleanup path assumed such a lock would +uniformly need releasing. Identify the case by setting "desc" to NULL, +thus allowing the unlock to be skipped as necessary. + +This is CVE-2024-31143 / XSA-458. + +Coverity ID: 1605298 +Fixes: d1b6d0a02489 ("x86: enable multi-vector MSI") +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/irq.c ++++ b/xen/arch/x86/irq.c +@@ -2273,6 +2273,7 @@ int map_domain_pirq( + + set_domain_irq_pirq(d, irq, info); + spin_unlock_irqrestore(&desc->lock, flags); ++ desc = NULL; + + info = NULL; + irq = create_irq(NUMA_NO_NODE, true); +@@ -2308,7 +2309,9 @@ int map_domain_pirq( + + if ( ret ) + { +- spin_unlock_irqrestore(&desc->lock, flags); ++ if ( desc ) ++ spin_unlock_irqrestore(&desc->lock, flags); ++ + pci_disable_msi(msi_desc); + if ( nr ) + { From 9e3a14be339565ae6ff93f5ec7a9922cfcb0d2aa Mon Sep 17 00:00:00 2001 From: Alejandro Vallejo Date: Sun, 14 Jul 2024 17:21:35 +0100 Subject: [PATCH 54/99] Split xen-runtime posttrans conditional $(ls -A ...) expands before the whole condition is passed to `[`. This means `-d ` does not gate the `ls` command being executed. While it's benign, it causes ls's stderr to propagate to yum/dnf output, which is somewhat disconcerting for the user. Fix it by forcing ls into its own conditional. --- xen.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 2782f96..7e7cf5a 100644 --- a/xen.spec +++ b/xen.spec @@ -612,7 +612,7 @@ fi %endif %posttrans runtime -if [ ! -L /usr/lib/xen -a -d /usr/lib/xen -a -z "$(ls -A /usr/lib/xen)" ]; then +if [ ! -L /usr/lib/xen -a -d /usr/lib/xen ] && [ -z "$(ls -A /usr/lib/xen)" ]; then rmdir /usr/lib/xen fi if [ ! -e /usr/lib/xen ]; then From 1b82c0189440c1c413588871749769aa22a8824d Mon Sep 17 00:00:00 2001 From: Michael Young Date: Thu, 18 Jul 2024 22:27:45 +0100 Subject: [PATCH 55/99] add bugzilla reference --- xen.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/xen.spec b/xen.spec index 7e7cf5a..0f8f439 100644 --- a/xen.spec +++ b/xen.spec @@ -950,6 +950,7 @@ fi %changelog * Tue Jul 16 2024 Michael Young - 4.18.2-4 - double unlock in x86 guest IRQ handling [XSA-458, CVE-2024-31143] + (#2298690) * Fri Jun 07 2024 Python Maint - 4.18.2-3 - Rebuilt for Python 3.13 From 589e86cf5627e92df5ac43147e66835f90ab81f7 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 20 Jul 2024 09:54:27 +0000 Subject: [PATCH 56/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 0f8f439..32950cd 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.2 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -948,6 +948,9 @@ fi %endif %changelog +* Sat Jul 20 2024 Fedora Release Engineering - 4.18.2-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + * Tue Jul 16 2024 Michael Young - 4.18.2-4 - double unlock in x86 guest IRQ handling [XSA-458, CVE-2024-31143] (#2298690) From 08778ae14d65ba945d82ef48b52931138025e89e Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sat, 3 Aug 2024 22:01:35 +0100 Subject: [PATCH 57/99] update to xen-4.19.0 --- .gitignore | 2 +- sources | 2 +- xen.efi.build.patch | 8 +- xen.fedora.systemd.patch | 4 +- xen.gcc14.fixes.patch | 12 --- ...7dca70d64c35c86e5d503f67366ebe2b9138.patch | 69 ----------------- ...302c33b117aa9a417056db241aefc840c2f0.patch | 32 -------- ...b0b98b53140102031ceca0611f22190227fd.patch | 49 ------------ ...9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch | 56 -------------- ...59767c82d833ebecdf8106e96482b04f3c40.patch | 36 --------- ...1d9cb96041a84a24857a6464628240deed4f.patch | 75 ------------------- xen.ocaml5.fixes.patch | 11 --- xen.spec | 39 +++++----- xsa458.patch | 38 ---------- 14 files changed, 26 insertions(+), 407 deletions(-) delete mode 100644 xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch delete mode 100644 xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch delete mode 100644 xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch delete mode 100644 xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch delete mode 100644 xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch delete mode 100644 xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch delete mode 100644 xsa458.patch diff --git a/.gitignore b/.gitignore index 439b7c0..a996079 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.18.2.tar.gz +/xen-4.19.0.tar.gz diff --git a/sources b/sources index 5b1c173..e979065 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.18.2.tar.gz) = c5feb450155883b5d2e7f43b05a64e7215b661b7d2f438d8f5a0896bd57283379ee11ca8e2e7a1d8787813cc6f1a260253fcb8688ed7d61a2bfb636db1626941 +SHA512 (xen-4.19.0.tar.gz) = bc0b4257cab66b0f9d4a1fe72e07f4980398b2934989c02ffe488b465eca3443caa0ded903871480aba6e36212921f335b68d67f202f22548c31899225f2d657 diff --git a/xen.efi.build.patch b/xen.efi.build.patch index 06ee249..69d1e93 100644 --- a/xen.efi.build.patch +++ b/xen.efi.build.patch @@ -1,7 +1,7 @@ ---- xen-4.17.0/xen/arch/x86/arch.mk.orig 2022-12-08 18:03:08.000000000 +0000 -+++ xen-4.17.0/xen/arch/x86/arch.mk 2022-12-10 12:13:11.043182208 +0000 -@@ -94,7 +94,9 @@ - XEN_BUILD_EFI := $(call if-success,$(CC) $(CFLAGS) -c $(srctree)/$(efi-check).c -o $(efi-check).o,y) +--- xen-4.19.0-rc1/xen/arch/x86/arch.mk.orig 2024-07-01 18:31:39.000000000 +0100 ++++ xen-4.19.0-rc1/xen/arch/x86/arch.mk 2024-07-02 21:10:00.796753718 +0100 +@@ -91,7 +91,9 @@ + -c $(srctree)/$(efi-check).c -o $(efi-check).o,y) # Check if the linker supports PE. -EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 diff --git a/xen.fedora.systemd.patch b/xen.fedora.systemd.patch index ac56245..5b6a7a3 100644 --- a/xen.fedora.systemd.patch +++ b/xen.fedora.systemd.patch @@ -64,8 +64,8 @@ diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/xen-qemu-dom0-disk-backend.s --- xen-4.17.0/tools/configure.orig 2022-12-08 18:03:08.000000000 +0000 +++ xen-4.17.0/tools/configure 2022-12-09 19:51:43.278708226 +0000 @@ -10081,7 +10081,7 @@ - - if test "x$systemd" = "xy"; then : + if test "x$systemd" = "xy" + then : - ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service" + ac_config_files="$ac_config_files hotplug/Linux/systemd/oxenstored.service hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service" diff --git a/xen.gcc14.fixes.patch b/xen.gcc14.fixes.patch index cc27089..a9fb2f3 100644 --- a/xen.gcc14.fixes.patch +++ b/xen.gcc14.fixes.patch @@ -10,15 +10,3 @@ Work around newlib build problems with gcc14 CROSS_ROOT=cross-root-$(GNU_TARGET_ARCH) CROSS_PREFIX=$(CURDIR)/$(CROSS_ROOT) ---- xen-4.18.0/extras/mini-os/include/posix/sys/mman.h.orig 2022-07-04 09:52:38.000000000 +0100 -+++ xen-4.18.0/extras/mini-os/include/posix/sys/mman.h 2024-02-01 23:00:19.923263409 +0000 -@@ -16,7 +16,7 @@ - - void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) asm("mmap64"); - int munmap(void *start, size_t length); --static inline mlock(const void *addr, size_t len) { return 0; } --static inline munlock(const void *addr, size_t len) { return 0; } -+static inline int mlock(const void *addr, size_t len) { return 0; } -+static inline int munlock(const void *addr, size_t len) { return 0; } - - #endif /* _POSIX_SYS_MMAN_H */ diff --git a/xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch b/xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch deleted file mode 100644 index fbaac26..0000000 --- a/xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0b0c7dca70d64c35c86e5d503f67366ebe2b9138 Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= -Date: Mon, 29 Apr 2024 09:37:04 +0200 -Subject: [PATCH] x86/spec: fix reporting of BHB clearing usage from guest - entry points -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Reporting whether the BHB clearing on entry is done for the different domains -types based on cpu_has_bhb_seq is unhelpful, as that variable signals whether -there's a BHB clearing sequence selected, but that alone doesn't imply that -such sequence is used from the PV and/or HVM entry points. - -Instead use opt_bhb_entry_{pv,hvm} which do signal whether BHB clearing is -performed on entry from PV/HVM. - -Fixes: 689ad48ce9cf ('x86/spec-ctrl: Wire up the Native-BHI software sequences') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -Reviewed-by: Andrew Cooper -master commit: 049ab0b2c9f1f5edb54b505fef0bc575787dafe9 -master date: 2024-04-25 16:35:56 +0200 ---- - xen/arch/x86/spec_ctrl.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index ba4349a024..8c67d6256a 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -634,7 +634,7 @@ static void __init print_details(enum ind_thunk thunk) - (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || - boot_cpu_has(X86_FEATURE_SC_RSB_HVM) || - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) || -- cpu_has_bhb_seq || amd_virt_spec_ctrl || -+ opt_bhb_entry_hvm || amd_virt_spec_ctrl || - opt_eager_fpu || opt_verw_hvm) ? "" : " None", - boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ? " MSR_SPEC_CTRL" : "", - (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || -@@ -643,7 +643,7 @@ static void __init print_details(enum ind_thunk thunk) - opt_eager_fpu ? " EAGER_FPU" : "", - opt_verw_hvm ? " VERW" : "", - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_HVM) ? " IBPB-entry" : "", -- cpu_has_bhb_seq ? " BHB-entry" : ""); -+ opt_bhb_entry_hvm ? " BHB-entry" : ""); - - #endif - #ifdef CONFIG_PV -@@ -651,14 +651,14 @@ static void __init print_details(enum ind_thunk thunk) - (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || - boot_cpu_has(X86_FEATURE_SC_RSB_PV) || - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) || -- cpu_has_bhb_seq || -+ opt_bhb_entry_pv || - opt_eager_fpu || opt_verw_pv) ? "" : " None", - boot_cpu_has(X86_FEATURE_SC_MSR_PV) ? " MSR_SPEC_CTRL" : "", - boot_cpu_has(X86_FEATURE_SC_RSB_PV) ? " RSB" : "", - opt_eager_fpu ? " EAGER_FPU" : "", - opt_verw_pv ? " VERW" : "", - boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) ? " IBPB-entry" : "", -- cpu_has_bhb_seq ? " BHB-entry" : ""); -+ opt_bhb_entry_pv ? " BHB-entry" : ""); - - printk(" XPTI (64-bit PV only): Dom0 %s, DomU %s (with%s PCID)\n", - opt_xpti_hwdom ? "enabled" : "disabled", --- -2.30.2 - diff --git a/xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch b/xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch deleted file mode 100644 index 4f4ba17..0000000 --- a/xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 2d38302c33b117aa9a417056db241aefc840c2f0 Mon Sep 17 00:00:00 2001 -From: Andrew Cooper -Date: Tue, 9 Apr 2024 21:39:51 +0100 -Subject: [PATCH] x86/entry: Fix build with older toolchains - -Binutils older than 2.29 doesn't know INCSSPD. - -Fixes: 8e186f98ce0e ("x86: Use indirect calls in reset-stack infrastructure") -Signed-off-by: Andrew Cooper -Reviewed-by: Stefano Stabellini -(cherry picked from commit a9fa82500818a8d8ce5f2843f1577bd2c29d088e) ---- - xen/arch/x86/x86_64/entry.S | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index ad7dd3b23b..054fcb225f 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -643,7 +643,9 @@ ENTRY(continue_pv_domain) - * JMPed to. Drop the return address. - */ - add $8, %rsp -+#ifdef CONFIG_XEN_SHSTK - ALTERNATIVE "", "mov $2, %eax; incsspd %eax", X86_FEATURE_XEN_SHSTK -+#endif - - call check_wakeup_from_wait - ret_from_intr: --- -2.30.2 - diff --git a/xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch b/xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch deleted file mode 100644 index 371ebe1..0000000 --- a/xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 8bdcb0b98b53140102031ceca0611f22190227fd Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= -Date: Mon, 29 Apr 2024 09:35:21 +0200 -Subject: [PATCH] altcall: fix __alt_call_maybe_initdata so it's safe for - livepatch -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Setting alternative call variables as __init is not safe for use with -livepatch, as livepatches can rightfully introduce new alternative calls to -structures marked as __alt_call_maybe_initdata (possibly just indirectly due to -replacing existing functions that use those). Attempting to resolve those -alternative calls then results in page faults as the variable that holds the -function pointer address has been freed. - -When livepatch is supported use the __ro_after_init attribute instead of -__initdata for __alt_call_maybe_initdata. - -Fixes: f26bb285949b ('xen: Implement xen/alternative-call.h for use in common code') -Signed-off-by: Roger Pau Monné -Reviewed-by: Andrew Cooper -master commit: af4cd0a6a61cdb03bc1afca9478b05b0c9703599 -master date: 2024-04-11 18:51:36 +0100 ---- - xen/include/xen/alternative-call.h | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/xen/include/xen/alternative-call.h b/xen/include/xen/alternative-call.h -index 5c6b9a562b..10f7d7637e 100644 ---- a/xen/include/xen/alternative-call.h -+++ b/xen/include/xen/alternative-call.h -@@ -50,7 +50,12 @@ - - #include - --#define __alt_call_maybe_initdata __initdata -+#ifdef CONFIG_LIVEPATCH -+/* Must keep for livepatches to resolve alternative calls. */ -+# define __alt_call_maybe_initdata __ro_after_init -+#else -+# define __alt_call_maybe_initdata __initdata -+#endif - - #else - --- -2.30.2 - diff --git a/xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch b/xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch deleted file mode 100644 index af34479..0000000 --- a/xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch +++ /dev/null @@ -1,56 +0,0 @@ -From af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41 Mon Sep 17 00:00:00 2001 -From: Ross Lagerwall -Date: Mon, 29 Apr 2024 09:36:04 +0200 -Subject: [PATCH] x86/rtc: Avoid UIP flag being set for longer than expected - -In a test, OVMF reported an error initializing the RTC without -indicating the precise nature of the error. The only plausible -explanation I can find is as follows: - -As part of the initialization, OVMF reads register C and then reads -register A repatedly until the UIP flag is not set. If this takes longer -than 100 ms, OVMF fails and reports an error. This may happen with the -following sequence of events: - -At guest time=0s, rtc_init() calls check_update_timer() which schedules -update_timer for t=(1 - 244us). - -At t=1s, the update_timer function happens to have been called >= 244us -late. In the timer callback, it sets the UIP flag and schedules -update_timer2 for t=1s. - -Before update_timer2 runs, the guest reads register C which calls -check_update_timer(). check_update_timer() stops the scheduled -update_timer2 and since the guest time is now outside of the update -cycle, it schedules update_timer for t=(2 - 244us). - -The UIP flag will therefore be set for a whole second from t=1 to t=2 -while the guest repeatedly reads register A waiting for the UIP flag to -clear. Fix it by clearing the UIP flag when scheduling update_timer. - -I was able to reproduce this issue with a synthetic test and this -resolves the issue. - -Signed-off-by: Ross Lagerwall -Reviewed-by: Jan Beulich -master commit: 43a07069863b419433dee12c9b58c1f7ce70aa97 -master date: 2024-04-23 14:09:18 +0200 ---- - xen/arch/x86/hvm/rtc.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c -index 206b4296e9..4839374352 100644 ---- a/xen/arch/x86/hvm/rtc.c -+++ b/xen/arch/x86/hvm/rtc.c -@@ -202,6 +202,7 @@ static void check_update_timer(RTCState *s) - } - else - { -+ s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP; - next_update_time = (USEC_PER_SEC - guest_usec - 244) * NS_PER_USEC; - expire_time = NOW() + next_update_time; - s->next_update_time = expire_time; --- -2.30.2 - diff --git a/xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch b/xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch deleted file mode 100644 index c27b537..0000000 --- a/xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch +++ /dev/null @@ -1,36 +0,0 @@ -From eb7059767c82d833ebecdf8106e96482b04f3c40 Mon Sep 17 00:00:00 2001 -From: Jan Beulich -Date: Mon, 29 Apr 2024 09:36:37 +0200 -Subject: [PATCH] x86/MTRR: correct inadvertently inverted WC check -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -The ! clearly got lost by mistake. - -Fixes: e9e0eb30d4d6 ("x86/MTRR: avoid several indirect calls") -Reported-by: Marek Marczykowski-Górecki -Signed-off-by: Jan Beulich -Acked-by: Roger Pau Monné -master commit: 77e25f0e30ddd11e043e6fce84bf108ce7de5b6f -master date: 2024-04-23 14:13:48 +0200 ---- - xen/arch/x86/cpu/mtrr/main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xen/arch/x86/cpu/mtrr/main.c b/xen/arch/x86/cpu/mtrr/main.c -index 55a4da54a7..90b235f57e 100644 ---- a/xen/arch/x86/cpu/mtrr/main.c -+++ b/xen/arch/x86/cpu/mtrr/main.c -@@ -316,7 +316,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, - } - - /* If the type is WC, check that this processor supports it */ -- if ((type == X86_MT_WC) && mtrr_have_wrcomb()) { -+ if ((type == X86_MT_WC) && !mtrr_have_wrcomb()) { - printk(KERN_WARNING - "mtrr: your processor doesn't support write-combining\n"); - return -EOPNOTSUPP; --- -2.30.2 - diff --git a/xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch b/xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch deleted file mode 100644 index 475a03d..0000000 --- a/xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch +++ /dev/null @@ -1,75 +0,0 @@ -From f0ff1d9cb96041a84a24857a6464628240deed4f Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= -Date: Mon, 29 Apr 2024 09:37:29 +0200 -Subject: [PATCH] x86/spec: adjust logic that elides lfence -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -It's currently too restrictive by just checking whether there's a BHB clearing -sequence selected. It should instead check whether BHB clearing is used on -entry from PV or HVM specifically. - -Switch to use opt_bhb_entry_{pv,hvm} instead, and then remove cpu_has_bhb_seq -since it no longer has any users. - -Reported-by: Jan Beulich -Fixes: 954c983abcee ('x86/spec-ctrl: Software BHB-clearing sequences') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich -Reviewed-by: Andrew Cooper -master commit: 656ae8f1091bcefec9c46ec3ea3ac2118742d4f6 -master date: 2024-04-25 16:37:01 +0200 ---- - xen/arch/x86/include/asm/cpufeature.h | 3 --- - xen/arch/x86/spec_ctrl.c | 6 +++--- - 2 files changed, 3 insertions(+), 6 deletions(-) - -diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h -index 7a312c485e..3c57f55de0 100644 ---- a/xen/arch/x86/include/asm/cpufeature.h -+++ b/xen/arch/x86/include/asm/cpufeature.h -@@ -228,9 +228,6 @@ static inline bool boot_cpu_has(unsigned int feat) - #define cpu_bug_fpu_ptrs boot_cpu_has(X86_BUG_FPU_PTRS) - #define cpu_bug_null_seg boot_cpu_has(X86_BUG_NULL_SEG) - --#define cpu_has_bhb_seq (boot_cpu_has(X86_SPEC_BHB_TSX) || \ -- boot_cpu_has(X86_SPEC_BHB_LOOPS)) -- - enum _cache_type { - CACHE_TYPE_NULL = 0, - CACHE_TYPE_DATA = 1, -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 8c67d6256a..12c19b7eca 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -2328,7 +2328,7 @@ void __init init_speculation_mitigations(void) - * unconditional WRMSR. If we do have it, or we're not using any - * prior conditional block, then it's safe to drop the LFENCE. - */ -- if ( !cpu_has_bhb_seq && -+ if ( !opt_bhb_entry_pv && - (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || - !boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV)) ) - setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_PV); -@@ -2344,7 +2344,7 @@ void __init init_speculation_mitigations(void) - * active in the block that is skipped when interrupting guest - * context, then it's safe to drop the LFENCE. - */ -- if ( !cpu_has_bhb_seq && -+ if ( !opt_bhb_entry_pv && - (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || - (!boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) && - !boot_cpu_has(X86_FEATURE_SC_RSB_PV))) ) -@@ -2356,7 +2356,7 @@ void __init init_speculation_mitigations(void) - * A BHB sequence, if used, is the only conditional action, so if we - * don't have it, we don't need the safety LFENCE. - */ -- if ( !cpu_has_bhb_seq ) -+ if ( !opt_bhb_entry_hvm ) - setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_VMX); - } - --- -2.30.2 - diff --git a/xen.ocaml5.fixes.patch b/xen.ocaml5.fixes.patch index bdffd4c..fc85a41 100644 --- a/xen.ocaml5.fixes.patch +++ b/xen.ocaml5.fixes.patch @@ -27,14 +27,3 @@ # define a library target .cmxa and .cma define OCAML_LIBRARY_template ---- xen-4.17.1/tools/ocaml/xenstored/disk.ml.orig 2023-04-27 06:53:19.000000000 -0600 -+++ xen-4.17.1/tools/ocaml/xenstored/disk.ml 2023-06-20 09:49:44.361963710 -0600 -@@ -30,7 +30,7 @@ let undec c = - | _ -> raise (Failure "undecify") - - let unhex c = -- let c = Char.lowercase c in -+ let c = Char.lowercase_ascii c in - match c with - | '0' .. '9' -> (Char.code c) - (Char.code '0') - | 'a' .. 'f' -> (Char.code c) - (Char.code 'a') + 10 diff --git a/xen.spec b/xen.spec index 32950cd..cd4b475 100644 --- a/xen.spec +++ b/xen.spec @@ -50,12 +50,12 @@ %endif # Hypervisor ABI -%define hv_abi 4.18 +%define hv_abi 4.19 Summary: Xen is a virtual machine monitor Name: xen -Version: 4.18.2 -Release: 5%{?dist} +Version: 4.19.0 +Release: 1%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -114,13 +114,6 @@ Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch -Patch54: xen.git-2d38302c33b117aa9a417056db241aefc840c2f0.patch -Patch55: xen.git-8bdcb0b98b53140102031ceca0611f22190227fd.patch -Patch56: xen.git-af0e9ba44a58c87d6d135d8ffbf468b4ceac0a41.patch -Patch57: xen.git-eb7059767c82d833ebecdf8106e96482b04f3c40.patch -Patch58: xen.git-0b0c7dca70d64c35c86e5d503f67366ebe2b9138.patch -Patch59: xen.git-f0ff1d9cb96041a84a24857a6464628240deed4f.patch -Patch60: xsa458.patch %if %build_qemutrad @@ -335,13 +328,6 @@ manage Xen virtual machines. %endif %patch 52 -p1 %patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 -%patch 57 -p1 -%patch 58 -p1 -%patch 59 -p1 -%patch 60 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -403,6 +389,9 @@ CONFIG_EXTRA="$CONFIG_EXTRA --with-system-seabios=/usr/share/seabios/bios-256k.b %else CONFIG_EXTRA="$CONFIG_EXTRA --disable-seabios" %endif +%if %with_systemd_presets +CONFIG_EXTRA="$CONFIG_EXTRA --enable-systemd" +%endif ./configure --prefix=%{_prefix} --libdir=%{_libdir} --libexecdir=%{_libexecdir} --with-system-qemu=/usr/bin/qemu-system-i386 --with-linux-backend-modules="xen-evtchn xen-gntdev xen-gntalloc xen-blkback xen-netback xen-pciback xen-scsiback xen-acpi-processor" $CONFIG_EXTRA unset CFLAGS CXXFLAGS FFLAGS LDFLAGS export LDFLAGS="$LDFLAGS_SAVE" @@ -553,7 +542,7 @@ ln -s %{_libexecdir}/%{name} %{buildroot}/%{_libdir}/%{name} %endif ############ create symlink to qemu-system-i386 in /usr/bin ############ -ln -s /usr/bin/qemu-system-i386 %{buildroot}/%{_libexecdir}/%{name}/bin/qemu-system-i386 +ln -s ../../../bin/qemu-system-i386 %{buildroot}/%{_libexecdir}/%{name}/bin/qemu-system-i386 ############ debug packaging: list files ############ @@ -773,7 +762,6 @@ fi # man pages %if %build_docs %{_mandir}/man1/xentop.1* -%{_mandir}/man1/xentrace_format.1* %{_mandir}/man8/xentrace.8* %{_mandir}/man1/xl.1* %{_mandir}/man5/xl.cfg.5* @@ -791,6 +779,7 @@ fi %{_mandir}/man1/xenhypfs.1.gz %{_mandir}/man7/xen-vbd-interface.7.gz %{_mandir}/man5/xl-pci-configuration.5.gz +%{_mandir}/man8/xenwatchdogd.8.gz %endif %{python3_sitearch}/xenfsimage*.so @@ -828,8 +817,6 @@ fi %{_bindir}/qemu-*-xen %{_bindir}/xenstore %{_bindir}/xenstore-* -%{_bindir}/pygrub -%{_bindir}/xentrace* #%#{_bindir}/remus # XSM %{_sbindir}/flask-* @@ -948,6 +935,16 @@ fi %endif %changelog +* Sat Aug 03 2024 Michael Young - 4.19.0-1 +- update to xen-4.19.0 + rebase xen.fedora.systemd.patch, xen.efi.build.patch + xen.ocaml5.fixes.patch and xen.gcc14.fixes.patch + remove patches now included or superceded upstream + now need to enable systemd explicitly + xentrace_format has gone, pygrub is now only in /usr/libexec/xen/bin/ + package xenwatchdogd.8.gz + use relative links for /usr/bin/qemu-system-i386 + * Sat Jul 20 2024 Fedora Release Engineering - 4.18.2-5 - Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild diff --git a/xsa458.patch b/xsa458.patch deleted file mode 100644 index 8be0a90..0000000 --- a/xsa458.patch +++ /dev/null @@ -1,38 +0,0 @@ -From: Jan Beulich -Subject: x86/IRQ: avoid double unlock in map_domain_pirq() - -Forever since its introduction the main loop in the function dealing -with multi-vector MSI had error exit points ("break") with different -properties: In one case no IRQ descriptor lock is being held. -Nevertheless the subsequent error cleanup path assumed such a lock would -uniformly need releasing. Identify the case by setting "desc" to NULL, -thus allowing the unlock to be skipped as necessary. - -This is CVE-2024-31143 / XSA-458. - -Coverity ID: 1605298 -Fixes: d1b6d0a02489 ("x86: enable multi-vector MSI") -Signed-off-by: Jan Beulich -Reviewed-by: Roger Pau Monné - ---- a/xen/arch/x86/irq.c -+++ b/xen/arch/x86/irq.c -@@ -2273,6 +2273,7 @@ int map_domain_pirq( - - set_domain_irq_pirq(d, irq, info); - spin_unlock_irqrestore(&desc->lock, flags); -+ desc = NULL; - - info = NULL; - irq = create_irq(NUMA_NO_NODE, true); -@@ -2308,7 +2309,9 @@ int map_domain_pirq( - - if ( ret ) - { -- spin_unlock_irqrestore(&desc->lock, flags); -+ if ( desc ) -+ spin_unlock_irqrestore(&desc->lock, flags); -+ - pci_disable_msi(msi_desc); - if ( nr ) - { From ef4574608ae2807bd37e8bf7415278594da7a781 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 14 Aug 2024 22:07:13 +0100 Subject: [PATCH 58/99] 2 security fixes error handling in x86 IOMMU identity mapping [XSA-460, CVE-2024-31145] PCI device pass-through with shared resources [XSA-461, CVE-2024-31146] --- xen.spec | 10 +++++- xsa460.patch | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ xsa461.patch | 33 +++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 xsa460.patch create mode 100644 xsa461.patch diff --git a/xen.spec b/xen.spec index cd4b475..371da8d 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.0 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -114,6 +114,8 @@ Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch +Patch54: xsa460.patch +Patch55: xsa461.patch %if %build_qemutrad @@ -328,6 +330,8 @@ manage Xen virtual machines. %endif %patch 52 -p1 %patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -935,6 +939,10 @@ fi %endif %changelog +* Wed Aug 14 2024 Michael Young - 4.19.0-2 +- error handling in x86 IOMMU identity mapping [XSA-460, CVE-2024-31145] +- PCI device pass-through with shared resources [XSA-461, CVE-2024-31146] + * Sat Aug 03 2024 Michael Young - 4.19.0-1 - update to xen-4.19.0 rebase xen.fedora.systemd.patch, xen.efi.build.patch diff --git a/xsa460.patch b/xsa460.patch new file mode 100644 index 0000000..270df8d --- /dev/null +++ b/xsa460.patch @@ -0,0 +1,93 @@ +From: Teddy Astie +Subject: x86/IOMMU: move tracking in iommu_identity_mapping() + +If for some reason xmalloc() fails after having mapped the reserved +regions, an error is reported, but the regions remain mapped in the P2M. + +Similarly if an error occurs during set_identity_p2m_entry() (except on +the first call), the partial mappings of the region would be retained +without being tracked anywhere, and hence without there being a way to +remove them again from the domain's P2M. + +Move the setting up of the list entry ahead of trying to map the region. +In cases other than the first mapping failing, keep record of the full +region, such that a subsequent unmapping request can be properly torn +down. + +To compensate for the potentially excess unmapping requests, don't log a +warning from p2m_remove_identity_entry() when there really was nothing +mapped at a given GFN. + +This is XSA-460 / CVE-2024-31145. + +Fixes: 2201b67b9128 ("VT-d: improve RMRR region handling") +Fixes: c0e19d7c6c42 ("IOMMU: generalize VT-d's tracking of mapped RMRR regions") +Signed-off-by: Teddy Astie +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/mm/p2m.c ++++ b/xen/arch/x86/mm/p2m.c +@@ -1267,9 +1267,11 @@ int p2m_remove_identity_entry(struct dom + else + { + gfn_unlock(p2m, gfn, 0); +- printk(XENLOG_G_WARNING +- "non-identity map d%d:%lx not cleared (mapped to %lx)\n", +- d->domain_id, gfn_l, mfn_x(mfn)); ++ if ( (p2mt != p2m_invalid && p2mt != p2m_mmio_dm) || ++ a != p2m_access_n || !mfn_eq(mfn, INVALID_MFN) ) ++ printk(XENLOG_G_WARNING ++ "non-identity map %pd:%lx not cleared (mapped to %lx)\n", ++ d, gfn_l, mfn_x(mfn)); + ret = 0; + } + +--- a/xen/drivers/passthrough/x86/iommu.c ++++ b/xen/drivers/passthrough/x86/iommu.c +@@ -267,24 +267,36 @@ int iommu_identity_mapping(struct domain + if ( p2ma == p2m_access_x ) + return -ENOENT; + +- while ( base_pfn < end_pfn ) +- { +- int err = set_identity_p2m_entry(d, base_pfn, p2ma, flag); +- +- if ( err ) +- return err; +- base_pfn++; +- } +- + map = xmalloc(struct identity_map); + if ( !map ) + return -ENOMEM; ++ + map->base = base; + map->end = end; + map->access = p2ma; + map->count = 1; ++ ++ /* ++ * Insert into list ahead of mapping, so the range can be found when ++ * trying to clean up. ++ */ + list_add_tail(&map->list, &hd->arch.identity_maps); + ++ for ( ; base_pfn < end_pfn; ++base_pfn ) ++ { ++ int err = set_identity_p2m_entry(d, base_pfn, p2ma, flag); ++ ++ if ( !err ) ++ continue; ++ ++ if ( (map->base >> PAGE_SHIFT_4K) == base_pfn ) ++ { ++ list_del(&map->list); ++ xfree(map); ++ } ++ return err; ++ } ++ + return 0; + } + diff --git a/xsa461.patch b/xsa461.patch new file mode 100644 index 0000000..82c1f29 --- /dev/null +++ b/xsa461.patch @@ -0,0 +1,33 @@ +From: Jan Beulich +Subject: x86/pass-through: documents as security-unsupported when sharing resources + +When multiple devices share resources and one of them is to be passed +through to a guest, security of the entire system and of respective +guests individually cannot really be guaranteed without knowing +internals of any of the involved guests. Therefore such a configuration +cannot really be security-supported, yet making that explicit was so far +missing. + +This is XSA-461 / CVE-2024-31146. + +Signed-off-by: Jan Beulich +Reviewed-by: Juergen Gross +--- +TBD: Of course the system bus(es) is a / are shared resource(s), too. + I'm afraid I don't know the low level details of PCI to be able to + tell whether there are any fairness guarantees there. + +--- a/SUPPORT.md ++++ b/SUPPORT.md +@@ -841,6 +841,11 @@ This feature is not security supported: + + Only systems using IOMMUs are supported. + ++Passing through of devices sharing resources with another device is not ++security supported. Such sharing could e.g. be the same line interrupt being ++used by multiple devices, one of which is to be passed through, or two such ++devices having memory BARs within the same 4k page. ++ + Not compatible with migration, populate-on-demand, altp2m, + introspection, memory sharing, or memory paging. + From b5342a4b6777071a3fab2faaf6989cb07935f11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Such=C3=BD?= Date: Wed, 4 Sep 2024 22:52:13 +0200 Subject: [PATCH 59/99] convert license to SPDX This is part of https://fedoraproject.org/wiki/Changes/SPDX_Licenses_Phase_4 --- xen.spec | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xen.spec b/xen.spec index 371da8d..8ebb09e 100644 --- a/xen.spec +++ b/xen.spec @@ -55,8 +55,9 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.0 -Release: 2%{?dist} -License: GPLv2+ and LGPLv2+ and BSD +Release: 3%{?dist} +# Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. +License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz Source2: %{name}.logrotate @@ -939,6 +940,9 @@ fi %endif %changelog +* Wed Sep 04 2024 Miroslav Suchý - 4.19.0-3 +- convert license to SPDX + * Wed Aug 14 2024 Michael Young - 4.19.0-2 - error handling in x86 IOMMU identity mapping [XSA-460, CVE-2024-31145] - PCI device pass-through with shared resources [XSA-461, CVE-2024-31146] From 417c2eb41aad8ddbadd3acb2aee775291cb7959b Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 24 Sep 2024 16:48:07 +0100 Subject: [PATCH 60/99] x86: Deadlock in vlapic_error() [XSA-462, CVE-2024-45817] --- xen.spec | 7 ++++++- xsa462.patch | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 xsa462.patch diff --git a/xen.spec b/xen.spec index 8ebb09e..7b24ac4 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.0 -Release: 3%{?dist} +Release: 4%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -117,6 +117,7 @@ Patch52: xen.gcc14.fixes.patch Patch53: newlib.gcc14.fixes.patch Patch54: xsa460.patch Patch55: xsa461.patch +Patch56: xsa462.patch %if %build_qemutrad @@ -333,6 +334,7 @@ manage Xen virtual machines. %patch 53 -p1 %patch 54 -p1 %patch 55 -p1 +%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -940,6 +942,9 @@ fi %endif %changelog +* Tue Sep 24 2024 Michael Young - 4.19.0-4 +- x86: Deadlock in vlapic_error() [XSA-462, CVE-2024-45817] + * Wed Sep 04 2024 Miroslav Suchý - 4.19.0-3 - convert license to SPDX diff --git a/xsa462.patch b/xsa462.patch new file mode 100644 index 0000000..be538f9 --- /dev/null +++ b/xsa462.patch @@ -0,0 +1,47 @@ +From: Jan Beulich +Subject: x86/vLAPIC: prevent undue recursion of vlapic_error() + +With the error vector set to an illegal value, the function invoking +vlapic_set_irq() would bring execution back here, with the non-recursive +lock already held. Avoid the call in this case, merely further updating +ESR (if necessary). + +This is XSA-462 / CVE-2024-45817. + +Fixes: 5f32d186a8b1 ("x86/vlapic: don't silently accept bad vectors") +Reported-by: Federico Serafini +Reported-by: Andrew Cooper +Signed-off-by: Jan Beulich +Signed-off-by: Andrew Cooper +Reviewed-by: Andrew Cooper + +diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c +index 2ec95942713e..8758c4217fab 100644 +--- a/xen/arch/x86/hvm/vlapic.c ++++ b/xen/arch/x86/hvm/vlapic.c +@@ -112,9 +112,24 @@ static void vlapic_error(struct vlapic *vlapic, unsigned int errmask) + if ( (esr & errmask) != errmask ) + { + uint32_t lvterr = vlapic_get_reg(vlapic, APIC_LVTERR); ++ bool inj = false; + +- vlapic_set_reg(vlapic, APIC_ESR, esr | errmask); + if ( !(lvterr & APIC_LVT_MASKED) ) ++ { ++ /* ++ * If LVTERR is unmasked and has an illegal vector, vlapic_set_irq() ++ * will end up back here. Break the cycle by only injecting LVTERR ++ * if it will succeed, and folding in RECVILL otherwise. ++ */ ++ if ( (lvterr & APIC_VECTOR_MASK) >= 16 ) ++ inj = true; ++ else ++ errmask |= APIC_ESR_RECVILL; ++ } ++ ++ vlapic_set_reg(vlapic, APIC_ESR, esr | errmask); ++ ++ if ( inj ) + vlapic_set_irq(vlapic, lvterr & APIC_VECTOR_MASK, 0); + } + spin_unlock_irqrestore(&vlapic->esr_lock, flags); From a322535e9ffceca01cb37dd3aefe60a8ad826356 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 25 Sep 2024 22:02:12 +0100 Subject: [PATCH 61/99] add bugzilla references --- xen.spec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 7b24ac4..d79eba9 100644 --- a/xen.spec +++ b/xen.spec @@ -943,14 +943,16 @@ fi %changelog * Tue Sep 24 2024 Michael Young - 4.19.0-4 -- x86: Deadlock in vlapic_error() [XSA-462, CVE-2024-45817] +- x86: Deadlock in vlapic_error() [XSA-462, CVE-2024-45817] (#2314782) * Wed Sep 04 2024 Miroslav Suchý - 4.19.0-3 - convert license to SPDX * Wed Aug 14 2024 Michael Young - 4.19.0-2 - error handling in x86 IOMMU identity mapping [XSA-460, CVE-2024-31145] + (#2314784) - PCI device pass-through with shared resources [XSA-461, CVE-2024-31146] + (#2314783) * Sat Aug 03 2024 Michael Young - 4.19.0-1 - update to xen-4.19.0 From 2b88083cfcffc5bd9f7d70a6256a4756ecdb1112 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Fri, 6 Dec 2024 19:19:08 +0000 Subject: [PATCH 62/99] update to xen-4.19.1 --- .gitignore | 2 +- newlib.gcc14.fixes.patch | 388 --------------------------------------- sources | 2 +- xen.gcc13.fixes.patch | 10 - xen.gcc14.fixes.patch | 12 -- xen.ocaml5.fixes.patch | 29 --- xen.spec | 29 ++- xsa460.patch | 93 ---------- xsa461.patch | 33 ---- xsa462.patch | 47 ----- 10 files changed, 13 insertions(+), 632 deletions(-) delete mode 100644 newlib.gcc14.fixes.patch delete mode 100644 xen.gcc13.fixes.patch delete mode 100644 xen.gcc14.fixes.patch delete mode 100644 xen.ocaml5.fixes.patch delete mode 100644 xsa460.patch delete mode 100644 xsa461.patch delete mode 100644 xsa462.patch diff --git a/.gitignore b/.gitignore index a996079..69cde46 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.19.0.tar.gz +/xen-4.19.1.tar.gz diff --git a/newlib.gcc14.fixes.patch b/newlib.gcc14.fixes.patch deleted file mode 100644 index bdb3594..0000000 --- a/newlib.gcc14.fixes.patch +++ /dev/null @@ -1,388 +0,0 @@ ---- xen-4.18.0/stubdom/newlib-makedoc.patch.orig 2023-11-16 21:44:21.000000000 +0000 -+++ xen-4.18.0/stubdom/newlib-makedoc.patch 2024-02-01 20:32:40.565785056 +0000 -@@ -33,3 +33,385 @@ - #include - - #define DEF_SIZE 5000 -+--- -+ -+patch makedoc.c for gcc14 build -+ -+--- newlib-1.16.0/newlib/doc/makedoc.c.orig 2007-01-02 16:59:59.000000000 +0000 -++++ newlib-1.16.0/newlib/doc/makedoc.c 2024-02-01 20:26:32.415396758 +0000 -+@@ -63,25 +63,20 @@ -+ -+ -+ -+-static void DEFUN(init_string_with_size,(buffer, size), -+- string_type *buffer AND -+- unsigned int size ) -++static void init_string_with_size (string_type *buffer, unsigned int size) -+ { -+ buffer->write_idx = 0; -+ buffer->size = size; -+ buffer->ptr = malloc(size); -+ } -+ -+-static void DEFUN(init_string,(buffer), -+- string_type *buffer) -++static void init_string (string_type *buffer) -+ { -+ init_string_with_size(buffer, DEF_SIZE); -+ -+ } -+ -+-static int DEFUN(find, (str, what), -+- string_type *str AND -+- char *what) -++static int find (string_type *str, char *what) -+ { -+ unsigned int i; -+ char *p; -+@@ -97,30 +92,24 @@ -+ -+ } -+ -+-static void DEFUN(write_buffer,(buffer), -+- string_type *buffer) -++static void write_buffer (string_type *buffer) -+ { -+ fwrite(buffer->ptr, buffer->write_idx, 1, stdout); -+ } -+ -+ -+-static void DEFUN(delete_string,(buffer), -+- string_type *buffer) -++static void delete_string (string_type *buffer) -+ { -+ free(buffer->ptr); -+ } -+ -+ -+-static char *DEFUN(addr, (buffer, idx), -+- string_type *buffer AND -+- unsigned int idx) -++static char * addr (string_type *buffer, unsigned int idx) -+ { -+ return buffer->ptr + idx; -+ } -+ -+-static char DEFUN(at,(buffer, pos), -+- string_type *buffer AND -+- unsigned int pos) -++static char at (string_type *buffer, unsigned int pos) -+ { -+ if ( pos >= buffer->write_idx) -+ { -+@@ -129,9 +118,7 @@ -+ return buffer->ptr[pos]; -+ } -+ -+-static void DEFUN(catchar,(buffer, ch), -+- string_type *buffer AND -+- char ch) -++static void catchar (string_type *buffer, char ch) -+ { -+ if (buffer->write_idx == buffer->size) -+ { -+@@ -143,9 +130,7 @@ -+ } -+ -+ -+-static void DEFUN(overwrite_string,(dst, src), -+- string_type *dst AND -+- string_type *src) -++static void overwrite_string (string_type *dst, string_type *src) -+ { -+ free(dst->ptr); -+ dst->size = src->size; -+@@ -153,9 +138,7 @@ -+ dst->ptr = src->ptr; -+ } -+ -+-static void DEFUN(catstr,(dst, src), -+- string_type *dst AND -+- string_type *src) -++static void catstr ( string_type *dst, string_type *src) -+ { -+ unsigned int i; -+ for (i = 0; i < src->write_idx; i++) -+@@ -165,9 +148,7 @@ -+ } -+ -+ -+-static void DEFUN(cattext,(buffer, string), -+- string_type *buffer AND -+- char *string) -++static void cattext (string_type *buffer, char *string) -+ { -+ -+ while (*string) -+@@ -177,10 +158,7 @@ -+ } -+ } -+ -+-static void DEFUN(catbuf,(buffer, buf, len), -+- string_type *buffer AND -+- char *buf AND -+- unsigned int len) -++static void catbuf ( string_type *buffer, char *buf, unsigned int len) -+ { -+ -+ while (len--) -+@@ -192,10 +170,7 @@ -+ -+ -+ -+-static unsigned int -+-DEFUN(skip_white_and_stars,(src, idx), -+- string_type *src AND -+- unsigned int idx) -++static unsigned int skip_white_and_stars (string_type *src, unsigned int idx) -+ { -+ while (isspace(at(src,idx)) -+ || (at(src,idx) == '*' && at(src,idx +1) !='/')) -+@@ -216,10 +191,23 @@ -+ stinst_type *pc; -+ stinst_type sstack[STACK]; -+ stinst_type *ssp = &sstack[0]; -+-int istack[STACK]; -+-int *isp = &istack[0]; -+ -+-typedef int *word_type; -++#if defined(__PTRDIFF_TYPE__) -++typedef signed __PTRDIFF_TYPE__ intptr_t; -++typedef unsigned __PTRDIFF_TYPE__ uintptr_t; -++#else -++/* -++ * Fallback to hardcoded values, -++ * should be valid on cpu's with 32bit int/32bit void* -++ */ -++typedef signed long intptr_t; -++typedef unsigned long uintptr_t; -++#endif -++ -++uintptr_t istack[STACK]; -++uintptr_t *isp = &istack[0]; -++ -++typedef uintptr_t *word_type; -+ -+ -+ -+@@ -236,8 +224,7 @@ -+ typedef struct dict_struct dict_type; -+ #define WORD(x) static void x() -+ -+-static void DEFUN(exec,(word), -+- dict_type *word) -++static void exec (dict_type *word) -+ { -+ pc = word->code; -+ while (*pc) -+@@ -267,7 +254,7 @@ -+ { -+ isp++; -+ pc++; -+- *isp = (int)(*pc); -++ *isp = (uintptr_t)(*pc); -+ pc++; -+ -+ } -+@@ -294,10 +281,7 @@ -+ Blank lines are turned into one blank line -+ */ -+ -+-static void -+-DEFUN(remove_noncomments,(src,dst), -+- string_type *src AND -+- string_type *dst) -++static void remove_noncomments (string_type *src, string_type *dst) -+ { -+ unsigned int idx = 0; -+ -+@@ -349,8 +333,7 @@ -+ -+ */ -+ -+-static void -+-DEFUN_VOID(exfunstuff) -++static void exfunstuff (void) -+ { -+ unsigned int openp; -+ unsigned int fname; -+@@ -522,8 +505,7 @@ -+ } -+ -+ /* Mod tos so that only lines with leading dots remain */ -+-static void -+-DEFUN_VOID(outputdots) -++static void (outputdots (void)) -+ { -+ unsigned int idx = 0; -+ string_type out; -+@@ -772,10 +754,7 @@ -+ -+ } -+ /* A command is all upper case,and alone on a line */ -+-static int -+-DEFUN( iscommand,(ptr, idx), -+- string_type *ptr AND -+- unsigned int idx) -++static int iscommand (string_type *ptr, unsigned int idx) -+ { -+ unsigned int len = 0; -+ while (at(ptr,idx)) { -+@@ -797,10 +776,7 @@ -+ } -+ -+ -+-DEFUN(copy_past_newline,(ptr, idx, dst), -+- string_type *ptr AND -+- unsigned int idx AND -+- string_type *dst) -++unsigned int copy_past_newline (string_type *ptr, unsigned int idx, string_type *dst) -+ { -+ while (at(ptr, idx) && at(ptr, idx) != '\n') -+ { -+@@ -1060,10 +1036,7 @@ -+ -+ } -+ -+-char * -+-DEFUN(nextword,(string, word), -+- char *string AND -+- char **word) -++char * nextword (char *string, char **word) -+ { -+ char *word_start; -+ int idx; -+@@ -1138,9 +1111,7 @@ -+ -+ } -+ dict_type *root; -+-dict_type * -+-DEFUN(lookup_word,(word), -+- char *word) -++dict_type * lookup_word (char *word) -+ { -+ dict_type *ptr = root; -+ while (ptr) { -+@@ -1154,7 +1125,7 @@ -+ -+ } -+ -+-static void DEFUN_VOID(perform) -++static int perform (void) -+ { -+ tos = stack; -+ -+@@ -1192,9 +1163,7 @@ -+ } -+ } -+ -+-dict_type * -+-DEFUN(newentry,(word), -+- char *word) -++dict_type * newentry (char *word) -+ { -+ dict_type *new = (dict_type *)malloc(sizeof(dict_type)); -+ new->word = word; -+@@ -1208,10 +1177,7 @@ -+ } -+ -+ -+-unsigned int -+-DEFUN(add_to_definition,(entry, word), -+- dict_type *entry AND -+- stinst_type word) -++unsigned int add_to_definition (dict_type *entry, stinst_type word) -+ { -+ if (entry->code_end == entry->code_length) -+ { -+@@ -1232,9 +1198,7 @@ -+ -+ -+ void -+-DEFUN(add_intrinsic,(name, func), -+- char *name AND -+- void (*func)()) -++add_intrinsic (char *name, void (*func)(void)) -+ { -+ dict_type *new = newentry(name); -+ add_to_definition(new, func); -+@@ -1247,9 +1211,7 @@ -+ -+ } -+ -+-void -+-DEFUN(add_var,(name), -+- char *name) -++void add_var (char *name) -+ { -+ dict_type *new = newentry(name); -+ add_to_definition(new, push_number); -+@@ -1262,8 +1224,7 @@ -+ -+ -+ void -+-DEFUN(compile, (string), -+- char *string) -++compile (char *string) -+ -+ { -+ int jstack[STACK]; -+@@ -1315,11 +1276,11 @@ -+ /* Got a number, embedd the magic push number -+ function */ -+ add_to_definition(ptr, push_number); -+- add_to_definition(ptr, atol(word)); -++ add_to_definition(ptr, (stinst_type)atol(word)); -+ break; -+ default: -+ add_to_definition(ptr, call); -+- add_to_definition(ptr, lookup_word(word)); -++ add_to_definition(ptr, (stinst_type)lookup_word(word)); -+ } -+ -+ string = nextword(string, &word); -+@@ -1336,9 +1297,9 @@ -+ } -+ -+ -+-static void DEFUN_VOID(bang) -++static void bang (void) -+ { -+-*(int *)((isp[0])) = isp[-1]; -++*(uintptr_t *)((isp[0])) = isp[-1]; -+ isp-=2; -+ pc++; -+ -+@@ -1359,9 +1320,7 @@ -+ -+ -+ -+-static void DEFUN(read_in, (str, file), -+- string_type *str AND -+- FILE *file) -++static void read_in (string_type *str, FILE *file) -+ { -+ char buff[10000]; -+ unsigned int r; -+@@ -1378,15 +1337,13 @@ -+ } -+ -+ -+-static void DEFUN_VOID(usage) -++static void usage (void) -+ { -+ fprintf(stderr,"usage: -[d|i|g] file\n"); -+ exit(33); -+ } -+ -+-int DEFUN(main,(ac,av), -+-int ac AND -+-char *av[]) -++int main (int ac, char *av[]) -+ { -+ unsigned int i; -+ diff --git a/sources b/sources index e979065..595852d 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.19.0.tar.gz) = bc0b4257cab66b0f9d4a1fe72e07f4980398b2934989c02ffe488b465eca3443caa0ded903871480aba6e36212921f335b68d67f202f22548c31899225f2d657 +SHA512 (xen-4.19.1.tar.gz) = 6971d07d4eafd40186f35cf6de235badbdf0e1640974693b8fbd415876c46634094178a6157e6dfdc16af885c70ff3b7a72be35a88dcc63daf36e6eb08f9b17b diff --git a/xen.gcc13.fixes.patch b/xen.gcc13.fixes.patch deleted file mode 100644 index d9800e2..0000000 --- a/xen.gcc13.fixes.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- xen-4.17.0/xen/common/bunzip2.c.orig 2022-12-08 18:03:08.000000000 +0000 -+++ xen-4.17.0/xen/common/bunzip2.c 2023-01-17 21:35:39.251292015 +0000 -@@ -223,6 +223,7 @@ - for (j = 0; j < groupCount; j++) { - unsigned char length[MAX_SYMBOLS], temp[MAX_HUFCODE_BITS+1]; - int minLen, maxLen, pp; -+ length[0]=0; - /* Read Huffman code lengths for each symbol. They're - stored in a way similar to mtf; record a starting - value for the first symbol, and an offset from the diff --git a/xen.gcc14.fixes.patch b/xen.gcc14.fixes.patch deleted file mode 100644 index a9fb2f3..0000000 --- a/xen.gcc14.fixes.patch +++ /dev/null @@ -1,12 +0,0 @@ -Work around newlib build problems with gcc14 - ---- xen-4.18.0/stubdom/Makefile.orig 2024-01-15 20:35:36.941740548 +0000 -+++ xen-4.18.0/stubdom/Makefile 2024-01-29 22:29:29.067367523 +0000 -@@ -45,6 +45,7 @@ - NEWLIB_CFLAGS+=-D_I386MACH_ALLOW_HW_INTERRUPTS - STUBDOM_SUPPORTED=1 - endif -+NEWLIB_CFLAGS+=-Wno-error=implicit-function-declaration - - CROSS_ROOT=cross-root-$(GNU_TARGET_ARCH) - CROSS_PREFIX=$(CURDIR)/$(CROSS_ROOT) diff --git a/xen.ocaml5.fixes.patch b/xen.ocaml5.fixes.patch deleted file mode 100644 index fc85a41..0000000 --- a/xen.ocaml5.fixes.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- xen-4.17.1/tools/ocaml/common.make.orig 2023-04-27 06:53:19.000000000 -0600 -+++ xen-4.17.1/tools/ocaml/common.make 2023-06-20 09:47:25.250969763 -0600 -@@ -11,9 +11,9 @@ OCAMLFIND ?= ocamlfind - - CFLAGS += -fPIC -I$(shell ocamlc -where) - --OCAMLOPTFLAG_G := $(shell $(OCAMLOPT) -h 2>&1 | sed -n 's/^ *\(-g\) .*/\1/p') --OCAMLOPTFLAGS = $(OCAMLOPTFLAG_G) -ccopt "$(LDFLAGS)" -dtypes $(OCAMLINCLUDE) -cc $(CC) -w F -warn-error F --OCAMLCFLAGS += -g $(OCAMLINCLUDE) -w F -warn-error F -+OCAMLOPTFLAG_G := -g -+OCAMLOPTFLAGS = $(OCAMLOPTFLAG_G) -ccopt "$(LDFLAGS)" -dtypes $(OCAMLINCLUDE) -cc $(CC) -w F -warn-error F -I +unix -+OCAMLCFLAGS += -g $(OCAMLINCLUDE) -w F -warn-error F -I +unix - - VERSION := 4.1 - ---- xen-4.17.1/tools/ocaml/Makefile.rules.orig 2023-04-27 06:53:19.000000000 -0600 -+++ xen-4.17.1/tools/ocaml/Makefile.rules 2023-06-20 10:00:58.769235173 -0600 -@@ -59,9 +59,9 @@ quiet-command = $(if $(V),$1,@printf " % - mk-caml-lib-native = $(call quiet-command, $(OCAMLOPT) $(OCAMLOPTFLAGS) -a -o $1 $2 $3,MLA,$1) - mk-caml-lib-bytecode = $(call quiet-command, $(OCAMLC) $(OCAMLCFLAGS) -a -o $1 $2 $3,MLA,$1) - --mk-caml-stubs = $(call quiet-command, $(OCAMLMKLIB) -o `basename $1 .a` $2,MKLIB,$1) -+mk-caml-stubs = $(call quiet-command, $(OCAMLMKLIB) -g -o `basename $1 .a` $2,MKLIB,$1) - mk-caml-lib-stubs = \ -- $(call quiet-command, $(AR) rcs $1 $2 && $(OCAMLMKLIB) -o `basename $1 .a | sed -e 's/^lib//'` $2,MKLIB,$1) -+ $(call quiet-command, $(AR) rcs $1 $2 && $(OCAMLMKLIB) -g -o `basename $1 .a | sed -e 's/^lib//'` $2,MKLIB,$1) - - # define a library target .cmxa and .cma - define OCAML_LIBRARY_template diff --git a/xen.spec b/xen.spec index d79eba9..b5f39ca 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.19.0 -Release: 4%{?dist} +Version: 4.19.1 +Release: 1%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -110,14 +110,7 @@ Patch41: xen.gcc9.fixes.patch Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch -Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch -Patch50: xen.ocaml5.fixes.patch -Patch52: xen.gcc14.fixes.patch -Patch53: newlib.gcc14.fixes.patch -Patch54: xsa460.patch -Patch55: xsa461.patch -Patch56: xsa462.patch %if %build_qemutrad @@ -325,16 +318,7 @@ manage Xen virtual machines. %patch 43 -p1 %patch 45 -p1 %patch 46 -p1 -%patch 47 -p1 %patch 49 -p1 -%if "%dist" != ".fc38" -%patch 50 -p1 -%endif -%patch 52 -p1 -%patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -942,6 +926,15 @@ fi %endif %changelog +* Thu Dec 05 2024 Michael Young - 4.19.1-1 +- update to xen-4.19.1 + remove patches now included or superceded upstream + +* Tue Nov 12 2024 Michael Young - 4.19.0-5 +- Deadlock in x86 HVM standard VGA handling [XSA-463, CVE-2024-45818] +- libxl leaks data to PVH guests via ACPI tables [XSA-464, CVE-2024-45819] +- additional patches so above applies cleanly + * Tue Sep 24 2024 Michael Young - 4.19.0-4 - x86: Deadlock in vlapic_error() [XSA-462, CVE-2024-45817] (#2314782) diff --git a/xsa460.patch b/xsa460.patch deleted file mode 100644 index 270df8d..0000000 --- a/xsa460.patch +++ /dev/null @@ -1,93 +0,0 @@ -From: Teddy Astie -Subject: x86/IOMMU: move tracking in iommu_identity_mapping() - -If for some reason xmalloc() fails after having mapped the reserved -regions, an error is reported, but the regions remain mapped in the P2M. - -Similarly if an error occurs during set_identity_p2m_entry() (except on -the first call), the partial mappings of the region would be retained -without being tracked anywhere, and hence without there being a way to -remove them again from the domain's P2M. - -Move the setting up of the list entry ahead of trying to map the region. -In cases other than the first mapping failing, keep record of the full -region, such that a subsequent unmapping request can be properly torn -down. - -To compensate for the potentially excess unmapping requests, don't log a -warning from p2m_remove_identity_entry() when there really was nothing -mapped at a given GFN. - -This is XSA-460 / CVE-2024-31145. - -Fixes: 2201b67b9128 ("VT-d: improve RMRR region handling") -Fixes: c0e19d7c6c42 ("IOMMU: generalize VT-d's tracking of mapped RMRR regions") -Signed-off-by: Teddy Astie -Signed-off-by: Jan Beulich -Reviewed-by: Roger Pau Monné - ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -1267,9 +1267,11 @@ int p2m_remove_identity_entry(struct dom - else - { - gfn_unlock(p2m, gfn, 0); -- printk(XENLOG_G_WARNING -- "non-identity map d%d:%lx not cleared (mapped to %lx)\n", -- d->domain_id, gfn_l, mfn_x(mfn)); -+ if ( (p2mt != p2m_invalid && p2mt != p2m_mmio_dm) || -+ a != p2m_access_n || !mfn_eq(mfn, INVALID_MFN) ) -+ printk(XENLOG_G_WARNING -+ "non-identity map %pd:%lx not cleared (mapped to %lx)\n", -+ d, gfn_l, mfn_x(mfn)); - ret = 0; - } - ---- a/xen/drivers/passthrough/x86/iommu.c -+++ b/xen/drivers/passthrough/x86/iommu.c -@@ -267,24 +267,36 @@ int iommu_identity_mapping(struct domain - if ( p2ma == p2m_access_x ) - return -ENOENT; - -- while ( base_pfn < end_pfn ) -- { -- int err = set_identity_p2m_entry(d, base_pfn, p2ma, flag); -- -- if ( err ) -- return err; -- base_pfn++; -- } -- - map = xmalloc(struct identity_map); - if ( !map ) - return -ENOMEM; -+ - map->base = base; - map->end = end; - map->access = p2ma; - map->count = 1; -+ -+ /* -+ * Insert into list ahead of mapping, so the range can be found when -+ * trying to clean up. -+ */ - list_add_tail(&map->list, &hd->arch.identity_maps); - -+ for ( ; base_pfn < end_pfn; ++base_pfn ) -+ { -+ int err = set_identity_p2m_entry(d, base_pfn, p2ma, flag); -+ -+ if ( !err ) -+ continue; -+ -+ if ( (map->base >> PAGE_SHIFT_4K) == base_pfn ) -+ { -+ list_del(&map->list); -+ xfree(map); -+ } -+ return err; -+ } -+ - return 0; - } - diff --git a/xsa461.patch b/xsa461.patch deleted file mode 100644 index 82c1f29..0000000 --- a/xsa461.patch +++ /dev/null @@ -1,33 +0,0 @@ -From: Jan Beulich -Subject: x86/pass-through: documents as security-unsupported when sharing resources - -When multiple devices share resources and one of them is to be passed -through to a guest, security of the entire system and of respective -guests individually cannot really be guaranteed without knowing -internals of any of the involved guests. Therefore such a configuration -cannot really be security-supported, yet making that explicit was so far -missing. - -This is XSA-461 / CVE-2024-31146. - -Signed-off-by: Jan Beulich -Reviewed-by: Juergen Gross ---- -TBD: Of course the system bus(es) is a / are shared resource(s), too. - I'm afraid I don't know the low level details of PCI to be able to - tell whether there are any fairness guarantees there. - ---- a/SUPPORT.md -+++ b/SUPPORT.md -@@ -841,6 +841,11 @@ This feature is not security supported: - - Only systems using IOMMUs are supported. - -+Passing through of devices sharing resources with another device is not -+security supported. Such sharing could e.g. be the same line interrupt being -+used by multiple devices, one of which is to be passed through, or two such -+devices having memory BARs within the same 4k page. -+ - Not compatible with migration, populate-on-demand, altp2m, - introspection, memory sharing, or memory paging. - diff --git a/xsa462.patch b/xsa462.patch deleted file mode 100644 index be538f9..0000000 --- a/xsa462.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Jan Beulich -Subject: x86/vLAPIC: prevent undue recursion of vlapic_error() - -With the error vector set to an illegal value, the function invoking -vlapic_set_irq() would bring execution back here, with the non-recursive -lock already held. Avoid the call in this case, merely further updating -ESR (if necessary). - -This is XSA-462 / CVE-2024-45817. - -Fixes: 5f32d186a8b1 ("x86/vlapic: don't silently accept bad vectors") -Reported-by: Federico Serafini -Reported-by: Andrew Cooper -Signed-off-by: Jan Beulich -Signed-off-by: Andrew Cooper -Reviewed-by: Andrew Cooper - -diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c -index 2ec95942713e..8758c4217fab 100644 ---- a/xen/arch/x86/hvm/vlapic.c -+++ b/xen/arch/x86/hvm/vlapic.c -@@ -112,9 +112,24 @@ static void vlapic_error(struct vlapic *vlapic, unsigned int errmask) - if ( (esr & errmask) != errmask ) - { - uint32_t lvterr = vlapic_get_reg(vlapic, APIC_LVTERR); -+ bool inj = false; - -- vlapic_set_reg(vlapic, APIC_ESR, esr | errmask); - if ( !(lvterr & APIC_LVT_MASKED) ) -+ { -+ /* -+ * If LVTERR is unmasked and has an illegal vector, vlapic_set_irq() -+ * will end up back here. Break the cycle by only injecting LVTERR -+ * if it will succeed, and folding in RECVILL otherwise. -+ */ -+ if ( (lvterr & APIC_VECTOR_MASK) >= 16 ) -+ inj = true; -+ else -+ errmask |= APIC_ESR_RECVILL; -+ } -+ -+ vlapic_set_reg(vlapic, APIC_ESR, esr | errmask); -+ -+ if ( inj ) - vlapic_set_irq(vlapic, lvterr & APIC_VECTOR_MASK, 0); - } - spin_unlock_irqrestore(&vlapic->esr_lock, flags); From ebbbc5ccb727feedec4f730c33c56f14f96b7d6d Mon Sep 17 00:00:00 2001 From: Andrea Perotti Date: Sat, 4 Jan 2025 14:12:34 +0100 Subject: [PATCH 63/99] FIX #2335558: xen-hypervisor %post doesn't load all needed grub2 modules (elf.mod is missing) --- xen.spec | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xen.spec b/xen.spec index b5f39ca..8a04075 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.1 -Release: 1%{?dist} +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -610,7 +610,7 @@ do_it() { if [ ! -d $TARGET ]; then mkdir $TARGET fi - for m in relocator.mod multiboot2.mod; do + for m in relocator.mod multiboot2.mod elf.mod; do if [ -f $DIR/$m ]; then if [ ! -f $TARGET/$m ] || ! cmp -s $DIR/$m $TARGET/$m; then cp -p $DIR/$m $TARGET/$m @@ -926,6 +926,10 @@ fi %endif %changelog +* Sat Jan 04 2025 Andrea Perotti - 4.19.1-2 +- xen-hypervisor %post doesn't load all needed grub2 modules + (#2335558) + * Thu Dec 05 2024 Michael Young - 4.19.1-1 - update to xen-4.19.1 remove patches now included or superceded upstream From d458004d8bff14222254bf36c0f76673b6d73a3b Mon Sep 17 00:00:00 2001 From: Michael Young Date: Thu, 9 Jan 2025 21:24:58 +0000 Subject: [PATCH 64/99] work around debugedit bug to fix aarch64 builds --- xen.spec | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 8a04075..1068616 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.1 -Release: 2%{?dist} +Release: 3%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -551,6 +551,11 @@ find . -path licensedir -prune -o -path stubdom/ioemu -prune -o \ install -m 644 $file licensedir/$file done +############ workaround debugedit bug +%ifarch aarch64 +/bin/rm -r dist/install/usr/{bin,lib64,libexec,sbin} +%endif + ############ all done now ############ %post @@ -926,6 +931,9 @@ fi %endif %changelog +* Thu Jan 09 2025 Michael Young - 4.19.1-3 +- work around debugedit bug to fix aarch64 builds + * Sat Jan 04 2025 Andrea Perotti - 4.19.1-2 - xen-hypervisor %post doesn't load all needed grub2 modules (#2335558) From 5c740ce63a9ca0526725f40283d0091ce327ae19 Mon Sep 17 00:00:00 2001 From: Jerry James Date: Fri, 10 Jan 2025 13:42:27 -0700 Subject: [PATCH 65/99] OCaml 5.3.0 rebuild for Fedora 42 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 1068616..558c54a 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.1 -Release: 3%{?dist} +Release: 4%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -931,6 +931,9 @@ fi %endif %changelog +* Fri Jan 10 2025 Jerry James - 4.19.1-4 +- OCaml 5.3.0 rebuild for Fedora 42 + * Thu Jan 09 2025 Michael Young - 4.19.1-3 - work around debugedit bug to fix aarch64 builds From 0d1f7da88aaa0b824a1f7ebc8ddc2a8527abedf6 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sun, 19 Jan 2025 15:38:51 +0000 Subject: [PATCH 66/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 558c54a..5126983 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.1 -Release: 4%{?dist} +Release: 5%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -931,6 +931,9 @@ fi %endif %changelog +* Sun Jan 19 2025 Fedora Release Engineering - 4.19.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + * Fri Jan 10 2025 Jerry James - 4.19.1-4 - OCaml 5.3.0 rebuild for Fedora 42 From 0e81fe4bff17648fc345e3f47449eedf4314413d Mon Sep 17 00:00:00 2001 From: Michael Young Date: Fri, 24 Jan 2025 22:32:04 +0000 Subject: [PATCH 67/99] adjust file locations now /usr/sbin is a symlink to /usr/bin remove debugedit fix as no longer needed --- xen.spec | 79 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/xen.spec b/xen.spec index 5126983..212efa4 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.1 -Release: 5%{?dist} +Release: 6%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -463,7 +463,7 @@ rm -rf %{buildroot}/boot rm -fr %{buildroot}%{_datadir}/doc/xen # Pointless helper -rm -f %{buildroot}%{_sbindir}/xen-python-path +rm -f %{buildroot}%{_bindir}/xen-python-path # qemu stuff (unused or available from upstream) rm -rf %{buildroot}/usr/share/xen/man @@ -551,10 +551,9 @@ find . -path licensedir -prune -o -path stubdom/ioemu -prune -o \ install -m 644 $file licensedir/$file done -############ workaround debugedit bug -%ifarch aarch64 -/bin/rm -r dist/install/usr/{bin,lib64,libexec,sbin} -%endif +############ move sbin files to bin + +mv %{buildroot}/usr/sbin/* %{buildroot}/usr/bin/ ############ all done now ############ @@ -815,57 +814,57 @@ fi %{_bindir}/xenstore-* #%#{_bindir}/remus # XSM -%{_sbindir}/flask-* +%{_bindir}/flask-* # Misc stuff %ifnarch armv7hl aarch64 %{_bindir}/xen-detect %endif %{_bindir}/xencov_split %ifnarch armv7hl aarch64 -%{_sbindir}/gdbsx -%{_sbindir}/xen-kdd +%{_bindir}/gdbsx +%{_bindir}/xen-kdd %endif %ifnarch armv7hl aarch64 -%{_sbindir}/xen-hptool -%{_sbindir}/xen-hvmcrash -%{_sbindir}/xen-hvmctx +%{_bindir}/xen-hptool +%{_bindir}/xen-hvmcrash +%{_bindir}/xen-hvmctx %endif -%{_sbindir}/xenconsoled -%{_sbindir}/xenlockprof -%{_sbindir}/xenmon -%{_sbindir}/xentop -%{_sbindir}/xentrace_setmask -%{_sbindir}/xenbaked -%{_sbindir}/xenstored -%{_sbindir}/xenpm -%{_sbindir}/xenpmd -%{_sbindir}/xenperf -%{_sbindir}/xenwatchdogd -%{_sbindir}/xl +%{_bindir}/xenconsoled +%{_bindir}/xenlockprof +%{_bindir}/xenmon +%{_bindir}/xentop +%{_bindir}/xentrace_setmask +%{_bindir}/xenbaked +%{_bindir}/xenstored +%{_bindir}/xenpm +%{_bindir}/xenpmd +%{_bindir}/xenperf +%{_bindir}/xenwatchdogd +%{_bindir}/xl %ifnarch armv7hl aarch64 -%{_sbindir}/xen-lowmemd +%{_bindir}/xen-lowmemd %endif -%{_sbindir}/xencov +%{_bindir}/xencov %ifnarch armv7hl aarch64 -%{_sbindir}/xen-mfndump +%{_bindir}/xen-mfndump %endif %{_bindir}/xenalyze -%{_sbindir}/xentrace -%{_sbindir}/xentrace_setsize +%{_bindir}/xentrace +%{_bindir}/xentrace_setsize %ifnarch armv7hl aarch64 %{_bindir}/xen-cpuid %endif -%{_sbindir}/xen-livepatch -%{_sbindir}/xen-diag +%{_bindir}/xen-livepatch +%{_bindir}/xen-diag %ifnarch armv7hl aarch64 -%{_sbindir}/xen-ucode -%{_sbindir}/xen-memshare -%{_sbindir}/xen-mceinj -%{_sbindir}/xen-vmtrace +%{_bindir}/xen-ucode +%{_bindir}/xen-memshare +%{_bindir}/xen-mceinj +%{_bindir}/xen-vmtrace %endif %{_bindir}/vchan-socket-proxy -%{_sbindir}/xenhypfs -%{_sbindir}/xen-access +%{_bindir}/xenhypfs +%{_bindir}/xen-access # Xen logfiles %dir %attr(0700,root,root) %{_localstatedir}/log/xen @@ -920,7 +919,7 @@ fi %exclude %{_libdir}/ocaml/xen*/*.cmx %{_libdir}/ocaml/stublibs/*.so %{_libdir}/ocaml/stublibs/*.so.owner -%{_sbindir}/oxenstored +%{_bindir}/oxenstored %config(noreplace) %{_sysconfdir}/xen/oxenstored.conf %{_unitdir}/oxenstored.service @@ -931,6 +930,10 @@ fi %endif %changelog +* Thu Jan 23 2025 Michael Young - 4.19.1-6 +- adjust file locations now /usr/sbin is a symlink to /usr/bin +- remove debugedit fix as no longer needed + * Sun Jan 19 2025 Fedora Release Engineering - 4.19.1-5 - Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild From 59fe5ad165212ec0c53c231b3a0edf8e88b5c5d9 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Thu, 27 Feb 2025 18:20:39 +0000 Subject: [PATCH 68/99] deadlock potential with VT-d and legacy PCI device pass-through [XSA-467, CVE-2025-1713] --- xen.spec | 8 ++++- xsa467.patch | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 xsa467.patch diff --git a/xen.spec b/xen.spec index 212efa4..d24a639 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.1 -Release: 6%{?dist} +Release: 7%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -111,6 +111,7 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch +Patch50: xsa467.patch %if %build_qemutrad @@ -319,6 +320,7 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 49 -p1 +%patch 50 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -930,6 +932,10 @@ fi %endif %changelog +* Thu Feb 27 2025 Michael Young - 4.19.1-7 +- deadlock potential with VT-d and legacy PCI device pass-through + [XSA-467, CVE-2025-1713] + * Thu Jan 23 2025 Michael Young - 4.19.1-6 - adjust file locations now /usr/sbin is a symlink to /usr/bin - remove debugedit fix as no longer needed diff --git a/xsa467.patch b/xsa467.patch new file mode 100644 index 0000000..baadd4c --- /dev/null +++ b/xsa467.patch @@ -0,0 +1,98 @@ +From: Jan Beulich +Subject: IOMMU/x86: the bus-to-bridge lock needs to be acquired IRQ-safe + +The function's use from set_msi_source_id() is guaranteed to be in an +IRQs-off region. While the invocation of that function could be moved +ahead in msi_msg_to_remap_entry() (doesn't need to be in the IOMMU- +intremap-locked region), the call tree from map_domain_pirq() holds an +IRQ descriptor lock. Hence all use sites of the lock need become IRQ- +safe ones. + +In find_upstream_bridge() do a tiny bit of tidying in adjacent code: +Change a variable's type to unsigned and merge a redundant assignment +into another variable's initializer. + +This is XSA-467 / CVE-2025-1713. + +Fixes: 476bbccc811c ("VT-d: fix MSI source-id of interrupt remapping") +Signed-off-by: Jan Beulich +Reviewed-by: Juergen Gross +Reviewed-by: Roger Pau Monné + +--- a/xen/drivers/passthrough/pci.c ++++ b/xen/drivers/passthrough/pci.c +@@ -354,20 +354,21 @@ static struct pci_dev *alloc_pdev(struct + switch ( pdev->type = pdev_type(pseg->nr, bus, devfn) ) + { + unsigned int cap, sec_bus, sub_bus; ++ unsigned long flags; + + case DEV_TYPE_PCIe2PCI_BRIDGE: + case DEV_TYPE_LEGACY_PCI_BRIDGE: + sec_bus = pci_conf_read8(pdev->sbdf, PCI_SECONDARY_BUS); + sub_bus = pci_conf_read8(pdev->sbdf, PCI_SUBORDINATE_BUS); + +- spin_lock(&pseg->bus2bridge_lock); ++ spin_lock_irqsave(&pseg->bus2bridge_lock, flags); + for ( ; sec_bus <= sub_bus; sec_bus++ ) + { + pseg->bus2bridge[sec_bus].map = 1; + pseg->bus2bridge[sec_bus].bus = bus; + pseg->bus2bridge[sec_bus].devfn = devfn; + } +- spin_unlock(&pseg->bus2bridge_lock); ++ spin_unlock_irqrestore(&pseg->bus2bridge_lock, flags); + break; + + case DEV_TYPE_PCIe_ENDPOINT: +@@ -437,16 +438,17 @@ static void free_pdev(struct pci_seg *ps + switch ( pdev->type ) + { + unsigned int sec_bus, sub_bus; ++ unsigned long flags; + + case DEV_TYPE_PCIe2PCI_BRIDGE: + case DEV_TYPE_LEGACY_PCI_BRIDGE: + sec_bus = pci_conf_read8(pdev->sbdf, PCI_SECONDARY_BUS); + sub_bus = pci_conf_read8(pdev->sbdf, PCI_SUBORDINATE_BUS); + +- spin_lock(&pseg->bus2bridge_lock); ++ spin_lock_irqsave(&pseg->bus2bridge_lock, flags); + for ( ; sec_bus <= sub_bus; sec_bus++ ) + pseg->bus2bridge[sec_bus] = pseg->bus2bridge[pdev->bus]; +- spin_unlock(&pseg->bus2bridge_lock); ++ spin_unlock_irqrestore(&pseg->bus2bridge_lock, flags); + break; + + default: +@@ -1053,8 +1055,9 @@ enum pdev_type pdev_type(u16 seg, u8 bus + int find_upstream_bridge(u16 seg, u8 *bus, u8 *devfn, u8 *secbus) + { + struct pci_seg *pseg = get_pseg(seg); +- int ret = 0; +- int cnt = 0; ++ int ret = 1; ++ unsigned long flags; ++ unsigned int cnt = 0; + + if ( *bus == 0 ) + return 0; +@@ -1065,8 +1068,7 @@ int find_upstream_bridge(u16 seg, u8 *bu + if ( !pseg->bus2bridge[*bus].map ) + return 0; + +- ret = 1; +- spin_lock(&pseg->bus2bridge_lock); ++ spin_lock_irqsave(&pseg->bus2bridge_lock, flags); + while ( pseg->bus2bridge[*bus].map ) + { + *secbus = *bus; +@@ -1080,7 +1082,7 @@ int find_upstream_bridge(u16 seg, u8 *bu + } + + out: +- spin_unlock(&pseg->bus2bridge_lock); ++ spin_unlock_irqrestore(&pseg->bus2bridge_lock, flags); + return ret; + } + From 88c9f05c391958000cbf4243edd6ce4335380ed1 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 7 Apr 2025 21:00:32 +0100 Subject: [PATCH 69/99] update to xen-4.19.2 remove patches now included or superceded upstream remove xen*.efi.elf files to avoid debuginfo failure --- .gitignore | 2 +- sources | 2 +- xen.spec | 18 +++++++--- xsa467.patch | 98 ---------------------------------------------------- 4 files changed, 16 insertions(+), 104 deletions(-) delete mode 100644 xsa467.patch diff --git a/.gitignore b/.gitignore index 69cde46..85e99f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.19.1.tar.gz +/xen-4.19.2.tar.gz diff --git a/sources b/sources index 595852d..1e984f8 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.19.1.tar.gz) = 6971d07d4eafd40186f35cf6de235badbdf0e1640974693b8fbd415876c46634094178a6157e6dfdc16af885c70ff3b7a72be35a88dcc63daf36e6eb08f9b17b +SHA512 (xen-4.19.2.tar.gz) = 35147b0d755b5a603915fa5017bc021d4a238ab96ee1139dfee8e0f6ba76e64b89d5f331fbd60549682f45ee983d3d8f1cb95c53eed22373a7fa06074ca8da09 diff --git a/xen.spec b/xen.spec index d24a639..f9977fc 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.19.1 -Release: 7%{?dist} +Version: 4.19.2 +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -111,7 +111,6 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch -Patch50: xsa467.patch %if %build_qemutrad @@ -320,7 +319,6 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 49 -p1 -%patch 50 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -557,6 +555,13 @@ done mv %{buildroot}/usr/sbin/* %{buildroot}/usr/bin/ +############ remove xen*.efi.elf files to avoid debuginfo failure + +%ifarch x86_64 +rm dist/install/usr/lib/debug/xen-*.efi.elf +rm %{buildroot}/usr/lib/debug/xen-*.efi.elf +%endif + ############ all done now ############ %post @@ -932,6 +937,11 @@ fi %endif %changelog +* Mon Apr 07 2025 Michael Young - 4.19.2-2 +- update to xen-4.19.2 + remove patches now included or superceded upstream + remove xen*.efi.elf files to avoid debuginfo failure + * Thu Feb 27 2025 Michael Young - 4.19.1-7 - deadlock potential with VT-d and legacy PCI device pass-through [XSA-467, CVE-2025-1713] diff --git a/xsa467.patch b/xsa467.patch deleted file mode 100644 index baadd4c..0000000 --- a/xsa467.patch +++ /dev/null @@ -1,98 +0,0 @@ -From: Jan Beulich -Subject: IOMMU/x86: the bus-to-bridge lock needs to be acquired IRQ-safe - -The function's use from set_msi_source_id() is guaranteed to be in an -IRQs-off region. While the invocation of that function could be moved -ahead in msi_msg_to_remap_entry() (doesn't need to be in the IOMMU- -intremap-locked region), the call tree from map_domain_pirq() holds an -IRQ descriptor lock. Hence all use sites of the lock need become IRQ- -safe ones. - -In find_upstream_bridge() do a tiny bit of tidying in adjacent code: -Change a variable's type to unsigned and merge a redundant assignment -into another variable's initializer. - -This is XSA-467 / CVE-2025-1713. - -Fixes: 476bbccc811c ("VT-d: fix MSI source-id of interrupt remapping") -Signed-off-by: Jan Beulich -Reviewed-by: Juergen Gross -Reviewed-by: Roger Pau Monné - ---- a/xen/drivers/passthrough/pci.c -+++ b/xen/drivers/passthrough/pci.c -@@ -354,20 +354,21 @@ static struct pci_dev *alloc_pdev(struct - switch ( pdev->type = pdev_type(pseg->nr, bus, devfn) ) - { - unsigned int cap, sec_bus, sub_bus; -+ unsigned long flags; - - case DEV_TYPE_PCIe2PCI_BRIDGE: - case DEV_TYPE_LEGACY_PCI_BRIDGE: - sec_bus = pci_conf_read8(pdev->sbdf, PCI_SECONDARY_BUS); - sub_bus = pci_conf_read8(pdev->sbdf, PCI_SUBORDINATE_BUS); - -- spin_lock(&pseg->bus2bridge_lock); -+ spin_lock_irqsave(&pseg->bus2bridge_lock, flags); - for ( ; sec_bus <= sub_bus; sec_bus++ ) - { - pseg->bus2bridge[sec_bus].map = 1; - pseg->bus2bridge[sec_bus].bus = bus; - pseg->bus2bridge[sec_bus].devfn = devfn; - } -- spin_unlock(&pseg->bus2bridge_lock); -+ spin_unlock_irqrestore(&pseg->bus2bridge_lock, flags); - break; - - case DEV_TYPE_PCIe_ENDPOINT: -@@ -437,16 +438,17 @@ static void free_pdev(struct pci_seg *ps - switch ( pdev->type ) - { - unsigned int sec_bus, sub_bus; -+ unsigned long flags; - - case DEV_TYPE_PCIe2PCI_BRIDGE: - case DEV_TYPE_LEGACY_PCI_BRIDGE: - sec_bus = pci_conf_read8(pdev->sbdf, PCI_SECONDARY_BUS); - sub_bus = pci_conf_read8(pdev->sbdf, PCI_SUBORDINATE_BUS); - -- spin_lock(&pseg->bus2bridge_lock); -+ spin_lock_irqsave(&pseg->bus2bridge_lock, flags); - for ( ; sec_bus <= sub_bus; sec_bus++ ) - pseg->bus2bridge[sec_bus] = pseg->bus2bridge[pdev->bus]; -- spin_unlock(&pseg->bus2bridge_lock); -+ spin_unlock_irqrestore(&pseg->bus2bridge_lock, flags); - break; - - default: -@@ -1053,8 +1055,9 @@ enum pdev_type pdev_type(u16 seg, u8 bus - int find_upstream_bridge(u16 seg, u8 *bus, u8 *devfn, u8 *secbus) - { - struct pci_seg *pseg = get_pseg(seg); -- int ret = 0; -- int cnt = 0; -+ int ret = 1; -+ unsigned long flags; -+ unsigned int cnt = 0; - - if ( *bus == 0 ) - return 0; -@@ -1065,8 +1068,7 @@ int find_upstream_bridge(u16 seg, u8 *bu - if ( !pseg->bus2bridge[*bus].map ) - return 0; - -- ret = 1; -- spin_lock(&pseg->bus2bridge_lock); -+ spin_lock_irqsave(&pseg->bus2bridge_lock, flags); - while ( pseg->bus2bridge[*bus].map ) - { - *secbus = *bus; -@@ -1080,7 +1082,7 @@ int find_upstream_bridge(u16 seg, u8 *bu - } - - out: -- spin_unlock(&pseg->bus2bridge_lock); -+ spin_unlock_irqrestore(&pseg->bus2bridge_lock, flags); - return ret; - } - From 3a0543c8d6015dfb9426d46ca7859c63ad83b719 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Mon, 12 May 2025 21:42:55 +0100 Subject: [PATCH 70/99] x86: Indirect Target Selection [XSA-469, CVE-2024-28956] --- xen.spec | 19 +- xsa469-4.19-01.patch | 83 +++++++ xsa469-4.19-02.patch | 314 +++++++++++++++++++++++++++ xsa469-4.19-03.patch | 46 ++++ xsa469-4.19-04.patch | 64 ++++++ xsa469-4.19-05.patch | 506 +++++++++++++++++++++++++++++++++++++++++++ xsa469-4.19-06.patch | 375 ++++++++++++++++++++++++++++++++ xsa469-4.19-07.patch | 154 +++++++++++++ 8 files changed, 1560 insertions(+), 1 deletion(-) create mode 100644 xsa469-4.19-01.patch create mode 100644 xsa469-4.19-02.patch create mode 100644 xsa469-4.19-03.patch create mode 100644 xsa469-4.19-04.patch create mode 100644 xsa469-4.19-05.patch create mode 100644 xsa469-4.19-06.patch create mode 100644 xsa469-4.19-07.patch diff --git a/xen.spec b/xen.spec index f9977fc..650144d 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.2 -Release: 2%{?dist} +Release: 4%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -111,6 +111,13 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch +Patch50: xsa469-4.19-01.patch +Patch51: xsa469-4.19-02.patch +Patch52: xsa469-4.19-03.patch +Patch53: xsa469-4.19-04.patch +Patch54: xsa469-4.19-05.patch +Patch55: xsa469-4.19-06.patch +Patch56: xsa469-4.19-07.patch %if %build_qemutrad @@ -319,6 +326,13 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 49 -p1 +%patch 50 -p1 +%patch 51 -p1 +%patch 52 -p1 +%patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 +%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -937,6 +951,9 @@ fi %endif %changelog +* Mon May 12 2025 Michael Young - 4.19.2-4 +- x86: Indirect Target Selection [XSA-469, CVE-2024-28956] + * Mon Apr 07 2025 Michael Young - 4.19.2-2 - update to xen-4.19.2 remove patches now included or superceded upstream diff --git a/xsa469-4.19-01.patch b/xsa469-4.19-01.patch new file mode 100644 index 0000000..cbbb14f --- /dev/null +++ b/xsa469-4.19-01.patch @@ -0,0 +1,83 @@ +From: Andrew Cooper +Subject: x86/alternative: Support replacements when a feature is not present + +Use the top bit of a->cpuid to express inverted polarity. This requires +stripping the top bit back out when performing the sanity checks. + +Despite only being used once, create a replace boolean to express the decision +more clearly in _apply_alternatives(). + +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c +index 1ba35cb9ede9..88c90044c20d 100644 +--- a/xen/arch/x86/alternative.c ++++ b/xen/arch/x86/alternative.c +@@ -197,6 +197,8 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, + uint8_t *repl = ALT_REPL_PTR(a); + uint8_t buf[MAX_PATCH_LEN]; + unsigned int total_len = a->orig_len + a->pad_len; ++ unsigned int feat = a->cpuid & ~ALT_FLAG_NOT; ++ bool inv = a->cpuid & ALT_FLAG_NOT, replace; + + if ( a->repl_len > total_len ) + { +@@ -214,11 +216,11 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, + return -ENOSPC; + } + +- if ( a->cpuid >= NCAPINTS * 32 ) ++ if ( feat >= NCAPINTS * 32 ) + { + printk(XENLOG_ERR + "Alt for %ps, feature %#x outside of featureset range %#x\n", +- ALT_ORIG_PTR(a), a->cpuid, NCAPINTS * 32); ++ ALT_ORIG_PTR(a), feat, NCAPINTS * 32); + return -ERANGE; + } + +@@ -243,8 +245,14 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, + continue; + } + ++ /* ++ * Should a replacement be performed? Most replacements have positive ++ * polarity, but we support negative polarity too. ++ */ ++ replace = boot_cpu_has(feat) ^ inv; ++ + /* If there is no replacement to make, see about optimising the nops. */ +- if ( !boot_cpu_has(a->cpuid) ) ++ if ( !replace ) + { + /* Origin site site already touched? Don't nop anything. */ + if ( base->priv ) +diff --git a/xen/arch/x86/include/asm/alternative.h b/xen/arch/x86/include/asm/alternative.h +index 69555d781ef9..89b7bdcb82e5 100644 +--- a/xen/arch/x86/include/asm/alternative.h ++++ b/xen/arch/x86/include/asm/alternative.h +@@ -1,6 +1,13 @@ + #ifndef __X86_ALTERNATIVE_H__ + #define __X86_ALTERNATIVE_H__ + ++/* ++ * Common to both C and ASM. Express a replacement when a feature is not ++ * available. ++ */ ++#define ALT_FLAG_NOT (1 << 15) ++#define ALT_NOT(x) (ALT_FLAG_NOT | (x)) ++ + #ifdef __ASSEMBLY__ + #include + #else +@@ -11,7 +18,7 @@ + struct __packed alt_instr { + int32_t orig_offset; /* original instruction */ + int32_t repl_offset; /* offset to replacement instruction */ +- uint16_t cpuid; /* cpuid bit set for replacement */ ++ uint16_t cpuid; /* cpuid bit set for replacement (top bit is polarity) */ + uint8_t orig_len; /* length of original instruction */ + uint8_t repl_len; /* length of new instruction */ + uint8_t pad_len; /* length of build-time padding */ + diff --git a/xsa469-4.19-02.patch b/xsa469-4.19-02.patch new file mode 100644 index 0000000..5fd285f --- /dev/null +++ b/xsa469-4.19-02.patch @@ -0,0 +1,314 @@ +From: Andrew Cooper +Subject: x86/guest: Remove use of the Xen hypercall_page + +In order to protect against ITS, Xen needs to start using return thunks. +Therefore the advice in XSA-466 becomes relevant, and the hypercall_page needs +to be removed. + +Implement early_hypercall(), with infrastructure to figure out the correct +instruction on first use. Use ALTERNATIVE()s to result in inline hypercalls, +including the ALT_NOT() form so we only need a single synthetic feature bit. + +No overall change. + +This is part of XSA-469 / CVE-2024-28956 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné + +diff --git a/xen/arch/x86/guest/xen/Makefile b/xen/arch/x86/guest/xen/Makefile +index 26fb4b1007c0..8b3250aa8886 100644 +--- a/xen/arch/x86/guest/xen/Makefile ++++ b/xen/arch/x86/guest/xen/Makefile +@@ -1,4 +1,4 @@ +-obj-y += hypercall_page.o ++obj-bin-y += hypercall.init.o + obj-y += xen.o + + obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o +diff --git a/xen/arch/x86/guest/xen/hypercall.S b/xen/arch/x86/guest/xen/hypercall.S +new file mode 100644 +index 000000000000..05e429794cc4 +--- /dev/null ++++ b/xen/arch/x86/guest/xen/hypercall.S +@@ -0,0 +1,50 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#include ++ ++ .section .init.text, "ax", @progbits ++ ++ /* ++ * Used during early boot, before alternatives have run and inlined ++ * the appropriate instruction. Called using the hypercall ABI. ++ */ ++FUNC(early_hypercall) ++ cmpb $0, early_hypercall_insn(%rip) ++ jl .L_setup ++ je 1f ++ ++ vmmcall ++ ret ++ ++1: vmcall ++ ret ++ ++.L_setup: ++ /* ++ * When setting up the first time around, all registers need ++ * preserving. Save the non-callee-saved ones. ++ */ ++ push %r11 ++ push %r10 ++ push %r9 ++ push %r8 ++ push %rdi ++ push %rsi ++ push %rdx ++ push %rcx ++ push %rax ++ ++ call early_hypercall_setup ++ ++ pop %rax ++ pop %rcx ++ pop %rdx ++ pop %rsi ++ pop %rdi ++ pop %r8 ++ pop %r9 ++ pop %r10 ++ pop %r11 ++ ++ jmp early_hypercall ++END(early_hypercall) +diff --git a/xen/arch/x86/guest/xen/hypercall_page.S b/xen/arch/x86/guest/xen/hypercall_page.S +deleted file mode 100644 +index 7ab55fc1f6e6..000000000000 +--- a/xen/arch/x86/guest/xen/hypercall_page.S ++++ /dev/null +@@ -1,76 +0,0 @@ +-#include +-#include +-#include +- +- .section ".text.page_aligned", "ax", @progbits +- +-DATA(hypercall_page, PAGE_SIZE) +- /* Poisoned with `ret` for safety before hypercalls are set up. */ +- .fill PAGE_SIZE, 1, 0xc3 +-END(hypercall_page) +- +-/* +- * Identify a specific hypercall in the hypercall page +- * @param name Hypercall name. +- */ +-#define DECLARE_HYPERCALL(name) \ +- .globl HYPERCALL_ ## name; \ +- .type HYPERCALL_ ## name, STT_FUNC; \ +- .size HYPERCALL_ ## name, 32; \ +- .set HYPERCALL_ ## name, hypercall_page + __HYPERVISOR_ ## name * 32 +- +-DECLARE_HYPERCALL(set_trap_table) +-DECLARE_HYPERCALL(mmu_update) +-DECLARE_HYPERCALL(set_gdt) +-DECLARE_HYPERCALL(stack_switch) +-DECLARE_HYPERCALL(set_callbacks) +-DECLARE_HYPERCALL(fpu_taskswitch) +-DECLARE_HYPERCALL(sched_op_compat) +-DECLARE_HYPERCALL(platform_op) +-DECLARE_HYPERCALL(set_debugreg) +-DECLARE_HYPERCALL(get_debugreg) +-DECLARE_HYPERCALL(update_descriptor) +-DECLARE_HYPERCALL(memory_op) +-DECLARE_HYPERCALL(multicall) +-DECLARE_HYPERCALL(update_va_mapping) +-DECLARE_HYPERCALL(set_timer_op) +-DECLARE_HYPERCALL(event_channel_op_compat) +-DECLARE_HYPERCALL(xen_version) +-DECLARE_HYPERCALL(console_io) +-DECLARE_HYPERCALL(physdev_op_compat) +-DECLARE_HYPERCALL(grant_table_op) +-DECLARE_HYPERCALL(vm_assist) +-DECLARE_HYPERCALL(update_va_mapping_otherdomain) +-DECLARE_HYPERCALL(iret) +-DECLARE_HYPERCALL(vcpu_op) +-DECLARE_HYPERCALL(set_segment_base) +-DECLARE_HYPERCALL(mmuext_op) +-DECLARE_HYPERCALL(xsm_op) +-DECLARE_HYPERCALL(nmi_op) +-DECLARE_HYPERCALL(sched_op) +-DECLARE_HYPERCALL(callback_op) +-DECLARE_HYPERCALL(xenoprof_op) +-DECLARE_HYPERCALL(event_channel_op) +-DECLARE_HYPERCALL(physdev_op) +-DECLARE_HYPERCALL(hvm_op) +-DECLARE_HYPERCALL(sysctl) +-DECLARE_HYPERCALL(domctl) +-DECLARE_HYPERCALL(kexec_op) +-DECLARE_HYPERCALL(argo_op) +-DECLARE_HYPERCALL(xenpmu_op) +- +-DECLARE_HYPERCALL(arch_0) +-DECLARE_HYPERCALL(arch_1) +-DECLARE_HYPERCALL(arch_2) +-DECLARE_HYPERCALL(arch_3) +-DECLARE_HYPERCALL(arch_4) +-DECLARE_HYPERCALL(arch_5) +-DECLARE_HYPERCALL(arch_6) +-DECLARE_HYPERCALL(arch_7) +- +-/* +- * Local variables: +- * tab-width: 8 +- * indent-tabs-mode: nil +- * End: +- */ +diff --git a/xen/arch/x86/guest/xen/xen.c b/xen/arch/x86/guest/xen/xen.c +index 7484b3f73ad3..2c30db05dfa7 100644 +--- a/xen/arch/x86/guest/xen/xen.c ++++ b/xen/arch/x86/guest/xen/xen.c +@@ -26,7 +26,6 @@ + bool __read_mostly xen_guest; + + uint32_t __read_mostly xen_cpuid_base; +-extern char hypercall_page[]; + static struct rangeset *mem; + + DEFINE_PER_CPU(unsigned int, vcpu_id); +@@ -35,6 +34,50 @@ static struct vcpu_info *vcpu_info; + static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)]; + DEFINE_PER_CPU(struct vcpu_info *, vcpu_info); + ++/* ++ * Which instruction to use for early hypercalls: ++ * < 0 setup ++ * 0 vmcall ++ * > 0 vmmcall ++ */ ++int8_t __initdata early_hypercall_insn = -1; ++ ++/* ++ * Called once during the first hypercall to figure out which instruction to ++ * use. Error handling options are limited. ++ */ ++void asmlinkage __init early_hypercall_setup(void) ++{ ++ BUG_ON(early_hypercall_insn != -1); ++ ++ if ( !boot_cpu_data.x86_vendor ) ++ { ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(0, &eax, &ebx, &ecx, &edx); ++ ++ boot_cpu_data.x86_vendor = x86_cpuid_lookup_vendor(ebx, ecx, edx); ++ } ++ ++ switch ( boot_cpu_data.x86_vendor ) ++ { ++ case X86_VENDOR_INTEL: ++ case X86_VENDOR_CENTAUR: ++ case X86_VENDOR_SHANGHAI: ++ early_hypercall_insn = 0; ++ setup_force_cpu_cap(X86_FEATURE_USE_VMCALL); ++ break; ++ ++ case X86_VENDOR_AMD: ++ case X86_VENDOR_HYGON: ++ early_hypercall_insn = 1; ++ break; ++ ++ default: ++ BUG(); ++ } ++} ++ + static void __init find_xen_leaves(void) + { + uint32_t eax, ebx, ecx, edx, base; +@@ -337,9 +380,6 @@ const struct hypervisor_ops *__init xg_probe(void) + if ( !xen_cpuid_base ) + return NULL; + +- /* Fill the hypercall page. */ +- wrmsrl(cpuid_ebx(xen_cpuid_base + 2), __pa(hypercall_page)); +- + xen_guest = true; + + return &ops; +diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h +index ba3df174b76e..9e3ed21c026d 100644 +--- a/xen/arch/x86/include/asm/cpufeatures.h ++++ b/xen/arch/x86/include/asm/cpufeatures.h +@@ -42,6 +42,7 @@ XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks * + XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ + XEN_CPUFEATURE(IBPB_ENTRY_PV, X86_SYNTH(28)) /* MSR_PRED_CMD used by Xen for PV */ + XEN_CPUFEATURE(IBPB_ENTRY_HVM, X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for HVM */ ++XEN_CPUFEATURE(USE_VMCALL, X86_SYNTH(30)) /* Use VMCALL instead of VMMCALL */ + + /* Bug words follow the synthetic words. */ + #define X86_NR_BUG 1 +diff --git a/xen/arch/x86/include/asm/guest/xen-hcall.h b/xen/arch/x86/include/asm/guest/xen-hcall.h +index 665b472d05ac..96004dec9909 100644 +--- a/xen/arch/x86/include/asm/guest/xen-hcall.h ++++ b/xen/arch/x86/include/asm/guest/xen-hcall.h +@@ -30,9 +30,11 @@ + ({ \ + long res, tmp__; \ + asm volatile ( \ +- "call hypercall_page + %c[offset]" \ ++ ALTERNATIVE_2("call early_hypercall", \ ++ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ ++ "vmcall", X86_FEATURE_USE_VMCALL) \ + : "=a" (res), "=D" (tmp__) ASM_CALL_CONSTRAINT \ +- : [offset] "i" (hcall * 32), \ ++ : "0" (hcall), \ + "1" ((long)(a1)) \ + : "memory" ); \ + (type)res; \ +@@ -42,10 +44,12 @@ + ({ \ + long res, tmp__; \ + asm volatile ( \ +- "call hypercall_page + %c[offset]" \ ++ ALTERNATIVE_2("call early_hypercall", \ ++ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ ++ "vmcall", X86_FEATURE_USE_VMCALL) \ + : "=a" (res), "=D" (tmp__), "=S" (tmp__) \ + ASM_CALL_CONSTRAINT \ +- : [offset] "i" (hcall * 32), \ ++ : "0" (hcall), \ + "1" ((long)(a1)), "2" ((long)(a2)) \ + : "memory" ); \ + (type)res; \ +@@ -55,10 +59,12 @@ + ({ \ + long res, tmp__; \ + asm volatile ( \ +- "call hypercall_page + %c[offset]" \ ++ ALTERNATIVE_2("call early_hypercall", \ ++ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ ++ "vmcall", X86_FEATURE_USE_VMCALL) \ + : "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__) \ + ASM_CALL_CONSTRAINT \ +- : [offset] "i" (hcall * 32), \ ++ : "0" (hcall), \ + "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)) \ + : "memory" ); \ + (type)res; \ +@@ -69,10 +75,12 @@ + long res, tmp__; \ + register long _a4 asm ("r10") = ((long)(a4)); \ + asm volatile ( \ +- "call hypercall_page + %c[offset]" \ ++ ALTERNATIVE_2("call early_hypercall", \ ++ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ ++ "vmcall", X86_FEATURE_USE_VMCALL) \ + : "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__), \ + "=&r" (tmp__) ASM_CALL_CONSTRAINT \ +- : [offset] "i" (hcall * 32), \ ++ : "0" (hcall), \ + "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)), \ + "4" (_a4) \ + : "memory" ); \ diff --git a/xsa469-4.19-03.patch b/xsa469-4.19-03.patch new file mode 100644 index 0000000..2e944f9 --- /dev/null +++ b/xsa469-4.19-03.patch @@ -0,0 +1,46 @@ +From: Jan Beulich +Subject: x86/thunk: (Mis)align __x86_indirect_thunk_* to mitigate ITS + +The Indirect Target Selection speculative vulnerability means that indirect +branches (including RETs) are unsafe when in the first half of a cacheline. + +Arrange for __x86_indirect_thunk_* to always be in the second half. + +This is part of XSA-469 / CVE-2024-28956 + +Signed-off-by: Jan Beulich +Signed-off-by: Andrew Cooper +Reviewed-by: Jan Beulich + +diff --git a/xen/arch/x86/indirect-thunk.S b/xen/arch/x86/indirect-thunk.S +index fd5493c22b16..c4b978d67b8e 100644 +--- a/xen/arch/x86/indirect-thunk.S ++++ b/xen/arch/x86/indirect-thunk.S +@@ -11,6 +11,10 @@ + + #include + ++/* Alignment is dealt with explicitly here; override the respective macro. */ ++#undef SYM_ALIGN ++#define SYM_ALIGN(align...) ++ + .macro IND_THUNK_RETPOLINE reg:req + call 1f + int3 +@@ -35,6 +39,16 @@ + .macro GEN_INDIRECT_THUNK reg:req + .section .text.__x86_indirect_thunk_\reg, "ax", @progbits + ++ /* ++ * The Indirect Target Selection speculative vulnerability means that ++ * indirect branches (including RETs) are unsafe when in the first ++ * half of a cacheline. Arrange for them to be in the second half. ++ * ++ * Align to 64, then skip 32. ++ */ ++ .balign 64 ++ .fill 32, 1, 0xcc ++ + FUNC(__x86_indirect_thunk_\reg) + ALTERNATIVE_2 __stringify(IND_THUNK_RETPOLINE \reg), \ + __stringify(IND_THUNK_LFENCE \reg), X86_FEATURE_IND_THUNK_LFENCE, \ diff --git a/xsa469-4.19-04.patch b/xsa469-4.19-04.patch new file mode 100644 index 0000000..81d77a9 --- /dev/null +++ b/xsa469-4.19-04.patch @@ -0,0 +1,64 @@ +From: Andrew Cooper +Subject: x86/thunk: (Mis)align the RETs in clear_bhb_loops() to mitigate ITS + +The Indirect Target Selection speculative vulnerability means that indirect +branches (including RETs) are unsafe when in the first half of a cacheline. + +clear_bhb_loops() has a precise layout of branches. The alignment for +performance cause the RETs to always be in an unsafe position, and converting +those to return thunks changes the branching pattern. While such a conversion +is believed to be safe, clear_bhb_loops() is also a performance-relevant +fastpath, so (mis)align the RETs to be in a safe position. + +No functional change. + +This is part of XSA-469 / CVE-2024-28956 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné + +diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S +index 678c00c5d06f..52625f4e2c17 100644 +--- a/xen/arch/x86/bhb-thunk.S ++++ b/xen/arch/x86/bhb-thunk.S +@@ -50,7 +50,12 @@ END(clear_bhb_tsx) + * ret + * + * The CALL/RETs are necessary to prevent the Loop Stream Detector from +- * interfering. The alignment is for performance and not safety. ++ * interfering. ++ * ++ * The .balign's are for performance, but they cause the RETs to be in unsafe ++ * positions with respect to Indirect Target Selection. The .skips are to ++ * move the RETs into ITS-safe positions, rather than using the slowpath ++ * through __x86_return_thunk. + * + * The "short" sequence (5 and 5) is for CPUs prior to Alder Lake / Sapphire + * Rapids (i.e. Cores prior to Golden Cove and/or Gracemont). +@@ -66,12 +71,14 @@ FUNC(clear_bhb_loops) + jmp 5f + int3 + +- .align 64 ++ .balign 64 ++ .skip 32 - (.Lr1 - 1f), 0xcc + 1: call 2f +- ret ++.Lr1: ret + int3 + +- .align 64 ++ .balign 64 ++ .skip 32 - 18 /* (.Lr2 - 2f) but Clang IAS doesn't like this */, 0xcc + 2: ALTERNATIVE "mov $5, %eax", "mov $7, %eax", X86_SPEC_BHB_LOOPS_LONG + + 3: jmp 4f +@@ -83,7 +90,7 @@ FUNC(clear_bhb_loops) + sub $1, %ecx + jnz 1b + +- ret ++.Lr2: ret + 5: + /* + * The Intel sequence has an LFENCE here. The purpose is to ensure diff --git a/xsa469-4.19-05.patch b/xsa469-4.19-05.patch new file mode 100644 index 0000000..51a135d --- /dev/null +++ b/xsa469-4.19-05.patch @@ -0,0 +1,506 @@ +From: Andrew Cooper +Subject: x86/stubs: Introduce place_ret() to abstract away raw 0xc3's + +The Indirect Target Selection speculative vulnerability means that indirect +branches (including RETs) are unsafe when in the first half of a cacheline. +This means it's not safe for logic using the stubs to write raw 0xc3's. + +Introduce place_ret() which, for now, writes a raw 0xc3 but will contain +additional logic when return thunks are in use. + +stub_selftest() doesn't strictly need to be converted as they only run on +boot, but doing so gets us a partial test of place_ret() too. + +No functional change. + +This is part of XSA-469 / CVE-2024-28956 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné + +diff --git a/tools/tests/x86_emulator/x86-emulate.h b/tools/tests/x86_emulator/x86-emulate.h +index 8f8accfe3e70..946aaa9d660b 100644 +--- a/tools/tests/x86_emulator/x86-emulate.h ++++ b/tools/tests/x86_emulator/x86-emulate.h +@@ -68,6 +68,12 @@ + + #define is_canonical_address(x) (((int64_t)(x) >> 47) == ((int64_t)(x) >> 63)) + ++static inline void *place_ret(void *ptr) ++{ ++ *(uint8_t *)ptr = 0xc3; ++ return ptr + 1; ++} ++ + extern uint32_t mxcsr_mask; + extern struct cpu_policy cp; + +diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile +index c1e64278ce85..a7e5a82689de 100644 +--- a/xen/arch/x86/Makefile ++++ b/xen/arch/x86/Makefile +@@ -11,9 +11,7 @@ obj-$(CONFIG_PV) += pv/ + obj-y += x86_64/ + obj-y += x86_emulate/ + +-alternative-y := alternative.init.o +-alternative-$(CONFIG_LIVEPATCH) := +-obj-bin-y += $(alternative-y) ++obj-y += alternative.o + obj-y += apic.o + obj-y += bhb-thunk.o + obj-y += bitops.o +@@ -41,7 +39,7 @@ obj-y += hypercall.o + obj-y += i387.o + obj-y += i8259.o + obj-y += io_apic.o +-obj-$(CONFIG_LIVEPATCH) += alternative.o livepatch.o ++obj-$(CONFIG_LIVEPATCH) += livepatch.o + obj-y += msi.o + obj-y += msr.o + obj-$(CONFIG_INDIRECT_THUNK) += indirect-thunk.o +diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c +index 88c90044c20d..ec451d962c10 100644 +--- a/xen/arch/x86/alternative.c ++++ b/xen/arch/x86/alternative.c +@@ -137,6 +137,20 @@ void init_or_livepatch add_nops(void *insns, unsigned int len) + } + } + ++/* ++ * Place a return at @ptr. @ptr must be in the writable alias of a stub. ++ * ++ * Returns the next position to write into the stub. ++ */ ++void *place_ret(void *ptr) ++{ ++ uint8_t *p = ptr; ++ ++ *p++ = 0xc3; ++ ++ return p; ++} ++ + /* + * text_poke - Update instructions on a live kernel or non-executed code. + * @addr: address to modify +diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c +index 705cf9eb94ca..1572efa69a00 100644 +--- a/xen/arch/x86/extable.c ++++ b/xen/arch/x86/extable.c +@@ -151,20 +151,20 @@ search_exception_table(const struct cpu_user_regs *regs, unsigned long *stub_ra) + int __init cf_check stub_selftest(void) + { + static const struct { +- uint8_t opc[8]; ++ uint8_t opc[7]; + uint64_t rax; + union stub_exception_token res; + } tests[] __initconst = { + #define endbr64 0xf3, 0x0f, 0x1e, 0xfa +- { .opc = { endbr64, 0x0f, 0xb9, 0xc3, 0xc3 }, /* ud1 */ ++ { .opc = { endbr64, 0x0f, 0xb9, 0x90 }, /* ud1 */ + .res.fields.trapnr = X86_EXC_UD }, +- { .opc = { endbr64, 0x90, 0x02, 0x00, 0xc3 }, /* nop; add (%rax),%al */ ++ { .opc = { endbr64, 0x90, 0x02, 0x00 }, /* nop; add (%rax),%al */ + .rax = 0x0123456789abcdef, + .res.fields.trapnr = X86_EXC_GP }, +- { .opc = { endbr64, 0x02, 0x04, 0x04, 0xc3 }, /* add (%rsp,%rax),%al */ ++ { .opc = { endbr64, 0x02, 0x04, 0x04 }, /* add (%rsp,%rax),%al */ + .rax = 0xfedcba9876543210UL, + .res.fields.trapnr = X86_EXC_SS }, +- { .opc = { endbr64, 0xcc, 0xc3, 0xc3, 0xc3 }, /* int3 */ ++ { .opc = { endbr64, 0xcc, 0x90, 0x90 }, /* int3 */ + .res.fields.trapnr = X86_EXC_BP }, + #undef endbr64 + }; +@@ -183,6 +183,7 @@ int __init cf_check stub_selftest(void) + + memset(ptr, 0xcc, STUB_BUF_SIZE / 2); + memcpy(ptr, tests[i].opc, ARRAY_SIZE(tests[i].opc)); ++ place_ret(ptr + ARRAY_SIZE(tests[i].opc)); + unmap_domain_page(ptr); + + asm volatile ( "INDIRECT_CALL %[stb]\n" +diff --git a/xen/arch/x86/include/asm/alternative.h b/xen/arch/x86/include/asm/alternative.h +index 89b7bdcb82e5..841a63ebf1b6 100644 +--- a/xen/arch/x86/include/asm/alternative.h ++++ b/xen/arch/x86/include/asm/alternative.h +@@ -30,6 +30,8 @@ struct __packed alt_instr { + #define ALT_REPL_PTR(a) __ALT_PTR(a, repl_offset) + + extern void add_nops(void *insns, unsigned int len); ++void *place_ret(void *ptr); ++ + /* Similar to alternative_instructions except it can be run with IRQs enabled. */ + extern int apply_alternatives(struct alt_instr *start, struct alt_instr *end); + extern void alternative_instructions(void); +diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c +index 70150c272276..ff5d1c9f8634 100644 +--- a/xen/arch/x86/pv/emul-priv-op.c ++++ b/xen/arch/x86/pv/emul-priv-op.c +@@ -76,7 +76,6 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, + 0x41, 0x5c, /* pop %r12 */ + 0x5d, /* pop %rbp */ + 0x5b, /* pop %rbx */ +- 0xc3, /* ret */ + }; + + const struct stubs *this_stubs = &this_cpu(stubs); +@@ -126,11 +125,13 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, + + APPEND_CALL(save_guest_gprs); + APPEND_BUFF(epilogue); ++ p = place_ret(p); + + /* Build-time best effort attempt to catch problems. */ + BUILD_BUG_ON(STUB_BUF_SIZE / 2 < + (sizeof(prologue) + sizeof(epilogue) + 10 /* 2x call */ + +- MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES))); ++ MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES) + ++ 1 /* ret */)); + /* Runtime confirmation that we haven't clobbered an adjacent stub. */ + BUG_ON(STUB_BUF_SIZE / 2 < (p - ctxt->io_emul_stub)); + +diff --git a/xen/arch/x86/x86_emulate/fpu.c b/xen/arch/x86/x86_emulate/fpu.c +index 480d87965705..03612d00a2ce 100644 +--- a/xen/arch/x86/x86_emulate/fpu.c ++++ b/xen/arch/x86/x86_emulate/fpu.c +@@ -32,36 +32,42 @@ static inline bool fpu_check_write(void) + + #define emulate_fpu_insn_memdst(opc, ext, arg) \ + do { \ ++ void *_p = get_stub(stub); \ + /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ + *insn_bytes = 2; \ +- memcpy(get_stub(stub), \ +- ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ ++ memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2; \ ++ place_ret(_p); \ + invoke_stub("", "", "+m" (arg) : "a" (&(arg))); \ + put_stub(stub); \ + } while (0) + + #define emulate_fpu_insn_memsrc(opc, ext, arg) \ + do { \ ++ void *_p = get_stub(stub); \ + /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ +- memcpy(get_stub(stub), \ +- ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ ++ memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2; \ ++ place_ret(_p); \ + invoke_stub("", "", "=m" (dummy) : "m" (arg), "a" (&(arg))); \ + put_stub(stub); \ + } while (0) + + #define emulate_fpu_insn_stub(bytes...) \ + do { \ ++ void *_p = get_stub(stub); \ + unsigned int nr_ = sizeof((uint8_t[]){ bytes }); \ +- memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ ++ memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_; \ ++ place_ret(_p); \ + invoke_stub("", "", "=m" (dummy) : "i" (0)); \ + put_stub(stub); \ + } while (0) + + #define emulate_fpu_insn_stub_eflags(bytes...) \ + do { \ ++ void *_p = get_stub(stub); \ + unsigned int nr_ = sizeof((uint8_t[]){ bytes }); \ + unsigned long tmp_; \ +- memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ ++ memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_; \ ++ place_ret(_p); \ + invoke_stub(_PRE_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ + _POST_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ + [eflags] "+g" (regs->eflags), [tmp] "=&r" (tmp_) \ +diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c +index b1d192cbbf1e..f40709682484 100644 +--- a/xen/arch/x86/x86_emulate/x86_emulate.c ++++ b/xen/arch/x86/x86_emulate/x86_emulate.c +@@ -1396,7 +1396,7 @@ x86_emulate( + stb[3] = 0x91; + stb[4] = evex.opmsk << 3; + insn_bytes = 5; +- stb[5] = 0xc3; ++ place_ret(&stb[5]); + + invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); + +@@ -3627,7 +3627,7 @@ x86_emulate( + } + opc[1] = (modrm & 0x38) | 0xc0; + insn_bytes = EVEX_PFX_BYTES + 2; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_EVEX(opc, evex); + invoke_stub("", "", "=g" (dummy) : "a" (src.val)); +@@ -3694,7 +3694,7 @@ x86_emulate( + insn_bytes = PFX_BYTES + 2; + copy_REX_VEX(opc, rex_prefix, vex); + } +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + ea.reg = decode_gpr(&_regs, modrm_reg); + invoke_stub("", "", "=a" (*ea.reg) : "c" (mmvalp), "m" (*mmvalp)); +@@ -3768,7 +3768,7 @@ x86_emulate( + insn_bytes = PFX_BYTES + 2; + copy_REX_VEX(opc, rex_prefix, vex); + } +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + _regs.eflags &= ~EFLAGS_MASK; + invoke_stub("", +@@ -4004,7 +4004,7 @@ x86_emulate( + opc[1] = modrm & 0xc7; + insn_bytes = PFX_BYTES + 2; + simd_0f_to_gpr: +- opc[insn_bytes - PFX_BYTES] = 0xc3; ++ place_ret(&opc[insn_bytes - PFX_BYTES]); + + generate_exception_if(ea.type != OP_REG, X86_EXC_UD); + +@@ -4401,7 +4401,7 @@ x86_emulate( + vex.w = 0; + opc[1] = modrm & 0x38; + insn_bytes = PFX_BYTES + 2; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_REX_VEX(opc, rex_prefix, vex); + invoke_stub("", "", "+m" (src.val) : "a" (&src.val)); +@@ -4438,7 +4438,7 @@ x86_emulate( + evex.w = 0; + opc[1] = modrm & 0x38; + insn_bytes = EVEX_PFX_BYTES + 2; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_EVEX(opc, evex); + invoke_stub("", "", "+m" (src.val) : "a" (&src.val)); +@@ -4633,7 +4633,7 @@ x86_emulate( + #endif /* X86EMUL_NO_SIMD */ + + simd_0f_reg_only: +- opc[insn_bytes - PFX_BYTES] = 0xc3; ++ place_ret(&opc[insn_bytes - PFX_BYTES]); + + copy_REX_VEX(opc, rex_prefix, vex); + invoke_stub("", "", [dummy_out] "=g" (dummy) : [dummy_in] "i" (0) ); +@@ -4967,7 +4967,7 @@ x86_emulate( + if ( !mode_64bit() ) + vex.w = 0; + opc[1] = modrm & 0xf8; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_VEX(opc, vex); + ea.reg = decode_gpr(&_regs, modrm_rm); +@@ -5010,7 +5010,7 @@ x86_emulate( + if ( !mode_64bit() ) + vex.w = 0; + opc[1] = modrm & 0xc7; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_VEX(opc, vex); + invoke_stub("", "", "=a" (dst.val) : [dummy] "i" (0)); +@@ -5040,7 +5040,7 @@ x86_emulate( + opc = init_prefixes(stub); + opc[0] = b; + opc[1] = modrm; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_VEX(opc, vex); + _regs.eflags &= ~EFLAGS_MASK; +@@ -5608,7 +5608,7 @@ x86_emulate( + if ( !mode_64bit() ) + vex.w = 0; + opc[1] = modrm & 0xc7; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_REX_VEX(opc, rex_prefix, vex); + invoke_stub("", "", "=a" (ea.val) : [dummy] "i" (0)); +@@ -5726,7 +5726,7 @@ x86_emulate( + opc[1] &= 0x38; + } + insn_bytes = PFX_BYTES + 2; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + if ( vex.opcx == vex_none ) + { + /* Cover for extra prefix byte. */ +@@ -6006,7 +6006,7 @@ x86_emulate( + pvex->b = !mode_64bit() || (vex.reg >> 3); + opc[1] = 0xc0 | (~vex.reg & 7); + pvex->reg = 0xf; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "=a" (ea.val) : [dummy] "i" (0)); + put_stub(stub); +@@ -6290,7 +6290,7 @@ x86_emulate( + evex.w = 0; + opc[1] = modrm & 0xf8; + insn_bytes = EVEX_PFX_BYTES + 2; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + copy_EVEX(opc, evex); + invoke_stub("", "", "=g" (dummy) : "a" (src.val)); +@@ -6389,7 +6389,7 @@ x86_emulate( + pvex->b = 1; + opc[1] = (modrm_reg & 7) << 3; + pvex->reg = 0xf; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); + +@@ -6459,7 +6459,7 @@ x86_emulate( + pvex->b = 1; + opc[1] = (modrm_reg & 7) << 3; + pvex->reg = 0xf; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "+m" (*mmvalp) : "a" (mmvalp)); + +@@ -6515,7 +6515,7 @@ x86_emulate( + pevex->b = 1; + opc[1] = (modrm_reg & 7) << 3; + pevex->RX = 1; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); + +@@ -6580,7 +6580,7 @@ x86_emulate( + pevex->b = 1; + opc[1] = (modrm_reg & 7) << 3; + pevex->RX = 1; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "+m" (*mmvalp) : "a" (mmvalp)); + +@@ -6594,7 +6594,7 @@ x86_emulate( + opc[2] = 0x90; + /* Use (%rax) as source. */ + opc[3] = evex.opmsk << 3; +- opc[4] = 0xc3; ++ place_ret(&opc[4]); + + invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); + put_stub(stub); +@@ -6688,7 +6688,7 @@ x86_emulate( + pevex->b = 1; + opc[1] = (modrm_reg & 7) << 3; + pevex->RX = 1; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); + +@@ -6766,7 +6766,7 @@ x86_emulate( + opc[2] = 0x90; + /* Use (%rax) as source. */ + opc[3] = evex.opmsk << 3; +- opc[4] = 0xc3; ++ place_ret(&opc[4]); + + invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); + put_stub(stub); +@@ -6848,7 +6848,7 @@ x86_emulate( + pevex->r = !mode_64bit() || !(state->sib_index & 0x08); + pevex->R = !mode_64bit() || !(state->sib_index & 0x10); + pevex->RX = 1; +- opc[2] = 0xc3; ++ place_ret(&opc[2]); + + invoke_stub("", "", "=m" (index) : "a" (&index)); + put_stub(stub); +@@ -7058,7 +7058,7 @@ x86_emulate( + pvex->reg = 0xf; /* rAX */ + buf[3] = b; + buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */ +- buf[5] = 0xc3; ++ place_ret(&buf[5]); + + src.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); + emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val), "a" (*src.reg)); +@@ -7094,7 +7094,7 @@ x86_emulate( + pvex->reg = 0xf; /* rAX */ + buf[3] = b; + buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */ +- buf[5] = 0xc3; ++ place_ret(&buf[5]); + + dst.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); + emulate_stub("=&a" (dst.val), "c" (&src.val)); +@@ -7335,7 +7335,7 @@ x86_emulate( + evex.w = vex.w = 0; + opc[1] = modrm & 0x38; + opc[2] = imm1; +- opc[3] = 0xc3; ++ place_ret(&opc[3]); + if ( vex.opcx == vex_none ) + { + /* Cover for extra prefix byte. */ +@@ -7502,7 +7502,7 @@ x86_emulate( + insn_bytes = PFX_BYTES + 3; + copy_VEX(opc, vex); + } +- opc[3] = 0xc3; ++ place_ret(&opc[3]); + + /* Latch MXCSR - we may need to restore it below. */ + invoke_stub("stmxcsr %[mxcsr]", "", +@@ -7748,7 +7748,7 @@ x86_emulate( + } + opc[2] = imm1; + insn_bytes = PFX_BYTES + 3; +- opc[3] = 0xc3; ++ place_ret(&opc[3]); + if ( vex.opcx == vex_none ) + { + /* Cover for extra prefix byte. */ +@@ -8094,7 +8094,7 @@ x86_emulate( + pxop->reg = 0xf; /* rAX */ + buf[3] = b; + buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */ +- buf[5] = 0xc3; ++ place_ret(&buf[5]); + + dst.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); + emulate_stub([dst] "=&a" (dst.val), "c" (&src.val)); +@@ -8203,7 +8203,7 @@ x86_emulate( + buf[3] = b; + buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */ + *(uint32_t *)(buf + 5) = imm1; +- buf[9] = 0xc3; ++ place_ret(&buf[9]); + + emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val)); + +@@ -8293,12 +8293,12 @@ x86_emulate( + BUG(); + if ( evex_encoded() ) + { +- opc[insn_bytes - EVEX_PFX_BYTES] = 0xc3; ++ place_ret(&opc[insn_bytes - EVEX_PFX_BYTES]); + copy_EVEX(opc, evex); + } + else + { +- opc[insn_bytes - PFX_BYTES] = 0xc3; ++ place_ret(&opc[insn_bytes - PFX_BYTES]); + copy_REX_VEX(opc, rex_prefix, vex); + } + diff --git a/xsa469-4.19-06.patch b/xsa469-4.19-06.patch new file mode 100644 index 0000000..724790e --- /dev/null +++ b/xsa469-4.19-06.patch @@ -0,0 +1,375 @@ +From: Jan Beulich +Subject: x86/thunk: Build Xen with Return Thunks + +The Indirect Target Selection speculative vulnerability means that indirect +branches (including RETs) are unsafe when in the first half of a cacheline. + +In order to mitigate this, build with return thunks and arrange for +__x86_return_thunk to be (mis)aligned in the same manner as +__x86_indirect_thunk_* so the RET instruction is placed in a safe location. + +place_ret() needs to conditionally emit JMP __x86_return_thunk instead of RET. + +This is part of XSA-469 / CVE-2024-28956 + +Signed-off-by: Jan Beulich +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné + +diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig +index 7e03e4bc5546..4542ea8408c7 100644 +--- a/xen/arch/x86/Kconfig ++++ b/xen/arch/x86/Kconfig +@@ -37,9 +37,14 @@ config ARCH_DEFCONFIG + default "arch/x86/configs/x86_64_defconfig" + + config CC_HAS_INDIRECT_THUNK ++ # GCC >= 8 or Clang >= 6 + def_bool $(cc-option,-mindirect-branch-register) || \ + $(cc-option,-mretpoline-external-thunk) + ++config CC_HAS_RETURN_THUNK ++ # GCC >= 8 or Clang >= 15 ++ def_bool $(cc-option,-mfunction-return=thunk-extern) ++ + config HAS_AS_CET_SS + # binutils >= 2.29 or LLVM >= 6 + def_bool $(as-instr,wrssq %rax$(comma)0;setssbsy) +diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile +index a7e5a82689de..27806a81aca8 100644 +--- a/xen/arch/x86/Makefile ++++ b/xen/arch/x86/Makefile +@@ -43,6 +43,7 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o + obj-y += msi.o + obj-y += msr.o + obj-$(CONFIG_INDIRECT_THUNK) += indirect-thunk.o ++obj-$(CONFIG_RETURN_THUNK) += indirect-thunk.o + obj-$(CONFIG_PV) += ioport_emulate.o + obj-y += irq.o + obj-$(CONFIG_KEXEC) += machine_kexec.o +diff --git a/xen/arch/x86/acpi/wakeup_prot.S b/xen/arch/x86/acpi/wakeup_prot.S +index 66f799339913..97bd676aaee2 100644 +--- a/xen/arch/x86/acpi/wakeup_prot.S ++++ b/xen/arch/x86/acpi/wakeup_prot.S +@@ -133,7 +133,7 @@ ENTRY(s3_resume) + pop %r12 + pop %rbx + pop %rbp +- ret ++ RET + + .data + .align 16 +diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c +index ec451d962c10..1b71ae959abe 100644 +--- a/xen/arch/x86/alternative.c ++++ b/xen/arch/x86/alternative.c +@@ -137,16 +137,45 @@ void init_or_livepatch add_nops(void *insns, unsigned int len) + } + } + ++void nocall __x86_return_thunk(void); ++ + /* + * Place a return at @ptr. @ptr must be in the writable alias of a stub. + * ++ * When CONFIG_RETURN_THUNK is active, this may be a JMP __x86_return_thunk ++ * instead, depending on the safety of @ptr with respect to Indirect Target ++ * Selection. ++ * + * Returns the next position to write into the stub. + */ + void *place_ret(void *ptr) + { ++ unsigned long addr = (unsigned long)ptr; + uint8_t *p = ptr; + +- *p++ = 0xc3; ++ /* ++ * When Return Thunks are used, if a RET would be unsafe at this location ++ * with respect to Indirect Target Selection (i.e. if addr is in the first ++ * half of a cacheline), insert a JMP __x86_return_thunk instead. ++ * ++ * The displacement needs to be relative to the executable alias of the ++ * stub, not to @ptr which is the writeable alias. ++ */ ++ if ( IS_ENABLED(CONFIG_RETURN_THUNK) && !(addr & 0x20) ) ++ { ++ long stub_va = (this_cpu(stubs.addr) & PAGE_MASK) + (addr & ~PAGE_MASK); ++ long disp = (long)__x86_return_thunk - (stub_va + 5); ++ ++ BUG_ON((int32_t)disp != disp); ++ ++ *p++ = 0xe9; ++ *(int32_t *)p = disp; ++ p += 4; ++ } ++ else ++ { ++ *p++ = 0xc3; ++ } + + return p; + } +diff --git a/xen/arch/x86/arch.mk b/xen/arch/x86/arch.mk +index b88d097a844b..85d3e7cbfeeb 100644 +--- a/xen/arch/x86/arch.mk ++++ b/xen/arch/x86/arch.mk +@@ -46,6 +46,9 @@ CFLAGS-$(CONFIG_CC_IS_GCC) += -fno-jump-tables + CFLAGS-$(CONFIG_CC_IS_CLANG) += -mretpoline-external-thunk + endif + ++# Compile with return thunk support if selected. ++CFLAGS-$(CONFIG_RETURN_THUNK) += -mfunction-return=thunk-extern ++ + # Disable the addition of a .note.gnu.property section to object files when + # livepatch support is enabled. The contents of that section can change + # depending on the instructions used, and livepatch-build-tools doesn't know +diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S +index 52625f4e2c17..7f92201a3cbb 100644 +--- a/xen/arch/x86/bhb-thunk.S ++++ b/xen/arch/x86/bhb-thunk.S +@@ -23,7 +23,7 @@ FUNC(clear_bhb_tsx) + 0: .byte 0xc6, 0xf8, 0 /* xabort $0 */ + int3 + 1: +- ret ++ RET + END(clear_bhb_tsx) + + /* +diff --git a/xen/arch/x86/clear_page.S b/xen/arch/x86/clear_page.S +index d6c076f1d8bc..dc3c3c26bfb7 100644 +--- a/xen/arch/x86/clear_page.S ++++ b/xen/arch/x86/clear_page.S +@@ -1,6 +1,8 @@ + .file __FILE__ + + #include ++ ++#include + #include + + FUNC(clear_page_sse2) +@@ -16,5 +18,5 @@ FUNC(clear_page_sse2) + jnz 0b + + sfence +- ret ++ RET + END(clear_page_sse2) +diff --git a/xen/arch/x86/copy_page.S b/xen/arch/x86/copy_page.S +index c3c436545bac..e43e5370c815 100644 +--- a/xen/arch/x86/copy_page.S ++++ b/xen/arch/x86/copy_page.S +@@ -1,6 +1,8 @@ + .file __FILE__ + + #include ++ ++#include + #include + + #define src_reg %rsi +@@ -41,5 +43,5 @@ FUNC(copy_page_sse2) + movnti tmp4_reg, 3*WORD_SIZE(dst_reg) + + sfence +- ret ++ RET + END(copy_page_sse2) +diff --git a/xen/arch/x86/efi/check.c b/xen/arch/x86/efi/check.c +index 9e473faad3c9..23ba30abf330 100644 +--- a/xen/arch/x86/efi/check.c ++++ b/xen/arch/x86/efi/check.c +@@ -3,6 +3,9 @@ int __attribute__((__ms_abi__)) test(int i) + return i; + } + ++/* In case -mfunction-return is in use. */ ++void __x86_return_thunk(void) {}; ++ + /* + * Populate an array with "addresses" of relocatable and absolute values. + * This is to probe ld for (a) emitting base relocations at all and (b) not +diff --git a/xen/arch/x86/include/asm/asm-defns.h b/xen/arch/x86/include/asm/asm-defns.h +index 32d6b4491063..97ebe21298a2 100644 +--- a/xen/arch/x86/include/asm/asm-defns.h ++++ b/xen/arch/x86/include/asm/asm-defns.h +@@ -58,6 +58,12 @@ + .endif + .endm + ++#ifdef CONFIG_RETURN_THUNK ++# define RET jmp __x86_return_thunk ++#else ++# define RET ret ++#endif ++ + #ifdef CONFIG_XEN_IBT + # define ENDBR64 endbr64 + #else +diff --git a/xen/arch/x86/indirect-thunk.S b/xen/arch/x86/indirect-thunk.S +index c4b978d67b8e..26dad15f12c9 100644 +--- a/xen/arch/x86/indirect-thunk.S ++++ b/xen/arch/x86/indirect-thunk.S +@@ -15,6 +15,8 @@ + #undef SYM_ALIGN + #define SYM_ALIGN(align...) + ++#ifdef CONFIG_INDIRECT_THUNK ++ + .macro IND_THUNK_RETPOLINE reg:req + call 1f + int3 +@@ -62,3 +64,25 @@ END(__x86_indirect_thunk_\reg) + .irp reg, ax, cx, dx, bx, bp, si, di, 8, 9, 10, 11, 12, 13, 14, 15 + GEN_INDIRECT_THUNK reg=r\reg + .endr ++ ++#endif /* CONFIG_INDIRECT_THUNK */ ++ ++#ifdef CONFIG_RETURN_THUNK ++ .section .text.entry.__x86_return_thunk, "ax", @progbits ++ ++ /* ++ * The Indirect Target Selection speculative vulnerability means that ++ * indirect branches (including RETs) are unsafe when in the first ++ * half of a cacheline. Arrange for them to be in the second half. ++ * ++ * Align to 64, then skip 32. ++ */ ++ .balign 64 ++ .fill 32, 1, 0xcc ++ ++FUNC(__x86_return_thunk) ++ ret ++ int3 /* Halt straight-line speculation */ ++END(__x86_return_thunk) ++ ++#endif /* CONFIG_RETURN_THUNK */ +diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c +index ff5d1c9f8634..295d847ea24c 100644 +--- a/xen/arch/x86/pv/emul-priv-op.c ++++ b/xen/arch/x86/pv/emul-priv-op.c +@@ -131,7 +131,7 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, + BUILD_BUG_ON(STUB_BUF_SIZE / 2 < + (sizeof(prologue) + sizeof(epilogue) + 10 /* 2x call */ + + MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES) + +- 1 /* ret */)); ++ (IS_ENABLED(CONFIG_RETURN_THUNK) ? 5 : 1) /* ret */)); + /* Runtime confirmation that we haven't clobbered an adjacent stub. */ + BUG_ON(STUB_BUF_SIZE / 2 < (p - ctxt->io_emul_stub)); + +diff --git a/xen/arch/x86/pv/gpr_switch.S b/xen/arch/x86/pv/gpr_switch.S +index 5409ad3b1447..362b5d241623 100644 +--- a/xen/arch/x86/pv/gpr_switch.S ++++ b/xen/arch/x86/pv/gpr_switch.S +@@ -26,7 +26,7 @@ FUNC(load_guest_gprs) + movq UREGS_r15(%rdi), %r15 + movq UREGS_rcx(%rdi), %rcx + movq UREGS_rdi(%rdi), %rdi +- ret ++ RET + END(load_guest_gprs) + + /* Save guest GPRs. Parameter on the stack above the return address. */ +@@ -48,5 +48,5 @@ FUNC(save_guest_gprs) + movq %rbx, UREGS_rbx(%rdi) + movq %rdx, UREGS_rdx(%rdi) + movq %rcx, UREGS_rcx(%rdi) +- ret ++ RET + END(save_guest_gprs) +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 35351044f901..019a0a81f4a7 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -569,6 +569,9 @@ static void __init print_details(enum ind_thunk thunk) + #ifdef CONFIG_INDIRECT_THUNK + " INDIRECT_THUNK" + #endif ++#ifdef CONFIG_RETURN_THUNK ++ " RETURN_THUNK" ++#endif + #ifdef CONFIG_SHADOW_PAGING + " SHADOW_PAGING" + #endif +diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S +index a99646c0cd4e..18f46c78cfbe 100644 +--- a/xen/arch/x86/x86_64/compat/entry.S ++++ b/xen/arch/x86/x86_64/compat/entry.S +@@ -180,7 +180,7 @@ FUNC(cr4_pv32_restore) + or cr4_pv32_mask(%rip), %rax + mov %rax, %cr4 + mov %rax, (%rcx) +- ret ++ RET + 0: + #ifndef NDEBUG + /* Check that _all_ of the bits intended to be set actually are. */ +@@ -198,7 +198,7 @@ FUNC(cr4_pv32_restore) + 1: + #endif + xor %eax, %eax +- ret ++ RET + END(cr4_pv32_restore) + + FUNC(compat_syscall) +@@ -329,7 +329,7 @@ __UNLIKELY_END(compat_bounce_null_selector) + xor %eax, %eax + mov %ax, TRAPBOUNCE_cs(%rdx) + mov %al, TRAPBOUNCE_flags(%rdx) +- ret ++ RET + + .section .fixup,"ax" + .Lfx13: +diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S +index 9b0cdb76408b..eb62e7c329bd 100644 +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S +@@ -604,7 +604,7 @@ __UNLIKELY_END(create_bounce_frame_bad_bounce_ip) + xor %eax, %eax + mov %rax, TRAPBOUNCE_eip(%rdx) + mov %al, TRAPBOUNCE_flags(%rdx) +- ret ++ RET + + .pushsection .fixup, "ax", @progbits + # Numeric tags below represent the intended overall %rsi adjustment. +diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S +index 9a1dfe1b340a..506993867502 100644 +--- a/xen/arch/x86/xen.lds.S ++++ b/xen/arch/x86/xen.lds.S +@@ -82,6 +82,7 @@ SECTIONS + . = ALIGN(PAGE_SIZE); + _stextentry = .; + *(.text.entry) ++ *(.text.entry.*) + . = ALIGN(PAGE_SIZE); + _etextentry = .; + +diff --git a/xen/common/Kconfig b/xen/common/Kconfig +index 565ceda741b9..da0fa7527643 100644 +--- a/xen/common/Kconfig ++++ b/xen/common/Kconfig +@@ -130,6 +130,17 @@ config INDIRECT_THUNK + When enabled, indirect branches are implemented using a new construct + called "retpoline" that prevents speculation. + ++config RETURN_THUNK ++ bool "Out-of-line Returns" ++ depends on CC_HAS_RETURN_THUNK ++ default INDIRECT_THUNK ++ help ++ Compile Xen with out-of-line returns. ++ ++ This allows Xen to mitigate a variety of speculative vulnerabilities ++ by choosing a hardware-dependent instruction sequence to implement ++ function returns safely. ++ + config SPECULATIVE_HARDEN_ARRAY + bool "Speculative Array Hardening" + default y diff --git a/xsa469-4.19-07.patch b/xsa469-4.19-07.patch new file mode 100644 index 0000000..2ba9d48 --- /dev/null +++ b/xsa469-4.19-07.patch @@ -0,0 +1,154 @@ +From: Andrew Cooper +Subject: x86/spec-ctrl: Synthesise ITS_NO to guests on unaffected hardware + +It is easier to express feature word 17 in terms of word 16 + [32, 64) as +that's how the layout is given in documentation. + +This is part of XSA-469 / CVE-2024-28956 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné + +diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h +index 9bc553681f4a..1729ba0c3097 100644 +--- a/xen/arch/x86/include/asm/cpufeature.h ++++ b/xen/arch/x86/include/asm/cpufeature.h +@@ -216,6 +216,7 @@ static inline bool boot_cpu_has(unsigned int feat) + #define cpu_has_gds_no boot_cpu_has(X86_FEATURE_GDS_NO) + #define cpu_has_rfds_no boot_cpu_has(X86_FEATURE_RFDS_NO) + #define cpu_has_rfds_clear boot_cpu_has(X86_FEATURE_RFDS_CLEAR) ++#define cpu_has_its_no boot_cpu_has(X86_FEATURE_ITS_NO) + + /* Synthesized. */ + #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) +diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c +index 019a0a81f4a7..94cdbd521c4d 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -1781,6 +1781,90 @@ static void __init bhi_calculations(void) + } + } + ++/* ++ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/indirect-target-selection.html ++ */ ++static void __init its_calculations(void) ++{ ++ /* ++ * Indirect Target Selection is a Branch Prediction bug whereby certain ++ * indirect branches (including RETs) get predicted using a direct branch ++ * target, rather than a suitable indirect target, bypassing hardware ++ * isolation protections. ++ * ++ * ITS affects Core (but not Atom) processors starting from the ++ * introduction of eIBRS, up to but not including Golden Cove cores ++ * (checked here with BHI_CTRL). ++ * ++ * The ITS_NO feature is not expected to be enumerated by hardware, and is ++ * only for VMMs to synthesise for guests. ++ * ++ * ITS comes in 3 flavours: ++ * ++ * 1) Across-IBPB. Indirect branches after the IBPB can be controlled ++ * by direct targets which existed prior to the IBPB. This is ++ * addressed in the IPU 2025.1 microcode drop, and has no other ++ * software interaction. ++ * ++ * 2) Guest/Host. Indirect branches in the VMM can be controlled by ++ * direct targets from the guest. This applies equally to PV guests ++ * (Ring3) and HVM guests (VMX), and applies to all Skylake-uarch ++ * cores with eIBRS. ++ * ++ * 3) Intra-mode. Indirect branches in the VMM can be controlled by ++ * other execution in the same mode. ++ */ ++ ++ /* ++ * If we can see ITS_NO, or we're virtualised, do nothing. We are or may ++ * migrate somewhere unsafe. ++ */ ++ if ( cpu_has_its_no || cpu_has_hypervisor ) ++ return; ++ ++ /* ITS is only known to affect Intel processors at this time. */ ++ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ) ++ return; ++ ++ /* ++ * ITS does not exist on: ++ * - non-Family 6 CPUs ++ * - those without eIBRS ++ * - those with BHI_CTRL ++ * but we still need to synthesise ITS_NO. ++ */ ++ if ( boot_cpu_data.x86 != 6 || !cpu_has_eibrs || ++ boot_cpu_has(X86_FEATURE_BHI_CTRL) ) ++ goto synthesise; ++ ++ switch ( boot_cpu_data.x86_model ) ++ { ++ /* These Skylake-uarch cores suffer cases #2 and #3. */ ++ case INTEL_FAM6_SKYLAKE_X: ++ case INTEL_FAM6_KABYLAKE_L: ++ case INTEL_FAM6_KABYLAKE: ++ case INTEL_FAM6_COMETLAKE: ++ case INTEL_FAM6_COMETLAKE_L: ++ return; ++ ++ /* These Sunny/Willow/Cypress Cove cores suffer case #3. */ ++ case INTEL_FAM6_ICELAKE_X: ++ case INTEL_FAM6_ICELAKE_D: ++ case INTEL_FAM6_ICELAKE_L: ++ case INTEL_FAM6_TIGERLAKE_L: ++ case INTEL_FAM6_TIGERLAKE: ++ case INTEL_FAM6_ROCKETLAKE: ++ return; ++ ++ default: ++ break; ++ } ++ ++ /* Platforms remaining are not believed to be vulnerable to ITS. */ ++ synthesise: ++ setup_force_cpu_cap(X86_FEATURE_ITS_NO); ++} ++ + void spec_ctrl_init_domain(struct domain *d) + { + bool pv = is_pv_domain(d); +@@ -2331,6 +2415,8 @@ void __init init_speculation_mitigations(void) + + bhi_calculations(); + ++ its_calculations(); ++ + print_details(thunk); + + /* +diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h +index 9c98e4992861..4d9e468af653 100644 +--- a/xen/include/public/arch-x86/cpufeatureset.h ++++ b/xen/include/public/arch-x86/cpufeatureset.h +@@ -365,7 +365,8 @@ XEN_CPUFEATURE(GDS_NO, 16*32+26) /*A No Gather Data Sampling */ + XEN_CPUFEATURE(RFDS_NO, 16*32+27) /*A No Register File Data Sampling */ + XEN_CPUFEATURE(RFDS_CLEAR, 16*32+28) /*!A| Register File(s) cleared by VERW */ + +-/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 */ ++/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 (express in terms of word 16) */ ++XEN_CPUFEATURE(ITS_NO, 16*32+62) /*!A No Indirect Target Selection */ + + #endif /* XEN_CPUFEATURE */ + +diff --git a/xen/tools/gen-cpuid.py b/xen/tools/gen-cpuid.py +index 601eec608983..dc33ca3181b1 100755 +--- a/xen/tools/gen-cpuid.py ++++ b/xen/tools/gen-cpuid.py +@@ -51,7 +51,7 @@ def parse_definitions(state): + r"\s+/\*([\w!|]*) .*$") + + word_regex = re.compile( +- r"^/\* .* word (\d*) \*/$") ++ r"^/\* .* word (\d*) .*\*/$") + last_word = -1 + + this = sys.modules[__name__] From 41f5d9097f54c7b963e079d3261159e075c07bd6 Mon Sep 17 00:00:00 2001 From: Python Maint Date: Mon, 2 Jun 2025 21:24:59 +0200 Subject: [PATCH 71/99] Rebuilt for Python 3.14 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 650144d..3801543 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.2 -Release: 4%{?dist} +Release: 5%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -951,6 +951,9 @@ fi %endif %changelog +* Mon Jun 02 2025 Python Maint - 4.19.2-5 +- Rebuilt for Python 3.14 + * Mon May 12 2025 Michael Young - 4.19.2-4 - x86: Indirect Target Selection [XSA-469, CVE-2024-28956] From 80e497a2951d965b7a45a1ca611cbdeae2d0b126 Mon Sep 17 00:00:00 2001 From: Jerry James Date: Fri, 11 Jul 2025 14:54:03 -0600 Subject: [PATCH 72/99] Rebuild to fix OCaml dependencies --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 3801543..0ea5f41 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.19.2 -Release: 5%{?dist} +Release: 6%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -951,6 +951,9 @@ fi %endif %changelog +* Fri Jul 11 2025 Jerry James - 4.19.2-6 +- Rebuild to fix OCaml dependencies + * Mon Jun 02 2025 Python Maint - 4.19.2-5 - Rebuilt for Python 3.14 From d382b68b39e4ff3d899e8cd1d4e95baacab95766 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 15 Jul 2025 21:03:56 +0100 Subject: [PATCH 73/99] update to xen 4.20.1 includes fixes for x86: Incorrect stubs exception handling for flags recovery [XSA-470, CVE-2025-27465] x86: Transitive Scheduler Attacks [XSA-471, CVE-2024-36350, CVE-2024-36357] --- .gitignore | 3 +- CVE-2014-0150.patch | 11 - qemu.trad.CVE-2015-5278.patch | 11 - qemu.trad.CVE-2015-5279.patch | 48 ---- qemu.trad.CVE-2015-6815.patch | 12 - qemu.trad.CVE-2015-7295.patch | 63 ----- qemu.trad.CVE-2015-7512.patch | 37 --- qemu.trad.CVE-2015-8345.patch | 38 --- qemu.trad.CVE-2015-8504.patch | 44 --- qemu.trad.CVE-2016-1714.patch | 30 -- qemu.trad.CVE-2016-1981.patch | 104 ------- qemu.trad.CVE-2016-2538.patch | 56 ---- qemu.trad.CVE-2016-2841.patch | 34 --- qemu.trad.CVE-2016-2857.patch | 45 --- qemu.trad.CVE-2016-4001.patch | 46 ---- qemu.trad.CVE-2016-4002.patch | 31 --- qemu.trad.CVE-2016-4439.patch | 44 --- qemu.trad.CVE-2016-4441.patch | 68 ----- qemu.trad.CVE-2016-5238.patch | 65 ----- qemu.trad.CVE-2016-5338.patch | 76 ----- qemu.trad.CVE-2016-6351.patch | 81 ------ qemu.trad.CVE-2016-8669.patch | 37 --- qemu.trad.CVE-2016-8910.patch | 29 -- qemu.trad.CVE-2016-9776.patch | 34 --- qemu.trad.CVE-2017-6505.patch | 51 ---- qemu.trad.CVE-2017-7718.patch | 51 ---- qemu.trad.CVE-2017-8309.patch | 38 --- qemu.trad.CVE-2017-9330.patch | 31 --- qemu.trad.bug1399055.patch | 76 ----- sources | 3 +- xen.drop.brctl.patch | 8 - xen.efi.build.patch | 12 +- xen.fedora.crypt.patch | 11 - xen.gcc7.fix.patch | 12 - xen.hypervisor.config | 109 ++++++-- xen.spec | 210 +++----------- xsa469-4.19-01.patch | 83 ------ xsa469-4.19-02.patch | 314 --------------------- xsa469-4.19-03.patch | 46 ---- xsa469-4.19-04.patch | 64 ----- xsa469-4.19-05.patch | 506 ---------------------------------- xsa469-4.19-06.patch | 375 ------------------------- xsa469-4.19-07.patch | 154 ----------- 43 files changed, 138 insertions(+), 3063 deletions(-) delete mode 100644 CVE-2014-0150.patch delete mode 100644 qemu.trad.CVE-2015-5278.patch delete mode 100644 qemu.trad.CVE-2015-5279.patch delete mode 100644 qemu.trad.CVE-2015-6815.patch delete mode 100644 qemu.trad.CVE-2015-7295.patch delete mode 100644 qemu.trad.CVE-2015-7512.patch delete mode 100644 qemu.trad.CVE-2015-8345.patch delete mode 100644 qemu.trad.CVE-2015-8504.patch delete mode 100644 qemu.trad.CVE-2016-1714.patch delete mode 100644 qemu.trad.CVE-2016-1981.patch delete mode 100644 qemu.trad.CVE-2016-2538.patch delete mode 100644 qemu.trad.CVE-2016-2841.patch delete mode 100644 qemu.trad.CVE-2016-2857.patch delete mode 100644 qemu.trad.CVE-2016-4001.patch delete mode 100644 qemu.trad.CVE-2016-4002.patch delete mode 100644 qemu.trad.CVE-2016-4439.patch delete mode 100644 qemu.trad.CVE-2016-4441.patch delete mode 100644 qemu.trad.CVE-2016-5238.patch delete mode 100644 qemu.trad.CVE-2016-5338.patch delete mode 100644 qemu.trad.CVE-2016-6351.patch delete mode 100644 qemu.trad.CVE-2016-8669.patch delete mode 100644 qemu.trad.CVE-2016-8910.patch delete mode 100644 qemu.trad.CVE-2016-9776.patch delete mode 100644 qemu.trad.CVE-2017-6505.patch delete mode 100644 qemu.trad.CVE-2017-7718.patch delete mode 100644 qemu.trad.CVE-2017-8309.patch delete mode 100644 qemu.trad.CVE-2017-9330.patch delete mode 100644 qemu.trad.bug1399055.patch delete mode 100644 xen.drop.brctl.patch delete mode 100644 xen.fedora.crypt.patch delete mode 100644 xen.gcc7.fix.patch delete mode 100644 xsa469-4.19-01.patch delete mode 100644 xsa469-4.19-02.patch delete mode 100644 xsa469-4.19-03.patch delete mode 100644 xsa469-4.19-04.patch delete mode 100644 xsa469-4.19-05.patch delete mode 100644 xsa469-4.19-06.patch delete mode 100644 xsa469-4.19-07.patch diff --git a/.gitignore b/.gitignore index 85e99f7..5d9b74e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.19.2.tar.gz +/xen-4.20.1.tar.gz +/mini-os-4.20.0.tar.xz diff --git a/CVE-2014-0150.patch b/CVE-2014-0150.patch deleted file mode 100644 index adcbcc7..0000000 --- a/CVE-2014-0150.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- xen-4.4.1/tools/qemu-xen-traditional/hw/virtio-net.c.orig 2014-07-02 15:54:37.000000000 +0100 -+++ xen-4.4.1/tools/qemu-xen-traditional/hw/virtio-net.c 2014-11-18 20:50:13.593122915 +0000 -@@ -192,7 +192,7 @@ - return VIRTIO_NET_ERR; - - if (mac_data.entries) { -- if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) { -+ if (n->mac_table.in_use <= MAC_TABLE_ENTRIES - mac_data.entries) { - memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN), - elem->out_sg[2].iov_base + sizeof(mac_data), - mac_data.entries * ETH_ALEN); diff --git a/qemu.trad.CVE-2015-5278.patch b/qemu.trad.CVE-2015-5278.patch deleted file mode 100644 index 950817a..0000000 --- a/qemu.trad.CVE-2015-5278.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c.orig 2015-09-26 17:27:49.494334726 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c 2015-09-26 17:31:53.107474932 +0100 -@@ -331,7 +331,7 @@ - if (index <= s->stop) - avail = s->stop - index; - else -- avail = 0; -+ break; - len = size; - if (len > avail) - len = avail; diff --git a/qemu.trad.CVE-2015-5279.patch b/qemu.trad.CVE-2015-5279.patch deleted file mode 100644 index ea08067..0000000 --- a/qemu.trad.CVE-2015-5279.patch +++ /dev/null @@ -1,48 +0,0 @@ ---- xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c.orig 2015-06-09 16:32:24.000000000 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c 2015-09-26 17:27:49.494334726 +0100 -@@ -304,6 +304,9 @@ - } - - index = s->curpag << 8; -+ if (index >= NE2000_PMEM_END) { -+ index = s->start; -+ } - /* 4 bytes for header */ - total_len = size + 4; - /* address for next packet (4 bytes for CRC) */ -@@ -387,15 +390,21 @@ - offset = addr | (page << 4); - switch(offset) { - case EN0_STARTPG: -- s->start = val << 8; -+ if (val << 8 <= NE2000_PMEM_END) { -+ s->start = val << 8; -+ } - s->tainted = 1; - break; - case EN0_STOPPG: -- s->stop = val << 8; -+ if (val << 8 <= NE2000_PMEM_END) { -+ s->stop = val << 8; -+ } - s->tainted = 1; - break; - case EN0_BOUNDARY: -- s->boundary = val; -+ if (val << 8 < NE2000_PMEM_END) { -+ s->boundary = val; -+ } - break; - case EN0_IMR: - s->imr = val; -@@ -436,7 +445,9 @@ - s->phys[offset - EN1_PHYS] = val; - break; - case EN1_CURPAG: -- s->curpag = val; -+ if (val << 8 < NE2000_PMEM_END) { -+ s->curpag = val; -+ } - s->tainted = 1; - break; - case EN1_MULT ... EN1_MULT + 7: diff --git a/qemu.trad.CVE-2015-6815.patch b/qemu.trad.CVE-2015-6815.patch deleted file mode 100644 index 7386d6c..0000000 --- a/qemu.trad.CVE-2015-6815.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- xen-4.5.1/tools/qemu-xen-traditional/hw/e1000.c.orig 2015-06-09 16:32:24.000000000 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/hw/e1000.c 2015-09-26 17:16:36.406544380 +0100 -@@ -461,7 +461,8 @@ - memmove(tp->data, tp->header, hdr); - tp->size = hdr; - } -- } while (split_size -= bytes); -+ split_size -= bytes; -+ } while (bytes && split_size); - } else if (!tp->tse && tp->cptse) { - // context descriptor TSE is not set, while data descriptor TSE is set - DBGOUT(TXERR, "TCP segmentaion Error\n"); diff --git a/qemu.trad.CVE-2015-7295.patch b/qemu.trad.CVE-2015-7295.patch deleted file mode 100644 index 1c74270..0000000 --- a/qemu.trad.CVE-2015-7295.patch +++ /dev/null @@ -1,63 +0,0 @@ ---- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.c.orig 2015-06-09 16:32:24.000000000 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.c 2015-10-10 16:57:01.806370020 +0100 -@@ -268,8 +268,8 @@ - return vring_avail_idx(vq) == vq->last_avail_idx; - } - --void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, -- unsigned int len, unsigned int idx) -+static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, -+ unsigned int len) - { - unsigned int offset; - int i; -@@ -302,7 +302,19 @@ - - offset += size; - } -+} - -+void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, -+ unsigned int len) -+{ -+ vq->last_avail_idx--; -+ virtqueue_unmap_sg(vq, elem, len); -+} -+ -+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, -+ unsigned int len, unsigned int idx) -+{ -+ virtqueue_unmap_sg(vq, elem, len); - idx = (idx + vring_used_idx(vq)) % vq->vring.num; - - /* Get a pointer to the next entry in the used ring. */ ---- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.h.orig 2015-06-09 16:32:24.000000000 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.h 2015-10-10 16:57:53.146216039 +0100 -@@ -105,6 +105,8 @@ - void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, - unsigned int len); - void virtqueue_flush(VirtQueue *vq, unsigned int count); -+void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, -+ unsigned int len); - void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, - unsigned int len, unsigned int idx); - ---- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio-net.c.orig 2015-10-10 16:10:05.071786348 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio-net.c 2015-10-10 19:05:34.510029916 +0100 -@@ -424,11 +424,15 @@ - len = iov_fill(sg, elem.in_num, - buf + offset, size - offset); - total += len; -+ offset += len; -+ if (!n->mergeable_rx_bufs && offset < size) { -+ virtqueue_discard(n->rx_vq, &elem, total); -+ return; -+ } - - /* signal other side */ - virtqueue_fill(n->rx_vq, &elem, total, i++); - -- offset += len; - } - - if (mhdr) diff --git a/qemu.trad.CVE-2015-7512.patch b/qemu.trad.CVE-2015-7512.patch deleted file mode 100644 index 6a1f33f..0000000 --- a/qemu.trad.CVE-2015-7512.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8b98a2f07175d46c3f7217639bd5e03f2ec56343 Mon Sep 17 00:00:00 2001 -From: Jason Wang -Date: Mon, 30 Nov 2015 15:00:06 +0800 -Subject: [PATCH] pcnet: fix rx buffer overflow(CVE-2015-7512) - -Backends could provide a packet whose length is greater than buffer -size. Check for this and truncate the packet to avoid rx buffer -overflow in this case. - -Cc: Prasad J Pandit -Cc: qemu-stable@nongnu.org -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Jason Wang ---- - tools/qemu-xen-traditional/hw/pcnet.c | 6 ++++++ - 1 files changed, 6 insertions(+), 0 deletions(-) - -diff --git a/tools/qemu-xen-traditional/hw/pcnet.c b/tools/qemu-xen-traditional/hw/pcnet.c -index 309c40b..1f4a3db 100644 ---- a/tools/qemu-xen-traditional/hw/pcnet.c -+++ b/tools/qemu-xen-traditional/hw/pcnet.c -@@ -1064,6 +1064,12 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) - int pktcount = 0; - - if (!s->looptest) { -+ if (size > 4092) { -+#ifdef PCNET_DEBUG_RMD -+ fprintf(stderr, "pcnet: truncates rx packet.\n"); -+#endif -+ size = 4092; -+ } - memcpy(src, buf, size); - /* no need to compute the CRC */ - src[size] = 0; --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2015-8345.patch b/qemu.trad.CVE-2015-8345.patch deleted file mode 100644 index 73215ca..0000000 --- a/qemu.trad.CVE-2015-8345.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 00837731d254908a841d69298a4f9f077babaf24 Mon Sep 17 00:00:00 2001 -From: Stefan Weil -Date: Fri, 20 Nov 2015 08:42:33 +0100 -Subject: [PATCH] eepro100: Prevent two endless loops - -http://lists.nongnu.org/archive/html/qemu-devel/2015-11/msg04592.html -shows an example how an endless loop in function action_command can -be achieved. - -During my code review, I noticed a 2nd case which can result in an -endless loop. - -Reported-by: Qinghao Tang -Signed-off-by: Stefan Weil -Signed-off-by: Jason Wang ---- - tools/qemu-xen-traditional/hw/eepro100.c | 16 ++++++++++++++++ - 1 files changed, 16 insertions(+), 0 deletions(-) - -diff --git a/tools/qemu-xen-traditional/hw/eepro100.c b/tools/qemu-xen-traditional/hw/eepro100.c -index 60333b7..685a478 100644 ---- a/tools/qemu-xen-traditional/hw/eepro100.c -+++ b/tools/qemu-xen-traditional/hw/eepro100.c -@@ -774,6 +774,11 @@ static void tx_command(EEPRO100State *s) - uint32_t tx_buffer_address = ldl_phys(tbd_address); - uint16_t tx_buffer_size = lduw_phys(tbd_address + 4); - //~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6); -+ if (tx_buffer_size == 0) { -+ /* Prevent an endless loop. */ -+ logout("loop in %s:%u\n", __FILE__, __LINE__); -+ break; -+ } - tbd_address += 8; - logout - ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n", --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2015-8504.patch b/qemu.trad.CVE-2015-8504.patch deleted file mode 100644 index 3620d40..0000000 --- a/qemu.trad.CVE-2015-8504.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 4c65fed8bdf96780735dbdb92a8bd0d6b6526cc3 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 3 Dec 2015 18:54:17 +0530 -Subject: [PATCH] ui: vnc: avoid floating point exception - -While sending 'SetPixelFormat' messages to a VNC server, -the client could set the 'red-max', 'green-max' and 'blue-max' -values to be zero. This leads to a floating point exception in -write_png_palette while doing frame buffer updates. - -Reported-by: Lian Yihan -Signed-off-by: Prasad J Pandit -Reviewed-by: Gerd Hoffmann -Signed-off-by: Peter Maydell ---- - tools/qemu-xen-traditional/vnc.c | 6 +++--- - 1 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/tools/qemu-xen-traditional/vnc.c b/tools/qemu-xen-traditional/vnc.c -index 7538405..cbe4d33 100644 ---- a/tools/qemu-xen-traditional/vnc.c -+++ b/tools/qemu-xen-traditional/vnc.c -@@ -2198,15 +2198,15 @@ static void set_pixel_format(VncState *vs, - } - - vs->clientds = vs->serverds; -- vs->clientds.pf.rmax = red_max; -+ vs->clientds.pf.rmax = red_max ? red_max : 0xFF; - count_bits(vs->clientds.pf.rbits, red_max); - vs->clientds.pf.rshift = red_shift; - vs->clientds.pf.rmask = red_max << red_shift; -- vs->clientds.pf.gmax = green_max; -+ vs->clientds.pf.gmax = green_max ? green_max : 0xFF; - count_bits(vs->clientds.pf.gbits, green_max); - vs->clientds.pf.gshift = green_shift; - vs->clientds.pf.gmask = green_max << green_shift; -- vs->clientds.pf.bmax = blue_max; -+ vs->clientds.pf.bmax = blue_max ? blue_max : 0xFF; - count_bits(vs->clientds.pf.bbits, blue_max); - vs->clientds.pf.bshift = blue_shift; - vs->clientds.pf.bmask = blue_max << blue_shift; --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2016-1714.patch b/qemu.trad.CVE-2016-1714.patch deleted file mode 100644 index 59b840b..0000000 --- a/qemu.trad.CVE-2016-1714.patch +++ /dev/null @@ -1,30 +0,0 @@ ---- xen-4.6.1/tools/qemu-xen-traditional/hw/fw_cfg.c.orig 2016-01-04 15:35:42.000000000 +0000 -+++ xen-4.6.1/tools/qemu-xen-traditional/hw/fw_cfg.c 2016-03-06 16:42:33.464296362 +0000 -@@ -54,11 +54,15 @@ - static void fw_cfg_write(FWCfgState *s, uint8_t value) - { - int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); -- FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; -+ FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL : -+ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; - - FW_CFG_DPRINTF("write %d\n", value); - -- if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) { -+ if (s->cur_entry & FW_CFG_WRITE_CHANNEL -+ && e != NULL -+ && e->callback -+ && s->cur_offset < e->len) { - e->data[s->cur_offset++] = value; - if (s->cur_offset == e->len) { - e->callback(e->callback_opaque, e->data); -@@ -88,7 +92,8 @@ - static uint8_t fw_cfg_read(FWCfgState *s) - { - int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); -- FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; -+ FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL : -+ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; - uint8_t ret; - - if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len) diff --git a/qemu.trad.CVE-2016-1981.patch b/qemu.trad.CVE-2016-1981.patch deleted file mode 100644 index cd2a8c1..0000000 --- a/qemu.trad.CVE-2016-1981.patch +++ /dev/null @@ -1,104 +0,0 @@ ------------------------------------------------------------------------- -*From*: Laszlo Ersek -*Subject*: [Qemu-devel] [PATCH] e1000: eliminate infinite loops on -out-of-bounds transfer start -*Date*: Tue, 19 Jan 2016 14:17:20 +0100 - ------------------------------------------------------------------------- - -The start_xmit() and e1000_receive_iov() functions implement DMA transfers -iterating over a set of descriptors that the guest's e1000 driver -prepares: - -- the TDLEN and RDLEN registers store the total size of the descriptor - area, - -- while the TDH and RDH registers store the offset (in whole tx / rx - descriptors) into the area where the transfer is supposed to start. - -Each time a descriptor is processed, the TDH and RDH register is bumped -(as appropriate for the transfer direction). - -QEMU already contains logic to deal with bogus transfers submitted by the -guest: - -- Normally, the transmit case wants to increase TDH from its initial value - to TDT. (TDT is allowed to be numerically smaller than the initial TDH - value; wrapping at or above TDLEN bytes to zero is normal.) The failsafe - that QEMU currently has here is a check against reaching the original - TDH value again -- a complete wraparound, which should never happen. - -- In the receive case RDH is increased from its initial value until - "total_size" bytes have been received; preferably in a single step, or - in "s->rxbuf_size" byte steps, if the latter is smaller. However, null - RX descriptors are skipped without receiving data, while RDH is - incremented just the same. QEMU tries to prevent an infinite loop - (processing only null RX descriptors) by detecting whether RDH assumes - its original value during the loop. (Again, wrapping from RDLEN to 0 is - normal.) - -What both directions miss is that the guest could program TDLEN and RDLEN -so low, and the initial TDH and RDH so high, that these registers will -immediately be truncated to zero, and then never reassume their initial -values in the loop -- a full wraparound will never occur. - -The condition that expresses this is: - - xdh_start >= s->mac_reg[XDLEN] / sizeof(desc) - -i.e., TDH or RDH start out after the last whole rx or tx descriptor that -fits into the TDLEN or RDLEN sized area. - -This condition could be checked before we enter the loops, but -pci_dma_read() / pci_dma_write() knows how to fill in buffers safely for -bogus DMA addresses, so we just extend the existing failsafes with the -above condition. - -Cc: "Michael S. Tsirkin" -Cc: Petr Matousek -Cc: Stefano Stabellini -Cc: Prasad Pandit -Cc: Michael Roth -Cc: Jason Wang -RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044 -Signed-off-by: Laszlo Ersek -Reviewed-by: Jason Wang ---- - -Notes: - Regarding the public posting: we made an honest effort to vet this - vulnerability, and the impact seems low -- no host side reads/writes, - "just" a DoS (infinite loop). We decided the patch could be posted - publicly, for the usual review process. Jason and Prasad checked the - patch in the internal discussion already, but comments, improvements - etc. are clearly welcome. The CVE request is underway. Thanks. - - hw/net/e1000.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/net/e1000.c b/hw/net/e1000.c -index bec06e9..34d0823 100644 ---- a/tools/qemu-xen-traditional/hw/e1000.c -+++ b/tools/qemu-xen-traditional/hw/e1000.c -@@ -908,7 +908,8 @@ start_xmit(E1000State *s) - * bogus values to TDT/TDLEN. - * there's nothing too intelligent we could do about this. - */ -- if (s->mac_reg[TDH] == tdh_start) { -+ if (s->mac_reg[TDH] == tdh_start || -+ tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) { - DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n", - tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]); - break; -@@ -1165,7 +1166,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) - s->mac_reg[RDH] = 0; - s->check_rxov = 1; - /* see comment in start_xmit; same here */ -- if (s->mac_reg[RDH] == rdh_start) { -+ if (s->mac_reg[RDH] == rdh_start || -+ rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) { - DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", - rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); - set_ics(s, 0, E1000_ICS_RXO); --- -1.8.3.1 diff --git a/qemu.trad.CVE-2016-2538.patch b/qemu.trad.CVE-2016-2538.patch deleted file mode 100644 index be05dd7..0000000 --- a/qemu.trad.CVE-2016-2538.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Prasad J Pandit - -When processing remote NDIS control message packets, -the USB Net device emulator uses a fixed length(4096) data buffer. -The incoming informationBufferOffset & Length combination could -overflow and cross that range. Check control message buffer -offsets and length to avoid it. - -Reported-by: Qinghao Tang -Signed-off-by: Prasad J Pandit ---- - hw/usb/dev-network.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -Update as per review - -> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg03475.html - -diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c -index 8a4ff49..180adce 100644 ---- a/tools/qemu-xen-traditional/hw/usb-net.c -+++ b/tools/qemu-xen-traditional/hw/usb-net.c -@@ -915,8 +915,9 @@ static int rndis_query_response(USBNetState *s, - - bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; - buflen = le32_to_cpu(buf->InformationBufferLength); -- if (bufoffs + buflen > length) -+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) { - return USB_RET_STALL; -+ } - - infobuflen = ndis_query(s, le32_to_cpu(buf->OID), - bufoffs + (uint8_t *) buf, buflen, infobuf, -@@ -961,8 +962,9 @@ static int rndis_set_response(USBNetState *s, - - bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; - buflen = le32_to_cpu(buf->InformationBufferLength); -- if (bufoffs + buflen > length) -+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) { - return USB_RET_STALL; -+ } - - ret = ndis_set(s, le32_to_cpu(buf->OID), - bufoffs + (uint8_t *) buf, buflen); -@@ -1212,8 +1214,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) - if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) { - uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); - uint32_t size = le32_to_cpu(msg->DataLength); -- if (offs + size <= len) -+ if (offs < len && size < len && offs + size <= len) { - qemu_send_packet(s->vc, s->out_buf + offs, size); -+ } - } - s->out_ptr -= len; - memmove(s->out_buf, &s->out_buf[len], s->out_ptr); --- -2.5.0 diff --git a/qemu.trad.CVE-2016-2841.patch b/qemu.trad.CVE-2016-2841.patch deleted file mode 100644 index 6979fbc..0000000 --- a/qemu.trad.CVE-2016-2841.patch +++ /dev/null @@ -1,34 +0,0 @@ -From: Prasad J Pandit - -Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152) -bytes to process network packets. Registers PSTART & PSTOP -define ring buffer size & location. Setting these registers -to invalid values could lead to infinite loop or OOB r/w -access issues. Add check to avoid it. - -Reported-by: Yang Hongke -Signed-off-by: Prasad J Pandit ---- - hw/net/ne2000.c | 4 ++++ - 1 file changed, 4 insertions(+) - -Update per review: - -> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg05522.html - -diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c -index b032212..ced4666 100644 ---- a/tools/qemu-xen-traditional/hw/ne2000.c -+++ b/tools/qemu-xen-traditional/hw/ne2000.c -@@ -154,6 +154,10 @@ static int ne2000_buffer_full(NE2000State *s) - { - int avail, index, boundary; - -+ if (s->stop <= s->start) { -+ return 1; -+ } -+ - index = s->curpag << 8; - boundary = s->boundary << 8; - if (index < boundary) --- -2.5.0 diff --git a/qemu.trad.CVE-2016-2857.patch b/qemu.trad.CVE-2016-2857.patch deleted file mode 100644 index 5bef1a7..0000000 --- a/qemu.trad.CVE-2016-2857.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Prasad J Pandit - -While computing IP checksum, 'net_checksum_calculate' reads -payload length from the packet. It could exceed the given 'data' -buffer size. Add a check to avoid it. - -Reported-by: Liu Ling -Signed-off-by: Prasad J Pandit ---- - net/checksum.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -Update as per review: - -> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg06121.html - -diff --git a/net/checksum.c b/net/checksum.c -index 14c0855..0942437 100644 ---- a/tools/qemu-xen-traditional/net-checksum.c -+++ b/tools/qemu-xen-traditional/net-checksum.c -@@ -59,6 +59,11 @@ void net_checksum_calculate(uint8_t *data, int length) - int hlen, plen, proto, csum_offset; - uint16_t csum; - -+ /* Ensure data has complete L2 & L3 headers. */ -+ if (length < 14 + 20) { -+ return; -+ } -+ - if ((data[14] & 0xf0) != 0x40) - return; /* not IPv4 */ - hlen = (data[14] & 0x0f) * 4; -@@ -76,8 +81,9 @@ void net_checksum_calculate(uint8_t *data, int length) - return; - } - -- if (plen < csum_offset+2) -- return; -+ if (plen < csum_offset + 2 || 14 + hlen + plen > length) { -+ return; -+ } - - data[14+hlen+csum_offset] = 0; - data[14+hlen+csum_offset+1] = 0; --- -2.5.0 diff --git a/qemu.trad.CVE-2016-4001.patch b/qemu.trad.CVE-2016-4001.patch deleted file mode 100644 index 9ca362f..0000000 --- a/qemu.trad.CVE-2016-4001.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 3a15cc0e1ee7168db0782133d2607a6bfa422d66 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Fri, 8 Apr 2016 11:33:48 +0530 -Subject: [PATCH] net: stellaris_enet: check packet length against receive buffer - -When receiving packets over Stellaris ethernet controller, it -uses receive buffer of size 2048 bytes. In case the controller -accepts large(MTU) packets, it could lead to memory corruption. -Add check to avoid it. - -Reported-by: Oleksandr Bazhaniuk -Signed-off-by: Prasad J Pandit -Message-id: 1460095428-22698-1-git-send-email-ppandit@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell ---- - tools/qemu-xen-traditional/hw/stellaris_enet.c | 12 +++++++++++- - 1 files changed, 11 insertions(+), 1 deletions(-) - -diff --git a/tools/qemu-xen-traditional/hw/stellaris_enet.c b/tools/qemu-xen-traditional/hw/stellaris_enet.c -index 84cf60b..6880894 100644 ---- a/tools/qemu-xen-traditional/hw/stellaris_enet.c -+++ b/tools/qemu-xen-traditional/hw/stellaris_enet.c -@@ -236,8 +236,18 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si - n = s->next_packet + s->np; - if (n >= 31) - n -= 31; -- s->np++; - -+ if (size >= sizeof(s->rx[n].data) - 6) { -+ /* If the packet won't fit into the -+ * emulated 2K RAM, this is reported -+ * as a FIFO overrun error. -+ */ -+ s->ris |= SE_INT_FOV; -+ stellaris_enet_update(s); -+ return -1; -+ } -+ -+ s->np++; - s->rx[n].len = size + 6; - p = s->rx[n].data; - *(p++) = (size + 6); --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2016-4002.patch b/qemu.trad.CVE-2016-4002.patch deleted file mode 100644 index e122297..0000000 --- a/qemu.trad.CVE-2016-4002.patch +++ /dev/null @@ -1,31 +0,0 @@ -From: Prasad J Pandit - -When receiving packets over MIPSnet network device, it uses - receive buffer of size 1514 bytes. In case the controller -accepts large(MTU) packets, it could lead to memory corruption. -Add check to avoid it. - -Reported by: Oleksandr Bazhaniuk - -Signed-off-by: Prasad J Pandit ---- - tools/qemu-xen-traditional/hw/mipsnet.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/tools/qemu-xen-traditional/hw/mipsnet.c b/tools/qemu-xen-traditional/hw/mipsnet.c -index f261011..e134b31 100644 ---- a/tools/qemu-xen-traditional/hw/mipsnet.c -+++ b/tools/qemu-xen-traditional/hw/mipsnet.c -@@ -82,6 +82,9 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si - if (!mipsnet_can_receive(opaque)) - return; - -+ if (size >= sizeof(s->rx_buffer)) { -+ return; -+ } - s->busy = 1; - - /* Just accept everything. */ --- -2.5.5 - diff --git a/qemu.trad.CVE-2016-4439.patch b/qemu.trad.CVE-2016-4439.patch deleted file mode 100644 index 6816695..0000000 --- a/qemu.trad.CVE-2016-4439.patch +++ /dev/null @@ -1,44 +0,0 @@ ------------------------------------------------------------------------- -*From*: P J P -*Subject*: [Qemu-devel] [PATCH 1/2] scsi: check command buffer length -before write(CVE-2016-4439) -*Date*: Thu, 19 May 2016 16:09:30 +0530 - ------------------------------------------------------------------------- - -From: Prasad J Pandit - -The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte -FIFO buffer. It is used to handle command and data transfer. While -writing to this command buffer 's->cmdbuf[TI_BUFSZ=16]', a check -was missing to validate input length. Add check to avoid OOB write -access. - -Fixes CVE-2016-4439 -Reported-by: Li Qiang - -Signed-off-by: Prasad J Pandit ---- - hw/scsi/esp.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c -index 8961be2..01497e6 100644 ---- a/tools/qemu-xen-traditional/hw/esp.c -+++ b/tools/qemu-xen-traditional/hw/esp.c -@@ -448,7 +448,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) - break; - case ESP_FIFO: - if (s->do_cmd) { -- s->cmdbuf[s->cmdlen++] = val & 0xff; -+ if (s->cmdlen < TI_BUFSZ) { -+ s->cmdbuf[s->cmdlen++] = val & 0xff; -+ } else { -+ ESP_ERROR("fifo overrun\n"); -+ } - } else if (s->ti_size == TI_BUFSZ - 1) { - ESP_ERROR("fifo overrun\n"); - } else { --- -2.5.5 - diff --git a/qemu.trad.CVE-2016-4441.patch b/qemu.trad.CVE-2016-4441.patch deleted file mode 100644 index fab6a35..0000000 --- a/qemu.trad.CVE-2016-4441.patch +++ /dev/null @@ -1,68 +0,0 @@ ------------------------------------------------------------------------- -*From*: P J P -*Subject*: [Qemu-devel] [PATCH 2/2] scsi: check dma length before -reading scsi command(CVE-2016-4441) -*Date*: Thu, 19 May 2016 16:09:31 +0530 - ------------------------------------------------------------------------- - -From: Prasad J Pandit - -The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte -FIFO buffer. It is used to handle command and data transfer. -Routine get_cmd() uses DMA to read scsi commands into this buffer. -Add check to validate DMA length against buffer size to avoid any -overrun. - -Fixes CVE-2016-4441 -Reported-by: Li Qiang - -Signed-off-by: Prasad J Pandit ---- - hw/scsi/esp.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c -index 01497e6..591c817 100644 ---- a/tools/qemu-xen-traditional/hw/esp.c -+++ b/tools/qemu-xen-traditional/hw/esp.c -@@ -82,7 +82,7 @@ void esp_request_cancelled(SCSIRequest *req) - } - } - --static uint32_t get_cmd(ESPState *s, uint8_t *buf) -+static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) - { - uint32_t dmalen; - int target; -@@ -92,6 +92,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) - target = s->wregs[ESP_WBUSID] & BUSID_DID; - if (s->dma) { - dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); -+ if (dmalen > buflen) { -+ return 0; -+ } - s->dma_memory_read(s->dma_opaque, buf, dmalen); - } else { - dmalen = s->ti_size; -@@ -166,7 +169,7 @@ static void handle_satn(ESPState *s) - uint8_t buf[32]; - int len; - -- len = get_cmd(s, buf); -+ len = get_cmd(s, buf, sizeof(buf)); - if (len) - do_cmd(s, buf); - } -@@ -192,7 +195,7 @@ static void handle_satn_stop(ESPState *s) - - static void handle_satn_stop(ESPState *s) - { -- s->cmdlen = get_cmd(s, s->cmdbuf); -+ s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf)); - if (s->cmdlen) { - DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); - s->do_cmd = 1; --- -2.5.5 - diff --git a/qemu.trad.CVE-2016-5238.patch b/qemu.trad.CVE-2016-5238.patch deleted file mode 100644 index f6767de..0000000 --- a/qemu.trad.CVE-2016-5238.patch +++ /dev/null @@ -1,65 +0,0 @@ ------------------------------------------------------------------------- -*From*: Paolo Bonzini -*Subject*: Re: [Qemu-devel] [PATCH] scsi: check buffer length before -reading scsi command -*Date*: Wed, 1 Jun 2016 15:10:16 +0200 -*User-agent*: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 -Thunderbird/45.1.0 - ------------------------------------------------------------------------- - - -On 31/05/2016 19:53, P J P wrote: ->/ From: Prasad J Pandit / ->/ / ->/ The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte/ ->/ FIFO buffer. It is used to handle command and data transfer./ ->/ Routine get_cmd() in non-DMA mode, uses 'ti_size' to read scsi/ ->/ command into a buffer. Add check to validate command length against/ ->/ buffer size to avoid any overrun./ ->/ / ->/ Reported-by: Li Qiang / ->/ Signed-off-by: Prasad J Pandit / ->/ ---/ ->/ hw/scsi/esp.c | 3 +++/ ->/ 1 file changed, 3 insertions(+)/ ->/ / ->/ diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c/ ->/ index 60c1b28..953027a 100644/ ->/ --- a/tools/qemu-xen-traditional/hw/esp.c/ ->/ +++ b/tools/qemu-xen-traditional/hw/esp.c/ ->/ @@ -98,6 +98,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t / ->/ buflen)/ ->/ s->dma_memory_read(s->dma_opaque, buf, dmalen);/ ->/ } else {/ ->/ dmalen = s->ti_size;/ ->/ + if (dmalen > TI_BUFSZ) {/ ->/ + return 0;/ ->/ + }/ ->/ memcpy(buf, s->ti_buf, dmalen);/ ->/ buf[0] = buf[2] >> 5;/ ->/ }/ ->/ / - -In theory this shouldn't happen, but I agree that it is better to be -defensive. I'm queuing this patch. - -At least the following patch is needed to ensure that ti_size always -matches ti_rptr/ti_wptr (Hervé, what do you think about it? should I -resubmit it formally?). Also, things are more complicated than -necessary due to ti_size being used for both DMA and FIFO transfers. - -diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c -index c2f6f8f..6407844 100644 ---- a/tools/qemu-xen-traditional/hw/esp.c -+++ b/tools/qemu-xen-traditional/hw/esp.c -@@ -222,7 +222,7 @@ static void write_response(ESPState *s) - } else { - s->ti_size = 2; - s->ti_rptr = 0; -- s->ti_wptr = 0; -+ s->ti_wptr = 2; - s->rregs[ESP_RFLAGS] = 2; - } - esp_raise_irq(s); - diff --git a/qemu.trad.CVE-2016-5338.patch b/qemu.trad.CVE-2016-5338.patch deleted file mode 100644 index be36dca..0000000 --- a/qemu.trad.CVE-2016-5338.patch +++ /dev/null @@ -1,76 +0,0 @@ ------------------------------------------------------------------------- -*From*: P J P -*Subject*: [Qemu-devel] [PATCH v3] scsi: esp: check TI buffer index -before read/write -*Date*: Mon, 6 Jun 2016 22:04:43 +0530 - ------------------------------------------------------------------------- - -From: Prasad J Pandit - -The 53C9X Fast SCSI Controller(FSC) comes with internal 16-byte -FIFO buffers. One is used to handle commands and other is for -information transfer. Three control variables 'ti_rptr', -'ti_wptr' and 'ti_size' are used to control r/w access to the -information transfer buffer ti_buf[TI_BUFSZ=16]. In that, - -'ti_rptr' is used as read index, where read occurs. -'ti_wptr' is a write index, where write would occur. -'ti_size' indicates total bytes to be read from the buffer. - -While reading/writing to this buffer, index could exceed its -size. Add check to avoid OOB r/w access. - -Reported-by: Huawei PSIRT -Reported-by: Li Qiang -Signed-off-by: Prasad J Pandit ---- - hw/scsi/esp.c | 20 +++++++++----------- - 1 file changed, 9 insertions(+), 11 deletions(-) - -Update as per: - -> https://lists.gnu.org/archive/html/qemu-devel/2016-06/msg01326.html - -diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c -index c2f6f8f..4b94bbc 100644 ---- a/tools/qemu-xen-traditional/hw/esp.c -+++ b/tools/qemu-xen-traditional/hw/esp.c -@@ -403,18 +403,17 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) - DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); - switch (saddr) { - case ESP_FIFO: -- if (s->ti_size > 0) { -+ if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { -+ /* Data out. */ -+ ESP_ERROR("PIO data read not implemented\n"); -+ s->rregs[ESP_FIFO] = 0; -+ esp_raise_irq(s); -+ } else if (s->ti_rptr < s->ti_wptr) { - s->ti_size--; -- if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { -- /* Data out. */ -- ESP_ERROR("PIO data read not implemented\n"); -- s->rregs[ESP_FIFO] = 0; -- } else { -- s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; -- } -+ s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; - esp_raise_irq(s); - } -- if (s->ti_size == 0) { -+ if (s->ti_rptr == s->ti_wptr) { - s->ti_rptr = 0; - s->ti_wptr = 0; - } -@@ -459,7 +457,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) - } else { - ESP_ERROR("fifo overrun\n"); - } -- } else if (s->ti_size == TI_BUFSZ - 1) { -+ } else if (s->ti_wptr == TI_BUFSZ - 1) { - ESP_ERROR("fifo overrun\n"); - } else { - s->ti_size++; --- -2.5.5 - diff --git a/qemu.trad.CVE-2016-6351.patch b/qemu.trad.CVE-2016-6351.patch deleted file mode 100644 index 10f1ab3..0000000 --- a/qemu.trad.CVE-2016-6351.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 926cde5f3e4d2504ed161ed0cb771ac7cad6fd11 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 16 Jun 2016 00:22:35 +0200 -Subject: [PATCH] scsi: esp: make cmdbuf big enough for maximum CDB size - -While doing DMA read into ESP command buffer 's->cmdbuf', it could -write past the 's->cmdbuf' area, if it was transferring more than 16 -bytes. Increase the command buffer size to 32, which is maximum when -'s->do_cmd' is set, and add a check on 'len' to avoid OOB access. - -Reported-by: Li Qiang -Signed-off-by: Prasad J Pandit -Signed-off-by: Paolo Bonzini ---- - hw/esp.c | 6 ++++-- - hw/esp.c | 3 ++- - 2 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/hw/esp.c b/hw/esp.c -index 64680b3..baa0a2c 100644 ---- a/hw/esp.c -+++ b/hw/esp.c -@@ -25,6 +25,7 @@ - #include "hw.h" - #include "scsi-disk.h" - #include "scsi.h" -+#include - - /* debug ESP card */ - //#define DEBUG_ESP -@@ -248,6 +248,8 @@ static void esp_do_dma(ESPState *s) - len = s->dma_left; - if (s->do_cmd) { - DPRINTF("command len %d + %d\n", s->cmdlen, len); -+ assert (s->cmdlen <= sizeof(s->cmdbuf) && -+ len <= sizeof(s->cmdbuf) - s->cmdlen); - s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); - s->ti_size = 0; - s->cmdlen = 0; -@@ -345,7 +347,7 @@ static void handle_ti(ESPState *s) - s->dma_counter = dmalen; - - if (s->do_cmd) -- minlen = (dmalen < 32) ? dmalen : 32; -+ minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ; - else if (s->ti_size < 0) - minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size; - else -@@ -449,7 +451,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) - break; - case ESP_FIFO: - if (s->do_cmd) { -- if (s->cmdlen < TI_BUFSZ) { -+ if (s->cmdlen < ESP_CMDBUF_SZ) { - s->cmdbuf[s->cmdlen++] = val & 0xff; - } else { - ESP_ERROR("fifo overrun\n"); -diff --git a/hw/esp.c b/hw/esp.c -index 6c79527..d2c4886 100644 ---- a/hw/esp.c -+++ b/hw/esp.c -@@ -14,6 +14,7 @@ void esp_init(hwaddr espaddr, int it_shift, - - #define ESP_REGS 16 - #define TI_BUFSZ 16 -+#define ESP_CMDBUF_SZ 32 - - typedef struct ESPState ESPState; - -@@ -31,7 +32,7 @@ struct ESPState { - uint32_t dma; - SCSIDevice *scsi_dev[ESP_MAX_DEVS]; - SCSIDevice *current_dev; -- uint8_t cmdbuf[TI_BUFSZ]; -+ uint8_t cmdbuf[ESP_CMDBUF_SZ]; - uint32_t cmdlen; - uint32_t do_cmd; - --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2016-8669.patch b/qemu.trad.CVE-2016-8669.patch deleted file mode 100644 index 05abe36..0000000 --- a/qemu.trad.CVE-2016-8669.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 3592fe0c919cf27a81d8e9f9b4f269553418bb01 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Wed, 12 Oct 2016 11:28:08 +0530 -Subject: [PATCH] char: serial: check divider value against baud base - -16550A UART device uses an oscillator to generate frequencies -(baud base), which decide communication speed. This speed could -be changed by dividing it by a divider. If the divider is -greater than the baud base, speed is set to zero, leading to a -divide by zero error. Add check to avoid it. - -Reported-by: Huawei PSIRT -Signed-off-by: Prasad J Pandit -Message-Id: <1476251888-20238-1-git-send-email-ppandit@redhat.com> -Signed-off-by: Paolo Bonzini ---- - hw/char/serial.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/hw/serial.c b/hw/serial.c -index 3442f47..eec72b7 100644 ---- a/hw/serial.c -+++ b/hw/serial.c -@@ -153,8 +153,9 @@ static void serial_update_parameters(SerialState *s) - int speed, parity, data_bits, stop_bits, frame_size; - QEMUSerialSetParams ssp; - -- if (s->divider == 0) -+ if (s->divider == 0 || s->divider > s->baudbase) { - return; -+ } - - frame_size = 1; - if (s->lcr & 0x08) { --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2016-8910.patch b/qemu.trad.CVE-2016-8910.patch deleted file mode 100644 index ddb67b1..0000000 --- a/qemu.trad.CVE-2016-8910.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Prasad J Pandit - -RTL8139 ethernet controller in C+ mode supports multiple -descriptor rings, each with maximum of 64 descriptors. While -processing transmit descriptor ring in 'rtl8139_cplus_transmit', -it does not limit the descriptor count and runs forever. Add -check to avoid it. - -Reported-by: Andrew Henderson -Signed-off-by: Prasad J Pandit ---- - hw/net/rtl8139.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/rtl8139.c b/hw/rtl8139.c -index 3345bc6..f05e59c 100644 ---- a/hw/rtl8139.c -+++ b/hw/rtl8139.c -@@ -2350,7 +2350,7 @@ static void rtl8139_cplus_transmit(RTL8139State *s) - { - int txcount = 0; - -- while (rtl8139_cplus_transmit_one(s)) -+ while (txcount < 64 && rtl8139_cplus_transmit_one(s)) - { - ++txcount; - } --- -2.7.4 diff --git a/qemu.trad.CVE-2016-9776.patch b/qemu.trad.CVE-2016-9776.patch deleted file mode 100644 index 2098ed3..0000000 --- a/qemu.trad.CVE-2016-9776.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 77d54985b85a0cb760330ec2bd92505e0a2a97a9 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 29 Nov 2016 00:38:39 +0530 -Subject: [PATCH] net: mcf: check receive buffer size register value - -ColdFire Fast Ethernet Controller uses a receive buffer size -register(EMRBR) to hold maximum size of all receive buffers. -It is set by a user before any operation. If it was set to be -zero, ColdFire emulator would go into an infinite loop while -receiving data in mcf_fec_receive. Add check to avoid it. - -Reported-by: Wjjzhang -Signed-off-by: Prasad J Pandit -Signed-off-by: Jason Wang ---- - hw/net/mcf_fec.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c -index dc61bac..4025eb3 100644 ---- a/hw/mcf_fec.c -+++ b/hw/mcf_fec.c -@@ -393,7 +393,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr, - s->tx_descriptor = s->etdsr; - break; - case 0x188: -- s->emrbr = value & 0x7f0; -+ s->emrbr = value > 0 ? value & 0x7F0 : 0x7F0; - break; - default: - cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n", --- -1.7.0.4 - diff --git a/qemu.trad.CVE-2017-6505.patch b/qemu.trad.CVE-2017-6505.patch deleted file mode 100644 index b374a3d..0000000 --- a/qemu.trad.CVE-2017-6505.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 95ed56939eb2eaa4e2f349fe6dcd13ca4edfd8fb Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 7 Feb 2017 02:23:33 -0800 -Subject: [PATCH] usb: ohci: limit the number of link eds - -The guest may builds an infinite loop with link eds. This patch -limit the number of linked ed to avoid this. - -Signed-off-by: Li Qiang -Message-id: 5899a02e.45ca240a.6c373.93c1@mx.google.com -Signed-off-by: Gerd Hoffmann ---- - hw/usb-ohci.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c -index 2cba3e3..21c93e0 100644 ---- a/hw/usb-ohci.c -+++ b/hw/usb-ohci.c -@@ -42,6 +42,8 @@ - - #define OHCI_MAX_PORTS 15 - -+#define ED_LINK_LIMIT 4 -+ - static int64_t usb_frame_time; - static int64_t usb_bit_time; - -@@ -1184,7 +1186,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) - uint32_t next_ed; - uint32_t cur; - int active; -- -+ uint32_t link_cnt = 0; - active = 0; - - if (head == 0) -@@ -1199,6 +1201,10 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) - - next_ed = ed.next & OHCI_DPTR_MASK; - -+ if (++link_cnt > ED_LINK_LIMIT) { -+ return 0; -+ } -+ - if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { - uint32_t addr; - /* Cancel pending packets for ED that have been paused. */ --- -1.8.3.1 - diff --git a/qemu.trad.CVE-2017-7718.patch b/qemu.trad.CVE-2017-7718.patch deleted file mode 100644 index 70382ab..0000000 --- a/qemu.trad.CVE-2017-7718.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 215902d7b6fb50c6fc216fc74f770858278ed904 Mon Sep 17 00:00:00 2001 -From: hangaohuai -Date: Tue, 14 Mar 2017 14:39:19 +0800 -Subject: [PATCH] fix :cirrus_vga fix OOB read case qemu Segmentation fault - -check the validity of parameters in cirrus_bitblt_rop_fwd_transp_xxx -and cirrus_bitblt_rop_fwd_xxx to avoid the OOB read which causes qemu Segmentation fault. - -After the fix, we will touch the assert in -cirrus_invalidate_region: -assert(off_cur_end >= off_cur); - -Signed-off-by: fangying -Signed-off-by: hangaohuai -Message-id: 20170314063919.16200-1-hangaohuai@huawei.com -Signed-off-by: Gerd Hoffmann ---- - hw/cirrus_vga_rop.h | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h -index 0925a00..b7447f8 100644 ---- a/hw/cirrus_vga_rop.h -+++ b/hw/cirrus_vga_rop.h -@@ -97,6 +97,11 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, - src = src_ - src_base; - dstpitch -= bltwidth; - srcpitch -= bltwidth; -+ -+ if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) { -+ return; -+ } -+ - for (y = 0; y < bltheight; y++) { - for (x = 0; x < bltwidth; x++) { - p = *(dst_base + m(dst)); -@@ -143,6 +148,11 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, - src = src_ - src_base; - dstpitch -= bltwidth; - srcpitch -= bltwidth; -+ -+ if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) { -+ return; -+ } -+ - for (y = 0; y < bltheight; y++) { - for (x = 0; x < bltwidth; x+=2) { - p1 = *(dst_base + m(dst)); --- -1.8.3.1 - diff --git a/qemu.trad.CVE-2017-8309.patch b/qemu.trad.CVE-2017-8309.patch deleted file mode 100644 index 10b5b05..0000000 --- a/qemu.trad.CVE-2017-8309.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 3268a845f41253fb55852a8429c32b50f36f349a Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 28 Apr 2017 09:56:12 +0200 -Subject: [PATCH] audio: release capture buffers - -AUD_add_capture() allocates two buffers which are never released. -Add the missing calls to AUD_del_capture(). - -Impact: Allows vnc clients to exhaust host memory by repeatedly -starting and stopping audio capture. - -Fixes: CVE-2017-8309 -Cc: P J P -Cc: Huawei PSIRT -Reported-by: "Jiangxin (hunter, SCC)" -Signed-off-by: Gerd Hoffmann -Reviewed-by: Prasad J Pandit -Message-id: 20170428075612.9997-1-kraxel@redhat.com ---- - audio/audio.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/audio/audio.c b/audio/audio.c -index c8898d8..beafed2 100644 ---- a/audio/audio.c -+++ b/audio/audio.c -@@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) - sw = sw1; - } - LIST_REMOVE (cap, entries); -+ qemu_free (cap->hw.mix_buf); -+ qemu_free (cap->buf); - qemu_free (cap); - } - return; --- -1.8.3.1 - diff --git a/qemu.trad.CVE-2017-9330.patch b/qemu.trad.CVE-2017-9330.patch deleted file mode 100644 index 046e3e0..0000000 --- a/qemu.trad.CVE-2017-9330.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 26f670a244982335cc08943fb1ec099a2c81e42d Mon Sep 17 00:00:00 2001 -From: Li Qiang -Date: Tue, 7 Feb 2017 03:15:03 -0800 -Subject: [PATCH] usb: ohci: fix error return code in servicing iso td - -It should return 1 if an error occurs when reading iso td. -This will avoid an infinite loop issue in ohci_service_ed_list. - -Signed-off-by: Li Qiang -Message-id: 5899ac3e.1033240a.944d5.9a2d@mx.google.com -Signed-off-by: Gerd Hoffmann ---- - hw/usb-ohci.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c -index c82a92f..2cba3e3 100644 ---- a/hw/usb-ohci.c -+++ b/hw/usb-ohci.c -@@ -725,7 +725,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, - - if (!ohci_read_iso_td(addr, &iso_td)) { - printf("usb-ohci: ISO_TD read error at %x\n", addr); -- return 0; -+ return 1; - } - - starting_frame = OHCI_BM(iso_td.flags, TD_SF); --- -1.8.3.1 - diff --git a/qemu.trad.bug1399055.patch b/qemu.trad.bug1399055.patch deleted file mode 100644 index 69f8fd6..0000000 --- a/qemu.trad.bug1399055.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 4299b90e9ba9ce5ca9024572804ba751aa1a7e70 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 18 Oct 2016 13:15:17 +0530 -Subject: [PATCH] display: cirrus: check vga bits per pixel(bpp) value - -In Cirrus CLGD 54xx VGA Emulator, if cirrus graphics mode is VGA, -'cirrus_get_bpp' returns zero(0), which could lead to a divide -by zero error in while copying pixel data. The same could occur -via blit pitch values. Add check to avoid it. - -Reported-by: Huawei PSIRT -Signed-off-by: Prasad J Pandit -Message-id: 1476776717-24807-1-git-send-email-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann ---- - hw/cirrus_vga.c | 14 ++++++++++---- - 1 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c -index 3d712d5..bdb092e 100644 ---- a/hw/cirrus_vga.c -+++ b/hw/cirrus_vga.c -@@ -272,6 +272,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s); - static bool blit_region_is_unsafe(struct CirrusVGAState *s, - int32_t pitch, int32_t addr) - { -+ if (!pitch) { -+ return true; -+ } - if (pitch < 0) { - int64_t min = addr - + ((int64_t)s->cirrus_blt_height - 1) * pitch -@@ -715,7 +718,7 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) - s->cirrus_addr_mask)); - } - --static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) -+static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) - { - int sx = 0, sy = 0; - int dx = 0, dy = 0; -@@ -729,6 +732,9 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) - int width, height; - - depth = s->get_bpp((VGAState *)s) / 8; -+ if (!depth) { -+ return 0; -+ } - s->get_resolution((VGAState *)s, &width, &height); - - /* extra x, y */ -@@ -783,6 +789,8 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); -+ -+ return 1; - } - - static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) -@@ -790,11 +798,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) - if (blit_is_unsafe(s)) - return 0; - -- cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, -+ return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, - s->cirrus_blt_srcaddr - s->start_addr, - s->cirrus_blt_width, s->cirrus_blt_height); -- -- return 1; - } - - /*************************************** --- -1.7.0.4 - diff --git a/sources b/sources index 1e984f8..0aa5da3 100644 --- a/sources +++ b/sources @@ -4,4 +4,5 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.19.2.tar.gz) = 35147b0d755b5a603915fa5017bc021d4a238ab96ee1139dfee8e0f6ba76e64b89d5f331fbd60549682f45ee983d3d8f1cb95c53eed22373a7fa06074ca8da09 +SHA512 (xen-4.20.1.tar.gz) = e4502ddaeb66de4c30d59e90af198586683c28b56bf0eb03ca5508f663fef5e6582c009861ff5b66b7f0df6e5f6bc12337eff0ec775d72e7cb189fd2079dbd9d +SHA512 (mini-os-4.20.0.tar.xz) = 52d5d0985e1b4c26b761c94a3f7ca543bc388a96f69710524ebf34dd5b01d8f774fd5a3f6a50739c8b7c7edfdf07b594f5d44de8f389ea4138a62f9c5884c4e6 diff --git a/xen.drop.brctl.patch b/xen.drop.brctl.patch deleted file mode 100644 index f420b8e..0000000 --- a/xen.drop.brctl.patch +++ /dev/null @@ -1,8 +0,0 @@ ---- xen-4.11.0-rc7/tools/qemu-xen-traditional/i386-dm/qemu-ifup-Linux.orig 2017-09-15 19:37:27.000000000 +0100 -+++ xen-4.11.0-rc7/tools/qemu-xen-traditional/i386-dm/qemu-ifup-Linux 2018-07-03 20:17:52.934780235 +0100 -@@ -34,4 +34,4 @@ - fi - - ifconfig $1 0.0.0.0 up --brctl addif $bridge $1 || true -+ip link set $1 master $bridge || true diff --git a/xen.efi.build.patch b/xen.efi.build.patch index 69d1e93..b5455df 100644 --- a/xen.efi.build.patch +++ b/xen.efi.build.patch @@ -1,13 +1,13 @@ ---- xen-4.19.0-rc1/xen/arch/x86/arch.mk.orig 2024-07-01 18:31:39.000000000 +0100 -+++ xen-4.19.0-rc1/xen/arch/x86/arch.mk 2024-07-02 21:10:00.796753718 +0100 -@@ -91,7 +91,9 @@ +--- xen-4.20.0-rc4/xen/arch/x86/arch.mk.orig 2025-02-07 11:56:01.000000000 +0000 ++++ xen-4.20.0-rc4/xen/arch/x86/arch.mk 2025-02-09 22:56:05.579507311 +0000 +@@ -95,7 +95,9 @@ -c $(srctree)/$(efi-check).c -o $(efi-check).o,y) # Check if the linker supports PE. --EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 -+#EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 +-EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names ++#EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names +# use a reduced set of options from LDFLAGS -+EFI_LDFLAGS = --as-needed --build-id=sha1 -mi386pep --subsystem=10 ++EFI_LDFLAGS = --as-needed --build-id=sha1 -mi386pep --subsystem=10 --enable-long-section-names LD_PE_check_cmd = $(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o $(efi-check).efi $(efi-check).o) XEN_BUILD_PE := $(LD_PE_check_cmd) diff --git a/xen.fedora.crypt.patch b/xen.fedora.crypt.patch deleted file mode 100644 index 7aba2d4..0000000 --- a/xen.fedora.crypt.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- xen-4.5.1/tools/qemu-xen-traditional/vnc.c.orig 2015-07-12 21:55:32.875504811 +0100 -+++ xen-4.5.1/tools/qemu-xen-traditional/vnc.c 2015-07-12 22:03:03.860005391 +0100 -@@ -2140,7 +2140,7 @@ - GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */ - static int vnc_set_gnutls_priority(gnutls_session_t s, int x509) - { -- const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH"; -+ const char *priority = x509 ? "@SYSTEM" : "@SYSTEM:+ANON-DH"; - int rc; - - rc = gnutls_priority_set_direct(s, priority, NULL); diff --git a/xen.gcc7.fix.patch b/xen.gcc7.fix.patch deleted file mode 100644 index b18ba2b..0000000 --- a/xen.gcc7.fix.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- xen-4.8.0/extras/mini-os/Makefile.orig 2016-09-28 12:09:38.000000000 +0100 -+++ xen-4.8.0/extras/mini-os/Makefile 2017-02-15 21:15:19.340197960 +0000 -@@ -142,6 +142,9 @@ - APP_LDLIBS += -lz - APP_LDLIBS += -lm - LDLIBS += -lc -+ifeq ($(MINIOS_TARGET_ARCH),x86_32) -+LDLIBS += -L$(shell dirname `gcc -m32 -print-libgcc-file-name`) -lgcc -+endif - endif - - ifneq ($(APP_OBJS)-$(lwip),-y) diff --git a/xen.hypervisor.config b/xen.hypervisor.config index a498382..7f11043 100644 --- a/xen.hypervisor.config +++ b/xen.hypervisor.config @@ -1,32 +1,50 @@ # # Automatically generated file; DO NOT EDIT. -# Xen/x86 4.14.0-rc Configuration +# Xen/x86 4.20 Configuration # CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=100101 +CONFIG_GCC_VERSION=150001 CONFIG_CLANG_VERSION=0 +CONFIG_LD_IS_GNU=y CONFIG_CC_HAS_VISIBILITY_ATTRIBUTE=y +CONFIG_CC_SPLIT_SECTIONS=y +CONFIG_FUNCTION_ALIGNMENT_16B=y +CONFIG_FUNCTION_ALIGNMENT=16 CONFIG_X86_64=y CONFIG_X86=y CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" -CONFIG_INDIRECT_THUNK=y +CONFIG_CC_HAS_INDIRECT_THUNK=y CONFIG_HAS_AS_CET_SS=y +CONFIG_HAS_CC_CET_IBT=y # # Architecture Features # +CONFIG_AMD=y +CONFIG_INTEL=y +CONFIG_64BIT=y CONFIG_NR_CPUS=256 +CONFIG_NR_NUMA_NODES=64 CONFIG_PV=y CONFIG_PV32=y CONFIG_PV_LINEAR_PT=y CONFIG_HVM=y +CONFIG_AMD_SVM=y +CONFIG_INTEL_VMX=y +CONFIG_XEN_SHSTK=y +CONFIG_XEN_IBT=y CONFIG_SHADOW_PAGING=y # CONFIG_BIGMEM is not set -CONFIG_TBOOT=y +CONFIG_HVM_FEP=y +CONFIG_X86_PSR=y CONFIG_XEN_ALIGN_DEFAULT=y # CONFIG_XEN_ALIGN_2M is not set +# CONFIG_X2APIC_PHYSICAL is not set +CONFIG_X2APIC_MIXED=y # CONFIG_XEN_GUEST is not set # CONFIG_HYPERV_GUEST is not set +# CONFIG_REQUIRE_NX is not set +CONFIG_ALTP2M=y # end of Architecture Features # @@ -35,42 +53,55 @@ CONFIG_XEN_ALIGN_DEFAULT=y CONFIG_COMPAT=y CONFIG_CORE_PARKING=y CONFIG_GRANT_TABLE=y +CONFIG_ALTERNATIVE_CALL=y +CONFIG_ARCH_MAP_DOMAIN_PAGE=y +CONFIG_GENERIC_BUG_FRAME=y CONFIG_HAS_ALTERNATIVE=y +CONFIG_HAS_COMPAT=y +CONFIG_HAS_DIT=y CONFIG_HAS_EX_TABLE=y CONFIG_HAS_FAST_MULTIPLY=y +CONFIG_HAS_IOPORTS=y +CONFIG_HAS_KEXEC=y +CONFIG_HAS_PIRQ=y +CONFIG_HAS_SCHED_GRANULARITY=y +CONFIG_HAS_UBSAN=y +CONFIG_HAS_VMAP=y CONFIG_MEM_ACCESS_ALWAYS_ON=y CONFIG_MEM_ACCESS=y -CONFIG_HAS_MEM_PAGING=y -CONFIG_HAS_PDX=y -CONFIG_HAS_UBSAN=y -CONFIG_HAS_KEXEC=y -CONFIG_HAS_IOPORTS=y -CONFIG_HAS_SCHED_GRANULARITY=y CONFIG_NEEDS_LIBELF=y +CONFIG_NUMA=y # # Speculative hardening # +CONFIG_INDIRECT_THUNK=y +CONFIG_RETURN_THUNK=y CONFIG_SPECULATIVE_HARDEN_ARRAY=y CONFIG_SPECULATIVE_HARDEN_BRANCH=y +CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS=y +CONFIG_SPECULATIVE_HARDEN_LOCK=y # end of Speculative hardening +# CONFIG_DIT_DEFAULT is not set CONFIG_HYPFS=y CONFIG_HYPFS_CONFIG=y +CONFIG_IOREQ_SERVER=y CONFIG_KEXEC=y -CONFIG_XENOPROF=y # CONFIG_XSM is not set CONFIG_SCHED_CREDIT=y CONFIG_SCHED_CREDIT2=y CONFIG_SCHED_RTDS=y +CONFIG_SCHED_ARINC653=y CONFIG_SCHED_NULL=y CONFIG_SCHED_DEFAULT="credit2" -CONFIG_CRYPTO=y +# CONFIG_BOOT_TIME_CPUPOOLS is not set CONFIG_LIVEPATCH=y CONFIG_FAST_SYMBOL_LOOKUP=y CONFIG_ENFORCE_UNIQUE_SYMBOLS=y CONFIG_CMDLINE="" CONFIG_DOM0_MEM="" +CONFIG_DTB_FILE="" CONFIG_TRACEBUFFER=y # end of Common Features @@ -79,35 +110,63 @@ CONFIG_TRACEBUFFER=y # CONFIG_ACPI=y CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y -CONFIG_NUMA=y +CONFIG_ACPI_NUMA=y CONFIG_HAS_NS16550=y CONFIG_HAS_EHCI=y +CONFIG_SERIAL_TX_BUFSIZE=32768 +# CONFIG_XHCI is not set CONFIG_HAS_CPUFREQ=y CONFIG_HAS_PASSTHROUGH=y +CONFIG_AMD_IOMMU=y +CONFIG_INTEL_IOMMU=y +# CONFIG_IOMMU_QUARANTINE_NONE is not set +CONFIG_IOMMU_QUARANTINE_BASIC=y +# CONFIG_IOMMU_QUARANTINE_SCRATCH_PAGE is not set CONFIG_HAS_PCI=y +CONFIG_HAS_PCI_MSI=y CONFIG_VIDEO=y CONFIG_VGA=y CONFIG_HAS_VPCI=y # end of Device Drivers # CONFIG_EXPERT is not set +# CONFIG_UNSUPPORTED is not set CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_ARCH_VCPU_IOREQ_COMPLETION=y # # Debugging Options # # CONFIG_DEBUG is not set +CONFIG_GDBSX=y +CONFIG_FRAME_POINTER=y +CONFIG_SELF_TESTS=y +# CONFIG_DEBUG_LOCK_PROFILE is not set +CONFIG_DEBUG_LOCKS=y +# CONFIG_PERF_COUNTERS is not set +CONFIG_VERBOSE_DEBUG=y +CONFIG_SCRUB_DEBUG=y +# CONFIG_UBSAN is not set +# CONFIG_DEBUG_TRACE is not set +CONFIG_XMEM_POOL_POISON=y +CONFIG_DEBUG_INFO=y # end of Debugging Options # ARM64 settings -CONFIG_64BIT=y +CONFIG_MMU=y CONFIG_ARM_64=y CONFIG_ARM=y +CONFIG_ARM_EFI=y +CONFIG_GICV2=y CONFIG_GICV3=y +CONFIG_VGICV2=y # CONFIG_NEW_VGIC is not set CONFIG_SBSA_VUART_CONSOLE=y +CONFIG_HWDOM_VUART=y CONFIG_ARM_SSBD=y CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_STATIC_EVTCHN=y +CONFIG_PARTIAL_EMULATION=y # # ARM errata workaround via the alternative framework @@ -115,8 +174,15 @@ CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARM64_ERRATUM_827319=y CONFIG_ARM64_ERRATUM_824069=y CONFIG_ARM64_ERRATUM_819472=y +CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_ERRATUM_832075=y CONFIG_ARM64_ERRATUM_834220=y +CONFIG_ARM_ERRATUM_858921=y +CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y +CONFIG_ARM64_ERRATUM_1286807=y +CONFIG_ARM64_ERRATUM_1508412=y + +# end of ARM errata workaround via the alternative framework CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR=y CONFIG_ALL_PLAT=y # CONFIG_QEMU is not set @@ -125,17 +191,18 @@ CONFIG_ALL_PLAT=y # CONFIG_NO_PLAT is not set CONFIG_ALL64_PLAT=y CONFIG_MPSOC_PLATFORM=y + +# +# Common Features +# CONFIG_HAS_DEVICE_TREE=y CONFIG_HAS_CADENCE_UART=y +CONFIG_HAS_LINFLEX=y +CONFIG_HAS_IMX_LPUART=y CONFIG_HAS_MVEBU=y CONFIG_HAS_MESON=y CONFIG_HAS_PL011=y +CONFIG_HAS_OMAP=y CONFIG_HAS_SCIF=y CONFIG_ARM_SMMU=y - -# ARM32 settings -CONFIG_ALL32_PLAT=y -CONFIG_ARM32_HARDEN_BRANCH_PREDICTOR=y -CONFIG_ARM_32=y -CONFIG_HAS_EXYNOS4210=y -CONFIG_HAS_OMAP=y +# CONFIG_IPMMU_VMSA is not set diff --git a/xen.spec b/xen.spec index 0ea5f41..8868407 100644 --- a/xen.spec +++ b/xen.spec @@ -6,13 +6,10 @@ %define build_docs %{?_without_docs: 0} %{?!_without_docs: 1} # Build with stubdom unless rpmbuild was run with --without stubdom %define build_stubdom %{?_without_stubdom: 0} %{?!_without_stubdom: 1} -# Only build with qemu-traditional if rpmbuild was run with --with qemutrad -%define build_qemutrad %{?_with_qemutrad: 1} %{?!_with_qemutrad: 0} # build with ovmf from edk2-ovmf unless rpmbuild was run with --without ovmf %define build_ovmf %{?_without_ovmf: 0} %{?!_without_ovmf: 1} -# set to 0 for archs that don't use qemu or ovmf (reduces build dependencies) -%ifnarch x86_64 %{ix86} -%define build_qemutrad 0 +# set to 0 for archs that don't use ovmf (reduces build dependencies) +%ifnarch x86_64 %define build_ovmf 0 %endif # Build with xen hypervisor unless rpmbuild was run with --without hyp @@ -39,8 +36,7 @@ # --without efi %define build_efi %{?_without_efi: 0} %{?!_without_efi: 1} # xen only supports efi boot images on x86_64 or aarch64 -# i686 builds a x86_64 hypervisor so add that as well -%ifnarch x86_64 aarch64 %{ix86} +%ifnarch x86_64 aarch64 %define build_efi 0 %endif %if "%dist" >= ".fc20" @@ -50,12 +46,12 @@ %endif # Hypervisor ABI -%define hv_abi 4.19 +%define hv_abi 4.20 Summary: Xen is a virtual machine monitor Name: xen -Version: 4.19.2 -Release: 6%{?dist} +Version: 4.20.1 +Release: 1%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -70,60 +66,20 @@ Source14: grub-0.97.tar.gz Source15: polarssl-1.1.4-gpl.tgz # .config file for xen hypervisor Source21: xen.hypervisor.config +# mini-os xen-RELEASE-4.20.0 with .git and .gitignore stripped +Source22: mini-os-4.20.0.tar.xz -Patch4: CVE-2014-0150.patch Patch5: xen.fedora.systemd.patch Patch6: xen.ocaml.selinux.fix.patch -Patch7: xen.fedora.crypt.patch -Patch8: qemu.trad.CVE-2015-6815.patch -Patch9: qemu.trad.CVE-2015-5279.patch -Patch10: qemu.trad.CVE-2015-5278.patch -Patch11: qemu.trad.CVE-2015-7295.patch -Patch12: qemu.trad.CVE-2015-8345.patch -Patch13: qemu.trad.CVE-2015-7512.patch -Patch14: qemu.trad.CVE-2015-8504.patch -Patch15: qemu.trad.CVE-2016-1714.patch -Patch16: qemu.trad.CVE-2016-1981.patch -Patch17: qemu.trad.CVE-2016-2841.patch -Patch18: qemu.trad.CVE-2016-2538.patch -Patch19: qemu.trad.CVE-2016-2857.patch -Patch20: qemu.trad.CVE-2016-4001.patch -Patch21: qemu.trad.CVE-2016-4002.patch -Patch22: qemu.trad.CVE-2016-4439.patch -Patch23: qemu.trad.CVE-2016-4441.patch -Patch24: qemu.trad.CVE-2016-5238.patch -Patch25: qemu.trad.CVE-2016-5338.patch -Patch27: qemu.trad.CVE-2016-6351.patch -Patch29: qemu.trad.CVE-2016-8669.patch -Patch30: qemu.trad.CVE-2016-8910.patch -Patch31: qemu.trad.bug1399055.patch -Patch32: qemu.trad.CVE-2016-9776.patch -Patch33: xen.gcc7.fix.patch Patch34: xen.canonicalize.patch -Patch35: qemu.trad.CVE-2017-6505.patch -Patch36: qemu.trad.CVE-2017-7718.patch Patch37: droplibvirtconflict.patch -Patch38: qemu.trad.CVE-2017-8309.patch -Patch39: qemu.trad.CVE-2017-9330.patch -Patch40: xen.drop.brctl.patch Patch41: xen.gcc9.fixes.patch Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch -Patch50: xsa469-4.19-01.patch -Patch51: xsa469-4.19-02.patch -Patch52: xsa469-4.19-03.patch -Patch53: xsa469-4.19-04.patch -Patch54: xsa469-4.19-05.patch -Patch55: xsa469-4.19-06.patch -Patch56: xsa469-4.19-07.patch -%if %build_qemutrad -BuildRequires: libidn-devel zlib-devel SDL-devel curl-devel -BuildRequires: libX11-devel gtk2-devel libaio-devel -%endif # build using Fedora seabios and ipxe packages for roms BuildRequires: seabios-bin ipxe-roms-qemu %ifarch %{ix86} x86_64 @@ -166,7 +122,6 @@ Requires: xen-runtime = %{version}-%{release} # installs xen. Requires: kpartx ExclusiveArch: x86_64 aarch64 -#ExclusiveArch: %#{ix86} x86_64 ia64 noarch %if %with_ocaml BuildRequires: ocaml, ocaml-findlib BuildRequires: perl(Data::Dumper) @@ -177,7 +132,7 @@ Requires(preun): systemd BuildRequires: systemd %endif BuildRequires: systemd-devel -%ifarch armv7hl aarch64 +%ifarch aarch64 BuildRequires: libfdt-devel %endif %if %build_hyp @@ -209,11 +164,9 @@ Requires: /usr/bin/qemu-img Requires: xen-hypervisor-abi = %{hv_abi} # perl is used in /etc/xen/scripts/locking.sh Recommends: perl -%ifnarch armv7hl aarch64 +%ifnarch aarch64 # use /usr/bin/qemu-system-i386 in Fedora instead of qemu-xen Recommends: qemu-system-x86-core -# rom file for qemu-xen-traditional -Recommends: ipxe-roms-qemu %endif %if %build_ovmf Recommends: edk2-ovmf-xen @@ -295,67 +248,23 @@ manage Xen virtual machines. %prep %setup -q -%patch 4 -p1 %patch 5 -p1 %patch 6 -p1 -%patch 7 -p1 -%patch 8 -p1 -%patch 9 -p1 -%patch 10 -p1 -%patch 11 -p1 -%patch 12 -p1 -%patch 13 -p1 -%patch 14 -p1 -%patch 15 -p1 -%patch 16 -p1 -%patch 17 -p1 -%patch 18 -p1 -%patch 19 -p1 -%patch 20 -p1 -%patch 21 -p1 -%patch 22 -p1 -%patch 23 -p1 -%patch 24 -p1 -%patch 25 -p1 -%patch 33 -p1 %patch 34 -p1 %patch 37 -p1 -%patch 40 -p1 %patch 41 -p1 %patch 43 -p1 %patch 45 -p1 %patch 46 -p1 %patch 49 -p1 -%patch 50 -p1 -%patch 51 -p1 -%patch 52 -p1 -%patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 - -# qemu-xen-traditional patches -pushd tools/qemu-xen-traditional -%patch 27 -p1 -%patch 29 -p1 -%patch 30 -p1 -%patch 31 -p1 -%patch 32 -p1 -%patch 35 -p1 -%patch 36 -p1 -%patch 38 -p1 -%patch 39 -p1 -popd - -# qemu-xen patches -pushd tools/qemu-xen -popd # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom # copy xen hypervisor .config file to change settings cp -v %{SOURCE21} xen/.config - +# mini-os is now separate file +mkdir extras +tar -C extras -xf %{SOURCE22} %build # This package calls binutils components directly and would need to pass @@ -373,20 +282,14 @@ mkdir -p dist/install/boot/efi/efi/fedora mkdir -p dist/install%{_libdir}/ocaml/stublibs %endif export EXTRA_CFLAGS_XEN_TOOLS="$RPM_OPT_FLAGS -Wno-error=use-after-free $LDFLAGS" -export EXTRA_CFLAGS_QEMU_TRADITIONAL="$RPM_OPT_FLAGS" -export EXTRA_CFLAGS_QEMU_XEN="$RPM_OPT_FLAGS" export PYTHON="/usr/bin/python3" export LDFLAGS_SAVE=`echo $LDFLAGS | sed -e 's/-Wl,//g' -e 's/,/ /g' -e 's? -specs=[-a-z/0-9]*??g'` export CFLAGS_SAVE="$CFLAGS" -%if %build_qemutrad -CONFIG_EXTRA="--enable-qemu-traditional" -%else CONFIG_EXTRA="" -%endif %if %build_ovmf CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ovmf=/usr/share/edk2/xen/OVMF.fd" %endif -%ifnarch armv7hl aarch64 +%ifarch aarch64 CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ipxe=/usr/share/ipxe/10ec8139.rom" %endif %if %(test -f /usr/share/seabios/bios-256k.bin && echo 1|| echo 0) @@ -400,20 +303,11 @@ CONFIG_EXTRA="$CONFIG_EXTRA --enable-systemd" ./configure --prefix=%{_prefix} --libdir=%{_libdir} --libexecdir=%{_libexecdir} --with-system-qemu=/usr/bin/qemu-system-i386 --with-linux-backend-modules="xen-evtchn xen-gntdev xen-gntalloc xen-blkback xen-netback xen-pciback xen-scsiback xen-acpi-processor" $CONFIG_EXTRA unset CFLAGS CXXFLAGS FFLAGS LDFLAGS export LDFLAGS="$LDFLAGS_SAVE" -export CFLAGS="$CFLAGS_SAVE -Wno-error=address" +export CFLAGS=`echo "$CFLAGS_SAVE -Wno-error=address" | sed -e s/-specs=\/usr\/lib\/rpm\/redhat/redhat-annobin-cc1//g` %if %build_hyp -%if %build_crosshyp -export CFLAGS=`echo $CFLAGS | sed -e 's/-m32//g' -e 's/-march=i686//g' 's/-specs=\/usr\/lib\/rpm\/redhat\/redhat-annobin-cc1//g'` -XEN_TARGET_ARCH=x86_64 %make_build prefix=/usr xen CC="/usr/bin/x86_64-linux-gnu-gcc" -%else -%ifarch armv7hl -export CFLAGS=`echo $CFLAGS | sed -e 's/-mfloat-abi=hard//g' -e 's/-march=armv7-a//g'` -%endif -# armv7hl aarch64 or x86_64 %make_build prefix=/usr xen %endif -%endif unset CFLAGS CXXFLAGS FFLAGS LDFLAGS %make_build %{?ocaml_flags} prefix=/usr tools @@ -421,9 +315,6 @@ unset CFLAGS CXXFLAGS FFLAGS LDFLAGS make prefix=/usr docs %endif export RPM_OPT_FLAGS_RED=`echo $RPM_OPT_FLAGS | sed -e 's/-m64//g' -e 's/--param=ssp-buffer-size=4//g' -e's/-fstack-protector-strong//'` -%ifarch %{ix86} -export EXTRA_CFLAGS_XEN_TOOLS="$RPM_OPT_FLAGS_RED" -%endif %if %build_stubdom %ifnarch armv7hl aarch64 make mini-os-dir @@ -479,18 +370,6 @@ rm -fr %{buildroot}%{_datadir}/doc/xen # Pointless helper rm -f %{buildroot}%{_bindir}/xen-python-path -# qemu stuff (unused or available from upstream) -rm -rf %{buildroot}/usr/share/xen/man -rm -rf %{buildroot}/usr/bin/qemu-*-xen -ln -s qemu-img %{buildroot}/%{_bindir}/qemu-img-xen -ln -s qemu-img %{buildroot}/%{_bindir}/qemu-nbd-xen -for file in bios.bin openbios-sparc32 openbios-sparc64 ppc_rom.bin \ - pxe-e1000.bin pxe-ne2k_pci.bin pxe-pcnet.bin pxe-rtl8139.bin \ - vgabios.bin vgabios-cirrus.bin video.x openbios-ppc bamboo.dtb -do - rm -f %{buildroot}/%{_datadir}/xen/qemu/$file -done - # README's not intended for end users rm -f %{buildroot}/%{_sysconfdir}/xen/README* @@ -502,20 +381,12 @@ rm -rf %{buildroot}/%{_libdir}/*.a %if %build_efi # clean up extra efi files -%ifarch %{ix86} -rm -f %{buildroot}/usr/lib64/efi/xen-%{hv_abi}.efi -rm -f %{buildroot}/usr/lib64/efi/xen-4.efi -rm -f %{buildroot}/usr/lib64/efi/xen.efi -cp -p %{buildroot}/usr/lib64/efi/xen-%{version}{,.notstripped}.efi -strip -s %{buildroot}/usr/lib64/efi/xen-%{version}.efi -%else rm -f %{buildroot}/%{_libdir}/efi/xen-%{hv_abi}.efi rm -f %{buildroot}/%{_libdir}/efi/xen-4.efi rm -f %{buildroot}/%{_libdir}/efi/xen.efi cp -p %{buildroot}/%{_libdir}/efi/xen-%{version}{,.notstripped}.efi strip -s %{buildroot}/%{_libdir}/efi/xen-%{version}.efi %endif -%endif %if ! %build_ocaml rm -rf %{buildroot}/%{_unitdir}/oxenstored.service @@ -766,14 +637,6 @@ fi %dir %{_libexecdir}/%{name} %dir %{_libexecdir}/%{name}/bin %attr(0700,root,root) %{_libexecdir}/%{name}/bin/* -# QEMU runtime files -%if %build_qemutrad -%ifnarch armv7hl aarch64 -%dir %{_datadir}/%{name}/qemu -%dir %{_datadir}/%{name}/qemu/keymaps -%{_datadir}/%{name}/qemu/keymaps/* -%endif -%endif # man pages %if %build_docs @@ -803,17 +666,12 @@ fi %{python3_sitearch}/pygrub-*.egg-info # The firmware -%ifarch %{ix86} x86_64 +%ifarch x86_64 %dir %{_libexecdir}/%{name}/boot %{_libexecdir}/xen/boot/hvmloader -%ifnarch %{ix86} %{_libexecdir}/%{name}/boot/xen-shim /usr/lib/debug%{_libexecdir}/xen/boot/xen-shim-syms -%endif %if %build_stubdom -%if %build_qemutrad -%{_libexecdir}/xen/boot/ioemu-stubdom.gz -%endif %{_libexecdir}/xen/boot/xenstore-stubdom.gz %{_libexecdir}/xen/boot/xenstorepvh-stubdom.gz %endif @@ -830,22 +688,21 @@ fi %ghost %{_localstatedir}/run/xenstored # All xenstore CLI tools -%{_bindir}/qemu-*-xen %{_bindir}/xenstore %{_bindir}/xenstore-* #%#{_bindir}/remus # XSM %{_bindir}/flask-* # Misc stuff -%ifnarch armv7hl aarch64 +%ifnarch aarch64 %{_bindir}/xen-detect %endif %{_bindir}/xencov_split -%ifnarch armv7hl aarch64 +%ifnarch aarch64 %{_bindir}/gdbsx %{_bindir}/xen-kdd %endif -%ifnarch armv7hl aarch64 +%ifnarch aarch64 %{_bindir}/xen-hptool %{_bindir}/xen-hvmcrash %{_bindir}/xen-hvmctx @@ -862,17 +719,17 @@ fi %{_bindir}/xenperf %{_bindir}/xenwatchdogd %{_bindir}/xl -%ifnarch armv7hl aarch64 +%ifnarch aarch64 %{_bindir}/xen-lowmemd %endif %{_bindir}/xencov -%ifnarch armv7hl aarch64 +%ifnarch aarch64 %{_bindir}/xen-mfndump %endif %{_bindir}/xenalyze %{_bindir}/xentrace %{_bindir}/xentrace_setsize -%ifnarch armv7hl aarch64 +%ifnarch aarch64 %{_bindir}/xen-cpuid %endif %{_bindir}/xen-livepatch @@ -894,7 +751,7 @@ fi %files hypervisor %if %build_hyp -%ifnarch armv7hl aarch64 +%ifnarch aarch64 /boot/xen-*.gz /boot/xen*.config %else @@ -907,12 +764,8 @@ fi /usr/lib/debug/xen* %endif %if %build_efi -%ifarch %{ix86} -/usr/lib64/efi/*.efi -%else %{_libdir}/efi/*.efi %endif -%endif %if %build_docs %files doc @@ -948,9 +801,26 @@ fi %{_libdir}/ocaml/xen*/*.a %{_libdir}/ocaml/xen*/*.cmxa %{_libdir}/ocaml/xen*/*.cmx +%{_libdir}/ocaml/xsd_glue/* +%{_libexecdir}/xen/ocaml/xsd_glue/xenctrl_plugin/domain_getinfo_v1.cmxs %endif %changelog +* Sun Jul 13 2025 Michael Young - 4.20.1-1 +- update to xen 4.20.1 + remove old qemu code for spac file + remove armv7hl and ix86 code from spec file + update configuration in xen.hypervisor.config + minios is now a separate file + package extra ocaml files + unset -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 for hypervisor build + rebase xen.efi.build.patch + includes fixes for security vulnerabilites + x86: Incorrect stubs exception handling for flags recovery [XSA-470, + CVE-2025-27465] + x86: Transitive Scheduler Attacks [XSA-471, CVE-2024-36350, + CVE-2024-36357] + * Fri Jul 11 2025 Jerry James - 4.19.2-6 - Rebuild to fix OCaml dependencies diff --git a/xsa469-4.19-01.patch b/xsa469-4.19-01.patch deleted file mode 100644 index cbbb14f..0000000 --- a/xsa469-4.19-01.patch +++ /dev/null @@ -1,83 +0,0 @@ -From: Andrew Cooper -Subject: x86/alternative: Support replacements when a feature is not present - -Use the top bit of a->cpuid to express inverted polarity. This requires -stripping the top bit back out when performing the sanity checks. - -Despite only being used once, create a replace boolean to express the decision -more clearly in _apply_alternatives(). - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c -index 1ba35cb9ede9..88c90044c20d 100644 ---- a/xen/arch/x86/alternative.c -+++ b/xen/arch/x86/alternative.c -@@ -197,6 +197,8 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, - uint8_t *repl = ALT_REPL_PTR(a); - uint8_t buf[MAX_PATCH_LEN]; - unsigned int total_len = a->orig_len + a->pad_len; -+ unsigned int feat = a->cpuid & ~ALT_FLAG_NOT; -+ bool inv = a->cpuid & ALT_FLAG_NOT, replace; - - if ( a->repl_len > total_len ) - { -@@ -214,11 +216,11 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, - return -ENOSPC; - } - -- if ( a->cpuid >= NCAPINTS * 32 ) -+ if ( feat >= NCAPINTS * 32 ) - { - printk(XENLOG_ERR - "Alt for %ps, feature %#x outside of featureset range %#x\n", -- ALT_ORIG_PTR(a), a->cpuid, NCAPINTS * 32); -+ ALT_ORIG_PTR(a), feat, NCAPINTS * 32); - return -ERANGE; - } - -@@ -243,8 +245,14 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, - continue; - } - -+ /* -+ * Should a replacement be performed? Most replacements have positive -+ * polarity, but we support negative polarity too. -+ */ -+ replace = boot_cpu_has(feat) ^ inv; -+ - /* If there is no replacement to make, see about optimising the nops. */ -- if ( !boot_cpu_has(a->cpuid) ) -+ if ( !replace ) - { - /* Origin site site already touched? Don't nop anything. */ - if ( base->priv ) -diff --git a/xen/arch/x86/include/asm/alternative.h b/xen/arch/x86/include/asm/alternative.h -index 69555d781ef9..89b7bdcb82e5 100644 ---- a/xen/arch/x86/include/asm/alternative.h -+++ b/xen/arch/x86/include/asm/alternative.h -@@ -1,6 +1,13 @@ - #ifndef __X86_ALTERNATIVE_H__ - #define __X86_ALTERNATIVE_H__ - -+/* -+ * Common to both C and ASM. Express a replacement when a feature is not -+ * available. -+ */ -+#define ALT_FLAG_NOT (1 << 15) -+#define ALT_NOT(x) (ALT_FLAG_NOT | (x)) -+ - #ifdef __ASSEMBLY__ - #include - #else -@@ -11,7 +18,7 @@ - struct __packed alt_instr { - int32_t orig_offset; /* original instruction */ - int32_t repl_offset; /* offset to replacement instruction */ -- uint16_t cpuid; /* cpuid bit set for replacement */ -+ uint16_t cpuid; /* cpuid bit set for replacement (top bit is polarity) */ - uint8_t orig_len; /* length of original instruction */ - uint8_t repl_len; /* length of new instruction */ - uint8_t pad_len; /* length of build-time padding */ - diff --git a/xsa469-4.19-02.patch b/xsa469-4.19-02.patch deleted file mode 100644 index 5fd285f..0000000 --- a/xsa469-4.19-02.patch +++ /dev/null @@ -1,314 +0,0 @@ -From: Andrew Cooper -Subject: x86/guest: Remove use of the Xen hypercall_page - -In order to protect against ITS, Xen needs to start using return thunks. -Therefore the advice in XSA-466 becomes relevant, and the hypercall_page needs -to be removed. - -Implement early_hypercall(), with infrastructure to figure out the correct -instruction on first use. Use ALTERNATIVE()s to result in inline hypercalls, -including the ALT_NOT() form so we only need a single synthetic feature bit. - -No overall change. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/guest/xen/Makefile b/xen/arch/x86/guest/xen/Makefile -index 26fb4b1007c0..8b3250aa8886 100644 ---- a/xen/arch/x86/guest/xen/Makefile -+++ b/xen/arch/x86/guest/xen/Makefile -@@ -1,4 +1,4 @@ --obj-y += hypercall_page.o -+obj-bin-y += hypercall.init.o - obj-y += xen.o - - obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o -diff --git a/xen/arch/x86/guest/xen/hypercall.S b/xen/arch/x86/guest/xen/hypercall.S -new file mode 100644 -index 000000000000..05e429794cc4 ---- /dev/null -+++ b/xen/arch/x86/guest/xen/hypercall.S -@@ -0,0 +1,50 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+ -+#include -+ -+ .section .init.text, "ax", @progbits -+ -+ /* -+ * Used during early boot, before alternatives have run and inlined -+ * the appropriate instruction. Called using the hypercall ABI. -+ */ -+FUNC(early_hypercall) -+ cmpb $0, early_hypercall_insn(%rip) -+ jl .L_setup -+ je 1f -+ -+ vmmcall -+ ret -+ -+1: vmcall -+ ret -+ -+.L_setup: -+ /* -+ * When setting up the first time around, all registers need -+ * preserving. Save the non-callee-saved ones. -+ */ -+ push %r11 -+ push %r10 -+ push %r9 -+ push %r8 -+ push %rdi -+ push %rsi -+ push %rdx -+ push %rcx -+ push %rax -+ -+ call early_hypercall_setup -+ -+ pop %rax -+ pop %rcx -+ pop %rdx -+ pop %rsi -+ pop %rdi -+ pop %r8 -+ pop %r9 -+ pop %r10 -+ pop %r11 -+ -+ jmp early_hypercall -+END(early_hypercall) -diff --git a/xen/arch/x86/guest/xen/hypercall_page.S b/xen/arch/x86/guest/xen/hypercall_page.S -deleted file mode 100644 -index 7ab55fc1f6e6..000000000000 ---- a/xen/arch/x86/guest/xen/hypercall_page.S -+++ /dev/null -@@ -1,76 +0,0 @@ --#include --#include --#include -- -- .section ".text.page_aligned", "ax", @progbits -- --DATA(hypercall_page, PAGE_SIZE) -- /* Poisoned with `ret` for safety before hypercalls are set up. */ -- .fill PAGE_SIZE, 1, 0xc3 --END(hypercall_page) -- --/* -- * Identify a specific hypercall in the hypercall page -- * @param name Hypercall name. -- */ --#define DECLARE_HYPERCALL(name) \ -- .globl HYPERCALL_ ## name; \ -- .type HYPERCALL_ ## name, STT_FUNC; \ -- .size HYPERCALL_ ## name, 32; \ -- .set HYPERCALL_ ## name, hypercall_page + __HYPERVISOR_ ## name * 32 -- --DECLARE_HYPERCALL(set_trap_table) --DECLARE_HYPERCALL(mmu_update) --DECLARE_HYPERCALL(set_gdt) --DECLARE_HYPERCALL(stack_switch) --DECLARE_HYPERCALL(set_callbacks) --DECLARE_HYPERCALL(fpu_taskswitch) --DECLARE_HYPERCALL(sched_op_compat) --DECLARE_HYPERCALL(platform_op) --DECLARE_HYPERCALL(set_debugreg) --DECLARE_HYPERCALL(get_debugreg) --DECLARE_HYPERCALL(update_descriptor) --DECLARE_HYPERCALL(memory_op) --DECLARE_HYPERCALL(multicall) --DECLARE_HYPERCALL(update_va_mapping) --DECLARE_HYPERCALL(set_timer_op) --DECLARE_HYPERCALL(event_channel_op_compat) --DECLARE_HYPERCALL(xen_version) --DECLARE_HYPERCALL(console_io) --DECLARE_HYPERCALL(physdev_op_compat) --DECLARE_HYPERCALL(grant_table_op) --DECLARE_HYPERCALL(vm_assist) --DECLARE_HYPERCALL(update_va_mapping_otherdomain) --DECLARE_HYPERCALL(iret) --DECLARE_HYPERCALL(vcpu_op) --DECLARE_HYPERCALL(set_segment_base) --DECLARE_HYPERCALL(mmuext_op) --DECLARE_HYPERCALL(xsm_op) --DECLARE_HYPERCALL(nmi_op) --DECLARE_HYPERCALL(sched_op) --DECLARE_HYPERCALL(callback_op) --DECLARE_HYPERCALL(xenoprof_op) --DECLARE_HYPERCALL(event_channel_op) --DECLARE_HYPERCALL(physdev_op) --DECLARE_HYPERCALL(hvm_op) --DECLARE_HYPERCALL(sysctl) --DECLARE_HYPERCALL(domctl) --DECLARE_HYPERCALL(kexec_op) --DECLARE_HYPERCALL(argo_op) --DECLARE_HYPERCALL(xenpmu_op) -- --DECLARE_HYPERCALL(arch_0) --DECLARE_HYPERCALL(arch_1) --DECLARE_HYPERCALL(arch_2) --DECLARE_HYPERCALL(arch_3) --DECLARE_HYPERCALL(arch_4) --DECLARE_HYPERCALL(arch_5) --DECLARE_HYPERCALL(arch_6) --DECLARE_HYPERCALL(arch_7) -- --/* -- * Local variables: -- * tab-width: 8 -- * indent-tabs-mode: nil -- * End: -- */ -diff --git a/xen/arch/x86/guest/xen/xen.c b/xen/arch/x86/guest/xen/xen.c -index 7484b3f73ad3..2c30db05dfa7 100644 ---- a/xen/arch/x86/guest/xen/xen.c -+++ b/xen/arch/x86/guest/xen/xen.c -@@ -26,7 +26,6 @@ - bool __read_mostly xen_guest; - - uint32_t __read_mostly xen_cpuid_base; --extern char hypercall_page[]; - static struct rangeset *mem; - - DEFINE_PER_CPU(unsigned int, vcpu_id); -@@ -35,6 +34,50 @@ static struct vcpu_info *vcpu_info; - static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)]; - DEFINE_PER_CPU(struct vcpu_info *, vcpu_info); - -+/* -+ * Which instruction to use for early hypercalls: -+ * < 0 setup -+ * 0 vmcall -+ * > 0 vmmcall -+ */ -+int8_t __initdata early_hypercall_insn = -1; -+ -+/* -+ * Called once during the first hypercall to figure out which instruction to -+ * use. Error handling options are limited. -+ */ -+void asmlinkage __init early_hypercall_setup(void) -+{ -+ BUG_ON(early_hypercall_insn != -1); -+ -+ if ( !boot_cpu_data.x86_vendor ) -+ { -+ unsigned int eax, ebx, ecx, edx; -+ -+ cpuid(0, &eax, &ebx, &ecx, &edx); -+ -+ boot_cpu_data.x86_vendor = x86_cpuid_lookup_vendor(ebx, ecx, edx); -+ } -+ -+ switch ( boot_cpu_data.x86_vendor ) -+ { -+ case X86_VENDOR_INTEL: -+ case X86_VENDOR_CENTAUR: -+ case X86_VENDOR_SHANGHAI: -+ early_hypercall_insn = 0; -+ setup_force_cpu_cap(X86_FEATURE_USE_VMCALL); -+ break; -+ -+ case X86_VENDOR_AMD: -+ case X86_VENDOR_HYGON: -+ early_hypercall_insn = 1; -+ break; -+ -+ default: -+ BUG(); -+ } -+} -+ - static void __init find_xen_leaves(void) - { - uint32_t eax, ebx, ecx, edx, base; -@@ -337,9 +380,6 @@ const struct hypervisor_ops *__init xg_probe(void) - if ( !xen_cpuid_base ) - return NULL; - -- /* Fill the hypercall page. */ -- wrmsrl(cpuid_ebx(xen_cpuid_base + 2), __pa(hypercall_page)); -- - xen_guest = true; - - return &ops; -diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h -index ba3df174b76e..9e3ed21c026d 100644 ---- a/xen/arch/x86/include/asm/cpufeatures.h -+++ b/xen/arch/x86/include/asm/cpufeatures.h -@@ -42,6 +42,7 @@ XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks * - XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ - XEN_CPUFEATURE(IBPB_ENTRY_PV, X86_SYNTH(28)) /* MSR_PRED_CMD used by Xen for PV */ - XEN_CPUFEATURE(IBPB_ENTRY_HVM, X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for HVM */ -+XEN_CPUFEATURE(USE_VMCALL, X86_SYNTH(30)) /* Use VMCALL instead of VMMCALL */ - - /* Bug words follow the synthetic words. */ - #define X86_NR_BUG 1 -diff --git a/xen/arch/x86/include/asm/guest/xen-hcall.h b/xen/arch/x86/include/asm/guest/xen-hcall.h -index 665b472d05ac..96004dec9909 100644 ---- a/xen/arch/x86/include/asm/guest/xen-hcall.h -+++ b/xen/arch/x86/include/asm/guest/xen-hcall.h -@@ -30,9 +30,11 @@ - ({ \ - long res, tmp__; \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__) ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)) \ - : "memory" ); \ - (type)res; \ -@@ -42,10 +44,12 @@ - ({ \ - long res, tmp__; \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__), "=S" (tmp__) \ - ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)), "2" ((long)(a2)) \ - : "memory" ); \ - (type)res; \ -@@ -55,10 +59,12 @@ - ({ \ - long res, tmp__; \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__) \ - ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)) \ - : "memory" ); \ - (type)res; \ -@@ -69,10 +75,12 @@ - long res, tmp__; \ - register long _a4 asm ("r10") = ((long)(a4)); \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__), \ - "=&r" (tmp__) ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)), \ - "4" (_a4) \ - : "memory" ); \ diff --git a/xsa469-4.19-03.patch b/xsa469-4.19-03.patch deleted file mode 100644 index 2e944f9..0000000 --- a/xsa469-4.19-03.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Jan Beulich -Subject: x86/thunk: (Mis)align __x86_indirect_thunk_* to mitigate ITS - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. - -Arrange for __x86_indirect_thunk_* to always be in the second half. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Jan Beulich -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/indirect-thunk.S b/xen/arch/x86/indirect-thunk.S -index fd5493c22b16..c4b978d67b8e 100644 ---- a/xen/arch/x86/indirect-thunk.S -+++ b/xen/arch/x86/indirect-thunk.S -@@ -11,6 +11,10 @@ - - #include - -+/* Alignment is dealt with explicitly here; override the respective macro. */ -+#undef SYM_ALIGN -+#define SYM_ALIGN(align...) -+ - .macro IND_THUNK_RETPOLINE reg:req - call 1f - int3 -@@ -35,6 +39,16 @@ - .macro GEN_INDIRECT_THUNK reg:req - .section .text.__x86_indirect_thunk_\reg, "ax", @progbits - -+ /* -+ * The Indirect Target Selection speculative vulnerability means that -+ * indirect branches (including RETs) are unsafe when in the first -+ * half of a cacheline. Arrange for them to be in the second half. -+ * -+ * Align to 64, then skip 32. -+ */ -+ .balign 64 -+ .fill 32, 1, 0xcc -+ - FUNC(__x86_indirect_thunk_\reg) - ALTERNATIVE_2 __stringify(IND_THUNK_RETPOLINE \reg), \ - __stringify(IND_THUNK_LFENCE \reg), X86_FEATURE_IND_THUNK_LFENCE, \ diff --git a/xsa469-4.19-04.patch b/xsa469-4.19-04.patch deleted file mode 100644 index 81d77a9..0000000 --- a/xsa469-4.19-04.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: Andrew Cooper -Subject: x86/thunk: (Mis)align the RETs in clear_bhb_loops() to mitigate ITS - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. - -clear_bhb_loops() has a precise layout of branches. The alignment for -performance cause the RETs to always be in an unsafe position, and converting -those to return thunks changes the branching pattern. While such a conversion -is believed to be safe, clear_bhb_loops() is also a performance-relevant -fastpath, so (mis)align the RETs to be in a safe position. - -No functional change. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S -index 678c00c5d06f..52625f4e2c17 100644 ---- a/xen/arch/x86/bhb-thunk.S -+++ b/xen/arch/x86/bhb-thunk.S -@@ -50,7 +50,12 @@ END(clear_bhb_tsx) - * ret - * - * The CALL/RETs are necessary to prevent the Loop Stream Detector from -- * interfering. The alignment is for performance and not safety. -+ * interfering. -+ * -+ * The .balign's are for performance, but they cause the RETs to be in unsafe -+ * positions with respect to Indirect Target Selection. The .skips are to -+ * move the RETs into ITS-safe positions, rather than using the slowpath -+ * through __x86_return_thunk. - * - * The "short" sequence (5 and 5) is for CPUs prior to Alder Lake / Sapphire - * Rapids (i.e. Cores prior to Golden Cove and/or Gracemont). -@@ -66,12 +71,14 @@ FUNC(clear_bhb_loops) - jmp 5f - int3 - -- .align 64 -+ .balign 64 -+ .skip 32 - (.Lr1 - 1f), 0xcc - 1: call 2f -- ret -+.Lr1: ret - int3 - -- .align 64 -+ .balign 64 -+ .skip 32 - 18 /* (.Lr2 - 2f) but Clang IAS doesn't like this */, 0xcc - 2: ALTERNATIVE "mov $5, %eax", "mov $7, %eax", X86_SPEC_BHB_LOOPS_LONG - - 3: jmp 4f -@@ -83,7 +90,7 @@ FUNC(clear_bhb_loops) - sub $1, %ecx - jnz 1b - -- ret -+.Lr2: ret - 5: - /* - * The Intel sequence has an LFENCE here. The purpose is to ensure diff --git a/xsa469-4.19-05.patch b/xsa469-4.19-05.patch deleted file mode 100644 index 51a135d..0000000 --- a/xsa469-4.19-05.patch +++ /dev/null @@ -1,506 +0,0 @@ -From: Andrew Cooper -Subject: x86/stubs: Introduce place_ret() to abstract away raw 0xc3's - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. -This means it's not safe for logic using the stubs to write raw 0xc3's. - -Introduce place_ret() which, for now, writes a raw 0xc3 but will contain -additional logic when return thunks are in use. - -stub_selftest() doesn't strictly need to be converted as they only run on -boot, but doing so gets us a partial test of place_ret() too. - -No functional change. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/tools/tests/x86_emulator/x86-emulate.h b/tools/tests/x86_emulator/x86-emulate.h -index 8f8accfe3e70..946aaa9d660b 100644 ---- a/tools/tests/x86_emulator/x86-emulate.h -+++ b/tools/tests/x86_emulator/x86-emulate.h -@@ -68,6 +68,12 @@ - - #define is_canonical_address(x) (((int64_t)(x) >> 47) == ((int64_t)(x) >> 63)) - -+static inline void *place_ret(void *ptr) -+{ -+ *(uint8_t *)ptr = 0xc3; -+ return ptr + 1; -+} -+ - extern uint32_t mxcsr_mask; - extern struct cpu_policy cp; - -diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile -index c1e64278ce85..a7e5a82689de 100644 ---- a/xen/arch/x86/Makefile -+++ b/xen/arch/x86/Makefile -@@ -11,9 +11,7 @@ obj-$(CONFIG_PV) += pv/ - obj-y += x86_64/ - obj-y += x86_emulate/ - --alternative-y := alternative.init.o --alternative-$(CONFIG_LIVEPATCH) := --obj-bin-y += $(alternative-y) -+obj-y += alternative.o - obj-y += apic.o - obj-y += bhb-thunk.o - obj-y += bitops.o -@@ -41,7 +39,7 @@ obj-y += hypercall.o - obj-y += i387.o - obj-y += i8259.o - obj-y += io_apic.o --obj-$(CONFIG_LIVEPATCH) += alternative.o livepatch.o -+obj-$(CONFIG_LIVEPATCH) += livepatch.o - obj-y += msi.o - obj-y += msr.o - obj-$(CONFIG_INDIRECT_THUNK) += indirect-thunk.o -diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c -index 88c90044c20d..ec451d962c10 100644 ---- a/xen/arch/x86/alternative.c -+++ b/xen/arch/x86/alternative.c -@@ -137,6 +137,20 @@ void init_or_livepatch add_nops(void *insns, unsigned int len) - } - } - -+/* -+ * Place a return at @ptr. @ptr must be in the writable alias of a stub. -+ * -+ * Returns the next position to write into the stub. -+ */ -+void *place_ret(void *ptr) -+{ -+ uint8_t *p = ptr; -+ -+ *p++ = 0xc3; -+ -+ return p; -+} -+ - /* - * text_poke - Update instructions on a live kernel or non-executed code. - * @addr: address to modify -diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c -index 705cf9eb94ca..1572efa69a00 100644 ---- a/xen/arch/x86/extable.c -+++ b/xen/arch/x86/extable.c -@@ -151,20 +151,20 @@ search_exception_table(const struct cpu_user_regs *regs, unsigned long *stub_ra) - int __init cf_check stub_selftest(void) - { - static const struct { -- uint8_t opc[8]; -+ uint8_t opc[7]; - uint64_t rax; - union stub_exception_token res; - } tests[] __initconst = { - #define endbr64 0xf3, 0x0f, 0x1e, 0xfa -- { .opc = { endbr64, 0x0f, 0xb9, 0xc3, 0xc3 }, /* ud1 */ -+ { .opc = { endbr64, 0x0f, 0xb9, 0x90 }, /* ud1 */ - .res.fields.trapnr = X86_EXC_UD }, -- { .opc = { endbr64, 0x90, 0x02, 0x00, 0xc3 }, /* nop; add (%rax),%al */ -+ { .opc = { endbr64, 0x90, 0x02, 0x00 }, /* nop; add (%rax),%al */ - .rax = 0x0123456789abcdef, - .res.fields.trapnr = X86_EXC_GP }, -- { .opc = { endbr64, 0x02, 0x04, 0x04, 0xc3 }, /* add (%rsp,%rax),%al */ -+ { .opc = { endbr64, 0x02, 0x04, 0x04 }, /* add (%rsp,%rax),%al */ - .rax = 0xfedcba9876543210UL, - .res.fields.trapnr = X86_EXC_SS }, -- { .opc = { endbr64, 0xcc, 0xc3, 0xc3, 0xc3 }, /* int3 */ -+ { .opc = { endbr64, 0xcc, 0x90, 0x90 }, /* int3 */ - .res.fields.trapnr = X86_EXC_BP }, - #undef endbr64 - }; -@@ -183,6 +183,7 @@ int __init cf_check stub_selftest(void) - - memset(ptr, 0xcc, STUB_BUF_SIZE / 2); - memcpy(ptr, tests[i].opc, ARRAY_SIZE(tests[i].opc)); -+ place_ret(ptr + ARRAY_SIZE(tests[i].opc)); - unmap_domain_page(ptr); - - asm volatile ( "INDIRECT_CALL %[stb]\n" -diff --git a/xen/arch/x86/include/asm/alternative.h b/xen/arch/x86/include/asm/alternative.h -index 89b7bdcb82e5..841a63ebf1b6 100644 ---- a/xen/arch/x86/include/asm/alternative.h -+++ b/xen/arch/x86/include/asm/alternative.h -@@ -30,6 +30,8 @@ struct __packed alt_instr { - #define ALT_REPL_PTR(a) __ALT_PTR(a, repl_offset) - - extern void add_nops(void *insns, unsigned int len); -+void *place_ret(void *ptr); -+ - /* Similar to alternative_instructions except it can be run with IRQs enabled. */ - extern int apply_alternatives(struct alt_instr *start, struct alt_instr *end); - extern void alternative_instructions(void); -diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c -index 70150c272276..ff5d1c9f8634 100644 ---- a/xen/arch/x86/pv/emul-priv-op.c -+++ b/xen/arch/x86/pv/emul-priv-op.c -@@ -76,7 +76,6 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, - 0x41, 0x5c, /* pop %r12 */ - 0x5d, /* pop %rbp */ - 0x5b, /* pop %rbx */ -- 0xc3, /* ret */ - }; - - const struct stubs *this_stubs = &this_cpu(stubs); -@@ -126,11 +125,13 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, - - APPEND_CALL(save_guest_gprs); - APPEND_BUFF(epilogue); -+ p = place_ret(p); - - /* Build-time best effort attempt to catch problems. */ - BUILD_BUG_ON(STUB_BUF_SIZE / 2 < - (sizeof(prologue) + sizeof(epilogue) + 10 /* 2x call */ + -- MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES))); -+ MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES) + -+ 1 /* ret */)); - /* Runtime confirmation that we haven't clobbered an adjacent stub. */ - BUG_ON(STUB_BUF_SIZE / 2 < (p - ctxt->io_emul_stub)); - -diff --git a/xen/arch/x86/x86_emulate/fpu.c b/xen/arch/x86/x86_emulate/fpu.c -index 480d87965705..03612d00a2ce 100644 ---- a/xen/arch/x86/x86_emulate/fpu.c -+++ b/xen/arch/x86/x86_emulate/fpu.c -@@ -32,36 +32,42 @@ static inline bool fpu_check_write(void) - - #define emulate_fpu_insn_memdst(opc, ext, arg) \ - do { \ -+ void *_p = get_stub(stub); \ - /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ - *insn_bytes = 2; \ -- memcpy(get_stub(stub), \ -- ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ -+ memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2; \ -+ place_ret(_p); \ - invoke_stub("", "", "+m" (arg) : "a" (&(arg))); \ - put_stub(stub); \ - } while (0) - - #define emulate_fpu_insn_memsrc(opc, ext, arg) \ - do { \ -+ void *_p = get_stub(stub); \ - /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ -- memcpy(get_stub(stub), \ -- ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ -+ memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2; \ -+ place_ret(_p); \ - invoke_stub("", "", "=m" (dummy) : "m" (arg), "a" (&(arg))); \ - put_stub(stub); \ - } while (0) - - #define emulate_fpu_insn_stub(bytes...) \ - do { \ -+ void *_p = get_stub(stub); \ - unsigned int nr_ = sizeof((uint8_t[]){ bytes }); \ -- memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ -+ memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_; \ -+ place_ret(_p); \ - invoke_stub("", "", "=m" (dummy) : "i" (0)); \ - put_stub(stub); \ - } while (0) - - #define emulate_fpu_insn_stub_eflags(bytes...) \ - do { \ -+ void *_p = get_stub(stub); \ - unsigned int nr_ = sizeof((uint8_t[]){ bytes }); \ - unsigned long tmp_; \ -- memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ -+ memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_; \ -+ place_ret(_p); \ - invoke_stub(_PRE_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ - _POST_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ - [eflags] "+g" (regs->eflags), [tmp] "=&r" (tmp_) \ -diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c -index b1d192cbbf1e..f40709682484 100644 ---- a/xen/arch/x86/x86_emulate/x86_emulate.c -+++ b/xen/arch/x86/x86_emulate/x86_emulate.c -@@ -1396,7 +1396,7 @@ x86_emulate( - stb[3] = 0x91; - stb[4] = evex.opmsk << 3; - insn_bytes = 5; -- stb[5] = 0xc3; -+ place_ret(&stb[5]); - - invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); - -@@ -3627,7 +3627,7 @@ x86_emulate( - } - opc[1] = (modrm & 0x38) | 0xc0; - insn_bytes = EVEX_PFX_BYTES + 2; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_EVEX(opc, evex); - invoke_stub("", "", "=g" (dummy) : "a" (src.val)); -@@ -3694,7 +3694,7 @@ x86_emulate( - insn_bytes = PFX_BYTES + 2; - copy_REX_VEX(opc, rex_prefix, vex); - } -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - ea.reg = decode_gpr(&_regs, modrm_reg); - invoke_stub("", "", "=a" (*ea.reg) : "c" (mmvalp), "m" (*mmvalp)); -@@ -3768,7 +3768,7 @@ x86_emulate( - insn_bytes = PFX_BYTES + 2; - copy_REX_VEX(opc, rex_prefix, vex); - } -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - _regs.eflags &= ~EFLAGS_MASK; - invoke_stub("", -@@ -4004,7 +4004,7 @@ x86_emulate( - opc[1] = modrm & 0xc7; - insn_bytes = PFX_BYTES + 2; - simd_0f_to_gpr: -- opc[insn_bytes - PFX_BYTES] = 0xc3; -+ place_ret(&opc[insn_bytes - PFX_BYTES]); - - generate_exception_if(ea.type != OP_REG, X86_EXC_UD); - -@@ -4401,7 +4401,7 @@ x86_emulate( - vex.w = 0; - opc[1] = modrm & 0x38; - insn_bytes = PFX_BYTES + 2; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_REX_VEX(opc, rex_prefix, vex); - invoke_stub("", "", "+m" (src.val) : "a" (&src.val)); -@@ -4438,7 +4438,7 @@ x86_emulate( - evex.w = 0; - opc[1] = modrm & 0x38; - insn_bytes = EVEX_PFX_BYTES + 2; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_EVEX(opc, evex); - invoke_stub("", "", "+m" (src.val) : "a" (&src.val)); -@@ -4633,7 +4633,7 @@ x86_emulate( - #endif /* X86EMUL_NO_SIMD */ - - simd_0f_reg_only: -- opc[insn_bytes - PFX_BYTES] = 0xc3; -+ place_ret(&opc[insn_bytes - PFX_BYTES]); - - copy_REX_VEX(opc, rex_prefix, vex); - invoke_stub("", "", [dummy_out] "=g" (dummy) : [dummy_in] "i" (0) ); -@@ -4967,7 +4967,7 @@ x86_emulate( - if ( !mode_64bit() ) - vex.w = 0; - opc[1] = modrm & 0xf8; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_VEX(opc, vex); - ea.reg = decode_gpr(&_regs, modrm_rm); -@@ -5010,7 +5010,7 @@ x86_emulate( - if ( !mode_64bit() ) - vex.w = 0; - opc[1] = modrm & 0xc7; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_VEX(opc, vex); - invoke_stub("", "", "=a" (dst.val) : [dummy] "i" (0)); -@@ -5040,7 +5040,7 @@ x86_emulate( - opc = init_prefixes(stub); - opc[0] = b; - opc[1] = modrm; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_VEX(opc, vex); - _regs.eflags &= ~EFLAGS_MASK; -@@ -5608,7 +5608,7 @@ x86_emulate( - if ( !mode_64bit() ) - vex.w = 0; - opc[1] = modrm & 0xc7; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_REX_VEX(opc, rex_prefix, vex); - invoke_stub("", "", "=a" (ea.val) : [dummy] "i" (0)); -@@ -5726,7 +5726,7 @@ x86_emulate( - opc[1] &= 0x38; - } - insn_bytes = PFX_BYTES + 2; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - if ( vex.opcx == vex_none ) - { - /* Cover for extra prefix byte. */ -@@ -6006,7 +6006,7 @@ x86_emulate( - pvex->b = !mode_64bit() || (vex.reg >> 3); - opc[1] = 0xc0 | (~vex.reg & 7); - pvex->reg = 0xf; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "=a" (ea.val) : [dummy] "i" (0)); - put_stub(stub); -@@ -6290,7 +6290,7 @@ x86_emulate( - evex.w = 0; - opc[1] = modrm & 0xf8; - insn_bytes = EVEX_PFX_BYTES + 2; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - copy_EVEX(opc, evex); - invoke_stub("", "", "=g" (dummy) : "a" (src.val)); -@@ -6389,7 +6389,7 @@ x86_emulate( - pvex->b = 1; - opc[1] = (modrm_reg & 7) << 3; - pvex->reg = 0xf; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); - -@@ -6459,7 +6459,7 @@ x86_emulate( - pvex->b = 1; - opc[1] = (modrm_reg & 7) << 3; - pvex->reg = 0xf; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "+m" (*mmvalp) : "a" (mmvalp)); - -@@ -6515,7 +6515,7 @@ x86_emulate( - pevex->b = 1; - opc[1] = (modrm_reg & 7) << 3; - pevex->RX = 1; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); - -@@ -6580,7 +6580,7 @@ x86_emulate( - pevex->b = 1; - opc[1] = (modrm_reg & 7) << 3; - pevex->RX = 1; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "+m" (*mmvalp) : "a" (mmvalp)); - -@@ -6594,7 +6594,7 @@ x86_emulate( - opc[2] = 0x90; - /* Use (%rax) as source. */ - opc[3] = evex.opmsk << 3; -- opc[4] = 0xc3; -+ place_ret(&opc[4]); - - invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); - put_stub(stub); -@@ -6688,7 +6688,7 @@ x86_emulate( - pevex->b = 1; - opc[1] = (modrm_reg & 7) << 3; - pevex->RX = 1; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); - -@@ -6766,7 +6766,7 @@ x86_emulate( - opc[2] = 0x90; - /* Use (%rax) as source. */ - opc[3] = evex.opmsk << 3; -- opc[4] = 0xc3; -+ place_ret(&opc[4]); - - invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); - put_stub(stub); -@@ -6848,7 +6848,7 @@ x86_emulate( - pevex->r = !mode_64bit() || !(state->sib_index & 0x08); - pevex->R = !mode_64bit() || !(state->sib_index & 0x10); - pevex->RX = 1; -- opc[2] = 0xc3; -+ place_ret(&opc[2]); - - invoke_stub("", "", "=m" (index) : "a" (&index)); - put_stub(stub); -@@ -7058,7 +7058,7 @@ x86_emulate( - pvex->reg = 0xf; /* rAX */ - buf[3] = b; - buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */ -- buf[5] = 0xc3; -+ place_ret(&buf[5]); - - src.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); - emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val), "a" (*src.reg)); -@@ -7094,7 +7094,7 @@ x86_emulate( - pvex->reg = 0xf; /* rAX */ - buf[3] = b; - buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */ -- buf[5] = 0xc3; -+ place_ret(&buf[5]); - - dst.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); - emulate_stub("=&a" (dst.val), "c" (&src.val)); -@@ -7335,7 +7335,7 @@ x86_emulate( - evex.w = vex.w = 0; - opc[1] = modrm & 0x38; - opc[2] = imm1; -- opc[3] = 0xc3; -+ place_ret(&opc[3]); - if ( vex.opcx == vex_none ) - { - /* Cover for extra prefix byte. */ -@@ -7502,7 +7502,7 @@ x86_emulate( - insn_bytes = PFX_BYTES + 3; - copy_VEX(opc, vex); - } -- opc[3] = 0xc3; -+ place_ret(&opc[3]); - - /* Latch MXCSR - we may need to restore it below. */ - invoke_stub("stmxcsr %[mxcsr]", "", -@@ -7748,7 +7748,7 @@ x86_emulate( - } - opc[2] = imm1; - insn_bytes = PFX_BYTES + 3; -- opc[3] = 0xc3; -+ place_ret(&opc[3]); - if ( vex.opcx == vex_none ) - { - /* Cover for extra prefix byte. */ -@@ -8094,7 +8094,7 @@ x86_emulate( - pxop->reg = 0xf; /* rAX */ - buf[3] = b; - buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */ -- buf[5] = 0xc3; -+ place_ret(&buf[5]); - - dst.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); - emulate_stub([dst] "=&a" (dst.val), "c" (&src.val)); -@@ -8203,7 +8203,7 @@ x86_emulate( - buf[3] = b; - buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */ - *(uint32_t *)(buf + 5) = imm1; -- buf[9] = 0xc3; -+ place_ret(&buf[9]); - - emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val)); - -@@ -8293,12 +8293,12 @@ x86_emulate( - BUG(); - if ( evex_encoded() ) - { -- opc[insn_bytes - EVEX_PFX_BYTES] = 0xc3; -+ place_ret(&opc[insn_bytes - EVEX_PFX_BYTES]); - copy_EVEX(opc, evex); - } - else - { -- opc[insn_bytes - PFX_BYTES] = 0xc3; -+ place_ret(&opc[insn_bytes - PFX_BYTES]); - copy_REX_VEX(opc, rex_prefix, vex); - } - diff --git a/xsa469-4.19-06.patch b/xsa469-4.19-06.patch deleted file mode 100644 index 724790e..0000000 --- a/xsa469-4.19-06.patch +++ /dev/null @@ -1,375 +0,0 @@ -From: Jan Beulich -Subject: x86/thunk: Build Xen with Return Thunks - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. - -In order to mitigate this, build with return thunks and arrange for -__x86_return_thunk to be (mis)aligned in the same manner as -__x86_indirect_thunk_* so the RET instruction is placed in a safe location. - -place_ret() needs to conditionally emit JMP __x86_return_thunk instead of RET. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Jan Beulich -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig -index 7e03e4bc5546..4542ea8408c7 100644 ---- a/xen/arch/x86/Kconfig -+++ b/xen/arch/x86/Kconfig -@@ -37,9 +37,14 @@ config ARCH_DEFCONFIG - default "arch/x86/configs/x86_64_defconfig" - - config CC_HAS_INDIRECT_THUNK -+ # GCC >= 8 or Clang >= 6 - def_bool $(cc-option,-mindirect-branch-register) || \ - $(cc-option,-mretpoline-external-thunk) - -+config CC_HAS_RETURN_THUNK -+ # GCC >= 8 or Clang >= 15 -+ def_bool $(cc-option,-mfunction-return=thunk-extern) -+ - config HAS_AS_CET_SS - # binutils >= 2.29 or LLVM >= 6 - def_bool $(as-instr,wrssq %rax$(comma)0;setssbsy) -diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile -index a7e5a82689de..27806a81aca8 100644 ---- a/xen/arch/x86/Makefile -+++ b/xen/arch/x86/Makefile -@@ -43,6 +43,7 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o - obj-y += msi.o - obj-y += msr.o - obj-$(CONFIG_INDIRECT_THUNK) += indirect-thunk.o -+obj-$(CONFIG_RETURN_THUNK) += indirect-thunk.o - obj-$(CONFIG_PV) += ioport_emulate.o - obj-y += irq.o - obj-$(CONFIG_KEXEC) += machine_kexec.o -diff --git a/xen/arch/x86/acpi/wakeup_prot.S b/xen/arch/x86/acpi/wakeup_prot.S -index 66f799339913..97bd676aaee2 100644 ---- a/xen/arch/x86/acpi/wakeup_prot.S -+++ b/xen/arch/x86/acpi/wakeup_prot.S -@@ -133,7 +133,7 @@ ENTRY(s3_resume) - pop %r12 - pop %rbx - pop %rbp -- ret -+ RET - - .data - .align 16 -diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c -index ec451d962c10..1b71ae959abe 100644 ---- a/xen/arch/x86/alternative.c -+++ b/xen/arch/x86/alternative.c -@@ -137,16 +137,45 @@ void init_or_livepatch add_nops(void *insns, unsigned int len) - } - } - -+void nocall __x86_return_thunk(void); -+ - /* - * Place a return at @ptr. @ptr must be in the writable alias of a stub. - * -+ * When CONFIG_RETURN_THUNK is active, this may be a JMP __x86_return_thunk -+ * instead, depending on the safety of @ptr with respect to Indirect Target -+ * Selection. -+ * - * Returns the next position to write into the stub. - */ - void *place_ret(void *ptr) - { -+ unsigned long addr = (unsigned long)ptr; - uint8_t *p = ptr; - -- *p++ = 0xc3; -+ /* -+ * When Return Thunks are used, if a RET would be unsafe at this location -+ * with respect to Indirect Target Selection (i.e. if addr is in the first -+ * half of a cacheline), insert a JMP __x86_return_thunk instead. -+ * -+ * The displacement needs to be relative to the executable alias of the -+ * stub, not to @ptr which is the writeable alias. -+ */ -+ if ( IS_ENABLED(CONFIG_RETURN_THUNK) && !(addr & 0x20) ) -+ { -+ long stub_va = (this_cpu(stubs.addr) & PAGE_MASK) + (addr & ~PAGE_MASK); -+ long disp = (long)__x86_return_thunk - (stub_va + 5); -+ -+ BUG_ON((int32_t)disp != disp); -+ -+ *p++ = 0xe9; -+ *(int32_t *)p = disp; -+ p += 4; -+ } -+ else -+ { -+ *p++ = 0xc3; -+ } - - return p; - } -diff --git a/xen/arch/x86/arch.mk b/xen/arch/x86/arch.mk -index b88d097a844b..85d3e7cbfeeb 100644 ---- a/xen/arch/x86/arch.mk -+++ b/xen/arch/x86/arch.mk -@@ -46,6 +46,9 @@ CFLAGS-$(CONFIG_CC_IS_GCC) += -fno-jump-tables - CFLAGS-$(CONFIG_CC_IS_CLANG) += -mretpoline-external-thunk - endif - -+# Compile with return thunk support if selected. -+CFLAGS-$(CONFIG_RETURN_THUNK) += -mfunction-return=thunk-extern -+ - # Disable the addition of a .note.gnu.property section to object files when - # livepatch support is enabled. The contents of that section can change - # depending on the instructions used, and livepatch-build-tools doesn't know -diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S -index 52625f4e2c17..7f92201a3cbb 100644 ---- a/xen/arch/x86/bhb-thunk.S -+++ b/xen/arch/x86/bhb-thunk.S -@@ -23,7 +23,7 @@ FUNC(clear_bhb_tsx) - 0: .byte 0xc6, 0xf8, 0 /* xabort $0 */ - int3 - 1: -- ret -+ RET - END(clear_bhb_tsx) - - /* -diff --git a/xen/arch/x86/clear_page.S b/xen/arch/x86/clear_page.S -index d6c076f1d8bc..dc3c3c26bfb7 100644 ---- a/xen/arch/x86/clear_page.S -+++ b/xen/arch/x86/clear_page.S -@@ -1,6 +1,8 @@ - .file __FILE__ - - #include -+ -+#include - #include - - FUNC(clear_page_sse2) -@@ -16,5 +18,5 @@ FUNC(clear_page_sse2) - jnz 0b - - sfence -- ret -+ RET - END(clear_page_sse2) -diff --git a/xen/arch/x86/copy_page.S b/xen/arch/x86/copy_page.S -index c3c436545bac..e43e5370c815 100644 ---- a/xen/arch/x86/copy_page.S -+++ b/xen/arch/x86/copy_page.S -@@ -1,6 +1,8 @@ - .file __FILE__ - - #include -+ -+#include - #include - - #define src_reg %rsi -@@ -41,5 +43,5 @@ FUNC(copy_page_sse2) - movnti tmp4_reg, 3*WORD_SIZE(dst_reg) - - sfence -- ret -+ RET - END(copy_page_sse2) -diff --git a/xen/arch/x86/efi/check.c b/xen/arch/x86/efi/check.c -index 9e473faad3c9..23ba30abf330 100644 ---- a/xen/arch/x86/efi/check.c -+++ b/xen/arch/x86/efi/check.c -@@ -3,6 +3,9 @@ int __attribute__((__ms_abi__)) test(int i) - return i; - } - -+/* In case -mfunction-return is in use. */ -+void __x86_return_thunk(void) {}; -+ - /* - * Populate an array with "addresses" of relocatable and absolute values. - * This is to probe ld for (a) emitting base relocations at all and (b) not -diff --git a/xen/arch/x86/include/asm/asm-defns.h b/xen/arch/x86/include/asm/asm-defns.h -index 32d6b4491063..97ebe21298a2 100644 ---- a/xen/arch/x86/include/asm/asm-defns.h -+++ b/xen/arch/x86/include/asm/asm-defns.h -@@ -58,6 +58,12 @@ - .endif - .endm - -+#ifdef CONFIG_RETURN_THUNK -+# define RET jmp __x86_return_thunk -+#else -+# define RET ret -+#endif -+ - #ifdef CONFIG_XEN_IBT - # define ENDBR64 endbr64 - #else -diff --git a/xen/arch/x86/indirect-thunk.S b/xen/arch/x86/indirect-thunk.S -index c4b978d67b8e..26dad15f12c9 100644 ---- a/xen/arch/x86/indirect-thunk.S -+++ b/xen/arch/x86/indirect-thunk.S -@@ -15,6 +15,8 @@ - #undef SYM_ALIGN - #define SYM_ALIGN(align...) - -+#ifdef CONFIG_INDIRECT_THUNK -+ - .macro IND_THUNK_RETPOLINE reg:req - call 1f - int3 -@@ -62,3 +64,25 @@ END(__x86_indirect_thunk_\reg) - .irp reg, ax, cx, dx, bx, bp, si, di, 8, 9, 10, 11, 12, 13, 14, 15 - GEN_INDIRECT_THUNK reg=r\reg - .endr -+ -+#endif /* CONFIG_INDIRECT_THUNK */ -+ -+#ifdef CONFIG_RETURN_THUNK -+ .section .text.entry.__x86_return_thunk, "ax", @progbits -+ -+ /* -+ * The Indirect Target Selection speculative vulnerability means that -+ * indirect branches (including RETs) are unsafe when in the first -+ * half of a cacheline. Arrange for them to be in the second half. -+ * -+ * Align to 64, then skip 32. -+ */ -+ .balign 64 -+ .fill 32, 1, 0xcc -+ -+FUNC(__x86_return_thunk) -+ ret -+ int3 /* Halt straight-line speculation */ -+END(__x86_return_thunk) -+ -+#endif /* CONFIG_RETURN_THUNK */ -diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c -index ff5d1c9f8634..295d847ea24c 100644 ---- a/xen/arch/x86/pv/emul-priv-op.c -+++ b/xen/arch/x86/pv/emul-priv-op.c -@@ -131,7 +131,7 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, - BUILD_BUG_ON(STUB_BUF_SIZE / 2 < - (sizeof(prologue) + sizeof(epilogue) + 10 /* 2x call */ + - MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES) + -- 1 /* ret */)); -+ (IS_ENABLED(CONFIG_RETURN_THUNK) ? 5 : 1) /* ret */)); - /* Runtime confirmation that we haven't clobbered an adjacent stub. */ - BUG_ON(STUB_BUF_SIZE / 2 < (p - ctxt->io_emul_stub)); - -diff --git a/xen/arch/x86/pv/gpr_switch.S b/xen/arch/x86/pv/gpr_switch.S -index 5409ad3b1447..362b5d241623 100644 ---- a/xen/arch/x86/pv/gpr_switch.S -+++ b/xen/arch/x86/pv/gpr_switch.S -@@ -26,7 +26,7 @@ FUNC(load_guest_gprs) - movq UREGS_r15(%rdi), %r15 - movq UREGS_rcx(%rdi), %rcx - movq UREGS_rdi(%rdi), %rdi -- ret -+ RET - END(load_guest_gprs) - - /* Save guest GPRs. Parameter on the stack above the return address. */ -@@ -48,5 +48,5 @@ FUNC(save_guest_gprs) - movq %rbx, UREGS_rbx(%rdi) - movq %rdx, UREGS_rdx(%rdi) - movq %rcx, UREGS_rcx(%rdi) -- ret -+ RET - END(save_guest_gprs) -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 35351044f901..019a0a81f4a7 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -569,6 +569,9 @@ static void __init print_details(enum ind_thunk thunk) - #ifdef CONFIG_INDIRECT_THUNK - " INDIRECT_THUNK" - #endif -+#ifdef CONFIG_RETURN_THUNK -+ " RETURN_THUNK" -+#endif - #ifdef CONFIG_SHADOW_PAGING - " SHADOW_PAGING" - #endif -diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S -index a99646c0cd4e..18f46c78cfbe 100644 ---- a/xen/arch/x86/x86_64/compat/entry.S -+++ b/xen/arch/x86/x86_64/compat/entry.S -@@ -180,7 +180,7 @@ FUNC(cr4_pv32_restore) - or cr4_pv32_mask(%rip), %rax - mov %rax, %cr4 - mov %rax, (%rcx) -- ret -+ RET - 0: - #ifndef NDEBUG - /* Check that _all_ of the bits intended to be set actually are. */ -@@ -198,7 +198,7 @@ FUNC(cr4_pv32_restore) - 1: - #endif - xor %eax, %eax -- ret -+ RET - END(cr4_pv32_restore) - - FUNC(compat_syscall) -@@ -329,7 +329,7 @@ __UNLIKELY_END(compat_bounce_null_selector) - xor %eax, %eax - mov %ax, TRAPBOUNCE_cs(%rdx) - mov %al, TRAPBOUNCE_flags(%rdx) -- ret -+ RET - - .section .fixup,"ax" - .Lfx13: -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 9b0cdb76408b..eb62e7c329bd 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -604,7 +604,7 @@ __UNLIKELY_END(create_bounce_frame_bad_bounce_ip) - xor %eax, %eax - mov %rax, TRAPBOUNCE_eip(%rdx) - mov %al, TRAPBOUNCE_flags(%rdx) -- ret -+ RET - - .pushsection .fixup, "ax", @progbits - # Numeric tags below represent the intended overall %rsi adjustment. -diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S -index 9a1dfe1b340a..506993867502 100644 ---- a/xen/arch/x86/xen.lds.S -+++ b/xen/arch/x86/xen.lds.S -@@ -82,6 +82,7 @@ SECTIONS - . = ALIGN(PAGE_SIZE); - _stextentry = .; - *(.text.entry) -+ *(.text.entry.*) - . = ALIGN(PAGE_SIZE); - _etextentry = .; - -diff --git a/xen/common/Kconfig b/xen/common/Kconfig -index 565ceda741b9..da0fa7527643 100644 ---- a/xen/common/Kconfig -+++ b/xen/common/Kconfig -@@ -130,6 +130,17 @@ config INDIRECT_THUNK - When enabled, indirect branches are implemented using a new construct - called "retpoline" that prevents speculation. - -+config RETURN_THUNK -+ bool "Out-of-line Returns" -+ depends on CC_HAS_RETURN_THUNK -+ default INDIRECT_THUNK -+ help -+ Compile Xen with out-of-line returns. -+ -+ This allows Xen to mitigate a variety of speculative vulnerabilities -+ by choosing a hardware-dependent instruction sequence to implement -+ function returns safely. -+ - config SPECULATIVE_HARDEN_ARRAY - bool "Speculative Array Hardening" - default y diff --git a/xsa469-4.19-07.patch b/xsa469-4.19-07.patch deleted file mode 100644 index 2ba9d48..0000000 --- a/xsa469-4.19-07.patch +++ /dev/null @@ -1,154 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Synthesise ITS_NO to guests on unaffected hardware - -It is easier to express feature word 17 in terms of word 16 + [32, 64) as -that's how the layout is given in documentation. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h -index 9bc553681f4a..1729ba0c3097 100644 ---- a/xen/arch/x86/include/asm/cpufeature.h -+++ b/xen/arch/x86/include/asm/cpufeature.h -@@ -216,6 +216,7 @@ static inline bool boot_cpu_has(unsigned int feat) - #define cpu_has_gds_no boot_cpu_has(X86_FEATURE_GDS_NO) - #define cpu_has_rfds_no boot_cpu_has(X86_FEATURE_RFDS_NO) - #define cpu_has_rfds_clear boot_cpu_has(X86_FEATURE_RFDS_CLEAR) -+#define cpu_has_its_no boot_cpu_has(X86_FEATURE_ITS_NO) - - /* Synthesized. */ - #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 019a0a81f4a7..94cdbd521c4d 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -1781,6 +1781,90 @@ static void __init bhi_calculations(void) - } - } - -+/* -+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/indirect-target-selection.html -+ */ -+static void __init its_calculations(void) -+{ -+ /* -+ * Indirect Target Selection is a Branch Prediction bug whereby certain -+ * indirect branches (including RETs) get predicted using a direct branch -+ * target, rather than a suitable indirect target, bypassing hardware -+ * isolation protections. -+ * -+ * ITS affects Core (but not Atom) processors starting from the -+ * introduction of eIBRS, up to but not including Golden Cove cores -+ * (checked here with BHI_CTRL). -+ * -+ * The ITS_NO feature is not expected to be enumerated by hardware, and is -+ * only for VMMs to synthesise for guests. -+ * -+ * ITS comes in 3 flavours: -+ * -+ * 1) Across-IBPB. Indirect branches after the IBPB can be controlled -+ * by direct targets which existed prior to the IBPB. This is -+ * addressed in the IPU 2025.1 microcode drop, and has no other -+ * software interaction. -+ * -+ * 2) Guest/Host. Indirect branches in the VMM can be controlled by -+ * direct targets from the guest. This applies equally to PV guests -+ * (Ring3) and HVM guests (VMX), and applies to all Skylake-uarch -+ * cores with eIBRS. -+ * -+ * 3) Intra-mode. Indirect branches in the VMM can be controlled by -+ * other execution in the same mode. -+ */ -+ -+ /* -+ * If we can see ITS_NO, or we're virtualised, do nothing. We are or may -+ * migrate somewhere unsafe. -+ */ -+ if ( cpu_has_its_no || cpu_has_hypervisor ) -+ return; -+ -+ /* ITS is only known to affect Intel processors at this time. */ -+ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ) -+ return; -+ -+ /* -+ * ITS does not exist on: -+ * - non-Family 6 CPUs -+ * - those without eIBRS -+ * - those with BHI_CTRL -+ * but we still need to synthesise ITS_NO. -+ */ -+ if ( boot_cpu_data.x86 != 6 || !cpu_has_eibrs || -+ boot_cpu_has(X86_FEATURE_BHI_CTRL) ) -+ goto synthesise; -+ -+ switch ( boot_cpu_data.x86_model ) -+ { -+ /* These Skylake-uarch cores suffer cases #2 and #3. */ -+ case INTEL_FAM6_SKYLAKE_X: -+ case INTEL_FAM6_KABYLAKE_L: -+ case INTEL_FAM6_KABYLAKE: -+ case INTEL_FAM6_COMETLAKE: -+ case INTEL_FAM6_COMETLAKE_L: -+ return; -+ -+ /* These Sunny/Willow/Cypress Cove cores suffer case #3. */ -+ case INTEL_FAM6_ICELAKE_X: -+ case INTEL_FAM6_ICELAKE_D: -+ case INTEL_FAM6_ICELAKE_L: -+ case INTEL_FAM6_TIGERLAKE_L: -+ case INTEL_FAM6_TIGERLAKE: -+ case INTEL_FAM6_ROCKETLAKE: -+ return; -+ -+ default: -+ break; -+ } -+ -+ /* Platforms remaining are not believed to be vulnerable to ITS. */ -+ synthesise: -+ setup_force_cpu_cap(X86_FEATURE_ITS_NO); -+} -+ - void spec_ctrl_init_domain(struct domain *d) - { - bool pv = is_pv_domain(d); -@@ -2331,6 +2415,8 @@ void __init init_speculation_mitigations(void) - - bhi_calculations(); - -+ its_calculations(); -+ - print_details(thunk); - - /* -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index 9c98e4992861..4d9e468af653 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -365,7 +365,8 @@ XEN_CPUFEATURE(GDS_NO, 16*32+26) /*A No Gather Data Sampling */ - XEN_CPUFEATURE(RFDS_NO, 16*32+27) /*A No Register File Data Sampling */ - XEN_CPUFEATURE(RFDS_CLEAR, 16*32+28) /*!A| Register File(s) cleared by VERW */ - --/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 */ -+/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 (express in terms of word 16) */ -+XEN_CPUFEATURE(ITS_NO, 16*32+62) /*!A No Indirect Target Selection */ - - #endif /* XEN_CPUFEATURE */ - -diff --git a/xen/tools/gen-cpuid.py b/xen/tools/gen-cpuid.py -index 601eec608983..dc33ca3181b1 100755 ---- a/xen/tools/gen-cpuid.py -+++ b/xen/tools/gen-cpuid.py -@@ -51,7 +51,7 @@ def parse_definitions(state): - r"\s+/\*([\w!|]*) .*$") - - word_regex = re.compile( -- r"^/\* .* word (\d*) \*/$") -+ r"^/\* .* word (\d*) .*\*/$") - last_word = -1 - - this = sys.modules[__name__] From e2d4d104a0d113f5b2c84986710e77e43f94caf8 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 25 Jul 2025 20:44:23 +0000 Subject: [PATCH 74/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 8868407..8f2f0a5 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 1%{?dist} +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -806,6 +806,9 @@ fi %endif %changelog +* Fri Jul 25 2025 Fedora Release Engineering - 4.20.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + * Sun Jul 13 2025 Michael Young - 4.20.1-1 - update to xen 4.20.1 remove old qemu code for spac file From 39101b511c87391cf9049115b44c7878093ac083 Mon Sep 17 00:00:00 2001 From: Python Maint Date: Fri, 15 Aug 2025 15:23:19 +0200 Subject: [PATCH 75/99] Rebuilt for Python 3.14.0rc2 bytecode --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 8f2f0a5..1490c91 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 2%{?dist} +Release: 3%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -806,6 +806,9 @@ fi %endif %changelog +* Fri Aug 15 2025 Python Maint - 4.20.1-3 +- Rebuilt for Python 3.14.0rc2 bytecode + * Fri Jul 25 2025 Fedora Release Engineering - 4.20.1-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild From ca8c5d51355e3e71281e73938c57d8821ac9fde0 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 2 Sep 2025 20:20:57 +0100 Subject: [PATCH 76/99] tools/xl: don't crash on NULL command line --- ...6b65098f790e6573f555c5ef170d3f373c6e.patch | 40 +++++++++++++++++++ xen.spec | 7 +++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch diff --git a/xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch b/xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch new file mode 100644 index 0000000..c072120 --- /dev/null +++ b/xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch @@ -0,0 +1,40 @@ +From 7cda6b65098f790e6573f555c5ef170d3f373c6e Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Marek=20Marczykowski-G=C3=B3recki?= + +Date: Mon, 4 Aug 2025 15:22:13 +0200 +Subject: [PATCH] tools/xl: don't crash on NULL command line +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +When running xl in a domU, it doesn't have access to the Xen command +line. Before the non-truncating xc_xenver_cmdline(), it was always set +with strdup, possibly of an empty string. Now it's NULL. Treat it the +same as empty cmdline, as it was before. Autoballoon isn't relevant for +xl devd in a domU anyway. + +Fixes: 75f91607621c ("tools: Introduce a non-truncating xc_xenver_cmdline()") +Signed-off-by: Marek Marczykowski-Górecki +Acked-by: Anthony PERARD +master commit: a4988c4177be81f225af1516e1bbb9ec14f76388 +master date: 2025-07-31 14:44:02 +0200 +--- + tools/xl/xl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/xl/xl.c b/tools/xl/xl.c +index ec72ca60c3..b3abc91b60 100644 +--- a/tools/xl/xl.c ++++ b/tools/xl/xl.c +@@ -79,7 +79,7 @@ static int auto_autoballoon(void) + int ret; + + info = libxl_get_version_info(ctx); +- if (!info) ++ if (!info || !info->commandline) + return 1; /* default to on */ + + #define SIZE_PATTERN "-?[0-9]+[bBkKmMgGtT]?" +-- +2.39.5 + diff --git a/xen.spec b/xen.spec index 1490c91..7c23230 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 3%{?dist} +Release: 4%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -78,6 +78,7 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch +Patch50: xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch # build using Fedora seabios and ipxe packages for roms @@ -257,6 +258,7 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 49 -p1 +%patch 50 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -806,6 +808,9 @@ fi %endif %changelog +* Tue Sep 02 2025 - 4.20.1-4 +- tools/xl: don't crash on NULL command line + * Fri Aug 15 2025 Python Maint - 4.20.1-3 - Rebuilt for Python 3.14.0rc2 bytecode From 8bc3f5aa328322597668e9325147eb7bfcdaae79 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 10 Sep 2025 23:41:07 +0100 Subject: [PATCH 77/99] 2 security updates Mutiple vulnerabilities in the Viridian interface [XSA-472, CVE-2025-27466, CVE-2025-58142, CVE-2025-58143] Arm issues with page refcounting [XSA-473, CVE-2025-58144, CVE-2025-58145] --- xen.spec | 20 +++++++++-- xsa472-1.patch | 43 +++++++++++++++++++++++ xsa472-2.patch | 41 ++++++++++++++++++++++ xsa472-3.patch | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ xsa473-1.patch | 43 +++++++++++++++++++++++ xsa473-2.patch | 62 +++++++++++++++++++++++++++++++++ 6 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 xsa472-1.patch create mode 100644 xsa472-2.patch create mode 100644 xsa472-3.patch create mode 100644 xsa473-1.patch create mode 100644 xsa473-2.patch diff --git a/xen.spec b/xen.spec index 7c23230..fc230e5 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 4%{?dist} +Release: 5%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -79,6 +79,11 @@ Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch Patch50: xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch +Patch51: xsa472-1.patch +Patch52: xsa472-2.patch +Patch53: xsa472-3.patch +Patch54: xsa473-1.patch +Patch55: xsa473-2.patch # build using Fedora seabios and ipxe packages for roms @@ -259,6 +264,11 @@ manage Xen virtual machines. %patch 46 -p1 %patch 49 -p1 %patch 50 -p1 +%patch 51 -p1 +%patch 52 -p1 +%patch 53 -p1 +%patch 54 -p1 +%patch 55 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -808,7 +818,13 @@ fi %endif %changelog -* Tue Sep 02 2025 - 4.20.1-4 +* Wed Sep 10 2025 Michael Young - 4.20.1-5 +- Mutiple vulnerabilities in the Viridian interface [XSA-472, + CVE-2025-27466, CVE-2025-58142, CVE-2025-58143] +- Arm issues with page refcounting [XSA-473, CVE-2025-58144, + CVE-2025-58145] + +* Tue Sep 02 2025 Michael Young - 4.20.1-4 - tools/xl: don't crash on NULL command line * Fri Aug 15 2025 Python Maint - 4.20.1-3 diff --git a/xsa472-1.patch b/xsa472-1.patch new file mode 100644 index 0000000..e69f3e7 --- /dev/null +++ b/xsa472-1.patch @@ -0,0 +1,43 @@ +From 262114a440bf7c32fd6d215e243b3eaebdd6d7cd Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Thu, 10 Jul 2025 15:51:40 +0200 +Subject: [PATCH 1/3] x86/viridian: avoid NULL pointer dereference in + update_reference_tsc() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function is only called when the MSR has the enabled bit set, but even +then the page might not be mapped because the guest provided gfn is not +suitable. + +Prevent a NULL pointer dereference in update_reference_tsc() by checking +whether the page is mapped. + +This is CVE-2025-27466 / part of XSA-472. + +Fixes: 386b3365221d ('viridian: use viridian_map/unmap_guest_page() for reference tsc page') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/hvm/viridian/time.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c +index 137577384f1e..ca6d526f46b7 100644 +--- a/xen/arch/x86/hvm/viridian/time.c ++++ b/xen/arch/x86/hvm/viridian/time.c +@@ -26,6 +26,10 @@ static void update_reference_tsc(const struct domain *d, bool initialize) + HV_REFERENCE_TSC_PAGE *p = rt->ptr; + uint32_t seq; + ++ /* Reference TSC page might not be mapped even if the MSR is enabled. */ ++ if ( !p ) ++ return; ++ + if ( initialize ) + clear_page(p); + +-- +2.49.0 + diff --git a/xsa472-2.patch b/xsa472-2.patch new file mode 100644 index 0000000..5b23b6d --- /dev/null +++ b/xsa472-2.patch @@ -0,0 +1,41 @@ +From 71c9568e290b51dfd7ab091ac98b272fd0aa0b90 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Thu, 10 Jul 2025 15:58:51 +0200 +Subject: [PATCH 2/3] x86/viridian: avoid NULL pointer dereference in + viridian_synic_deliver_timer_msg() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function is called unconditionally, regardless of whether the SIM page +is mapped. Avoid a NULL pointer dereference in +viridian_synic_deliver_timer_msg() by checking whether the SIM page is +mapped. + +This is CVE-2025-58142 / part of XSA-472. + +Fixes: 26fba3c85571 ('viridian: add implementation of synthetic timers') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/hvm/viridian/synic.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/xen/arch/x86/hvm/viridian/synic.c b/xen/arch/x86/hvm/viridian/synic.c +index c3dc573b003d..e6cba7548f1b 100644 +--- a/xen/arch/x86/hvm/viridian/synic.c ++++ b/xen/arch/x86/hvm/viridian/synic.c +@@ -338,6 +338,10 @@ bool viridian_synic_deliver_timer_msg(struct vcpu *v, unsigned int sintx, + .DeliveryTime = delivery, + }; + ++ /* Don't assume SIM page to be mapped. */ ++ if ( !msg ) ++ return false; ++ + /* + * To avoid using an atomic test-and-set, and barrier before calling + * vlapic_set_irq(), this function must be called in context of the +-- +2.49.0 + diff --git a/xsa472-3.patch b/xsa472-3.patch new file mode 100644 index 0000000..5dfdf48 --- /dev/null +++ b/xsa472-3.patch @@ -0,0 +1,94 @@ +From aed4cfd64d178aee677a8790440addda03678cd6 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Thu, 3 Jul 2025 13:09:03 +0200 +Subject: [PATCH 3/3] x86/viridian: protect concurrent modification of the + reference TSC page +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The reference TSC page is shared between all vCPUs, and the data stored in +the domain struct. However the handlers to set and clear it are not safe +against concurrent accesses. It's possible for two (or more) vCPUs to call +HV_X64_MSR_REFERENCE_TSC at the same time and cause the in-use reference +TSC page to be freed, while still being on the p2m. This creates an +information leak, where the page can end up mapped in another domain while +still being part of the original domain p2m. + +It's also possible to underflow the reference counter, as multiple +concurrent writes to HV_X64_MSR_REFERENCE_TSC can create an imbalance on +the number of put_page_and_type() calls. + +Introduce a lock to protect the reference TSC domain field, thus +serializing concurrent vCPU accesses. + +This is CVE-2025-58143 / part of XSA-472. + +Fixes: 386b3365221d ('viridian: use viridian_map/unmap_guest_page() for reference tsc page') +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/hvm/viridian/time.c | 4 ++++ + xen/arch/x86/hvm/viridian/viridian.c | 2 ++ + xen/arch/x86/include/asm/hvm/viridian.h | 1 + + 3 files changed, 7 insertions(+) + +diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c +index ca6d526f46b7..9311858d63c0 100644 +--- a/xen/arch/x86/hvm/viridian/time.c ++++ b/xen/arch/x86/hvm/viridian/time.c +@@ -108,8 +108,10 @@ static void time_ref_count_thaw(const struct domain *d) + + trc->off = (int64_t)trc->val - trc_val(d, 0); + ++ spin_lock(&vd->lock); + if ( vd->reference_tsc.msr.enabled ) + update_reference_tsc(d, false); ++ spin_unlock(&vd->lock); + } + + static uint64_t time_ref_count(const struct domain *d) +@@ -331,6 +333,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) + if ( !(viridian_feature_mask(d) & HVMPV_reference_tsc) ) + return X86EMUL_EXCEPTION; + ++ spin_lock(&vd->lock); + viridian_unmap_guest_page(&vd->reference_tsc); + vd->reference_tsc.msr.raw = val; + viridian_dump_guest_page(v, "REFERENCE_TSC", &vd->reference_tsc); +@@ -339,6 +342,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) + viridian_map_guest_page(d, &vd->reference_tsc); + update_reference_tsc(d, true); + } ++ spin_unlock(&vd->lock); + break; + + case HV_X64_MSR_TIME_REF_COUNT: +diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c +index 7ea6c9016894..c0be24bd2210 100644 +--- a/xen/arch/x86/hvm/viridian/viridian.c ++++ b/xen/arch/x86/hvm/viridian/viridian.c +@@ -494,6 +494,8 @@ int viridian_domain_init(struct domain *d) + if ( !d->arch.hvm.viridian ) + return -ENOMEM; + ++ spin_lock_init(&d->arch.hvm.viridian->lock); ++ + rc = viridian_synic_domain_init(d); + if ( rc ) + goto fail; +diff --git a/xen/arch/x86/include/asm/hvm/viridian.h b/xen/arch/x86/include/asm/hvm/viridian.h +index 4c8ff6e80b6f..47c9d13841ac 100644 +--- a/xen/arch/x86/include/asm/hvm/viridian.h ++++ b/xen/arch/x86/include/asm/hvm/viridian.h +@@ -71,6 +71,7 @@ struct viridian_domain + DECLARE_BITMAP(hypercall_flags, _HCALL_nr); + struct viridian_time_ref_count time_ref_count; + struct viridian_page reference_tsc; ++ spinlock_t lock; + }; + + void cpuid_viridian_leaves(const struct vcpu *v, uint32_t leaf, +-- +2.49.0 + diff --git a/xsa473-1.patch b/xsa473-1.patch new file mode 100644 index 0000000..e8689b6 --- /dev/null +++ b/xsa473-1.patch @@ -0,0 +1,43 @@ +From: Jan Beulich +Subject: Arm: foreign page handling in p2m_get_page_from_gfn() + +I can't see what would make the 1st of the assertions safe: For example, +the P2M lock not being held, the foreign page may disappear before we +get to call page_get_owner_and_reference(), which hence may return NULL. + +Even the 2nd, which appears to be safe safe, is lacking proper release +build fallbacks. + +Drop the former in favor of an if(), and convert the latter to the +equivalent of what x86 uses: ASSERT_UNREACHABLE() plus putting of the +obtained page. + +This is CVE-2025-58144 / part of XSA-473. + +Fixes: 9486a8d07ba8 ("xen/arm: Handle remove foreign mapping") +Signed-off-by: Jan Beulich +Reviewed-by: Julien Grall + +--- a/xen/arch/arm/p2m.c ++++ b/xen/arch/arm/p2m.c +@@ -74,10 +74,16 @@ struct page_info *p2m_get_page_from_gfn( + */ + if ( p2m_is_foreign(p2mt) ) + { +- struct domain *fdom = page_get_owner_and_reference(page); +- ASSERT(fdom != NULL); +- ASSERT(fdom != d); +- return page; ++ const struct domain *fdom = page_get_owner_and_reference(page); ++ ++ if ( fdom ) ++ { ++ if ( fdom != d ) ++ return page; ++ ASSERT_UNREACHABLE(); ++ put_page(page); ++ } ++ return NULL; + } + + return get_page(page, d) ? page : NULL; diff --git a/xsa473-2.patch b/xsa473-2.patch new file mode 100644 index 0000000..7d66f79 --- /dev/null +++ b/xsa473-2.patch @@ -0,0 +1,62 @@ +From: Jan Beulich +Subject: Arm: adjust locking in p2m_get_page_from_gfn() + +In order to safely acquire a reference for a foreign page mapping, the +P2M lock needs to be held until we have the reference in hand (or +getting one failed). Otherwise the page can change P2M type and +ownership in between. + +This is CVE-2025-58145 / part of XSA-473. + +Fixes: 9486a8d07ba8 ("xen/arm: Handle remove foreign mapping") +Signed-off-by: Jan Beulich +Reviewed-by: Julien Grall + +--- a/xen/arch/arm/p2m.c ++++ b/xen/arch/arm/p2m.c +@@ -53,18 +53,22 @@ mfn_t p2m_lookup(struct domain *d, gfn_t + struct page_info *p2m_get_page_from_gfn(struct domain *d, gfn_t gfn, + p2m_type_t *t) + { ++ struct p2m_domain *p2m = p2m_get_hostp2m(d); + struct page_info *page; + p2m_type_t p2mt; +- mfn_t mfn = p2m_lookup(d, gfn, &p2mt); ++ mfn_t mfn; ++ ++ p2m_read_lock(p2m); ++ mfn = p2m_get_entry(p2m, gfn, &p2mt, NULL, NULL, NULL); + + if ( t ) + *t = p2mt; + +- if ( !p2m_is_any_ram(p2mt) ) +- return NULL; +- +- if ( !mfn_valid(mfn) ) ++ if ( !p2m_is_any_ram(p2mt) || !mfn_valid(mfn) ) ++ { ++ p2m_read_unlock(p2m); + return NULL; ++ } + + page = mfn_to_page(mfn); + +@@ -76,6 +80,8 @@ struct page_info *p2m_get_page_from_gfn( + { + const struct domain *fdom = page_get_owner_and_reference(page); + ++ p2m_read_unlock(p2m); ++ + if ( fdom ) + { + if ( fdom != d ) +@@ -86,6 +92,8 @@ struct page_info *p2m_get_page_from_gfn( + return NULL; + } + ++ p2m_read_unlock(p2m); ++ + return get_page(page, d) ? page : NULL; + } + From d001d8f7cf1dda9f1809cd4ec2a6fd55587c7429 Mon Sep 17 00:00:00 2001 From: Python Maint Date: Fri, 19 Sep 2025 15:03:51 +0200 Subject: [PATCH 78/99] Rebuilt for Python 3.14.0rc3 bytecode --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index fc230e5..a16cd27 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 5%{?dist} +Release: 6%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -818,6 +818,9 @@ fi %endif %changelog +* Fri Sep 19 2025 Python Maint - 4.20.1-6 +- Rebuilt for Python 3.14.0rc3 bytecode + * Wed Sep 10 2025 Michael Young - 4.20.1-5 - Mutiple vulnerabilities in the Viridian interface [XSA-472, CVE-2025-27466, CVE-2025-58142, CVE-2025-58143] From 932125ac66f860a3fb1af7aacc744aa2113de00b Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 15 Oct 2025 17:21:56 +0100 Subject: [PATCH 79/99] OCaml 5.4.0 rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index a16cd27..01bf24c 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 6%{?dist} +Release: 7%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -818,6 +818,9 @@ fi %endif %changelog +* Wed Oct 15 2025 Richard W.M. Jones - 4.20.1-7 +- OCaml 5.4.0 rebuild + * Fri Sep 19 2025 Python Maint - 4.20.1-6 - Rebuilt for Python 3.14.0rc3 bytecode From 310309c8d59d280057f9e12df729a6d288e024dd Mon Sep 17 00:00:00 2001 From: Michael Young Date: Sun, 26 Oct 2025 12:39:49 +0000 Subject: [PATCH 80/99] teecr32_el1 and teehbr32_el1 support dropped in binutils 2.45.50-5.fc44 Incorrect removal of permissions on PCI device unplug [XSA-476, CVE-2025-58149] x86: Incorrect input sanitisation in Viridian hypercalls [XSA-475, CVE-2025-58147, CVE-2025-58148] --- dropped.regs.patch | 28 +++++++++++++++++++++++ xen.spec | 21 ++++++++++++++++- xsa475-1.patch | 26 +++++++++++++++++++++ xsa475-2.patch | 52 ++++++++++++++++++++++++++++++++++++++++++ xsa476-4.20.patch | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 dropped.regs.patch create mode 100644 xsa475-1.patch create mode 100644 xsa475-2.patch create mode 100644 xsa476-4.20.patch diff --git a/dropped.regs.patch b/dropped.regs.patch new file mode 100644 index 0000000..995498e --- /dev/null +++ b/dropped.regs.patch @@ -0,0 +1,28 @@ +--- xen-4.21.0-rc2/xen/arch/arm/domain.c.orig 2025-10-22 12:01:02.000000000 +0100 ++++ xen-4.21.0-rc2/xen/arch/arm/domain.c 2025-10-26 00:02:03.017300510 +0100 +@@ -111,12 +111,6 @@ + p->arch.cntkctl = READ_SYSREG(CNTKCTL_EL1); + virt_timer_save(p); + +- if ( is_32bit_domain(p->domain) && cpu_has_thumbee ) +- { +- p->arch.teecr = READ_SYSREG(TEECR32_EL1); +- p->arch.teehbr = READ_SYSREG(TEEHBR32_EL1); +- } +- + #ifdef CONFIG_ARM_32 + p->arch.joscr = READ_CP32(JOSCR); + p->arch.jmcr = READ_CP32(JMCR); +@@ -244,12 +238,6 @@ + WRITE_SYSREG(n->arch.tpidrro_el0, TPIDRRO_EL0); + WRITE_SYSREG(n->arch.tpidr_el1, TPIDR_EL1); + +- if ( is_32bit_domain(n->domain) && cpu_has_thumbee ) +- { +- WRITE_SYSREG(n->arch.teecr, TEECR32_EL1); +- WRITE_SYSREG(n->arch.teehbr, TEEHBR32_EL1); +- } +- + #ifdef CONFIG_ARM_32 + WRITE_CP32(n->arch.joscr, JOSCR); + WRITE_CP32(n->arch.jmcr, JMCR); diff --git a/xen.spec b/xen.spec index 01bf24c..b817d86 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.20.1 -Release: 7%{?dist} +Release: 9%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -84,6 +84,10 @@ Patch52: xsa472-2.patch Patch53: xsa472-3.patch Patch54: xsa473-1.patch Patch55: xsa473-2.patch +Patch56: xsa475-1.patch +Patch57: xsa475-2.patch +Patch58: xsa476-4.20.patch +Patch59: dropped.regs.patch # build using Fedora seabios and ipxe packages for roms @@ -269,6 +273,10 @@ manage Xen virtual machines. %patch 53 -p1 %patch 54 -p1 %patch 55 -p1 +%patch 56 -p1 +%patch 57 -p1 +%patch 58 -p1 +%patch 59 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -818,6 +826,17 @@ fi %endif %changelog +* Sun Oct 26 2025 Michael Young - 4.20.1-9 +- teecr32_el1 and teehbr32_el1 support dropped in binutils 2.45.50-5.fc44 + +* Fri Oct 24 2025 Michael Young +- Incorrect removal of permissions on PCI device unplug [XSA-476, + CVE-2025-58149] + +* Tue Oct 21 2025 Michael Young +- x86: Incorrect input sanitisation in Viridian hypercalls [XSA-475, + CVE-2025-58147, CVE-2025-58148] + * Wed Oct 15 2025 Richard W.M. Jones - 4.20.1-7 - OCaml 5.4.0 rebuild diff --git a/xsa475-1.patch b/xsa475-1.patch new file mode 100644 index 0000000..6ebc3e0 --- /dev/null +++ b/xsa475-1.patch @@ -0,0 +1,26 @@ +From: Teddy Astie +Subject: x86/viridian: Enforce bounds check in vpmask_set() + +Callers can pass vp/mask values which exceed the size of vpmask->mask. Ensure +we only set bits which are within bounds. + +This is XSA-475 / CVE-2025-58147. + +Fixes: b4124682db6e ("viridian: add ExProcessorMasks variants of the flush hypercalls") +Signed-off-by: Teddy Astie +Reviewed-by: Andrew Cooper + +diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c +index c0be24bd2210..703f9ac8bcc1 100644 +--- a/xen/arch/x86/hvm/viridian/viridian.c ++++ b/xen/arch/x86/hvm/viridian/viridian.c +@@ -562,7 +562,8 @@ static void vpmask_set(struct hypercall_vpmask *vpmask, unsigned int vp, + + if ( mask & 1 ) + { +- ASSERT(vp < HVM_MAX_VCPUS); ++ if ( vp >= HVM_MAX_VCPUS ) ++ break; + __set_bit(vp, vpmask->mask); + } + diff --git a/xsa475-2.patch b/xsa475-2.patch new file mode 100644 index 0000000..213d7ce --- /dev/null +++ b/xsa475-2.patch @@ -0,0 +1,52 @@ +From: Teddy Astie +Subject: x86/viridian: Enforce bounds check in send_ipi() + +Callers can pass in a vpmask which exceeds d->max_vcpus. Prevent out-of-bound +reads of d->vcpu[]. + +This is XSA-475 / CVE-2025-58148. + +Fixes: 728acba1ba4a ("viridian: use hypercall_vpmask in hvcall_ipi()") +Signed-off-by: Teddy Astie +Reviewed-by: Andrew Cooper + +diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c +index 703f9ac8bcc1..f79cffcb3767 100644 +--- a/xen/arch/x86/hvm/viridian/viridian.c ++++ b/xen/arch/x86/hvm/viridian/viridian.c +@@ -577,26 +577,6 @@ static void vpmask_fill(struct hypercall_vpmask *vpmask) + bitmap_fill(vpmask->mask, HVM_MAX_VCPUS); + } + +-static unsigned int vpmask_first(const struct hypercall_vpmask *vpmask) +-{ +- return find_first_bit(vpmask->mask, HVM_MAX_VCPUS); +-} +- +-static unsigned int vpmask_next(const struct hypercall_vpmask *vpmask, +- unsigned int vp) +-{ +- /* +- * If vp + 1 > HVM_MAX_VCPUS then find_next_bit() will return +- * HVM_MAX_VCPUS, ensuring the for_each_vp ( ... ) loop terminates. +- */ +- return find_next_bit(vpmask->mask, HVM_MAX_VCPUS, vp + 1); +-} +- +-#define for_each_vp(vpmask, vp) \ +- for ( (vp) = vpmask_first(vpmask); \ +- (vp) < HVM_MAX_VCPUS; \ +- (vp) = vpmask_next(vpmask, vp) ) +- + static unsigned int vpmask_nr(const struct hypercall_vpmask *vpmask) + { + return bitmap_weight(vpmask->mask, HVM_MAX_VCPUS); +@@ -813,7 +793,7 @@ static void send_ipi(struct hypercall_vpmask *vpmask, uint8_t vector) + if ( nr > 1 ) + cpu_raise_softirq_batch_begin(); + +- for_each_vp ( vpmask, vp ) ++ bitmap_for_each ( vp, vpmask->mask, currd->max_vcpus ) + { + struct vlapic *vlapic = vcpu_vlapic(currd->vcpu[vp]); + diff --git a/xsa476-4.20.patch b/xsa476-4.20.patch new file mode 100644 index 0000000..2d3cc04 --- /dev/null +++ b/xsa476-4.20.patch @@ -0,0 +1,57 @@ +From: Jiqian Chen +Subject: tools/libs/light: fix BAR memory address truncation + +64-bit BAR memory address is truncated when removing a passthrough +pci device from guest since it uses "unsigned int". + +So, change to use 64-bit type to fix this problem. + +This is XSA-476 / CVE-2025-58149. + +Fixes: b0a1af61678b ("libxenlight: implement pci passthrough") +Signed-off-by: Jiqian Chen +Release-Acked-by: Oleksii Kurochko +Reviewed-by: Juergen Gross +Acked-by: Anthony PERARD + +diff --git a/tools/libs/light/libxl_pci.c b/tools/libs/light/libxl_pci.c +index 1647fd6f4756..7af602224aba 100644 +--- a/tools/libs/light/libxl_pci.c ++++ b/tools/libs/light/libxl_pci.c +@@ -2179,7 +2179,7 @@ static void pci_remove_detached(libxl__egc *egc, + { + STATE_AO_GC(prs->aodev->ao); + libxl_ctx *ctx = libxl__gc_owner(gc); +- unsigned int start = 0, end = 0, flags = 0, size = 0; ++ uint64_t start = 0, end = 0, flags = 0, size = 0; + int irq = 0, i, stubdomid = 0; + const char *sysfs_path; + FILE *f; +@@ -2209,7 +2209,8 @@ static void pci_remove_detached(libxl__egc *egc, + } + + for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) { +- if (fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags) != 3) ++ if (fscanf(f, "0x%"SCNx64" 0x%"SCNx64" 0x%"SCNx64"\n", ++ &start, &end, &flags) != 3) + continue; + size = end - start + 1; + if (start) { +@@ -2218,7 +2219,7 @@ static void pci_remove_detached(libxl__egc *egc, + size, 0); + if (rc < 0) + LOGED(ERROR, domid, +- "xc_domain_ioport_permission error 0x%x/0x%x", ++ "xc_domain_ioport_permission error %#"PRIx64"/%#"PRIx64, + start, + size); + } else { +@@ -2228,7 +2229,7 @@ static void pci_remove_detached(libxl__egc *egc, + 0); + if (rc < 0) + LOGED(ERROR, domid, +- "xc_domain_iomem_permission error 0x%x/0x%x", ++ "xc_domain_iomem_permission error %#"PRIx64"/%#"PRIx64, + start, + size); + } From b27c4b799dbddd05aad6d2c62a05d9fb6461316f Mon Sep 17 00:00:00 2001 From: Michael Young Date: Fri, 14 Nov 2025 18:46:13 +0000 Subject: [PATCH 81/99] update to xen 4.20.2 --- .gitignore | 2 +- sources | 2 +- ...6b65098f790e6573f555c5ef170d3f373c6e.patch | 40 -------- xen.spec | 26 ++--- xsa472-1.patch | 43 --------- xsa472-2.patch | 41 -------- xsa472-3.patch | 94 ------------------- xsa473-1.patch | 43 --------- xsa473-2.patch | 62 ------------ xsa475-1.patch | 26 ----- xsa475-2.patch | 52 ---------- xsa476-4.20.patch | 57 ----------- 12 files changed, 8 insertions(+), 480 deletions(-) delete mode 100644 xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch delete mode 100644 xsa472-1.patch delete mode 100644 xsa472-2.patch delete mode 100644 xsa472-3.patch delete mode 100644 xsa473-1.patch delete mode 100644 xsa473-2.patch delete mode 100644 xsa475-1.patch delete mode 100644 xsa475-2.patch delete mode 100644 xsa476-4.20.patch diff --git a/.gitignore b/.gitignore index 5d9b74e..2f6f692 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.20.1.tar.gz /mini-os-4.20.0.tar.xz +/xen-4.20.2.tar.gz diff --git a/sources b/sources index 0aa5da3..0032636 100644 --- a/sources +++ b/sources @@ -4,5 +4,5 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.20.1.tar.gz) = e4502ddaeb66de4c30d59e90af198586683c28b56bf0eb03ca5508f663fef5e6582c009861ff5b66b7f0df6e5f6bc12337eff0ec775d72e7cb189fd2079dbd9d SHA512 (mini-os-4.20.0.tar.xz) = 52d5d0985e1b4c26b761c94a3f7ca543bc388a96f69710524ebf34dd5b01d8f774fd5a3f6a50739c8b7c7edfdf07b594f5d44de8f389ea4138a62f9c5884c4e6 +SHA512 (xen-4.20.2.tar.gz) = 4a40668020cb142de0e182d6c7f846a58391828fb1db28c9325cd55d78ef0549c1187886cfe0c366c02803aa1b46c09334ab06748e30a2b509a9bbbb7886a8f1 diff --git a/xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch b/xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch deleted file mode 100644 index c072120..0000000 --- a/xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7cda6b65098f790e6573f555c5ef170d3f373c6e Mon Sep 17 00:00:00 2001 -From: =?utf8?q?Marek=20Marczykowski-G=C3=B3recki?= - -Date: Mon, 4 Aug 2025 15:22:13 +0200 -Subject: [PATCH] tools/xl: don't crash on NULL command line -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -When running xl in a domU, it doesn't have access to the Xen command -line. Before the non-truncating xc_xenver_cmdline(), it was always set -with strdup, possibly of an empty string. Now it's NULL. Treat it the -same as empty cmdline, as it was before. Autoballoon isn't relevant for -xl devd in a domU anyway. - -Fixes: 75f91607621c ("tools: Introduce a non-truncating xc_xenver_cmdline()") -Signed-off-by: Marek Marczykowski-Górecki -Acked-by: Anthony PERARD -master commit: a4988c4177be81f225af1516e1bbb9ec14f76388 -master date: 2025-07-31 14:44:02 +0200 ---- - tools/xl/xl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/xl/xl.c b/tools/xl/xl.c -index ec72ca60c3..b3abc91b60 100644 ---- a/tools/xl/xl.c -+++ b/tools/xl/xl.c -@@ -79,7 +79,7 @@ static int auto_autoballoon(void) - int ret; - - info = libxl_get_version_info(ctx); -- if (!info) -+ if (!info || !info->commandline) - return 1; /* default to on */ - - #define SIZE_PATTERN "-?[0-9]+[bBkKmMgGtT]?" --- -2.39.5 - diff --git a/xen.spec b/xen.spec index b817d86..b6fe4e8 100644 --- a/xen.spec +++ b/xen.spec @@ -50,8 +50,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.20.1 -Release: 9%{?dist} +Version: 4.20.2 +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -78,15 +78,6 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch -Patch50: xen.git-7cda6b65098f790e6573f555c5ef170d3f373c6e.patch -Patch51: xsa472-1.patch -Patch52: xsa472-2.patch -Patch53: xsa472-3.patch -Patch54: xsa473-1.patch -Patch55: xsa473-2.patch -Patch56: xsa475-1.patch -Patch57: xsa475-2.patch -Patch58: xsa476-4.20.patch Patch59: dropped.regs.patch @@ -267,15 +258,6 @@ manage Xen virtual machines. %patch 45 -p1 %patch 46 -p1 %patch 49 -p1 -%patch 50 -p1 -%patch 51 -p1 -%patch 52 -p1 -%patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 -%patch 57 -p1 -%patch 58 -p1 %patch 59 -p1 # stubdom sources @@ -826,6 +808,10 @@ fi %endif %changelog +* Thu Nov 13 2025 Michael Young - 4.20.2-2.fc44 +- update to xen 4.20.2 + remove patches now included or superceded upstream + * Sun Oct 26 2025 Michael Young - 4.20.1-9 - teecr32_el1 and teehbr32_el1 support dropped in binutils 2.45.50-5.fc44 diff --git a/xsa472-1.patch b/xsa472-1.patch deleted file mode 100644 index e69f3e7..0000000 --- a/xsa472-1.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 262114a440bf7c32fd6d215e243b3eaebdd6d7cd Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Thu, 10 Jul 2025 15:51:40 +0200 -Subject: [PATCH 1/3] x86/viridian: avoid NULL pointer dereference in - update_reference_tsc() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The function is only called when the MSR has the enabled bit set, but even -then the page might not be mapped because the guest provided gfn is not -suitable. - -Prevent a NULL pointer dereference in update_reference_tsc() by checking -whether the page is mapped. - -This is CVE-2025-27466 / part of XSA-472. - -Fixes: 386b3365221d ('viridian: use viridian_map/unmap_guest_page() for reference tsc page') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/hvm/viridian/time.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c -index 137577384f1e..ca6d526f46b7 100644 ---- a/xen/arch/x86/hvm/viridian/time.c -+++ b/xen/arch/x86/hvm/viridian/time.c -@@ -26,6 +26,10 @@ static void update_reference_tsc(const struct domain *d, bool initialize) - HV_REFERENCE_TSC_PAGE *p = rt->ptr; - uint32_t seq; - -+ /* Reference TSC page might not be mapped even if the MSR is enabled. */ -+ if ( !p ) -+ return; -+ - if ( initialize ) - clear_page(p); - --- -2.49.0 - diff --git a/xsa472-2.patch b/xsa472-2.patch deleted file mode 100644 index 5b23b6d..0000000 --- a/xsa472-2.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 71c9568e290b51dfd7ab091ac98b272fd0aa0b90 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Thu, 10 Jul 2025 15:58:51 +0200 -Subject: [PATCH 2/3] x86/viridian: avoid NULL pointer dereference in - viridian_synic_deliver_timer_msg() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The function is called unconditionally, regardless of whether the SIM page -is mapped. Avoid a NULL pointer dereference in -viridian_synic_deliver_timer_msg() by checking whether the SIM page is -mapped. - -This is CVE-2025-58142 / part of XSA-472. - -Fixes: 26fba3c85571 ('viridian: add implementation of synthetic timers') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/hvm/viridian/synic.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/xen/arch/x86/hvm/viridian/synic.c b/xen/arch/x86/hvm/viridian/synic.c -index c3dc573b003d..e6cba7548f1b 100644 ---- a/xen/arch/x86/hvm/viridian/synic.c -+++ b/xen/arch/x86/hvm/viridian/synic.c -@@ -338,6 +338,10 @@ bool viridian_synic_deliver_timer_msg(struct vcpu *v, unsigned int sintx, - .DeliveryTime = delivery, - }; - -+ /* Don't assume SIM page to be mapped. */ -+ if ( !msg ) -+ return false; -+ - /* - * To avoid using an atomic test-and-set, and barrier before calling - * vlapic_set_irq(), this function must be called in context of the --- -2.49.0 - diff --git a/xsa472-3.patch b/xsa472-3.patch deleted file mode 100644 index 5dfdf48..0000000 --- a/xsa472-3.patch +++ /dev/null @@ -1,94 +0,0 @@ -From aed4cfd64d178aee677a8790440addda03678cd6 Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Thu, 3 Jul 2025 13:09:03 +0200 -Subject: [PATCH 3/3] x86/viridian: protect concurrent modification of the - reference TSC page -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The reference TSC page is shared between all vCPUs, and the data stored in -the domain struct. However the handlers to set and clear it are not safe -against concurrent accesses. It's possible for two (or more) vCPUs to call -HV_X64_MSR_REFERENCE_TSC at the same time and cause the in-use reference -TSC page to be freed, while still being on the p2m. This creates an -information leak, where the page can end up mapped in another domain while -still being part of the original domain p2m. - -It's also possible to underflow the reference counter, as multiple -concurrent writes to HV_X64_MSR_REFERENCE_TSC can create an imbalance on -the number of put_page_and_type() calls. - -Introduce a lock to protect the reference TSC domain field, thus -serializing concurrent vCPU accesses. - -This is CVE-2025-58143 / part of XSA-472. - -Fixes: 386b3365221d ('viridian: use viridian_map/unmap_guest_page() for reference tsc page') -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/hvm/viridian/time.c | 4 ++++ - xen/arch/x86/hvm/viridian/viridian.c | 2 ++ - xen/arch/x86/include/asm/hvm/viridian.h | 1 + - 3 files changed, 7 insertions(+) - -diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c -index ca6d526f46b7..9311858d63c0 100644 ---- a/xen/arch/x86/hvm/viridian/time.c -+++ b/xen/arch/x86/hvm/viridian/time.c -@@ -108,8 +108,10 @@ static void time_ref_count_thaw(const struct domain *d) - - trc->off = (int64_t)trc->val - trc_val(d, 0); - -+ spin_lock(&vd->lock); - if ( vd->reference_tsc.msr.enabled ) - update_reference_tsc(d, false); -+ spin_unlock(&vd->lock); - } - - static uint64_t time_ref_count(const struct domain *d) -@@ -331,6 +333,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) - if ( !(viridian_feature_mask(d) & HVMPV_reference_tsc) ) - return X86EMUL_EXCEPTION; - -+ spin_lock(&vd->lock); - viridian_unmap_guest_page(&vd->reference_tsc); - vd->reference_tsc.msr.raw = val; - viridian_dump_guest_page(v, "REFERENCE_TSC", &vd->reference_tsc); -@@ -339,6 +342,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) - viridian_map_guest_page(d, &vd->reference_tsc); - update_reference_tsc(d, true); - } -+ spin_unlock(&vd->lock); - break; - - case HV_X64_MSR_TIME_REF_COUNT: -diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c -index 7ea6c9016894..c0be24bd2210 100644 ---- a/xen/arch/x86/hvm/viridian/viridian.c -+++ b/xen/arch/x86/hvm/viridian/viridian.c -@@ -494,6 +494,8 @@ int viridian_domain_init(struct domain *d) - if ( !d->arch.hvm.viridian ) - return -ENOMEM; - -+ spin_lock_init(&d->arch.hvm.viridian->lock); -+ - rc = viridian_synic_domain_init(d); - if ( rc ) - goto fail; -diff --git a/xen/arch/x86/include/asm/hvm/viridian.h b/xen/arch/x86/include/asm/hvm/viridian.h -index 4c8ff6e80b6f..47c9d13841ac 100644 ---- a/xen/arch/x86/include/asm/hvm/viridian.h -+++ b/xen/arch/x86/include/asm/hvm/viridian.h -@@ -71,6 +71,7 @@ struct viridian_domain - DECLARE_BITMAP(hypercall_flags, _HCALL_nr); - struct viridian_time_ref_count time_ref_count; - struct viridian_page reference_tsc; -+ spinlock_t lock; - }; - - void cpuid_viridian_leaves(const struct vcpu *v, uint32_t leaf, --- -2.49.0 - diff --git a/xsa473-1.patch b/xsa473-1.patch deleted file mode 100644 index e8689b6..0000000 --- a/xsa473-1.patch +++ /dev/null @@ -1,43 +0,0 @@ -From: Jan Beulich -Subject: Arm: foreign page handling in p2m_get_page_from_gfn() - -I can't see what would make the 1st of the assertions safe: For example, -the P2M lock not being held, the foreign page may disappear before we -get to call page_get_owner_and_reference(), which hence may return NULL. - -Even the 2nd, which appears to be safe safe, is lacking proper release -build fallbacks. - -Drop the former in favor of an if(), and convert the latter to the -equivalent of what x86 uses: ASSERT_UNREACHABLE() plus putting of the -obtained page. - -This is CVE-2025-58144 / part of XSA-473. - -Fixes: 9486a8d07ba8 ("xen/arm: Handle remove foreign mapping") -Signed-off-by: Jan Beulich -Reviewed-by: Julien Grall - ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -74,10 +74,16 @@ struct page_info *p2m_get_page_from_gfn( - */ - if ( p2m_is_foreign(p2mt) ) - { -- struct domain *fdom = page_get_owner_and_reference(page); -- ASSERT(fdom != NULL); -- ASSERT(fdom != d); -- return page; -+ const struct domain *fdom = page_get_owner_and_reference(page); -+ -+ if ( fdom ) -+ { -+ if ( fdom != d ) -+ return page; -+ ASSERT_UNREACHABLE(); -+ put_page(page); -+ } -+ return NULL; - } - - return get_page(page, d) ? page : NULL; diff --git a/xsa473-2.patch b/xsa473-2.patch deleted file mode 100644 index 7d66f79..0000000 --- a/xsa473-2.patch +++ /dev/null @@ -1,62 +0,0 @@ -From: Jan Beulich -Subject: Arm: adjust locking in p2m_get_page_from_gfn() - -In order to safely acquire a reference for a foreign page mapping, the -P2M lock needs to be held until we have the reference in hand (or -getting one failed). Otherwise the page can change P2M type and -ownership in between. - -This is CVE-2025-58145 / part of XSA-473. - -Fixes: 9486a8d07ba8 ("xen/arm: Handle remove foreign mapping") -Signed-off-by: Jan Beulich -Reviewed-by: Julien Grall - ---- a/xen/arch/arm/p2m.c -+++ b/xen/arch/arm/p2m.c -@@ -53,18 +53,22 @@ mfn_t p2m_lookup(struct domain *d, gfn_t - struct page_info *p2m_get_page_from_gfn(struct domain *d, gfn_t gfn, - p2m_type_t *t) - { -+ struct p2m_domain *p2m = p2m_get_hostp2m(d); - struct page_info *page; - p2m_type_t p2mt; -- mfn_t mfn = p2m_lookup(d, gfn, &p2mt); -+ mfn_t mfn; -+ -+ p2m_read_lock(p2m); -+ mfn = p2m_get_entry(p2m, gfn, &p2mt, NULL, NULL, NULL); - - if ( t ) - *t = p2mt; - -- if ( !p2m_is_any_ram(p2mt) ) -- return NULL; -- -- if ( !mfn_valid(mfn) ) -+ if ( !p2m_is_any_ram(p2mt) || !mfn_valid(mfn) ) -+ { -+ p2m_read_unlock(p2m); - return NULL; -+ } - - page = mfn_to_page(mfn); - -@@ -76,6 +80,8 @@ struct page_info *p2m_get_page_from_gfn( - { - const struct domain *fdom = page_get_owner_and_reference(page); - -+ p2m_read_unlock(p2m); -+ - if ( fdom ) - { - if ( fdom != d ) -@@ -86,6 +92,8 @@ struct page_info *p2m_get_page_from_gfn( - return NULL; - } - -+ p2m_read_unlock(p2m); -+ - return get_page(page, d) ? page : NULL; - } - diff --git a/xsa475-1.patch b/xsa475-1.patch deleted file mode 100644 index 6ebc3e0..0000000 --- a/xsa475-1.patch +++ /dev/null @@ -1,26 +0,0 @@ -From: Teddy Astie -Subject: x86/viridian: Enforce bounds check in vpmask_set() - -Callers can pass vp/mask values which exceed the size of vpmask->mask. Ensure -we only set bits which are within bounds. - -This is XSA-475 / CVE-2025-58147. - -Fixes: b4124682db6e ("viridian: add ExProcessorMasks variants of the flush hypercalls") -Signed-off-by: Teddy Astie -Reviewed-by: Andrew Cooper - -diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c -index c0be24bd2210..703f9ac8bcc1 100644 ---- a/xen/arch/x86/hvm/viridian/viridian.c -+++ b/xen/arch/x86/hvm/viridian/viridian.c -@@ -562,7 +562,8 @@ static void vpmask_set(struct hypercall_vpmask *vpmask, unsigned int vp, - - if ( mask & 1 ) - { -- ASSERT(vp < HVM_MAX_VCPUS); -+ if ( vp >= HVM_MAX_VCPUS ) -+ break; - __set_bit(vp, vpmask->mask); - } - diff --git a/xsa475-2.patch b/xsa475-2.patch deleted file mode 100644 index 213d7ce..0000000 --- a/xsa475-2.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: Teddy Astie -Subject: x86/viridian: Enforce bounds check in send_ipi() - -Callers can pass in a vpmask which exceeds d->max_vcpus. Prevent out-of-bound -reads of d->vcpu[]. - -This is XSA-475 / CVE-2025-58148. - -Fixes: 728acba1ba4a ("viridian: use hypercall_vpmask in hvcall_ipi()") -Signed-off-by: Teddy Astie -Reviewed-by: Andrew Cooper - -diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c -index 703f9ac8bcc1..f79cffcb3767 100644 ---- a/xen/arch/x86/hvm/viridian/viridian.c -+++ b/xen/arch/x86/hvm/viridian/viridian.c -@@ -577,26 +577,6 @@ static void vpmask_fill(struct hypercall_vpmask *vpmask) - bitmap_fill(vpmask->mask, HVM_MAX_VCPUS); - } - --static unsigned int vpmask_first(const struct hypercall_vpmask *vpmask) --{ -- return find_first_bit(vpmask->mask, HVM_MAX_VCPUS); --} -- --static unsigned int vpmask_next(const struct hypercall_vpmask *vpmask, -- unsigned int vp) --{ -- /* -- * If vp + 1 > HVM_MAX_VCPUS then find_next_bit() will return -- * HVM_MAX_VCPUS, ensuring the for_each_vp ( ... ) loop terminates. -- */ -- return find_next_bit(vpmask->mask, HVM_MAX_VCPUS, vp + 1); --} -- --#define for_each_vp(vpmask, vp) \ -- for ( (vp) = vpmask_first(vpmask); \ -- (vp) < HVM_MAX_VCPUS; \ -- (vp) = vpmask_next(vpmask, vp) ) -- - static unsigned int vpmask_nr(const struct hypercall_vpmask *vpmask) - { - return bitmap_weight(vpmask->mask, HVM_MAX_VCPUS); -@@ -813,7 +793,7 @@ static void send_ipi(struct hypercall_vpmask *vpmask, uint8_t vector) - if ( nr > 1 ) - cpu_raise_softirq_batch_begin(); - -- for_each_vp ( vpmask, vp ) -+ bitmap_for_each ( vp, vpmask->mask, currd->max_vcpus ) - { - struct vlapic *vlapic = vcpu_vlapic(currd->vcpu[vp]); - diff --git a/xsa476-4.20.patch b/xsa476-4.20.patch deleted file mode 100644 index 2d3cc04..0000000 --- a/xsa476-4.20.patch +++ /dev/null @@ -1,57 +0,0 @@ -From: Jiqian Chen -Subject: tools/libs/light: fix BAR memory address truncation - -64-bit BAR memory address is truncated when removing a passthrough -pci device from guest since it uses "unsigned int". - -So, change to use 64-bit type to fix this problem. - -This is XSA-476 / CVE-2025-58149. - -Fixes: b0a1af61678b ("libxenlight: implement pci passthrough") -Signed-off-by: Jiqian Chen -Release-Acked-by: Oleksii Kurochko -Reviewed-by: Juergen Gross -Acked-by: Anthony PERARD - -diff --git a/tools/libs/light/libxl_pci.c b/tools/libs/light/libxl_pci.c -index 1647fd6f4756..7af602224aba 100644 ---- a/tools/libs/light/libxl_pci.c -+++ b/tools/libs/light/libxl_pci.c -@@ -2179,7 +2179,7 @@ static void pci_remove_detached(libxl__egc *egc, - { - STATE_AO_GC(prs->aodev->ao); - libxl_ctx *ctx = libxl__gc_owner(gc); -- unsigned int start = 0, end = 0, flags = 0, size = 0; -+ uint64_t start = 0, end = 0, flags = 0, size = 0; - int irq = 0, i, stubdomid = 0; - const char *sysfs_path; - FILE *f; -@@ -2209,7 +2209,8 @@ static void pci_remove_detached(libxl__egc *egc, - } - - for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) { -- if (fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags) != 3) -+ if (fscanf(f, "0x%"SCNx64" 0x%"SCNx64" 0x%"SCNx64"\n", -+ &start, &end, &flags) != 3) - continue; - size = end - start + 1; - if (start) { -@@ -2218,7 +2219,7 @@ static void pci_remove_detached(libxl__egc *egc, - size, 0); - if (rc < 0) - LOGED(ERROR, domid, -- "xc_domain_ioport_permission error 0x%x/0x%x", -+ "xc_domain_ioport_permission error %#"PRIx64"/%#"PRIx64, - start, - size); - } else { -@@ -2228,7 +2229,7 @@ static void pci_remove_detached(libxl__egc *egc, - 0); - if (rc < 0) - LOGED(ERROR, domid, -- "xc_domain_iomem_permission error 0x%x/0x%x", -+ "xc_domain_iomem_permission error %#"PRIx64"/%#"PRIx64, - start, - size); - } From aa9dce01d1aa8c08c2de629d31028b9c4f166ad3 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 7 Jan 2026 20:11:57 +0000 Subject: [PATCH 82/99] update to xen 4.21.0 --- .gitignore | 4 +- sources | 4 +- xen.gcc16.fixes.patch | 31 +++++++++++++++ xen.json.nocpuid.patch | 27 +++++++++++++ xen.spec | 87 ++++++++++++++++++++++++++++-------------- 5 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 xen.gcc16.fixes.patch create mode 100644 xen.json.nocpuid.patch diff --git a/.gitignore b/.gitignore index 2f6f692..4d2b84e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/mini-os-4.20.0.tar.xz -/xen-4.20.2.tar.gz +/mini-os-4.21.0.tar.xz +/xen-4.21.0.tar.xz diff --git a/sources b/sources index 0032636..48e84e7 100644 --- a/sources +++ b/sources @@ -4,5 +4,5 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (mini-os-4.20.0.tar.xz) = 52d5d0985e1b4c26b761c94a3f7ca543bc388a96f69710524ebf34dd5b01d8f774fd5a3f6a50739c8b7c7edfdf07b594f5d44de8f389ea4138a62f9c5884c4e6 -SHA512 (xen-4.20.2.tar.gz) = 4a40668020cb142de0e182d6c7f846a58391828fb1db28c9325cd55d78ef0549c1187886cfe0c366c02803aa1b46c09334ab06748e30a2b509a9bbbb7886a8f1 +SHA512 (mini-os-4.21.0.tar.xz) = 7543774d15da84476d93d04154990923c82209cb3fa125574c0383652c5a310957200f54b63b34502161f9c3afce4907e0060d9036f3eaf3a7cb6b1b3119b546 +SHA512 (xen-4.21.0.tar.xz) = f8bd08e190b1f5013474718ecad687eddb97c57f7ae6b8262ffb7b91d70f0a5d30bce69c0301e7a97237d43ae2d75179e12be28f8c464d8cf5318a40acbf77ca diff --git a/xen.gcc16.fixes.patch b/xen.gcc16.fixes.patch new file mode 100644 index 0000000..5bad057 --- /dev/null +++ b/xen.gcc16.fixes.patch @@ -0,0 +1,31 @@ +--- xen-4.21.0/tools/libs/light/libxl_internal.c.orig 2025-11-18 18:02:13.000000000 +0000 ++++ xen-4.21.0/tools/libs/light/libxl_internal.c 2026-01-05 20:55:36.678719203 +0000 +@@ -204,7 +204,7 @@ + + char *libxl__dirname(libxl__gc *gc, const char *s) + { +- char *c = strrchr(s, '/'); ++ char *c = strrchr((char *) s, '/'); + + if (!c) + return NULL; +--- xen-4.21.0/tools/libs/light/libxl_cpuid.c.orig 2025-11-18 18:02:13.000000000 +0000 ++++ xen-4.21.0/tools/libs/light/libxl_cpuid.c 2026-01-05 23:46:40.203837602 +0000 +@@ -444,14 +444,14 @@ + return 4; + } + value = str[1] - 'a'; +- endptr = strchr(str, '='); ++ endptr = strchr((char *) str, '='); + if (value > 3 || endptr == NULL) { + return 4; + } + str = endptr + 1; +- endptr = strchr(str, ','); ++ endptr = strchr((char *) str, ','); + if (endptr == NULL) { +- endptr = strchr(str, 0); ++ endptr = strchr((char *) str, 0); + } + if (endptr - str != 32) { + return 5; diff --git a/xen.json.nocpuid.patch b/xen.json.nocpuid.patch new file mode 100644 index 0000000..f701f0d --- /dev/null +++ b/xen.json.nocpuid.patch @@ -0,0 +1,27 @@ +--- xen-4.21.0/tools/libs/light/libxl_nocpuid.c.orig 2025-11-18 18:02:13.000000000 +0000 ++++ xen-4.21.0/tools/libs/light/libxl_nocpuid.c 2025-11-20 09:03:56.517804514 +0000 +@@ -40,11 +40,24 @@ + return 0; + } + ++#ifdef HAVE_LIBJSONC ++#ifndef _hidden ++#define _hidden ++#endif ++_hidden int libxl_cpuid_policy_list_gen_jso(json_object **jso_r, ++ libxl_cpuid_policy_list *pcpuid) ++{ ++ return 0; ++} ++#endif ++ ++#if defined(HAVE_LIBYAJL) + yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand, + libxl_cpuid_policy_list *pcpuid) + { + return 0; + } ++#endif + + int libxl__cpuid_policy_list_parse_json(libxl__gc *gc, + const libxl__json_object *o, diff --git a/xen.spec b/xen.spec index b6fe4e8..925f4ff 100644 --- a/xen.spec +++ b/xen.spec @@ -46,16 +46,16 @@ %endif # Hypervisor ABI -%define hv_abi 4.20 +%define hv_abi 4.21 Summary: Xen is a virtual machine monitor Name: xen -Version: 4.20.2 -Release: 2%{?dist} +Version: 4.21.0 +Release: 1%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ -Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz +Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.xz Source2: %{name}.logrotate # used by stubdoms Source10: lwip-1.3.0.tar.gz @@ -66,19 +66,21 @@ Source14: grub-0.97.tar.gz Source15: polarssl-1.1.4-gpl.tgz # .config file for xen hypervisor Source21: xen.hypervisor.config -# mini-os xen-RELEASE-4.20.0 with .git and .gitignore stripped -Source22: mini-os-4.20.0.tar.xz +# mini-os xen-RELEASE-4.21.0 with .git and .gitignore stripped +Source22: mini-os-4.21.0.tar.xz -Patch5: xen.fedora.systemd.patch -Patch6: xen.ocaml.selinux.fix.patch -Patch34: xen.canonicalize.patch -Patch37: droplibvirtconflict.patch -Patch41: xen.gcc9.fixes.patch -Patch43: xen.gcc11.fixes.patch -Patch45: xen.gcc12.fixes.patch -Patch46: xen.efi.build.patch -Patch49: xen.python3.12.patch -Patch59: dropped.regs.patch +Patch1: xen.fedora.systemd.patch +Patch2: xen.ocaml.selinux.fix.patch +Patch3: xen.canonicalize.patch +Patch4: droplibvirtconflict.patch +Patch5: xen.gcc9.fixes.patch +Patch6: xen.gcc11.fixes.patch +Patch7: xen.gcc12.fixes.patch +Patch8: xen.efi.build.patch +Patch9: xen.python3.12.patch +Patch10: dropped.regs.patch +Patch11: xen.json.nocpuid.patch +Patch12: xen.gcc16.fixes.patch # build using Fedora seabios and ipxe packages for roms @@ -102,8 +104,10 @@ BuildRequires: acpica-tools BuildRequires: bzip2-devel xz-devel libzstd-devel # libfsimage BuildRequires: e2fsprogs-devel -# tools now require yajl and wget -BuildRequires: yajl-devel wget +# tools now require wget +BuildRequires: wget +# use json-c instead of yajl +BuildRequires: json-c-devel # remus support now needs libnl3 BuildRequires: libnl3-devel %if %with_xsm @@ -246,19 +250,25 @@ This package contains libraries for developing ocaml tools to manage Xen virtual machines. %endif +%package test +Summary: internal xen tests +%description test +This package contains files used in testing the xen builds %prep %setup -q +%patch 1 -p1 +%patch 2 -p1 +%patch 3 -p1 +%patch 4 -p1 %patch 5 -p1 %patch 6 -p1 -%patch 34 -p1 -%patch 37 -p1 -%patch 41 -p1 -%patch 43 -p1 -%patch 45 -p1 -%patch 46 -p1 -%patch 49 -p1 -%patch 59 -p1 +%patch 7 -p1 +%patch 8 -p1 +%patch 9 -p1 +%patch 10 -p1 +%patch 11 -p1 +%patch 12 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -305,7 +315,7 @@ CONFIG_EXTRA="$CONFIG_EXTRA --enable-systemd" ./configure --prefix=%{_prefix} --libdir=%{_libdir} --libexecdir=%{_libexecdir} --with-system-qemu=/usr/bin/qemu-system-i386 --with-linux-backend-modules="xen-evtchn xen-gntdev xen-gntalloc xen-blkback xen-netback xen-pciback xen-scsiback xen-acpi-processor" $CONFIG_EXTRA unset CFLAGS CXXFLAGS FFLAGS LDFLAGS export LDFLAGS="$LDFLAGS_SAVE" -export CFLAGS=`echo "$CFLAGS_SAVE -Wno-error=address" | sed -e s/-specs=\/usr\/lib\/rpm\/redhat/redhat-annobin-cc1//g` +export CFLAGS=`echo "$CFLAGS_SAVE -Wno-error=address" | sed -e 's/-specs=\/usr\/lib\/rpm\/redhat/redhat-annobin-cc1//g'` %if %build_hyp %make_build prefix=/usr xen @@ -598,7 +608,7 @@ fi %{_libdir}/libxenlight.so.4.* %{_libdir}/libxenstat.so.4.* %{_libdir}/libxenstore.so.4 -%{_libdir}/libxenstore.so.4.0 +%{_libdir}/libxenstore.so.4.1 %{_libdir}/libxentoolcore.so.1 %{_libdir}/libxentoolcore.so.1.0 %{_libdir}/libxentoollog.so.1 @@ -608,6 +618,8 @@ fi %{_libdir}/xenfsimage %{_libdir}/libxenhypfs.so.1 %{_libdir}/libxenhypfs.so.1.0 +%{_libdir}/libxenmanage.so.1 +%{_libdir}/libxenmanage.so.1.0 # All runtime stuff except for XenD/xm python stuff %files runtime @@ -625,7 +637,8 @@ fi %{_unitdir}/xen-watchdog.service %{_unitdir}/xen-qemu-dom0-disk-backend.service %{_unitdir}/xendriverdomain.service -/usr/lib/modules-load.d/xen.conf +%{_modulesloaddir}/xen.conf +%{_systemd_util_dir}/system-sleep/xen-watchdog-sleep.sh %config(noreplace) %{_sysconfdir}/sysconfig/xencommons %config(noreplace) %{_sysconfdir}/xen/xl.conf @@ -807,7 +820,23 @@ fi %{_libexecdir}/xen/ocaml/xsd_glue/xenctrl_plugin/domain_getinfo_v1.cmxs %endif +%files test +%{_libexecdir}/xen/tests/* + %changelog +* Wed Jan 07 2026 Michael Young - 4.21.0-1 +- update to xen 4.21.0 + rebase mini-os + use .xz xen tarball instead of .gz + fix quotes around sed command + update libxenstore version + package libxenmanage and xen-watchdog-sleep.sh files + add a new package for test files + renumber patches + use json-c instead of yajl +- fix bug in xen code when using json-c +- fix code issues detected by gcc16 + * Thu Nov 13 2025 Michael Young - 4.20.2-2.fc44 - update to xen 4.20.2 remove patches now included or superceded upstream From ca062906823d74116cd6a04a9f346a77af2bfbd8 Mon Sep 17 00:00:00 2001 From: Jerry James Date: Tue, 13 Jan 2026 20:56:05 -0700 Subject: [PATCH 83/99] Fix a changelog entry --- xen.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 925f4ff..1c4f773 100644 --- a/xen.spec +++ b/xen.spec @@ -888,7 +888,7 @@ fi x86: Transitive Scheduler Attacks [XSA-471, CVE-2024-36350, CVE-2024-36357] -* Fri Jul 11 2025 Jerry James - 4.19.2-6 +* Fri Jul 11 2025 Jerry James - 4.19.2-6 - Rebuild to fix OCaml dependencies * Mon Jun 02 2025 Python Maint - 4.19.2-5 From 461c19a5ca798a589685fb403b57643af1eb6f83 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 17 Jan 2026 20:34:16 +0000 Subject: [PATCH 84/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 1c4f773..467681d 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.0 -Release: 1%{?dist} +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -824,6 +824,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Sat Jan 17 2026 Fedora Release Engineering - 4.21.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild + * Wed Jan 07 2026 Michael Young - 4.21.0-1 - update to xen 4.21.0 rebase mini-os From d409186bf51f4ef8a617a67e6708aa0fc9b36060 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Wed, 28 Jan 2026 22:25:55 +0000 Subject: [PATCH 85/99] 2 security updates x86: buffer overrun with shadow paging + tracing [XSA-477, CVE-2025-58150] x86: incomplete IBPB for vCPU isolation [XSA-479, CVE-2026-23553] --- xen.spec | 10 ++++- xsa477.patch | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ xsa479.patch | 81 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 xsa477.patch create mode 100644 xsa479.patch diff --git a/xen.spec b/xen.spec index 467681d..8c9d9a9 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.0 -Release: 2%{?dist} +Release: 3%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -81,6 +81,8 @@ Patch9: xen.python3.12.patch Patch10: dropped.regs.patch Patch11: xen.json.nocpuid.patch Patch12: xen.gcc16.fixes.patch +Patch13: xsa477.patch +Patch14: xsa479.patch # build using Fedora seabios and ipxe packages for roms @@ -269,6 +271,8 @@ This package contains files used in testing the xen builds %patch 10 -p1 %patch 11 -p1 %patch 12 -p1 +%patch 13 -p1 +%patch 14 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -824,6 +828,10 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Wed Jan 28 2026 Michael Young - 4.21.0-3 + x86: buffer overrun with shadow paging + tracing [XSA-477, CVE-2025-58150] + x86: incomplete IBPB for vCPU isolation [XSA-479, CVE-2026-23553] + * Sat Jan 17 2026 Fedora Release Engineering - 4.21.0-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild diff --git a/xsa477.patch b/xsa477.patch new file mode 100644 index 0000000..48a9484 --- /dev/null +++ b/xsa477.patch @@ -0,0 +1,105 @@ +From: Jan Beulich +Subject: x86/shadow: don't overrun trace_emul_write_val + +Guests can do wider-than-PTE-size writes on page tables. The tracing +helper variable, however, only offers space for a single PTE (and it is +being switched to the more correct type right here). Therefore bound +incoming write sizes to the amount of space available. + +To not leave dead code (which is a Misra concern), drop the now unused +guest_pa_t as well. + +Also move and adjust GUEST_PTE_SIZE: Derive it rather than using hard- +coded numbers, and put it in the sole source file where it's actually +needed. This then also addresses a Misra rule 20.9 ("All identifiers +used in the controlling expression of #if or #elif preprocessing +directives shall be #define'd before evaluation") violation: +GUEST_PAGING_LEVELS is #define'd only in multi.c. + +This is XSA-477 / CVE-2025-58150. + +Fixes: 9a86ac1aa3d2 ("xentrace 5/7: Additional tracing for the shadow code") +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/xen/arch/x86/mm/shadow/multi.c ++++ b/xen/arch/x86/mm/shadow/multi.c +@@ -1970,15 +1970,15 @@ static void sh_prefetch(struct vcpu *v, + + #if GUEST_PAGING_LEVELS == 4 + typedef u64 guest_va_t; +-typedef u64 guest_pa_t; + #elif GUEST_PAGING_LEVELS == 3 + typedef u32 guest_va_t; +-typedef u64 guest_pa_t; + #else + typedef u32 guest_va_t; +-typedef u32 guest_pa_t; + #endif + ++/* Size (in bytes) of a guest PTE */ ++#define GUEST_PTE_SIZE sizeof(guest_l1e_t) ++ + /* Shadow trace event with GUEST_PAGING_LEVELS folded into the event field. */ + static void sh_trace(uint32_t event, unsigned int extra, const void *extra_data) + { +@@ -2048,11 +2048,14 @@ static void __maybe_unused sh_trace_gfn_ + static DEFINE_PER_CPU(guest_va_t,trace_emulate_initial_va); + static DEFINE_PER_CPU(int,trace_extra_emulation_count); + #endif +-static DEFINE_PER_CPU(guest_pa_t,trace_emulate_write_val); ++static DEFINE_PER_CPU(guest_l1e_t, trace_emulate_write_val); + + static void cf_check trace_emulate_write_val( + const void *ptr, unsigned long vaddr, const void *src, unsigned int bytes) + { ++ if ( bytes > sizeof(this_cpu(trace_emulate_write_val)) ) ++ bytes = sizeof(this_cpu(trace_emulate_write_val)); ++ + #if GUEST_PAGING_LEVELS == 3 + if ( vaddr == this_cpu(trace_emulate_initial_va) ) + memcpy(&this_cpu(trace_emulate_write_val), src, bytes); +@@ -2077,13 +2080,16 @@ static inline void sh_trace_emulate(gues + /* + * For GUEST_PAGING_LEVELS=3 (PAE paging), guest_l1e is 64 while + * guest_va is 32. Put it first to avoid padding. ++ * ++ * Note: .write_val is an arbitrary set of written bytes, possibly ++ * misaligned and possibly spanning the next gl1e. + */ + guest_l1e_t gl1e, write_val; + guest_va_t va; + uint32_t flags:29, emulation_count:3; + } d = { + .gl1e = gl1e, +- .write_val.l1 = this_cpu(trace_emulate_write_val), ++ .write_val = this_cpu(trace_emulate_write_val), + .va = va, + #if GUEST_PAGING_LEVELS == 3 + .emulation_count = this_cpu(trace_extra_emulation_count), +@@ -2672,7 +2677,7 @@ static int cf_check sh_page_fault( + paging_unlock(d); + put_gfn(d, gfn_x(gfn)); + +- this_cpu(trace_emulate_write_val) = 0; ++ this_cpu(trace_emulate_write_val) = (guest_l1e_t){}; + + #if SHADOW_OPTIMIZATIONS & SHOPT_FAST_EMULATION + early_emulation: +--- a/xen/arch/x86/mm/shadow/private.h ++++ b/xen/arch/x86/mm/shadow/private.h +@@ -120,14 +120,6 @@ enum { + TRCE_SFLAG_OOS_FIXUP_EVICT, + }; + +- +-/* Size (in bytes) of a guest PTE */ +-#if GUEST_PAGING_LEVELS >= 3 +-# define GUEST_PTE_SIZE 8 +-#else +-# define GUEST_PTE_SIZE 4 +-#endif +- + /****************************************************************************** + * Auditing routines + */ diff --git a/xsa479.patch b/xsa479.patch new file mode 100644 index 0000000..448d46b --- /dev/null +++ b/xsa479.patch @@ -0,0 +1,81 @@ +From: Roger Pau Monné +Subject: x86/spec-ctrl: Fix incomplete IBPB flushing during context switch + +The previous logic attempted to skip an IBPB in the case of vCPU returning to +a CPU on which it was the previous vCPU to run. While safe for Xen's +isolation between vCPUs, this prevents the guest kernel correctly isolation +between tasks. Consider: + + 1) vCPU runs on CPU A, running task 1. + 2) vCPU moves to CPU B, idle gets scheduled on A. Xen skips IBPB. + 3) On CPU B, guest kernel switches from task 1 to 2, issuing IBPB. + 4) vCPU moves back to CPU A. Xen skips IBPB again. + +Now, task 2 is running on CPU A with task 1's training still in the BTB. + +Do the flush unconditionally when switching to a vCPU different than the +idle one. Note there's no need to explicitly gate the IBPB to next domain +!= idle, as the context where the IBPB is issued is subject to that +condition already unless the pCPU is going offline, at which point we don't +really care to issue an extra IBPB. + +Also add a comment with the reasoning why the IBPB needs to be in +context_switch() rather than __context_switch(). + +This is XSA-479 / CVE-2026-23553. + +Fixes: a2ed643ed783 ("x86/ctxt: Issue a speculation barrier between vcpu contexts") +Reported-by: David Kaplan +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/domain.c | 36 +++++++++--------------------------- + 1 file changed, 9 insertions(+), 27 deletions(-) + +diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c +index c29a6b0decee..c1eded3eb604 100644 +--- a/xen/arch/x86/domain.c ++++ b/xen/arch/x86/domain.c +@@ -2174,33 +2174,15 @@ void context_switch(struct vcpu *prev, struct vcpu *next) + + ctxt_switch_levelling(next); + +- if ( opt_ibpb_ctxt_switch && !is_idle_domain(nextd) ) +- { +- static DEFINE_PER_CPU(unsigned int, last); +- unsigned int *last_id = &this_cpu(last); +- +- /* +- * Squash the domid and vcpu id together for comparison +- * efficiency. We could in principle stash and compare the struct +- * vcpu pointer, but this risks a false alias if a domain has died +- * and the same 4k page gets reused for a new vcpu. +- */ +- unsigned int next_id = (((unsigned int)nextd->domain_id << 16) | +- (uint16_t)next->vcpu_id); +- BUILD_BUG_ON(MAX_VIRT_CPUS > 0xffff); +- +- /* +- * When scheduling from a vcpu, to idle, and back to the same vcpu +- * (which might be common in a lightly loaded system, or when +- * using vcpu pinning), there is no need to issue IBPB, as we are +- * returning to the same security context. +- */ +- if ( *last_id != next_id ) +- { +- spec_ctrl_new_guest_context(); +- *last_id = next_id; +- } +- } ++ /* ++ * Issue an IBPB when scheduling a different vCPU if required. ++ * ++ * IBPB clears the RSB/RAS/RAP, but that's fine as we leave this ++ * function via reset_stack_and_call_ind() rather than via a RET ++ * instruction. ++ */ ++ if ( opt_ibpb_ctxt_switch ) ++ spec_ctrl_new_guest_context(); + + /* Update the top-of-stack block with the new speculation settings. */ + info->scf = From 2b36f2e8ca182677c4b05915912b8126bc0b6ad0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 20 Feb 2026 16:06:05 +0000 Subject: [PATCH 86/99] OCaml 5.4.1 rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 8c9d9a9..ee1a627 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.0 -Release: 3%{?dist} +Release: 4%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -828,6 +828,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Fri Feb 20 2026 Richard W.M. Jones - 4.21.0-4 +- OCaml 5.4.1 rebuild + * Wed Jan 28 2026 Michael Young - 4.21.0-3 x86: buffer overrun with shadow paging + tracing [XSA-477, CVE-2025-58150] x86: incomplete IBPB for vCPU isolation [XSA-479, CVE-2026-23553] From fbec0bc65a05818f3c41391f36c828e7acfeb999 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 17 Mar 2026 19:57:45 +0000 Subject: [PATCH 87/99] 2 security updates Use after free of paging structures in EPT [XSA-480, CVE-2026-23554] Xenstored DoS by unprivileged domain [XSA-481, CVE-2026-23555] --- xen.spec | 10 +++++++++- xsa480.patch | 46 ++++++++++++++++++++++++++++++++++++++++++ xsa481.patch | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 xsa480.patch create mode 100644 xsa481.patch diff --git a/xen.spec b/xen.spec index ee1a627..2a74fb6 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.0 -Release: 4%{?dist} +Release: 5%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -83,6 +83,8 @@ Patch11: xen.json.nocpuid.patch Patch12: xen.gcc16.fixes.patch Patch13: xsa477.patch Patch14: xsa479.patch +Patch15: xsa480.patch +Patch16: xsa481.patch # build using Fedora seabios and ipxe packages for roms @@ -273,6 +275,8 @@ This package contains files used in testing the xen builds %patch 12 -p1 %patch 13 -p1 %patch 14 -p1 +%patch 15 -p1 +%patch 16 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -828,6 +832,10 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Tue Mar 17 2026 Michael Young - 4.21.0-5 +- Use after free of paging structures in EPT [XSA-480, CVE-2026-23554] +- Xenstored DoS by unprivileged domain [XSA-481, CVE-2026-23555] + * Fri Feb 20 2026 Richard W.M. Jones - 4.21.0-4 - OCaml 5.4.1 rebuild diff --git a/xsa480.patch b/xsa480.patch new file mode 100644 index 0000000..d01ea35 --- /dev/null +++ b/xsa480.patch @@ -0,0 +1,46 @@ +From 45f6866e34b7e9ee8b6ac16d646a2e954c97e48e Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Tue, 17 Feb 2026 09:33:43 +0100 +Subject: [PATCH] x86/p2m: issue a sync flush before freeing paging pages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the EPT implementation, the defer flushing logic is used +unconditionally, and that would lead to paging memory being returned to the +paging pool before its references had been flushed. + +Issue any pending flushes before freeing the paging memory back to the +pool. + +Note AMD (NPT) and Shadow paging are not affected, as they don't implement +the deferred flushing logic. + +This is XSA-480 / CVE-2026-23554 + +Fixes: 4a59e6bb3a96 ("x86/EPT: squash meaningless TLB flush") +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +--- + xen/arch/x86/mm/p2m.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c +index e915da26a832..fddecdf978ec 100644 +--- a/xen/arch/x86/mm/p2m.c ++++ b/xen/arch/x86/mm/p2m.c +@@ -479,6 +479,11 @@ void p2m_free_ptp(struct p2m_domain *p2m, struct page_info *pg) + ASSERT(p2m->domain); + ASSERT(p2m->domain->arch.paging.free_page); + ++ /* ++ * Issue any pending flush here, in case it was deferred before. The page ++ * will be returned to the paging pool now. ++ */ ++ p2m_tlb_flush_sync(p2m); + page_list_del(pg, &p2m->pages); + p2m->domain->arch.paging.free_page(p2m->domain, pg); + +-- +2.51.0 + diff --git a/xsa481.patch b/xsa481.patch new file mode 100644 index 0000000..c21f910 --- /dev/null +++ b/xsa481.patch @@ -0,0 +1,56 @@ +From 0cff16f0a997f1b0871b621a1d6050652530e5d9 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Thu, 12 Feb 2026 08:29:38 +0100 +Subject: [PATCH] tools/xenstored: fix canonicalize() error testing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The setting of errno in canonicalize() is rather fragile and seems to +be even wrong in one corner case: when the invalid path "/local/domain/" +is passed, sscanf() will set errno to 0, resulting in canonicalize() to +return NULL with errno being 0. This can result in triggering the +assert(conn->in == NULL) in consider_message(). + +Don't assume the initial setting of errno to "EINVAL" will stay valid +in all cases and set it to EINVAL only when returning NULL due to an +invalid path. + +This is XSA-481/CVE-2026-23555 + +Reported-by: Marek Marczykowski-Górecki +Signed-off-by: Juergen Gross +Reviewed-by: Julien Grall +--- + tools/xenstored/core.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/tools/xenstored/core.c b/tools/xenstored/core.c +index 64c478a801..2e826f99eb 100644 +--- a/tools/xenstored/core.c ++++ b/tools/xenstored/core.c +@@ -1240,11 +1240,10 @@ const char *canonicalize(struct connection *conn, const void *ctx, + * - illegal character in node + * - starts with '@' but no special node allowed + */ +- errno = EINVAL; + if (!node || + !valid_chars(node) || + (node[0] == '@' && !allow_special)) +- return NULL; ++ goto inval; + + if (node[0] != '/' && node[0] != '@') { + name = talloc_asprintf(ctx, "%s/%s", get_implicit_path(conn), +@@ -1272,6 +1271,8 @@ const char *canonicalize(struct connection *conn, const void *ctx, + if (name != node) + talloc_free(name); + ++ inval: ++ errno = EINVAL; + return NULL; + } + +-- +2.53.0 + From 30cb19d1ba60c594520bb1bfa2ec62018a569fa0 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Thu, 26 Mar 2026 20:52:44 +0000 Subject: [PATCH 88/99] update to xen 4.21.1 --- .gitignore | 2 +- dropped.regs.patch | 28 ----------- sources | 2 +- xen.gcc16.fixes.patch | 31 ------------- xen.spec | 20 +++----- xsa477.patch | 105 ------------------------------------------ xsa479.patch | 81 -------------------------------- xsa480.patch | 46 ------------------ xsa481.patch | 56 ---------------------- 9 files changed, 8 insertions(+), 363 deletions(-) delete mode 100644 dropped.regs.patch delete mode 100644 xen.gcc16.fixes.patch delete mode 100644 xsa477.patch delete mode 100644 xsa479.patch delete mode 100644 xsa480.patch delete mode 100644 xsa481.patch diff --git a/.gitignore b/.gitignore index 4d2b84e..6b74118 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz /mini-os-4.21.0.tar.xz -/xen-4.21.0.tar.xz +/xen-4.21.1.tar.xz diff --git a/dropped.regs.patch b/dropped.regs.patch deleted file mode 100644 index 995498e..0000000 --- a/dropped.regs.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- xen-4.21.0-rc2/xen/arch/arm/domain.c.orig 2025-10-22 12:01:02.000000000 +0100 -+++ xen-4.21.0-rc2/xen/arch/arm/domain.c 2025-10-26 00:02:03.017300510 +0100 -@@ -111,12 +111,6 @@ - p->arch.cntkctl = READ_SYSREG(CNTKCTL_EL1); - virt_timer_save(p); - -- if ( is_32bit_domain(p->domain) && cpu_has_thumbee ) -- { -- p->arch.teecr = READ_SYSREG(TEECR32_EL1); -- p->arch.teehbr = READ_SYSREG(TEEHBR32_EL1); -- } -- - #ifdef CONFIG_ARM_32 - p->arch.joscr = READ_CP32(JOSCR); - p->arch.jmcr = READ_CP32(JMCR); -@@ -244,12 +238,6 @@ - WRITE_SYSREG(n->arch.tpidrro_el0, TPIDRRO_EL0); - WRITE_SYSREG(n->arch.tpidr_el1, TPIDR_EL1); - -- if ( is_32bit_domain(n->domain) && cpu_has_thumbee ) -- { -- WRITE_SYSREG(n->arch.teecr, TEECR32_EL1); -- WRITE_SYSREG(n->arch.teehbr, TEEHBR32_EL1); -- } -- - #ifdef CONFIG_ARM_32 - WRITE_CP32(n->arch.joscr, JOSCR); - WRITE_CP32(n->arch.jmcr, JMCR); diff --git a/sources b/sources index 48e84e7..4b30fea 100644 --- a/sources +++ b/sources @@ -5,4 +5,4 @@ SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea3 SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 SHA512 (mini-os-4.21.0.tar.xz) = 7543774d15da84476d93d04154990923c82209cb3fa125574c0383652c5a310957200f54b63b34502161f9c3afce4907e0060d9036f3eaf3a7cb6b1b3119b546 -SHA512 (xen-4.21.0.tar.xz) = f8bd08e190b1f5013474718ecad687eddb97c57f7ae6b8262ffb7b91d70f0a5d30bce69c0301e7a97237d43ae2d75179e12be28f8c464d8cf5318a40acbf77ca +SHA512 (xen-4.21.1.tar.xz) = 8dfe65255e202b3dacf9d0d7265636bc1f97627c11b08babc13a5b8e74c7c65e7e2c6a1513e28b3c713fe512edb6702a73b2bf667e2a8f2ce825b196a2cd5aab diff --git a/xen.gcc16.fixes.patch b/xen.gcc16.fixes.patch deleted file mode 100644 index 5bad057..0000000 --- a/xen.gcc16.fixes.patch +++ /dev/null @@ -1,31 +0,0 @@ ---- xen-4.21.0/tools/libs/light/libxl_internal.c.orig 2025-11-18 18:02:13.000000000 +0000 -+++ xen-4.21.0/tools/libs/light/libxl_internal.c 2026-01-05 20:55:36.678719203 +0000 -@@ -204,7 +204,7 @@ - - char *libxl__dirname(libxl__gc *gc, const char *s) - { -- char *c = strrchr(s, '/'); -+ char *c = strrchr((char *) s, '/'); - - if (!c) - return NULL; ---- xen-4.21.0/tools/libs/light/libxl_cpuid.c.orig 2025-11-18 18:02:13.000000000 +0000 -+++ xen-4.21.0/tools/libs/light/libxl_cpuid.c 2026-01-05 23:46:40.203837602 +0000 -@@ -444,14 +444,14 @@ - return 4; - } - value = str[1] - 'a'; -- endptr = strchr(str, '='); -+ endptr = strchr((char *) str, '='); - if (value > 3 || endptr == NULL) { - return 4; - } - str = endptr + 1; -- endptr = strchr(str, ','); -+ endptr = strchr((char *) str, ','); - if (endptr == NULL) { -- endptr = strchr(str, 0); -+ endptr = strchr((char *) str, 0); - } - if (endptr - str != 32) { - return 5; diff --git a/xen.spec b/xen.spec index 2a74fb6..7c73619 100644 --- a/xen.spec +++ b/xen.spec @@ -50,8 +50,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.21.0 -Release: 5%{?dist} +Version: 4.21.1 +Release: 1%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -78,13 +78,7 @@ Patch6: xen.gcc11.fixes.patch Patch7: xen.gcc12.fixes.patch Patch8: xen.efi.build.patch Patch9: xen.python3.12.patch -Patch10: dropped.regs.patch Patch11: xen.json.nocpuid.patch -Patch12: xen.gcc16.fixes.patch -Patch13: xsa477.patch -Patch14: xsa479.patch -Patch15: xsa480.patch -Patch16: xsa481.patch # build using Fedora seabios and ipxe packages for roms @@ -270,13 +264,7 @@ This package contains files used in testing the xen builds %patch 7 -p1 %patch 8 -p1 %patch 9 -p1 -%patch 10 -p1 %patch 11 -p1 -%patch 12 -p1 -%patch 13 -p1 -%patch 14 -p1 -%patch 15 -p1 -%patch 16 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -832,6 +820,10 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Thu Mar 26 2026 Michael Young - 4.21.1-1 +- update to xen 4.21.0 + remove patches now included or superceded upstream + * Tue Mar 17 2026 Michael Young - 4.21.0-5 - Use after free of paging structures in EPT [XSA-480, CVE-2026-23554] - Xenstored DoS by unprivileged domain [XSA-481, CVE-2026-23555] diff --git a/xsa477.patch b/xsa477.patch deleted file mode 100644 index 48a9484..0000000 --- a/xsa477.patch +++ /dev/null @@ -1,105 +0,0 @@ -From: Jan Beulich -Subject: x86/shadow: don't overrun trace_emul_write_val - -Guests can do wider-than-PTE-size writes on page tables. The tracing -helper variable, however, only offers space for a single PTE (and it is -being switched to the more correct type right here). Therefore bound -incoming write sizes to the amount of space available. - -To not leave dead code (which is a Misra concern), drop the now unused -guest_pa_t as well. - -Also move and adjust GUEST_PTE_SIZE: Derive it rather than using hard- -coded numbers, and put it in the sole source file where it's actually -needed. This then also addresses a Misra rule 20.9 ("All identifiers -used in the controlling expression of #if or #elif preprocessing -directives shall be #define'd before evaluation") violation: -GUEST_PAGING_LEVELS is #define'd only in multi.c. - -This is XSA-477 / CVE-2025-58150. - -Fixes: 9a86ac1aa3d2 ("xentrace 5/7: Additional tracing for the shadow code") -Signed-off-by: Jan Beulich -Reviewed-by: Andrew Cooper - ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -1970,15 +1970,15 @@ static void sh_prefetch(struct vcpu *v, - - #if GUEST_PAGING_LEVELS == 4 - typedef u64 guest_va_t; --typedef u64 guest_pa_t; - #elif GUEST_PAGING_LEVELS == 3 - typedef u32 guest_va_t; --typedef u64 guest_pa_t; - #else - typedef u32 guest_va_t; --typedef u32 guest_pa_t; - #endif - -+/* Size (in bytes) of a guest PTE */ -+#define GUEST_PTE_SIZE sizeof(guest_l1e_t) -+ - /* Shadow trace event with GUEST_PAGING_LEVELS folded into the event field. */ - static void sh_trace(uint32_t event, unsigned int extra, const void *extra_data) - { -@@ -2048,11 +2048,14 @@ static void __maybe_unused sh_trace_gfn_ - static DEFINE_PER_CPU(guest_va_t,trace_emulate_initial_va); - static DEFINE_PER_CPU(int,trace_extra_emulation_count); - #endif --static DEFINE_PER_CPU(guest_pa_t,trace_emulate_write_val); -+static DEFINE_PER_CPU(guest_l1e_t, trace_emulate_write_val); - - static void cf_check trace_emulate_write_val( - const void *ptr, unsigned long vaddr, const void *src, unsigned int bytes) - { -+ if ( bytes > sizeof(this_cpu(trace_emulate_write_val)) ) -+ bytes = sizeof(this_cpu(trace_emulate_write_val)); -+ - #if GUEST_PAGING_LEVELS == 3 - if ( vaddr == this_cpu(trace_emulate_initial_va) ) - memcpy(&this_cpu(trace_emulate_write_val), src, bytes); -@@ -2077,13 +2080,16 @@ static inline void sh_trace_emulate(gues - /* - * For GUEST_PAGING_LEVELS=3 (PAE paging), guest_l1e is 64 while - * guest_va is 32. Put it first to avoid padding. -+ * -+ * Note: .write_val is an arbitrary set of written bytes, possibly -+ * misaligned and possibly spanning the next gl1e. - */ - guest_l1e_t gl1e, write_val; - guest_va_t va; - uint32_t flags:29, emulation_count:3; - } d = { - .gl1e = gl1e, -- .write_val.l1 = this_cpu(trace_emulate_write_val), -+ .write_val = this_cpu(trace_emulate_write_val), - .va = va, - #if GUEST_PAGING_LEVELS == 3 - .emulation_count = this_cpu(trace_extra_emulation_count), -@@ -2672,7 +2677,7 @@ static int cf_check sh_page_fault( - paging_unlock(d); - put_gfn(d, gfn_x(gfn)); - -- this_cpu(trace_emulate_write_val) = 0; -+ this_cpu(trace_emulate_write_val) = (guest_l1e_t){}; - - #if SHADOW_OPTIMIZATIONS & SHOPT_FAST_EMULATION - early_emulation: ---- a/xen/arch/x86/mm/shadow/private.h -+++ b/xen/arch/x86/mm/shadow/private.h -@@ -120,14 +120,6 @@ enum { - TRCE_SFLAG_OOS_FIXUP_EVICT, - }; - -- --/* Size (in bytes) of a guest PTE */ --#if GUEST_PAGING_LEVELS >= 3 --# define GUEST_PTE_SIZE 8 --#else --# define GUEST_PTE_SIZE 4 --#endif -- - /****************************************************************************** - * Auditing routines - */ diff --git a/xsa479.patch b/xsa479.patch deleted file mode 100644 index 448d46b..0000000 --- a/xsa479.patch +++ /dev/null @@ -1,81 +0,0 @@ -From: Roger Pau Monné -Subject: x86/spec-ctrl: Fix incomplete IBPB flushing during context switch - -The previous logic attempted to skip an IBPB in the case of vCPU returning to -a CPU on which it was the previous vCPU to run. While safe for Xen's -isolation between vCPUs, this prevents the guest kernel correctly isolation -between tasks. Consider: - - 1) vCPU runs on CPU A, running task 1. - 2) vCPU moves to CPU B, idle gets scheduled on A. Xen skips IBPB. - 3) On CPU B, guest kernel switches from task 1 to 2, issuing IBPB. - 4) vCPU moves back to CPU A. Xen skips IBPB again. - -Now, task 2 is running on CPU A with task 1's training still in the BTB. - -Do the flush unconditionally when switching to a vCPU different than the -idle one. Note there's no need to explicitly gate the IBPB to next domain -!= idle, as the context where the IBPB is issued is subject to that -condition already unless the pCPU is going offline, at which point we don't -really care to issue an extra IBPB. - -Also add a comment with the reasoning why the IBPB needs to be in -context_switch() rather than __context_switch(). - -This is XSA-479 / CVE-2026-23553. - -Fixes: a2ed643ed783 ("x86/ctxt: Issue a speculation barrier between vcpu contexts") -Reported-by: David Kaplan -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/domain.c | 36 +++++++++--------------------------- - 1 file changed, 9 insertions(+), 27 deletions(-) - -diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c -index c29a6b0decee..c1eded3eb604 100644 ---- a/xen/arch/x86/domain.c -+++ b/xen/arch/x86/domain.c -@@ -2174,33 +2174,15 @@ void context_switch(struct vcpu *prev, struct vcpu *next) - - ctxt_switch_levelling(next); - -- if ( opt_ibpb_ctxt_switch && !is_idle_domain(nextd) ) -- { -- static DEFINE_PER_CPU(unsigned int, last); -- unsigned int *last_id = &this_cpu(last); -- -- /* -- * Squash the domid and vcpu id together for comparison -- * efficiency. We could in principle stash and compare the struct -- * vcpu pointer, but this risks a false alias if a domain has died -- * and the same 4k page gets reused for a new vcpu. -- */ -- unsigned int next_id = (((unsigned int)nextd->domain_id << 16) | -- (uint16_t)next->vcpu_id); -- BUILD_BUG_ON(MAX_VIRT_CPUS > 0xffff); -- -- /* -- * When scheduling from a vcpu, to idle, and back to the same vcpu -- * (which might be common in a lightly loaded system, or when -- * using vcpu pinning), there is no need to issue IBPB, as we are -- * returning to the same security context. -- */ -- if ( *last_id != next_id ) -- { -- spec_ctrl_new_guest_context(); -- *last_id = next_id; -- } -- } -+ /* -+ * Issue an IBPB when scheduling a different vCPU if required. -+ * -+ * IBPB clears the RSB/RAS/RAP, but that's fine as we leave this -+ * function via reset_stack_and_call_ind() rather than via a RET -+ * instruction. -+ */ -+ if ( opt_ibpb_ctxt_switch ) -+ spec_ctrl_new_guest_context(); - - /* Update the top-of-stack block with the new speculation settings. */ - info->scf = diff --git a/xsa480.patch b/xsa480.patch deleted file mode 100644 index d01ea35..0000000 --- a/xsa480.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 45f6866e34b7e9ee8b6ac16d646a2e954c97e48e Mon Sep 17 00:00:00 2001 -From: Roger Pau Monne -Date: Tue, 17 Feb 2026 09:33:43 +0100 -Subject: [PATCH] x86/p2m: issue a sync flush before freeing paging pages -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In the EPT implementation, the defer flushing logic is used -unconditionally, and that would lead to paging memory being returned to the -paging pool before its references had been flushed. - -Issue any pending flushes before freeing the paging memory back to the -pool. - -Note AMD (NPT) and Shadow paging are not affected, as they don't implement -the deferred flushing logic. - -This is XSA-480 / CVE-2026-23554 - -Fixes: 4a59e6bb3a96 ("x86/EPT: squash meaningless TLB flush") -Signed-off-by: Roger Pau Monné -Reviewed-by: Jan Beulich ---- - xen/arch/x86/mm/p2m.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c -index e915da26a832..fddecdf978ec 100644 ---- a/xen/arch/x86/mm/p2m.c -+++ b/xen/arch/x86/mm/p2m.c -@@ -479,6 +479,11 @@ void p2m_free_ptp(struct p2m_domain *p2m, struct page_info *pg) - ASSERT(p2m->domain); - ASSERT(p2m->domain->arch.paging.free_page); - -+ /* -+ * Issue any pending flush here, in case it was deferred before. The page -+ * will be returned to the paging pool now. -+ */ -+ p2m_tlb_flush_sync(p2m); - page_list_del(pg, &p2m->pages); - p2m->domain->arch.paging.free_page(p2m->domain, pg); - --- -2.51.0 - diff --git a/xsa481.patch b/xsa481.patch deleted file mode 100644 index c21f910..0000000 --- a/xsa481.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0cff16f0a997f1b0871b621a1d6050652530e5d9 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Thu, 12 Feb 2026 08:29:38 +0100 -Subject: [PATCH] tools/xenstored: fix canonicalize() error testing -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The setting of errno in canonicalize() is rather fragile and seems to -be even wrong in one corner case: when the invalid path "/local/domain/" -is passed, sscanf() will set errno to 0, resulting in canonicalize() to -return NULL with errno being 0. This can result in triggering the -assert(conn->in == NULL) in consider_message(). - -Don't assume the initial setting of errno to "EINVAL" will stay valid -in all cases and set it to EINVAL only when returning NULL due to an -invalid path. - -This is XSA-481/CVE-2026-23555 - -Reported-by: Marek Marczykowski-Górecki -Signed-off-by: Juergen Gross -Reviewed-by: Julien Grall ---- - tools/xenstored/core.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/tools/xenstored/core.c b/tools/xenstored/core.c -index 64c478a801..2e826f99eb 100644 ---- a/tools/xenstored/core.c -+++ b/tools/xenstored/core.c -@@ -1240,11 +1240,10 @@ const char *canonicalize(struct connection *conn, const void *ctx, - * - illegal character in node - * - starts with '@' but no special node allowed - */ -- errno = EINVAL; - if (!node || - !valid_chars(node) || - (node[0] == '@' && !allow_special)) -- return NULL; -+ goto inval; - - if (node[0] != '/' && node[0] != '@') { - name = talloc_asprintf(ctx, "%s/%s", get_implicit_path(conn), -@@ -1272,6 +1271,8 @@ const char *canonicalize(struct connection *conn, const void *ctx, - if (name != node) - talloc_free(name); - -+ inval: -+ errno = EINVAL; - return NULL; - } - --- -2.53.0 - From 545511922a2051d9845ed087831dd16da9c99818 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Fri, 27 Mar 2026 14:13:04 -0700 Subject: [PATCH 89/99] Make licenses package noarch It only has licenses in it, after all. Signed-off-by: Adam Williamson --- xen.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/xen.spec b/xen.spec index 7c73619..b72f389 100644 --- a/xen.spec +++ b/xen.spec @@ -223,6 +223,7 @@ which manage Xen virtual machines. %package licenses Summary: License files from Xen source +BuildArch: noarch %description licenses This package contains the license files from the source used From 18cf277715db3e31199921761aecd370b56f1bb2 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Fri, 27 Mar 2026 15:59:02 -0700 Subject: [PATCH 90/99] Revert "Make licenses package noarch" This reverts commit 545511922a2051d9845ed087831dd16da9c99818. Turns out we can't do this because different license files show up on x86_64 and aarch64 (there are more on x86_64 as we build more stuff there). --- xen.spec | 1 - 1 file changed, 1 deletion(-) diff --git a/xen.spec b/xen.spec index b72f389..7c73619 100644 --- a/xen.spec +++ b/xen.spec @@ -223,7 +223,6 @@ which manage Xen virtual machines. %package licenses Summary: License files from Xen source -BuildArch: noarch %description licenses This package contains the license files from the source used From cf70d8c84ec2e313566bd6de122a25476f281e6f Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 28 Apr 2026 21:20:56 +0100 Subject: [PATCH 91/99] 4 security patches +- oxenstored keeps quota related use counts across domain destruction + [XSA-483, CVE-2026-23556] +- Xenstored DoS via XS_RESET_WATCHES command [XSA-484, CVE-2026-23557] +- grant table v2 race in status page mapping [XSA-486, CVE-2026-23558] +- x86: Floating Point Divider State Sampling [XSA-488, CVE-2025-54505] --- ...0547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch | 88 +++++++++ xen.spec | 19 +- xsa483.patch | 30 +++ xsa484.patch | 89 +++++++++ xsa486.patch | 181 ++++++++++++++++++ 5 files changed, 405 insertions(+), 2 deletions(-) create mode 100644 xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch create mode 100644 xsa483.patch create mode 100644 xsa484.patch create mode 100644 xsa486.patch diff --git a/xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch b/xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch new file mode 100644 index 0000000..a5e65ba --- /dev/null +++ b/xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch @@ -0,0 +1,88 @@ +From 90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3 Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Fri, 10 Apr 2026 21:55:46 +0100 +Subject: [PATCH] x86/amd: Mitigate AMD-SN-7053 / FP-DSS +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +This is XSA-488 / CVE-2025-54505 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +(cherry picked from commit 99912d346009fda1e7fb1510c9501fbab17e92a0) +--- + xen/arch/x86/cpu/amd.c | 37 ++++++++++++++++++++++++++++ + xen/arch/x86/include/asm/msr-index.h | 1 + + 2 files changed, 38 insertions(+) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 8c55d233f3..1bb0766ebf 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -1048,6 +1048,42 @@ void amd_init_de_cfg(const struct cpuinfo_x86 *c) + wrmsrl(MSR_AMD64_DE_CFG, val | new); + } + ++static void amd_init_fp_cfg(const struct cpuinfo_x86 *c) ++{ ++ uint64_t val, new = 0; ++ ++ /* If virtualised, we won't have mutable access even if we can read it. */ ++ if ( cpu_has_hypervisor ) ++ return; ++ ++ /* ++ * On Zen1, mitigate SB-7053 / FP-DSS Floating Point Divider State ++ * Sampling by setting bit 9 as instructed. ++ */ ++ if ( c->family == 0x17 && is_zen1_uarch() ) ++ new |= 1 << 9; ++ ++ /* ++ * Avoid reading FP_CFG if we don't intend to change anything. The ++ * register doesn't exist on all families. ++ */ ++ if ( !new ) ++ return; ++ ++ val = rdmsr(MSR_AMD64_FP_CFG); ++ ++ if ( (val & new) == new ) ++ return; ++ ++ /* ++ * FP_CFG is a Core-scoped MSR, and this write is racy. However, both ++ * threads calculate the new value from state which expected to be ++ * consistent across CPUs and unrelated to the old value, so the result ++ * should be consistent. ++ */ ++ wrmsr(MSR_AMD64_FP_CFG, val | new); ++} ++ + void __init amd_init_lfence_dispatch(void) + { + struct cpuinfo_x86 *c = &boot_cpu_data; +@@ -1120,6 +1156,7 @@ static void cf_check init_amd(struct cpuinfo_x86 *c) + uint64_t value; + + amd_init_de_cfg(c); ++ amd_init_fp_cfg(c); + + if (c == &boot_cpu_data) + amd_init_lfence_dispatch(); /* Needs amd_init_de_cfg() */ +diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h +index df52587c85..6c5b2569e1 100644 +--- a/xen/arch/x86/include/asm/msr-index.h ++++ b/xen/arch/x86/include/asm/msr-index.h +@@ -428,6 +428,7 @@ + #define MSR_AMD64_LS_CFG 0xc0011020U + #define MSR_AMD64_IC_CFG 0xc0011021U + #define MSR_AMD64_DC_CFG 0xc0011022U ++#define MSR_AMD64_FP_CFG 0xc0011028U + #define MSR_AMD64_DE_CFG 0xc0011029U + #define AMD64_DE_CFG_LFENCE_SERIALISE (_AC(1, ULL) << 1) + #define MSR_AMD64_EX_CFG 0xc001102cU +-- +2.39.5 + diff --git a/xen.spec b/xen.spec index 7c73619..ba3662c 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 1%{?dist} +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -79,6 +79,10 @@ Patch7: xen.gcc12.fixes.patch Patch8: xen.efi.build.patch Patch9: xen.python3.12.patch Patch11: xen.json.nocpuid.patch +Patch12: xsa483.patch +Patch13: xsa484.patch +Patch14: xsa486.patch +Patch15: xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch # build using Fedora seabios and ipxe packages for roms @@ -265,6 +269,10 @@ This package contains files used in testing the xen builds %patch 8 -p1 %patch 9 -p1 %patch 11 -p1 +%patch 12 -p1 +%patch 13 -p1 +%patch 14 -p1 +%patch 15 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -820,8 +828,15 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Tue Apr 28 2026 Michael Young - 4.21.1-2 +- oxenstored keeps quota related use counts across domain destruction + [XSA-483, CVE-2026-23556] +- Xenstored DoS via XS_RESET_WATCHES command [XSA-484, CVE-2026-23557] +- grant table v2 race in status page mapping [XSA-486, CVE-2026-23558] +- x86: Floating Point Divider State Sampling [XSA-488, CVE-2025-54505] + * Thu Mar 26 2026 Michael Young - 4.21.1-1 -- update to xen 4.21.0 +- update to xen 4.21.1 remove patches now included or superceded upstream * Tue Mar 17 2026 Michael Young - 4.21.0-5 diff --git a/xsa483.patch b/xsa483.patch new file mode 100644 index 0000000..8ecb2e9 --- /dev/null +++ b/xsa483.patch @@ -0,0 +1,30 @@ +From: Andrii Sultanov +Subject: tools/oxenstored: Reset quota when resetting permissions + +The quota object contains both limits and the current node usage counts. + +When a domain is torn down, the node data itself is cleaned up but the node +usage counts are not. A later domain reusing the same domid can create fewer +nodes before being deemed to be over quota. + +Reset the count when the node permissions are cleaned up. + +This is XSA-483 / CVE-2026-23556. + +Signed-off-by: Andrii Sultanov +Signed-off-by: Andrew Cooper + +diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml +index 9b8dd2812df0..aa9204ead3ec 100644 +--- a/tools/ocaml/xenstored/store.ml ++++ b/tools/ocaml/xenstored/store.ml +@@ -465,7 +465,8 @@ let reset_permissions store domid = + if perms <> node.perms then + Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); + Some { node with Node.perms } +- ) store.root ++ ) store.root; ++ store.quota <- Quota.del store.quota domid + + type ops = { + store: t; diff --git a/xsa484.patch b/xsa484.patch new file mode 100644 index 0000000..522549e --- /dev/null +++ b/xsa484.patch @@ -0,0 +1,89 @@ +From 3d0d19ad17f29c64dde4a7baf392da4fd58f3654 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Mon, 16 Mar 2026 15:06:11 +0100 +Subject: [PATCH] tools/xenstored: make conn_delete_all_transactions() + idempotent + +conn_delete_all_transactions() should be callable in any context, +resetting ALL transaction related data. + +This includes number of active transactions and the transaction +pointer in struct connection. + +So reset conn->trans to NULL in conn_delete_all_transactions() and +do the cleanup for each transaction in destroy_transaction(). + +This avoids triggering the assert() in conn_delete_all_transactions() +in case e.g. ignore_connection() was called while an operation inside +a transaction was performed, or XS_RESET_WATCHES was called in a +transaction. + +This is XSA-484 / CVE-2026-23557. + +Reported-by: Andrii Sultanov +Fixes: 1f9d04fb021c ("xenstored: allow guest to shutdown all its watches/transactions") +Signed-off-by: Juergen Gross +--- + tools/xenstored/transaction.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/tools/xenstored/transaction.c b/tools/xenstored/transaction.c +index 167cd597fd..0825c48859 100644 +--- a/tools/xenstored/transaction.c ++++ b/tools/xenstored/transaction.c +@@ -432,17 +432,23 @@ static int finalize_transaction(struct connection *conn, + static int destroy_transaction(void *_transaction) + { + struct transaction *trans = _transaction; ++ struct connection *conn = trans->conn; + struct accessed_node *i; + + wrl_ntransactions--; + trace_destroy(trans, "transaction"); + while ((i = list_top(&trans->accessed, struct accessed_node, list))) { + if (i->ta_node) +- db_delete(trans->conn, i->trans_name, NULL); ++ db_delete(conn, i->trans_name, NULL); + list_del(&i->list); + talloc_free(i); + } + ++ list_del(&trans->list); ++ domain_transaction_dec(conn); ++ if (list_empty(&conn->transaction_list)) ++ conn->ta_start_time = 0; ++ + return 0; + } + +@@ -523,10 +529,6 @@ int do_transaction_end(const void *ctx, struct connection *conn, + return ENOENT; + + conn->transaction = NULL; +- list_del(&trans->list); +- domain_transaction_dec(conn); +- if (list_empty(&conn->transaction_list)) +- conn->ta_start_time = 0; + + chk_quota = trans->node_created && domain_is_unprivileged(conn); + +@@ -572,14 +574,10 @@ void conn_delete_all_transactions(struct connection *conn) + struct transaction *trans; + + while ((trans = list_top(&conn->transaction_list, +- struct transaction, list))) { +- list_del(&trans->list); ++ struct transaction, list))) + talloc_free(trans); +- } +- +- assert(conn->transaction == NULL); + +- conn->ta_start_time = 0; ++ conn->transaction = NULL; + } + + int check_transactions(struct hashtable *hash) +-- +2.53.0 + diff --git a/xsa486.patch b/xsa486.patch new file mode 100644 index 0000000..654e957 --- /dev/null +++ b/xsa486.patch @@ -0,0 +1,181 @@ +From: Jan Beulich +Subject: gnttab: split gnttab_map_frame() + +If a domain tries to map status frames in parallel to switching grant +table version from 2 to 1, the mapping operation may put in place P2M +entries referencing MFNs which gnttab_unpopulate_status_frames() is in the +process of freeing. + +Ideally we would refcount pages when entered into P2M tables, but that's a +significant change. Extend the grant-table-locked region instead in +xenmem_add_to_physmap_one() (being the sole caller of gnttab_map_frame()), +such that a race with gnttab_unpopulate_status_frames() is no longer +possible. + +This is XSA-486 / CVE-2026-23558. + +Fixes: 5ce8fafa947c ("Dynamic grant-table sizing") +Fixes: a98dc13703e0 ("Introduce a grant_entry_v2 structure") +Reported-by: Rafal Wojtczuk +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/arm/mm.c ++++ b/xen/arch/arm/mm.c +@@ -174,12 +174,10 @@ int xenmem_add_to_physmap_one( + switch ( space ) + { + case XENMAPSPACE_grant_table: +- rc = gnttab_map_frame(d, idx, gfn, &mfn); ++ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn); + if ( rc ) + return rc; + +- /* Need to take care of the reference obtained in gnttab_map_frame(). */ +- page = mfn_to_page(mfn); + t = p2m_ram_rw; + + break; +@@ -281,10 +279,23 @@ int xenmem_add_to_physmap_one( + * to drop the reference we took earlier. In all other cases we need to + * drop any reference we took earlier (perhaps indirectly). + */ +- if ( space == XENMAPSPACE_gmfn_foreign ? rc : page != NULL ) ++ switch ( space ) + { ++ default: ++ if ( page ) ++ put_page(page); ++ break; ++ ++ case XENMAPSPACE_grant_table: ++ gnttab_map_frame_end(d, mfn); ++ break; ++ ++ case XENMAPSPACE_gmfn_foreign: ++ if ( !rc ) ++ break; + ASSERT(page != NULL); + put_page(page); ++ break; + } + + return rc; +--- a/xen/arch/x86/mm/p2m.c ++++ b/xen/arch/x86/mm/p2m.c +@@ -2009,11 +2009,9 @@ int xenmem_add_to_physmap_one( + break; + + case XENMAPSPACE_grant_table: +- rc = gnttab_map_frame(d, idx, gfn, &mfn); ++ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn); + if ( rc ) + return rc; +- /* Need to take care of the reference obtained in gnttab_map_frame(). */ +- page = mfn_to_page(mfn); + break; + + case XENMAPSPACE_gmfn: +@@ -2095,19 +2093,28 @@ int xenmem_add_to_physmap_one( + put_gfn(d, gfn_x(gfn)); + + put_both: +- /* +- * In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top. +- * We also may need to transfer ownership of the page reference to our +- * caller. +- */ +- if ( space == XENMAPSPACE_gmfn ) ++ switch ( space ) + { ++ case XENMAPSPACE_gmfn: ++ /* ++ * We took a ref of the gfn at the top. We also may need to transfer ++ * ownership of the page reference to our caller. ++ */ + put_gfn(d, gmfn); + if ( !rc && extra.ppage ) + { + *extra.ppage = page; + page = NULL; + } ++ break; ++ ++ case XENMAPSPACE_grant_table: ++ /* ++ * We (gnttab_map_frame_begin()) acquired a lock and took a ref of the ++ * page underlying the MFN at the top. ++ */ ++ gnttab_map_frame_end(d, mfn); ++ break; + } + + if ( page ) +--- a/xen/common/grant_table.c ++++ b/xen/common/grant_table.c +@@ -4250,7 +4250,8 @@ int gnttab_acquire_resource( + return rc; + } + +-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn) ++int gnttab_map_frame_begin( ++ struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn) + { + int rc = 0; + struct grant_table *gt = d->grant_table; +@@ -4288,11 +4289,19 @@ int gnttab_map_frame(struct domain *d, u + put_page(pg); + } + +- grant_write_unlock(gt); ++ if ( rc ) ++ grant_write_unlock(d->grant_table); + + return rc; + } + ++void gnttab_map_frame_end(struct domain *d, mfn_t mfn) ++{ ++ put_page(mfn_to_page(mfn)); ++ ++ grant_write_unlock(d->grant_table); ++} ++ + static void gnttab_usage_print(struct domain *rd) + { + int first = 1; +--- a/xen/include/xen/grant_table.h ++++ b/xen/include/xen/grant_table.h +@@ -60,8 +60,13 @@ int gnttab_release_mappings(struct domai + int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref, + gfn_t *gfn, uint16_t *status); + +-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, +- mfn_t *mfn); ++/* ++ * These need to be used as a pair, as the first (in the success case) returns ++ * with a lock and page reference held which the second needs to drop. ++ */ ++int gnttab_map_frame_begin(struct domain *d, unsigned long idx, gfn_t gfn, ++ mfn_t *mfn); ++void gnttab_map_frame_end(struct domain *d, mfn_t mfn); + + unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id); + +@@ -100,12 +105,14 @@ static inline int mem_sharing_gref_to_gf + return -EINVAL; + } + +-static inline int gnttab_map_frame(struct domain *d, unsigned long idx, +- gfn_t gfn, mfn_t *mfn) ++static inline int gnttab_map_frame_begin(struct domain *d, unsigned long idx, ++ gfn_t gfn, mfn_t *mfn) + { + return -EINVAL; + } + ++static inline void gnttab_map_frame_end(struct domain *d, mfn_t mfn) {} ++ + static inline unsigned int gnttab_resource_max_frames( + const struct domain *d, unsigned int id) + { From b448fd6e2fcf9fe6fd1ef10ae18f820a63c6d218 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Tue, 12 May 2026 20:57:06 +0100 Subject: [PATCH 92/99] x86: CPU Opcode Cache corruption [XSA-490,CVE-2025-54518] --- xen.spec | 7 ++++++- xsa490-4.21.patch | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 xsa490-4.21.patch diff --git a/xen.spec b/xen.spec index ba3662c..fdb9fba 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 2%{?dist} +Release: 3%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -83,6 +83,7 @@ Patch12: xsa483.patch Patch13: xsa484.patch Patch14: xsa486.patch Patch15: xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch +Patch16: xsa490-4.21.patch # build using Fedora seabios and ipxe packages for roms @@ -273,6 +274,7 @@ This package contains files used in testing the xen builds %patch 13 -p1 %patch 14 -p1 %patch 15 -p1 +%patch 16 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -828,6 +830,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Tue May 12 2026 Michael Young - 4.21.1-3 +- x86: CPU Opcode Cache corruption [XSA-490,CVE-2025-54518] + * Tue Apr 28 2026 Michael Young - 4.21.1-2 - oxenstored keeps quota related use counts across domain destruction [XSA-483, CVE-2026-23556] diff --git a/xsa490-4.21.patch b/xsa490-4.21.patch new file mode 100644 index 0000000..5a560cb --- /dev/null +++ b/xsa490-4.21.patch @@ -0,0 +1,43 @@ +From: Andrew Cooper +Subject: x86/amd: Mitigate AMD-SN-7052 + +This is XSA-490 / CVE-2025-54518. + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index 1bb0766ebf13..b5bf2b732e8f 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -1116,11 +1116,25 @@ static void amd_check_bp_cfg(void) + { + uint64_t val, new = 0; + +- /* +- * AMD Erratum #1485. Set bit 5, as instructed. +- */ +- if (!cpu_has_hypervisor && boot_cpu_data.x86 == 0x19 && is_zen4_uarch()) +- new |= (1 << 5); ++ if (!cpu_has_hypervisor) { ++ /* ++ * AMD Erratum #1485. If SMT is enabled and STIBP disabled, ++ * the CPU may fetch incorrect instruction bytes. ++ * ++ * Set bit 5, as instructed. ++ */ ++ if (boot_cpu_data.x86 == 0x19 && is_zen4_uarch()) ++ new |= (1 << 5); ++ ++ /* ++ * AMD SB-7052. CPU OP Cache corruption, causing instructions ++ * to be executed at a higher privilege. ++ * ++ * Set bit 33, as instructed. ++ */ ++ if (boot_cpu_data.x86 == 0x17 && is_zen2_uarch()) ++ new |= (1UL << 33); ++ } + + /* + * On hardware supporting SRSO_MSR_FIX, activate BP_SPEC_REDUCE by From f67d5718e2ead23721883b7f90bdb20148b5a453 Mon Sep 17 00:00:00 2001 From: Python Maint Date: Wed, 3 Jun 2026 19:38:16 +0200 Subject: [PATCH 93/99] Rebuilt for Python 3.15 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index fdb9fba..bdcc012 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 3%{?dist} +Release: 4%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -830,6 +830,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Wed Jun 03 2026 Python Maint - 4.21.1-4 +- Rebuilt for Python 3.15 + * Tue May 12 2026 Michael Young - 4.21.1-3 - x86: CPU Opcode Cache corruption [XSA-490,CVE-2025-54518] From 124455e6320df45354cd73d2d5fb7a16dd755f90 Mon Sep 17 00:00:00 2001 From: Yaakov Selkowitz Date: Fri, 12 Jun 2026 20:07:37 -0400 Subject: [PATCH 94/99] Rebuilt for openssl 4.0 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index bdcc012..68100b4 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 4%{?dist} +Release: 5%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -830,6 +830,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Sat Jun 13 2026 Yaakov Selkowitz - 4.21.1-5 +- Rebuilt for openssl 4.0 + * Wed Jun 03 2026 Python Maint - 4.21.1-4 - Rebuilt for Python 3.15 From 0c18c23c4c540b04358f824f0130e82c7734c2ab Mon Sep 17 00:00:00 2001 From: Michael Young Date: Thu, 18 Jun 2026 21:14:50 +0100 Subject: [PATCH 95/99] 4 security updates x86 HVM I/O port list traversal [XSA-491, CVE-2026-42487] domctl lock open to abuse [XSA-492, CVE-2026-42489, CVE-2026-42490] Arm: Completion of memory accesses not guaranteed by completion of a TLBI [XSA-493, CVE-2025-10263] x86: mismatched mapcache metadata [XSA-494, CVE-2026-42488] --- xen.spec | 61 ++++++- xsa491-4.21.patch | 211 ++++++++++++++++++++++ xsa492-4.21-01.patch | 264 ++++++++++++++++++++++++++++ xsa492-4.21-02.patch | 104 +++++++++++ xsa492-4.21-03.patch | 87 ++++++++++ xsa492-4.21-04.patch | 81 +++++++++ xsa492-4.21-05.patch | 156 +++++++++++++++++ xsa492-4.21-06.patch | 84 +++++++++ xsa492-4.21-07.patch | 202 ++++++++++++++++++++++ xsa492-4.21-08.patch | 85 +++++++++ xsa492-4.21-09.patch | 194 +++++++++++++++++++++ xsa492-4.21-10.patch | 97 +++++++++++ xsa492-4.21-11.patch | 128 ++++++++++++++ xsa492-4.21-12.patch | 172 ++++++++++++++++++ xsa492-4.21-13.patch | 163 +++++++++++++++++ xsa492-4.21-14.patch | 179 +++++++++++++++++++ xsa492-4.21-15.patch | 108 ++++++++++++ xsa492-4.21-16.patch | 112 ++++++++++++ xsa492-4.21-17.patch | 124 +++++++++++++ xsa492-4.21-18.patch | 94 ++++++++++ xsa492-4.21-19.patch | 378 ++++++++++++++++++++++++++++++++++++++++ xsa492-4.21-20.patch | 123 +++++++++++++ xsa493-4.21-01.patch | 311 +++++++++++++++++++++++++++++++++ xsa493-4.21-02.patch | 71 ++++++++ xsa493-4.21-03.patch | 37 ++++ xsa493-4.21-04.patch | 37 ++++ xsa494-4.21.patch | 404 +++++++++++++++++++++++++++++++++++++++++++ 27 files changed, 4066 insertions(+), 1 deletion(-) create mode 100644 xsa491-4.21.patch create mode 100644 xsa492-4.21-01.patch create mode 100644 xsa492-4.21-02.patch create mode 100644 xsa492-4.21-03.patch create mode 100644 xsa492-4.21-04.patch create mode 100644 xsa492-4.21-05.patch create mode 100644 xsa492-4.21-06.patch create mode 100644 xsa492-4.21-07.patch create mode 100644 xsa492-4.21-08.patch create mode 100644 xsa492-4.21-09.patch create mode 100644 xsa492-4.21-10.patch create mode 100644 xsa492-4.21-11.patch create mode 100644 xsa492-4.21-12.patch create mode 100644 xsa492-4.21-13.patch create mode 100644 xsa492-4.21-14.patch create mode 100644 xsa492-4.21-15.patch create mode 100644 xsa492-4.21-16.patch create mode 100644 xsa492-4.21-17.patch create mode 100644 xsa492-4.21-18.patch create mode 100644 xsa492-4.21-19.patch create mode 100644 xsa492-4.21-20.patch create mode 100644 xsa493-4.21-01.patch create mode 100644 xsa493-4.21-02.patch create mode 100644 xsa493-4.21-03.patch create mode 100644 xsa493-4.21-04.patch create mode 100644 xsa494-4.21.patch diff --git a/xen.spec b/xen.spec index 68100b4..a9bf097 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 5%{?dist} +Release: 6%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -84,6 +84,32 @@ Patch13: xsa484.patch Patch14: xsa486.patch Patch15: xen.git-90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3.patch Patch16: xsa490-4.21.patch +Patch17: xsa491-4.21.patch +Patch18: xsa492-4.21-01.patch +Patch19: xsa492-4.21-02.patch +Patch20: xsa492-4.21-03.patch +Patch21: xsa492-4.21-04.patch +Patch22: xsa492-4.21-05.patch +Patch23: xsa492-4.21-06.patch +Patch24: xsa492-4.21-07.patch +Patch25: xsa492-4.21-08.patch +Patch26: xsa492-4.21-09.patch +Patch27: xsa492-4.21-10.patch +Patch28: xsa492-4.21-11.patch +Patch29: xsa492-4.21-12.patch +Patch30: xsa492-4.21-13.patch +Patch31: xsa492-4.21-14.patch +Patch32: xsa492-4.21-15.patch +Patch33: xsa492-4.21-16.patch +Patch34: xsa492-4.21-17.patch +Patch35: xsa492-4.21-18.patch +Patch36: xsa492-4.21-19.patch +Patch37: xsa492-4.21-20.patch +Patch38: xsa493-4.21-01.patch +Patch39: xsa493-4.21-02.patch +Patch40: xsa493-4.21-03.patch +Patch41: xsa493-4.21-04.patch +Patch42: xsa494-4.21.patch # build using Fedora seabios and ipxe packages for roms @@ -275,6 +301,32 @@ This package contains files used in testing the xen builds %patch 14 -p1 %patch 15 -p1 %patch 16 -p1 +%patch 17 -p1 +%patch 18 -p1 +%patch 19 -p1 +%patch 20 -p1 +%patch 21 -p1 +%patch 22 -p1 +%patch 23 -p1 +%patch 24 -p1 +%patch 25 -p1 +%patch 26 -p1 +%patch 27 -p1 +%patch 28 -p1 +%patch 29 -p1 +%patch 30 -p1 +%patch 31 -p1 +%patch 32 -p1 +%patch 33 -p1 +%patch 34 -p1 +%patch 35 -p1 +%patch 36 -p1 +%patch 37 -p1 +%patch 38 -p1 +%patch 39 -p1 +%patch 40 -p1 +%patch 41 -p1 +%patch 42 -p1 # stubdom sources cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom @@ -830,6 +882,13 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Thu Jun 18 2026 Michael Young - 4.21.1-6 +- x86 HVM I/O port list traversal [XSA-491, CVE-2026-42487] +- domctl lock open to abuse [XSA-492, CVE-2026-42489, CVE-2026-42490] +- Arm: Completion of memory accesses not guaranteed by completion of a TLBI + [XSA-493, CVE-2025-10263] +- x86: mismatched mapcache metadata [XSA-494, CVE-2026-42488] + * Sat Jun 13 2026 Yaakov Selkowitz - 4.21.1-5 - Rebuilt for openssl 4.0 diff --git a/xsa491-4.21.patch b/xsa491-4.21.patch new file mode 100644 index 0000000..d1ebc1a --- /dev/null +++ b/xsa491-4.21.patch @@ -0,0 +1,211 @@ +From: Jan Beulich +Subject: x86/HVM: add locking to I/O port translation list traversal + +XEN_DOMCTL_ioport_mapping is usable by DM stubdoms, and hence we can't +assume the list to be left unaltered while the guest (really: the +hypervisor on behalf of the guest) is accessing it. + +This is XSA-491 / CVE-2026-42487. + +Fixes: 192c4dabc344 ("domctl and p2m changes for PCI passthru") +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -663,6 +663,7 @@ long arch_do_domctl( + "ioport_map:add: dom%d gport=%x mport=%x nr=%x\n", + d->domain_id, fgp, fmp, np); + ++ write_lock(&hvm->g2m_ioport_lock); + list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list) + if (g2m_ioport->mport == fmp ) + { +@@ -684,11 +685,14 @@ long arch_do_domctl( + g2m_ioport->np = np; + list_add_tail(&g2m_ioport->list, &hvm->g2m_ioport_list); + } ++ write_unlock(&hvm->g2m_ioport_lock); + if ( !ret ) + ret = ioports_permit_access(d, fmp, fmp + np - 1); + if ( ret && !found && g2m_ioport ) + { ++ write_lock(&hvm->g2m_ioport_lock); + list_del(&g2m_ioport->list); ++ write_unlock(&hvm->g2m_ioport_lock); + xfree(g2m_ioport); + } + } +@@ -697,6 +701,8 @@ long arch_do_domctl( + printk(XENLOG_G_INFO + "ioport_map:remove: dom%d gport=%x mport=%x nr=%x\n", + d->domain_id, fgp, fmp, np); ++ ++ write_lock(&hvm->g2m_ioport_lock); + list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list) + if ( g2m_ioport->mport == fmp ) + { +@@ -704,6 +710,8 @@ long arch_do_domctl( + xfree(g2m_ioport); + break; + } ++ write_unlock(&hvm->g2m_ioport_lock); ++ + ret = ioports_deny_access(d, fmp, fmp + np - 1); + if ( ret && is_hardware_domain(currd) ) + printk(XENLOG_ERR +--- a/xen/arch/x86/hvm/emulate.c ++++ b/xen/arch/x86/hvm/emulate.c +@@ -160,7 +160,6 @@ void hvmemul_cancel(struct vcpu *v) + hvio->mmio_insn_bytes = 0; + hvio->mmio_access = (struct npfec){}; + hvio->mmio_retry = false; +- hvio->g2m_ioport = NULL; + + hvmemul_cache_disable(v); + } +--- a/xen/arch/x86/hvm/hvm.c ++++ b/xen/arch/x86/hvm/hvm.c +@@ -610,6 +610,7 @@ int hvm_domain_initialise(struct domain + spin_lock_init(&d->arch.hvm.irq_lock); + spin_lock_init(&d->arch.hvm.uc_lock); + spin_lock_init(&d->arch.hvm.write_map.lock); ++ rwlock_init(&d->arch.hvm.g2m_ioport_lock); + rwlock_init(&d->arch.hvm.mmcfg_lock); + INIT_LIST_HEAD(&d->arch.hvm.write_map.list); + INIT_LIST_HEAD(&d->arch.hvm.g2m_ioport_list); +--- a/xen/arch/x86/hvm/io.c ++++ b/xen/arch/x86/hvm/io.c +@@ -143,36 +143,56 @@ bool handle_pio(uint16_t port, unsigned + return true; + } + +-static bool cf_check g2m_portio_accept( +- const struct hvm_io_handler *handler, const ioreq_t *p) ++/* NB: Returns with the lock held in the success case. */ ++static const struct g2m_ioport *g2m_portio_find_and_lock(struct hvm_domain *hvm, ++ uint64_t addr, ++ uint32_t size) + { +- struct vcpu *curr = current; +- const struct hvm_domain *hvm = &curr->domain->arch.hvm; +- struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io; +- struct g2m_ioport *g2m_ioport; +- unsigned int start, end; ++ const struct g2m_ioport *g2m_ioport; ++ ++ read_lock(&hvm->g2m_ioport_lock); + + list_for_each_entry( g2m_ioport, &hvm->g2m_ioport_list, list ) + { +- start = g2m_ioport->gport; +- end = start + g2m_ioport->np; +- if ( (p->addr >= start) && (p->addr + p->size <= end) ) +- { +- hvio->g2m_ioport = g2m_ioport; +- return 1; +- } ++ unsigned int start = g2m_ioport->gport; ++ ++ if ( addr >= start && addr + size <= start + g2m_ioport->np ) ++ return g2m_ioport; + } + +- return 0; ++ read_unlock(&hvm->g2m_ioport_lock); ++ ++ return NULL; ++} ++ ++static bool cf_check g2m_portio_accept( ++ const struct hvm_io_handler *handler, const ioreq_t *p) ++{ ++ struct hvm_domain *hvm = ¤t->domain->arch.hvm; ++ const struct g2m_ioport *g2m_ioport = ++ g2m_portio_find_and_lock(hvm, p->addr, p->size); ++ ++ if ( !g2m_ioport ) ++ return false; ++ ++ read_unlock(&hvm->g2m_ioport_lock); ++ ++ return true; + } + + static int cf_check g2m_portio_read( + const struct hvm_io_handler *handler, uint64_t addr, uint32_t size, + uint64_t *data) + { +- struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io; +- const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport; +- unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport; ++ struct hvm_domain *hvm = ¤t->domain->arch.hvm; ++ const struct g2m_ioport *g2m_ioport = ++ g2m_portio_find_and_lock(hvm, addr, size); ++ unsigned int mport; ++ ++ if ( !g2m_ioport ) ++ return X86EMUL_RETRY; ++ ++ mport = addr - g2m_ioport->gport + g2m_ioport->mport; + + switch ( size ) + { +@@ -189,6 +209,8 @@ static int cf_check g2m_portio_read( + BUG(); + } + ++ read_unlock(&hvm->g2m_ioport_lock); ++ + return X86EMUL_OKAY; + } + +@@ -196,9 +218,15 @@ static int cf_check g2m_portio_write( + const struct hvm_io_handler *handler, uint64_t addr, uint32_t size, + uint64_t data) + { +- struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io; +- const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport; +- unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport; ++ struct hvm_domain *hvm = ¤t->domain->arch.hvm; ++ const struct g2m_ioport *g2m_ioport = ++ g2m_portio_find_and_lock(hvm, addr, size); ++ unsigned int mport; ++ ++ if ( !g2m_ioport ) ++ return X86EMUL_RETRY; ++ ++ mport = addr - g2m_ioport->gport + g2m_ioport->mport; + + switch ( size ) + { +@@ -215,6 +243,8 @@ static int cf_check g2m_portio_write( + BUG(); + } + ++ read_unlock(&hvm->g2m_ioport_lock); ++ + return X86EMUL_OKAY; + } + +--- a/xen/arch/x86/include/asm/hvm/domain.h ++++ b/xen/arch/x86/include/asm/hvm/domain.h +@@ -125,6 +125,7 @@ struct hvm_domain { + + /* List of guest to machine IO ports mapping. */ + struct list_head g2m_ioport_list; ++ rwlock_t g2m_ioport_lock; + + /* List of MMCFG regions trapped by Xen. */ + struct list_head mmcfg_regions; +--- a/xen/arch/x86/include/asm/hvm/vcpu.h ++++ b/xen/arch/x86/include/asm/hvm/vcpu.h +@@ -54,8 +54,6 @@ struct hvm_vcpu_io { + unsigned long msix_unmask_address; + unsigned long msix_snoop_address; + unsigned long msix_snoop_gpa; +- +- const struct g2m_ioport *g2m_ioport; + }; + + struct nestedvcpu { diff --git a/xsa492-4.21-01.patch b/xsa492-4.21-01.patch new file mode 100644 index 0000000..7244ebd --- /dev/null +++ b/xsa492-4.21-01.patch @@ -0,0 +1,264 @@ +From: Jan Beulich +Subject: sched: use sequence counter to enlighten vcpu_runstate_get() + +Subsequently XEN_DOMCTL_getdomaininfo will want to invoke the function +without holding a lock, thus allowing parallel execution of potentially +many instances. As was learned from 228ab9992ffb ("domctl: improve +locking during domain destruction"), reverted by d0887cc6b16e, such +parallelism can result in severe lock contention on any (previously) +inner lock. To avoid taking that risk replace the use of the scheduler +lock in vcpu_runstate_get() by a newly introduced sequence counter. +Convert the "no lock if current" property to "use a local counter +instance", thus guaranteeing the loop to exit after the first iteration. + +Skeleton and commentary of the seqcount implementation based on / +derived from Linux 6.11-rc. + +To have runstate_seq placed next to runstate in struct vcpu, without +introducing a new obvious padding hole, yet while keeping the latter +adjacent to runstate_guest{,_area} as well, move runstate down a little. + +This is part of XSA-492. + +Requested-by: Andrew Cooper +Signed-off-by: Jan Beulich +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +Reviewed-by: Juergen Gross + +--- a/xen/common/sched/core.c ++++ b/xen/common/sched/core.c +@@ -281,13 +281,18 @@ static inline void vcpu_runstate_change( + } + + delta = new_entry_time - v->runstate.state_entry_time; +- if ( delta > 0 ) ++ ++ /* Serialization: ->schedule_lock (see ASSERT() above). */ ++ with_seq_write(&v->runstate_seq) + { +- v->runstate.time[v->runstate.state] += delta; +- v->runstate.state_entry_time = new_entry_time; +- } ++ if ( delta > 0 ) ++ { ++ v->runstate.time[v->runstate.state] += delta; ++ v->runstate.state_entry_time = new_entry_time; ++ } + +- v->runstate.state = new_state; ++ v->runstate.state = new_state; ++ } + } + + void sched_guest_idle(void (*idle) (void), unsigned int cpu) +@@ -307,30 +312,18 @@ void sched_guest_idle(void (*idle) (void + void vcpu_runstate_get(const struct vcpu *v, + struct vcpu_runstate_info *runstate) + { +- spinlock_t *lock; +- s_time_t delta; +- struct sched_unit *unit; ++ struct seqcount seq = SEQCNT_ZERO(); ++ const struct seqcount *s = likely(v == current) ? &seq : &v->runstate_seq; + +- rcu_read_lock(&sched_res_rculock); +- +- /* +- * Be careful in case of an idle vcpu: the assignment to a unit might +- * change even with the scheduling lock held, so be sure to use the +- * correct unit for locking in order to avoid triggering an ASSERT() in +- * the unlock function. +- */ +- unit = is_idle_vcpu(v) ? get_sched_res(v->processor)->sched_unit_idle +- : v->sched_unit; +- lock = likely(v == current) ? NULL : unit_schedule_lock_irq(unit); +- memcpy(runstate, &v->runstate, sizeof(*runstate)); +- delta = NOW() - runstate->state_entry_time; +- if ( delta > 0 ) +- runstate->time[runstate->state] += delta; +- +- if ( unlikely(lock != NULL) ) +- unit_schedule_unlock_irq(lock, unit); ++ until_seq_read(s) ++ { ++ s_time_t delta; + +- rcu_read_unlock(&sched_res_rculock); ++ *runstate = v->runstate; ++ delta = NOW() - runstate->state_entry_time; ++ if ( delta > 0 ) ++ runstate->time[runstate->state] += delta; ++ } + } + + uint64_t get_cpu_idle_time(unsigned int cpu) +--- a/xen/include/xen/sched.h ++++ b/xen/include/xen/sched.h +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -198,7 +199,6 @@ struct vcpu + + struct sched_unit *sched_unit; + +- struct vcpu_runstate_info runstate; + #ifndef CONFIG_COMPAT + # define runstate_guest(v) ((v)->runstate_guest) + XEN_GUEST_HANDLE(vcpu_runstate_info_t) runstate_guest; /* guest address */ +@@ -210,6 +210,8 @@ struct vcpu + } runstate_guest; /* guest address */ + #endif + struct guest_area runstate_guest_area; ++ struct vcpu_runstate_info runstate; ++ struct seqcount runstate_seq; + unsigned int new_state; + + /* Has the FPU been initialised? */ +--- /dev/null ++++ b/xen/include/xen/seqcount.h +@@ -0,0 +1,139 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++#ifndef XEN_SEQCOUNT_H ++#define XEN_SEQCOUNT_H ++ ++#include ++#include ++ ++#include ++#include ++ ++/* ++ * Sequence counters (seqcount_t) ++ * ++ * This is the raw counting mechanism, without any writer protection. ++ * ++ * Write side critical sections must be serialized (and non-preemptible). ++ * ++ * If readers can be invoked from interrupt contexts, interrupts must also ++ * be respectively disabled before entering the write section. ++ * ++ * This mechanism can't be used if the protected data contains pointers, ++ * as the writer can invalidate a pointer that a reader is following. ++ */ ++struct seqcount { ++ unsigned int sequence; ++}; ++ ++/* ++ * SEQCNT_ZERO() - initializer for seqcount_t ++ * @name: Name of the struct seqcount instance ++ */ ++#define SEQCNT_ZERO() { .sequence = 0 } ++ ++static inline unsigned int seqprop_sequence(const struct seqcount *s) ++{ ++ return ACCESS_ONCE(s->sequence); ++} ++ ++/* ++ * read_seqcount_begin() - begin a seqcount read critical section ++ * @s: Pointer to struct seqcount ++ * ++ * Return: count to be passed to read_seqcount_retry() ++ */ ++static inline unsigned int _read_seqcount_begin(const struct seqcount *s) ++{ ++ unsigned int seq; ++ ++ while ((seq = seqprop_sequence(s)) & 1) ++ cpu_relax(); ++ ++ smp_rmb(); ++ ++ return seq; ++} ++ ++static always_inline unsigned int read_seqcount_begin(const struct seqcount *s) ++{ ++ unsigned int seq = _read_seqcount_begin(s); ++ ++ block_lock_speculation(); ++ ++ return seq; ++} ++ ++/* ++ * read_seqcount_retry() - end a seqcount read critical section ++ * @s: Pointer to struct seqcount ++ * @start: count, from read_seqcount_begin() ++ * ++ * read_seqcount_retry closes the read critical section of given struct ++ * seqcount. If the critical section was invalid, it must be ignored ++ * (and typically retried). ++ * ++ * Return: true if a read section retry is required, else false ++ */ ++static inline bool _read_seqcount_retry(const struct seqcount *s, ++ unsigned int start) ++{ ++ smp_rmb(); ++ return unlikely(seqprop_sequence(s) != start); ++} ++ ++static always_inline bool read_seqcount_retry(const struct seqcount *s, ++ unsigned int start) ++{ ++ return lock_evaluate_nospec(_read_seqcount_retry(s, start)); ++} ++ ++/* Loops until a consistent count has been observed across the loop body. */ ++#define until_seq_read(seq) \ ++ for ( unsigned int retry_ = 1, count_; \ ++ retry_ && (count_ = read_seqcount_begin(seq), true); \ ++ retry_ = read_seqcount_retry(seq, count_) ) ++ ++/* ++ * write_seqcount_begin() - start a struct seqcount write side critical section ++ * @s: Pointer to struct seqcount ++ * ++ * Context: sequence counter write side sections must be serialized. ++ * If readers can be invoked from interrupt context, interrupts must be ++ * respectively disabled. ++ */ ++static inline void write_seqcount_begin(struct seqcount *s) ++{ ++ add_sized(&s->sequence, 1); ++ smp_wmb(); ++} ++ ++/* ++ * write_seqcount_end() - end a struct seqcount write side critical section ++ * @s: Pointer to seqcount ++ */ ++static inline void write_seqcount_end(struct seqcount *s) ++{ ++ smp_wmb(); ++ add_sized(&s->sequence, 1); ++} ++ ++/* ++ * Not really a loop, but we need write_seqcount_{begin,end}() in the correct ++ * position. ++ */ ++#define with_seq_write(seq) \ ++ for ( bool once_ = true; \ ++ once_ && (write_seqcount_begin(seq), true); \ ++ (write_seqcount_end(seq), once_ = false) ) ++ ++#endif /* XEN_SEQCOUNT_H */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-file-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ diff --git a/xsa492-4.21-02.patch b/xsa492-4.21-02.patch new file mode 100644 index 0000000..75ca8ca --- /dev/null +++ b/xsa492-4.21-02.patch @@ -0,0 +1,104 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_getdomaininfo without acquiring domctl lock + +getdomaininfo() is not called under consistently the same lock. Thus, +with caller side locking irrelevant, it can as well be called with the +domctl lock not held. (Callers not pausing the domain they want to +retrieve information for already need to be aware that not all of the +data returned can be relied on as being consistent; most data will also +be stale by the time the caller gets to look at it.) + +Move the handling not only ahead of acquiring the lock, but also ahead +of the XSM check, leveraging that the sub-op has its own hook. + +While moving, convert an assignment to an assertion: The domain in +question was determined from the field which previously was "updated". + +This is part of XSA-492. + +Fixes: 5513bd0b4675 ("add xenstore domain flag to hypervisor") +Reported-by: Andrew Cooper +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné +Acked-by: Daniel P. Smith + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -318,6 +318,26 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + break; + } + ++ /* Handle sub-ops not requiring the domctl lock. */ ++ switch ( op->cmd ) ++ { ++ case XEN_DOMCTL_getdomaininfo: ++ ret = xsm_getdomaininfo(XSM_XS_PRIV, d); ++ if ( !ret ) ++ { ++ getdomaininfo(d, &op->u.getdomaininfo); ++ ++ ASSERT(op->domain == op->u.getdomaininfo.domain); ++ copyback = true; ++ } ++ ++ goto domctl_out_unlock_domonly; ++ ++ default: ++ /* Everything else handled further down. */ ++ break; ++ } ++ + ret = xsm_domctl(XSM_OTHER, d, op->cmd, + /* SSIDRef only applicable for cmd == createdomain */ + op->u.createdomain.ssidref); +@@ -516,17 +536,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + copyback = 1; + break; + +- case XEN_DOMCTL_getdomaininfo: +- ret = xsm_getdomaininfo(XSM_XS_PRIV, d); +- if ( ret ) +- break; +- +- getdomaininfo(d, &op->u.getdomaininfo); +- +- op->domain = op->u.getdomaininfo.domain; +- copyback = 1; +- break; +- + case XEN_DOMCTL_getvcpucontext: + { + vcpu_guest_context_u c = { .nat = NULL }; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -172,9 +172,13 @@ static XSM_INLINE int cf_check xsm_domct + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + return xsm_default_action(XSM_DM_PRIV, current->domain, d); +- case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: + return xsm_default_action(XSM_XS_PRIV, current->domain, d); ++ ++ case XEN_DOMCTL_getdomaininfo: ++ ASSERT_UNREACHABLE(); ++ return -EILSEQ; ++ + default: + return xsm_default_action(XSM_PRIV, current->domain, d); + } +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -682,8 +682,12 @@ static int cf_check flask_domctl(struct + */ + return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL); + +- /* These have individual XSM hooks (common/domctl.c) */ ++ /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_getdomaininfo: ++ ASSERT_UNREACHABLE(); ++ return -EILSEQ; ++ ++ /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_iomem_permission: diff --git a/xsa492-4.21-03.patch b/xsa492-4.21-03.patch new file mode 100644 index 0000000..5a0db22 --- /dev/null +++ b/xsa492-4.21-03.patch @@ -0,0 +1,87 @@ +From: Daniel P. Smith +Subject: domctl: protect locking for get_domain_state + +When DOMID_INVALID is passed, the dom exec handler lock is being taken +without any check that the domain is even allowed to take the lock. This +allows for an unauthorized domain to DoS the get_domain_state domctl op. +Move to consider the op effectively being called against the hypervisor. +Thus it is the target of the call being invoked to identify the last +domain with a state change. The subsequent check of whether the source +domain is allowed the state of the last domain to change state is still +relevant. + +This is part of XSA-492. + +Signed-off-by: Daniel P. Smith +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/tools/flask/policy/modules/xenstore.te ++++ b/tools/flask/policy/modules/xenstore.te +@@ -14,6 +14,7 @@ allow xenstore_t xen_t:xen writeconsole; + # Xenstore queries domaininfo on all domains + allow xenstore_t domain_type:domain getdomaininfo; + allow xenstore_t domain_type:domain2 get_domain_state; ++allow xenstore_t domxen_t:domain2 get_domain_state; + + # As a shortcut, the following 3 rules are used instead of adding a domain_comms + # rule between xenstore_t and every domain type that talks to xenstore +--- a/xen/common/domain.c ++++ b/xen/common/domain.c +@@ -216,12 +216,8 @@ int get_domain_state(struct xen_domctl_g + if ( info->pad0 ) + return -EINVAL; + +- if ( d ) ++ if ( d != dom_xen ) + { +- rc = xsm_get_domain_state(XSM_XS_PRIV, d); +- if ( rc ) +- return rc; +- + set_domain_state_info(info, d); + + return 0; +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -304,13 +304,19 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + fallthrough; + case XEN_DOMCTL_test_assign_device: + case XEN_DOMCTL_vm_event_op: +- case XEN_DOMCTL_get_domain_state: + if ( op->domain == DOMID_INVALID ) + { + d = NULL; + break; + } + fallthrough; ++ case XEN_DOMCTL_get_domain_state: ++ if ( op->domain == DOMID_INVALID ) ++ { ++ d = dom_xen; ++ break; ++ } ++ fallthrough; + default: + d = rcu_lock_domain_by_id(op->domain); + if ( !d ) +@@ -863,7 +869,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + break; + + case XEN_DOMCTL_get_domain_state: +- ret = get_domain_state(&op->u.get_domain_state, d, &op->domain); ++ ret = xsm_get_domain_state(XSM_XS_PRIV, d); ++ if ( !ret ) ++ ret = get_domain_state(&op->u.get_domain_state, d, &op->domain); + if ( !ret ) + copyback = true; + break; +@@ -876,7 +884,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + domctl_lock_release(); + + domctl_out_unlock_domonly: +- if ( d && d != dom_io ) ++ if ( d && !is_system_domain(d) ) + rcu_unlock_domain(d); + + if ( copyback && __copy_to_guest(u_domctl, op, 1) ) diff --git a/xsa492-4.21-04.patch b/xsa492-4.21-04.patch new file mode 100644 index 0000000..481ff5d --- /dev/null +++ b/xsa492-4.21-04.patch @@ -0,0 +1,81 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_get_domain_state without acquiring domctl lock + +get_domain_state() uses its own locking. Thus, with caller side locking +irrelevant, it can as well be called with the domctl lock not held. + +Move the handling not only ahead of acquiring the lock, but also ahead +of the XSM check, leveraging that the sub-op has its own hook. + +This is part of XSA-492. + +Fixes: 3ad3df1bd0aa ("xen: add new domctl get_domain_state") +Reported-by: Andrew Cooper +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -339,6 +339,14 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + + goto domctl_out_unlock_domonly; + ++ case XEN_DOMCTL_get_domain_state: ++ ret = xsm_get_domain_state(XSM_XS_PRIV, d); ++ if ( !ret ) ++ ret = get_domain_state(&op->u.get_domain_state, d, &op->domain); ++ if ( !ret ) ++ copyback = true; ++ goto domctl_out_unlock_domonly; ++ + default: + /* Everything else handled further down. */ + break; +@@ -868,14 +876,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + ret = -EOPNOTSUPP; + break; + +- case XEN_DOMCTL_get_domain_state: +- ret = xsm_get_domain_state(XSM_XS_PRIV, d); +- if ( !ret ) +- ret = get_domain_state(&op->u.get_domain_state, d, &op->domain); +- if ( !ret ) +- copyback = true; +- break; +- + default: + ret = arch_do_domctl(op, d, u_domctl); + break; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -172,10 +172,9 @@ static XSM_INLINE int cf_check xsm_domct + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + return xsm_default_action(XSM_DM_PRIV, current->domain, d); +- case XEN_DOMCTL_get_domain_state: +- return xsm_default_action(XSM_XS_PRIV, current->domain, d); + + case XEN_DOMCTL_getdomaininfo: ++ case XEN_DOMCTL_get_domain_state: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -684,6 +684,7 @@ static int cf_check flask_domctl(struct + + /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_getdomaininfo: ++ case XEN_DOMCTL_get_domain_state: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +@@ -694,7 +695,6 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_set_target: + case XEN_DOMCTL_vm_event_op: +- case XEN_DOMCTL_get_domain_state: + + /* These have individual XSM hooks (arch/../domctl.c) */ + case XEN_DOMCTL_bind_pt_irq: diff --git a/xsa492-4.21-05.patch b/xsa492-4.21-05.patch new file mode 100644 index 0000000..cb7beaa --- /dev/null +++ b/xsa492-4.21-05.patch @@ -0,0 +1,156 @@ +From: Jan Beulich +Subject: domain: locking for iomem_caps accesses + +In order to be able to pull at least the XEN_DOMCTL_iomem_mapping handling +out of the domctl-locked region, a separate (per-domain) lock is needed to +synchronize in particular with XEN_DOMCTL_iomem_permission. + +Locking is added only as far as domctl-s are affected. Uses presently +outside of the domctl lock may want dealing with subsequently (perhaps +limited to non-__init code). + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domain.c ++++ b/xen/common/domain.c +@@ -518,10 +518,15 @@ static int late_hwdom_init(struct domain + * may be modified after this hypercall returns if a more complex + * device model is desired. + */ ++ write_lock(&dom0->caps_lock); + rangeset_swap(d->irq_caps, dom0->irq_caps); + rangeset_swap(d->iomem_caps, dom0->iomem_caps); + #ifdef CONFIG_X86 + rangeset_swap(d->arch.ioport_caps, dom0->arch.ioport_caps); ++#endif ++ write_unlock(&dom0->caps_lock); ++ ++#ifdef CONFIG_X86 + setup_io_bitmap(d); + setup_io_bitmap(dom0); + #endif +@@ -873,6 +878,7 @@ struct domain *domain_create(domid_t dom + rspin_lock_init_prof(d, domain_lock); + rspin_lock_init_prof(d, page_alloc_lock); + spin_lock_init(&d->hypercall_deadlock_mutex); ++ rwlock_init(&d->caps_lock); + INIT_PAGE_LIST_HEAD(&d->page_list); + INIT_PAGE_LIST_HEAD(&d->extra_page_list); + INIT_PAGE_LIST_HEAD(&d->xenpage_list); +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -267,6 +267,35 @@ static struct vnuma_info *vnuma_init(con + return ERR_PTR(ret); + } + ++void iocaps_double_lock(struct domain *d, bool write) ++{ ++ struct domain *currd = current->domain; ++ ++ if ( d->domain_id > currd->domain_id ) ++ read_lock(&currd->caps_lock); ++ ++ if ( write ) ++ write_lock(&d->caps_lock); ++ else ++ read_lock(&d->caps_lock); ++ ++ if ( d->domain_id < currd->domain_id ) ++ read_lock(&currd->caps_lock); ++} ++ ++void iocaps_double_unlock(struct domain *d, bool write) ++{ ++ struct domain *currd = current->domain; ++ ++ if ( d != currd ) ++ read_unlock(&currd->caps_lock); ++ ++ if ( write ) ++ write_unlock(&d->caps_lock); ++ else ++ read_unlock(&d->caps_lock); ++} ++ + static bool is_stable_domctl(uint32_t cmd) + { + return cmd == XEN_DOMCTL_get_domain_state; +@@ -687,6 +716,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */ + break; + ++ iocaps_double_lock(d, true); ++ + if ( !iomem_access_permitted(current->domain, + mfn, mfn + nr_mfns - 1) || + xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) ) +@@ -695,6 +726,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1); + else + ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); ++ ++ iocaps_double_unlock(d, true); + break; + } + +@@ -719,19 +752,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + break; + #endif + ++ iocaps_double_lock(d, false); ++ + ret = -EPERM; + if ( !iomem_access_permitted(current->domain, mfn, mfn_end) || +- !iomem_access_permitted(d, mfn, mfn_end) ) +- break; +- +- ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add); +- if ( ret ) +- break; +- +- if ( !paging_mode_translate(d) ) +- break; +- +- if ( add ) ++ !iomem_access_permitted(d, mfn, mfn_end) || ++ (ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add)) || ++ !paging_mode_translate(d) ) ++ /* Nothing. */; ++ else if ( add ) + { + printk(XENLOG_G_DEBUG + "memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n", +@@ -755,6 +784,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + "memory_map: error %ld removing dom%d access to [%lx,%lx]\n", + ret, d->domain_id, mfn, mfn_end); + } ++ ++ iocaps_double_unlock(d, false); + break; + } + +--- a/xen/include/xen/iocap.h ++++ b/xen/include/xen/iocap.h +@@ -12,6 +12,9 @@ + #include + #include + ++void iocaps_double_lock(struct domain *d, bool write); ++void iocaps_double_unlock(struct domain *d, bool write); ++ + static inline int iomem_permit_access(struct domain *d, unsigned long s, + unsigned long e) + { +--- a/xen/include/xen/sched.h ++++ b/xen/include/xen/sched.h +@@ -536,6 +536,7 @@ struct domain + #endif + + /* I/O capabilities (access to IRQs and memory-mapped I/O). */ ++ rwlock_t caps_lock; + struct rangeset *iomem_caps; + struct rangeset *irq_caps; + diff --git a/xsa492-4.21-06.patch b/xsa492-4.21-06.patch new file mode 100644 index 0000000..c9e0061 --- /dev/null +++ b/xsa492-4.21-06.patch @@ -0,0 +1,84 @@ +From: Jan Beulich +Subject: x86/domain: locking for ioport_caps accesses + +In order to be able to pull at least the XEN_DOMCTL_ioport_mapping +handling out of the domctl-locked region, the new separate (per-domain) +lock is used to synchronize in particular with +XEN_DOMCTL_ioport_permission. + +Locking is added only as far as domctl-s are affected. Uses presently +outside of the domctl lock may want dealing with subsequently (perhaps +limited to non-__init code). + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -233,6 +233,8 @@ long arch_do_domctl( + unsigned int np = domctl->u.ioport_permission.nr_ports; + int allow = domctl->u.ioport_permission.allow_access; + ++ iocaps_double_lock(d, true); ++ + if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS ) + ret = -EINVAL; + else if ( !ioports_access_permitted(currd, fp, fp + np - 1) || +@@ -242,6 +244,8 @@ long arch_do_domctl( + ret = ioports_permit_access(d, fp, fp + np - 1); + else + ret = ioports_deny_access(d, fp, fp + np - 1); ++ ++ iocaps_double_unlock(d, true); + break; + } + +@@ -648,16 +652,13 @@ long arch_do_domctl( + break; + } + +- ret = -EPERM; +- if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) ) +- break; +- +- ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add); +- if ( ret ) +- break; +- + hvm = &d->arch.hvm; +- if ( add ) ++ iocaps_double_lock(d, true); ++ ++ if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) || ++ (ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add)) ) ++ ret = ret ?: -EPERM; ++ else if ( add ) + { + printk(XENLOG_G_INFO + "ioport_map:add: dom%d gport=%x mport=%x nr=%x\n", +@@ -718,6 +720,8 @@ long arch_do_domctl( + "ioport_map: error %ld denying dom%d access to [%x,%x]\n", + ret, d->domain_id, fmp, fmp + np - 1); + } ++ ++ iocaps_double_unlock(d, true); + break; + } + +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -2339,9 +2339,12 @@ void __hwdom_init setup_io_bitmap(struct + return; + + bitmap_fill(d->arch.hvm.io_bitmap, 0x10000); ++ ++ read_lock(&d->caps_lock); + if ( rangeset_report_ranges(d->arch.ioport_caps, 0, 0x10000, + io_bitmap_cb, d) ) + BUG(); ++ read_unlock(&d->caps_lock); + + /* + * We need to trap 4-byte accesses to 0xcf8 (see admin_io_okay(), diff --git a/xsa492-4.21-07.patch b/xsa492-4.21-07.patch new file mode 100644 index 0000000..e343773 --- /dev/null +++ b/xsa492-4.21-07.patch @@ -0,0 +1,202 @@ +From: Jan Beulich +Subject: domain: locking for irq_caps accesses + +In order to be able to pull at least the XEN_DOMCTL_{,un}bind_pt_irq +handling out of the domctl-locked region, a separate (per-domain) lock is +needed to synchronize in particular with XEN_DOMCTL_{irq,gsi}_permission. + +Locking is added only as far as domctl-s are affected. Uses presently +outside of the domctl lock may want dealing with subsequently (perhaps +limited to non-__init code). + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné +Reviewed-by: Julien Grall + +--- a/xen/arch/arm/domctl.c ++++ b/xen/arch/arm/domctl.c +@@ -76,6 +76,7 @@ long arch_do_domctl(struct xen_domctl *d + case XEN_DOMCTL_bind_pt_irq: + { + int rc; ++ struct domain *currd = current->domain; + struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq; + uint32_t irq = bind->u.spi.spi; + uint32_t virq = bind->machine_irq; +@@ -107,21 +108,26 @@ long arch_do_domctl(struct xen_domctl *d + if ( rc ) + return rc; + +- if ( !irq_access_permitted(current->domain, irq) ) +- return -EPERM; ++ read_lock(&currd->caps_lock); + +- if ( !vgic_reserve_virq(d, virq) ) +- return -EBUSY; +- +- rc = route_irq_to_guest(d, virq, irq, "routed IRQ"); +- if ( rc ) +- vgic_free_virq(d, virq); ++ if ( !irq_access_permitted(currd, irq) ) ++ rc = -EPERM; ++ else if ( !vgic_reserve_virq(d, virq) ) ++ rc = -EBUSY; ++ else ++ { ++ rc = route_irq_to_guest(d, virq, irq, "routed IRQ"); ++ if ( rc ) ++ vgic_free_virq(d, virq); ++ } + ++ read_unlock(&currd->caps_lock); + return rc; + } + case XEN_DOMCTL_unbind_pt_irq: + { + int rc; ++ struct domain *currd = current->domain; + struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq; + uint32_t irq = bind->u.spi.spi; + uint32_t virq = bind->machine_irq; +@@ -138,16 +144,15 @@ long arch_do_domctl(struct xen_domctl *d + if ( rc ) + return rc; + +- if ( !irq_access_permitted(current->domain, irq) ) +- return -EPERM; +- +- rc = release_guest_irq(d, virq); +- if ( rc ) +- return rc; ++ read_lock(&currd->caps_lock); + +- vgic_free_virq(d, virq); ++ if ( !irq_access_permitted(currd, irq) ) ++ rc = -EPERM; ++ else if ( !(rc = release_guest_irq(d, virq)) ) ++ vgic_free_virq(d, virq); + +- return 0; ++ read_unlock(&currd->caps_lock); ++ return rc; + } + + case XEN_DOMCTL_vuart_op: +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -267,16 +267,17 @@ long arch_do_domctl( + break; + } + +- ret = -EPERM; ++ iocaps_double_lock(d, true); ++ + if ( !irq_access_permitted(currd, irq) || + xsm_irq_permission(XSM_HOOK, d, irq, flags) ) +- break; +- +- if ( flags ) ++ ret = -EPERM; ++ else if ( flags ) + ret = irq_permit_access(d, irq); + else + ret = irq_deny_access(d, irq); + ++ iocaps_double_unlock(d, true); + break; + } + +@@ -579,20 +580,27 @@ long arch_do_domctl( + break; + + irq = domain_pirq_to_irq(d, bind->machine_irq); +- ret = -EPERM; +- if ( irq <= 0 || !irq_access_permitted(currd, irq) ) +- break; ++ if ( irq <= 0 ) ++ ret = -EPERM; + +- ret = -ESRCH; +- if ( is_iommu_enabled(d) ) ++ read_lock(&currd->caps_lock); ++ ++ if ( !irq_access_permitted(currd, irq) ) ++ ret = -EPERM; ++ else if ( is_iommu_enabled(d) ) + { + pcidevs_lock(); + ret = pt_irq_create_bind(d, bind); + pcidevs_unlock(); ++ ++ if ( ret < 0 ) ++ printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for %pd\n", ++ ret, d); + } +- if ( ret < 0 ) +- printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for dom%d\n", +- ret, d->domain_id); ++ else ++ ret = -ESRCH; ++ ++ read_unlock(&currd->caps_lock); + break; + } + +@@ -605,23 +613,26 @@ long arch_do_domctl( + if ( !is_hvm_domain(d) ) + break; + +- ret = -EPERM; +- if ( irq <= 0 || !irq_access_permitted(currd, irq) ) +- break; +- + ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind); + if ( ret ) + break; + +- if ( is_iommu_enabled(d) ) ++ read_lock(&currd->caps_lock); ++ ++ if ( !irq_access_permitted(currd, irq) ) ++ ret = -EPERM; ++ else if ( is_iommu_enabled(d) ) + { + pcidevs_lock(); + ret = pt_irq_destroy_bind(d, bind); + pcidevs_unlock(); ++ ++ if ( ret < 0 ) ++ printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for %pd\n", ++ ret, d); + } +- if ( ret < 0 ) +- printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for dom%d\n", +- ret, d->domain_id); ++ ++ read_unlock(&currd->caps_lock); + break; + } + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -695,6 +695,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + ret = -EINVAL; + break; + } ++ ++ iocaps_double_lock(d, true); ++ + irq = pirq_access_permitted(current->domain, pirq); + if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) ) + ret = -EPERM; +@@ -702,6 +705,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + ret = irq_permit_access(d, irq); + else + ret = irq_deny_access(d, irq); ++ ++ iocaps_double_unlock(d, true); + break; + } + #endif diff --git a/xsa492-4.21-08.patch b/xsa492-4.21-08.patch new file mode 100644 index 0000000..4aefbf4 --- /dev/null +++ b/xsa492-4.21-08.patch @@ -0,0 +1,85 @@ +From: Jan Beulich +Subject: XSM/Flask: split the .iomem_mapping() hook + +It's used twice in entirely different situations. The use in do_domctl() +wants to become an ordinary XSM_DM_PRIV invocation, while the one in vPCI +code need to remain XSM_HOOK (it may plausibly become XSM_TARGET). For +Flask, the same backing function will continue to be used for the time +being. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith + +--- a/xen/drivers/vpci/header.c ++++ b/xen/drivers/vpci/header.c +@@ -67,7 +67,7 @@ static int cf_check map_range( + return -EPERM; + } + +- rc = xsm_iomem_mapping(XSM_HOOK, map->d, map_mfn, m_end, map->map); ++ rc = xsm_iomem_mapping_vpci(XSM_HOOK, map->d, map_mfn, m_end, map->map); + if ( rc ) + { + printk(XENLOG_G_WARNING +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -580,6 +580,13 @@ static XSM_INLINE int cf_check xsm_iomem + return xsm_default_action(action, current->domain, d); + } + ++static XSM_INLINE int cf_check xsm_iomem_mapping_vpci( ++ XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow) ++{ ++ XSM_ASSERT_ACTION(XSM_HOOK); ++ return xsm_default_action(action, current->domain, d); ++} ++ + static XSM_INLINE int cf_check xsm_pci_config_permission( + XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf, uint16_t start, + uint16_t end, uint8_t access) +--- a/xen/include/xsm/xsm.h ++++ b/xen/include/xsm/xsm.h +@@ -118,6 +118,8 @@ struct xsm_ops { + uint8_t allow); + int (*iomem_mapping)(struct domain *d, uint64_t s, uint64_t e, + uint8_t allow); ++ int (*iomem_mapping_vpci)(struct domain *d, uint64_t s, uint64_t e, ++ uint8_t allow); + int (*pci_config_permission)(struct domain *d, uint32_t machine_bdf, + uint16_t start, uint16_t end, uint8_t access); + +@@ -523,6 +525,12 @@ static inline int xsm_iomem_mapping( + return alternative_call(xsm_ops.iomem_mapping, d, s, e, allow); + } + ++static inline int xsm_iomem_mapping_vpci( ++ xsm_default_t def, struct domain *d, uint64_t s, uint64_t e, uint8_t allow) ++{ ++ return alternative_call(xsm_ops.iomem_mapping_vpci, d, s, e, allow); ++} ++ + static inline int xsm_pci_config_permission( + xsm_default_t def, struct domain *d, uint32_t machine_bdf, uint16_t start, + uint16_t end, uint8_t access) +--- a/xen/xsm/dummy.c ++++ b/xen/xsm/dummy.c +@@ -76,6 +76,7 @@ static const struct xsm_ops __initconst_ + .irq_permission = xsm_irq_permission, + .iomem_permission = xsm_iomem_permission, + .iomem_mapping = xsm_iomem_mapping, ++ .iomem_mapping_vpci = xsm_iomem_mapping_vpci, + .pci_config_permission = xsm_pci_config_permission, + .get_vnumainfo = xsm_get_vnumainfo, + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -1950,6 +1950,7 @@ static const struct xsm_ops __initconst_ + .irq_permission = flask_irq_permission, + .iomem_permission = flask_iomem_permission, + .iomem_mapping = flask_iomem_mapping, ++ .iomem_mapping_vpci = flask_iomem_mapping, + .pci_config_permission = flask_pci_config_permission, + + .resource_plug_core = flask_resource_plug_core, diff --git a/xsa492-4.21-09.patch b/xsa492-4.21-09.patch new file mode 100644 index 0000000..96e9403 --- /dev/null +++ b/xsa492-4.21-09.patch @@ -0,0 +1,194 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_memory_mapping without acquiring domctl lock + +With dedicated locking added, the domctl lock isn't required here anymore. +Move the re-purposed dedicated XSM check as early as possible. + +Minimal "modernization": Switch "add" to bool and use %pd in log messages. + +This is part of XSA-492. + +Fixes: fda49f9b3fbb ("Add build option to allow more hypercalls from stubdoms") +Reported-by: Andrew Cooper +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -376,6 +376,66 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + copyback = true; + goto domctl_out_unlock_domonly; + ++ case XEN_DOMCTL_memory_mapping: ++ { ++ unsigned long gfn = op->u.memory_mapping.first_gfn; ++ unsigned long mfn = op->u.memory_mapping.first_mfn; ++ unsigned long nr_mfns = op->u.memory_mapping.nr_mfns; ++ unsigned long mfn_end = mfn + nr_mfns - 1; ++ bool add = op->u.memory_mapping.add_mapping; ++ ++ ret = -EINVAL; ++ if ( mfn_end < mfn || /* Wrap? */ ++ ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) || ++ (gfn + nr_mfns - 1) < gfn ) /* Wrap? */ ++ goto domctl_out_unlock_domonly; ++ ++ ret = xsm_iomem_mapping(XSM_DM_PRIV, d, mfn, mfn_end, add); ++ if ( ret || !paging_mode_translate(d) ) ++ goto domctl_out_unlock_domonly; ++ ++#ifndef CONFIG_X86 /* XXX ARM!? */ ++ ret = -E2BIG; ++ /* Must break hypercall up as this could take a while. */ ++ if ( nr_mfns > 64 ) ++ goto domctl_out_unlock_domonly; ++#endif ++ ++ iocaps_double_lock(d, false); ++ ++ ret = -EPERM; ++ if ( !iomem_access_permitted(current->domain, mfn, mfn_end) || ++ !iomem_access_permitted(d, mfn, mfn_end) ) ++ /* Nothing. */; ++ else if ( add ) ++ { ++ printk(XENLOG_G_DEBUG ++ "memory_map:add: %pd gfn=%lx mfn=%lx nr=%lx\n", ++ d, gfn, mfn, nr_mfns); ++ ++ ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); ++ if ( ret < 0 ) ++ printk(XENLOG_G_WARNING ++ "memory_map:fail: %pd gfn=%lx mfn=%lx nr=%lx ret:%ld\n", ++ d, gfn, mfn, nr_mfns, ret); ++ } ++ else ++ { ++ printk(XENLOG_G_DEBUG ++ "memory_map:remove: %pd gfn=%lx mfn=%lx nr=%lx\n", ++ d, gfn, mfn, nr_mfns); ++ ++ ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); ++ if ( ret < 0 && is_hardware_domain(current->domain) ) ++ printk(XENLOG_ERR ++ "memory_map: error %ld removing %pd access to [%lx,%lx]\n", ++ ret, d, mfn, mfn_end); ++ } ++ ++ iocaps_double_unlock(d, false); ++ goto domctl_out_unlock_domonly; ++ } ++ + default: + /* Everything else handled further down. */ + break; +@@ -736,64 +796,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + break; + } + +- case XEN_DOMCTL_memory_mapping: +- { +- unsigned long gfn = op->u.memory_mapping.first_gfn; +- unsigned long mfn = op->u.memory_mapping.first_mfn; +- unsigned long nr_mfns = op->u.memory_mapping.nr_mfns; +- unsigned long mfn_end = mfn + nr_mfns - 1; +- int add = op->u.memory_mapping.add_mapping; +- +- ret = -EINVAL; +- if ( mfn_end < mfn || /* wrap? */ +- ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) || +- (gfn + nr_mfns - 1) < gfn ) /* wrap? */ +- break; +- +-#ifndef CONFIG_X86 /* XXX ARM!? */ +- ret = -E2BIG; +- /* Must break hypercall up as this could take a while. */ +- if ( nr_mfns > 64 ) +- break; +-#endif +- +- iocaps_double_lock(d, false); +- +- ret = -EPERM; +- if ( !iomem_access_permitted(current->domain, mfn, mfn_end) || +- !iomem_access_permitted(d, mfn, mfn_end) || +- (ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add)) || +- !paging_mode_translate(d) ) +- /* Nothing. */; +- else if ( add ) +- { +- printk(XENLOG_G_DEBUG +- "memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n", +- d->domain_id, gfn, mfn, nr_mfns); +- +- ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); +- if ( ret < 0 ) +- printk(XENLOG_G_WARNING +- "memory_map:fail: dom%d gfn=%lx mfn=%lx nr=%lx ret:%ld\n", +- d->domain_id, gfn, mfn, nr_mfns, ret); +- } +- else +- { +- printk(XENLOG_G_DEBUG +- "memory_map:remove: dom%d gfn=%lx mfn=%lx nr=%lx\n", +- d->domain_id, gfn, mfn, nr_mfns); +- +- ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn)); +- if ( ret < 0 && is_hardware_domain(current->domain) ) +- printk(XENLOG_ERR +- "memory_map: error %ld removing dom%d access to [%lx,%lx]\n", +- ret, d->domain_id, mfn, mfn_end); +- } +- +- iocaps_double_unlock(d, false); +- break; +- } +- + case XEN_DOMCTL_settimeoffset: + domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds); + break; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -168,13 +168,13 @@ static XSM_INLINE int cf_check xsm_domct + switch ( cmd ) + { + case XEN_DOMCTL_ioport_mapping: +- case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + return xsm_default_action(XSM_DM_PRIV, current->domain, d); + + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_memory_mapping: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +@@ -576,7 +576,7 @@ static XSM_INLINE int cf_check xsm_iomem + static XSM_INLINE int cf_check xsm_iomem_mapping( + XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_DM_PRIV); + return xsm_default_action(action, current->domain, d); + } + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -685,6 +685,7 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_memory_mapping: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +@@ -692,7 +693,6 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_iomem_permission: +- case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_set_target: + case XEN_DOMCTL_vm_event_op: + diff --git a/xsa492-4.21-10.patch b/xsa492-4.21-10.patch new file mode 100644 index 0000000..6406a19 --- /dev/null +++ b/xsa492-4.21-10.patch @@ -0,0 +1,97 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_ioport_mapping without acquiring domctl lock + +With dedicated locking added, the domctl lock isn't required here anymore. +As the handling is in arch-specific code (x86 only), almost no code is +being moved, but a 2nd (extensible to other sub-ops) invocation of +arch_do_domctl() is being added. Move just the re-purposed dedicated XSM +check as early as possible. + +In flask_domctl() don't put #ifdef around the moved case label. + +This is part of XSA-492. + +Fixes: fda49f9b3fbb ("Add build option to allow more hypercalls from stubdoms") +Reported-by: Andrew Cooper +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné +Acked-by: Daniel P. Smith + +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -663,12 +663,15 @@ long arch_do_domctl( + break; + } + ++ ret = xsm_ioport_mapping(XSM_DM_PRIV, d, fmp, fmp + np - 1, add); ++ if ( ret ) ++ break; ++ + hvm = &d->arch.hvm; + iocaps_double_lock(d, true); + +- if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) || +- (ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add)) ) +- ret = ret ?: -EPERM; ++ if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) ) ++ ret = -EPERM; + else if ( add ) + { + printk(XENLOG_G_INFO +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -436,6 +436,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + goto domctl_out_unlock_domonly; + } + ++ case XEN_DOMCTL_ioport_mapping: ++ ret = arch_do_domctl(op, d, u_domctl); ++ goto domctl_out_unlock_domonly; ++ + default: + /* Everything else handled further down. */ + break; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -167,13 +167,13 @@ static XSM_INLINE int cf_check xsm_domct + XSM_ASSERT_ACTION(XSM_OTHER); + switch ( cmd ) + { +- case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + return xsm_default_action(XSM_DM_PRIV, current->domain, d); + + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_memory_mapping: + ASSERT_UNREACHABLE(); + return -EILSEQ; +@@ -772,7 +772,7 @@ static XSM_INLINE int cf_check xsm_iopor + static XSM_INLINE int cf_check xsm_ioport_mapping( + XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_DM_PRIV); + return xsm_default_action(action, current->domain, d); + } + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -685,6 +685,7 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_memory_mapping: + ASSERT_UNREACHABLE(); + return -EILSEQ; +@@ -703,7 +704,6 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks (arch/x86/domctl.c) */ + case XEN_DOMCTL_shadow_op: + case XEN_DOMCTL_ioport_permission: +- case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_gsi_permission: + #endif + #ifdef CONFIG_HAS_PASSTHROUGH diff --git a/xsa492-4.21-11.patch b/xsa492-4.21-11.patch new file mode 100644 index 0000000..647fd5a --- /dev/null +++ b/xsa492-4.21-11.patch @@ -0,0 +1,128 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_{,un}bind_pt_irq without acquiring domctl lock + +With dedicated locking added, the domctl lock isn't required here anymore. +(It also already isn't used when pt_irq_{create,destroy}_bind() are +invoked for PVH Dom0.) As the handling is in arch-specific code, no code +is being moved, but the 2nd (extensible to other sub-ops like the ones +here) invocation of arch_do_domctl() is being re-used. + +This is part of XSA-492. + +Fixes: fda49f9b3fbb ("Add build option to allow more hypercalls from stubdoms") +Reported-by: Andrew Cooper +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné +Acked-by: Daniel P. Smith +Acked-by: Julien Grall + +--- a/xen/arch/arm/domctl.c ++++ b/xen/arch/arm/domctl.c +@@ -104,7 +104,7 @@ long arch_do_domctl(struct xen_domctl *d + if ( rc ) + return rc; + +- rc = xsm_bind_pt_irq(XSM_HOOK, d, bind); ++ rc = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind); + if ( rc ) + return rc; + +@@ -140,7 +140,7 @@ long arch_do_domctl(struct xen_domctl *d + if ( irq != virq ) + return -EINVAL; + +- rc = xsm_unbind_pt_irq(XSM_HOOK, d, bind); ++ rc = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind); + if ( rc ) + return rc; + +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -575,7 +575,7 @@ long arch_do_domctl( + if ( !is_hvm_domain(d) ) + break; + +- ret = xsm_bind_pt_irq(XSM_HOOK, d, bind); ++ ret = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind); + if ( ret ) + break; + +@@ -613,7 +613,7 @@ long arch_do_domctl( + if ( !is_hvm_domain(d) ) + break; + +- ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind); ++ ret = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind); + if ( ret ) + break; + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -437,6 +437,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + } + + case XEN_DOMCTL_ioport_mapping: ++ case XEN_DOMCTL_bind_pt_irq: ++ case XEN_DOMCTL_unbind_pt_irq: + ret = arch_do_domctl(op, d, u_domctl); + goto domctl_out_unlock_domonly; + +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -168,13 +168,11 @@ static XSM_INLINE int cf_check xsm_domct + switch ( cmd ) + { + case XEN_DOMCTL_bind_pt_irq: +- case XEN_DOMCTL_unbind_pt_irq: +- return xsm_default_action(XSM_DM_PRIV, current->domain, d); +- + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_memory_mapping: ++ case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +@@ -541,14 +539,14 @@ static XSM_INLINE int cf_check xsm_unmap + static XSM_INLINE int cf_check xsm_bind_pt_irq( + XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_DM_PRIV); + return xsm_default_action(action, current->domain, d); + } + + static XSM_INLINE int cf_check xsm_unbind_pt_irq( + XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_DM_PRIV); + return xsm_default_action(action, current->domain, d); + } + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -683,10 +683,12 @@ static int cf_check flask_domctl(struct + return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL); + + /* These have individual XSM hooks and don't make it here. */ ++ case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_memory_mapping: ++ case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +@@ -697,9 +699,6 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_set_target: + case XEN_DOMCTL_vm_event_op: + +- /* These have individual XSM hooks (arch/../domctl.c) */ +- case XEN_DOMCTL_bind_pt_irq: +- case XEN_DOMCTL_unbind_pt_irq: + #ifdef CONFIG_X86 + /* These have individual XSM hooks (arch/x86/domctl.c) */ + case XEN_DOMCTL_shadow_op: diff --git a/xsa492-4.21-12.patch b/xsa492-4.21-12.patch new file mode 100644 index 0000000..c19d1e1 --- /dev/null +++ b/xsa492-4.21-12.patch @@ -0,0 +1,172 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_io{mem,port}_permission without acquiring domctl lock + +With dedicated locking added, the domctl lock isn't required here anymore. +As the I/O port handling is in arch-specific code (x86 only), no code is +being moved, but the 2nd invocation of arch_do_domctl() is re-used. Move +the re-purposed dedicated XSM checks as early as possible. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné +Acked-by: Daniel P. Smith + +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -233,12 +233,17 @@ long arch_do_domctl( + unsigned int np = domctl->u.ioport_permission.nr_ports; + int allow = domctl->u.ioport_permission.allow_access; + ++ ret = -EINVAL; ++ if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS ) ++ break; ++ ++ ret = xsm_ioport_permission(XSM_PRIV, d, fp, fp + np - 1, allow); ++ if ( ret ) ++ break; ++ + iocaps_double_lock(d, true); + +- if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS ) +- ret = -EINVAL; +- else if ( !ioports_access_permitted(currd, fp, fp + np - 1) || +- xsm_ioport_permission(XSM_HOOK, d, fp, fp + np - 1, allow) ) ++ if ( !ioports_access_permitted(currd, fp, fp + np - 1) ) + ret = -EPERM; + else if ( allow ) + ret = ioports_permit_access(d, fp, fp + np - 1); +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -376,6 +376,34 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + copyback = true; + goto domctl_out_unlock_domonly; + ++ case XEN_DOMCTL_iomem_permission: ++ { ++ unsigned long mfn = op->u.iomem_permission.first_mfn; ++ unsigned long nr_mfns = op->u.iomem_permission.nr_mfns; ++ bool allow = op->u.iomem_permission.allow_access; ++ ++ ret = -EINVAL; ++ if ( (mfn + nr_mfns - 1) < mfn ) /* Wrap? */ ++ goto domctl_out_unlock_domonly; ++ ++ ret = xsm_iomem_permission(XSM_PRIV, d, mfn, mfn + nr_mfns - 1, allow); ++ if ( ret ) ++ goto domctl_out_unlock_domonly; ++ ++ iocaps_double_lock(d, true); ++ ++ if ( !iomem_access_permitted(current->domain, ++ mfn, mfn + nr_mfns - 1) ) ++ ret = -EPERM; ++ else if ( allow ) ++ ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1); ++ else ++ ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); ++ ++ iocaps_double_unlock(d, true); ++ goto domctl_out_unlock_domonly; ++ } ++ + case XEN_DOMCTL_memory_mapping: + { + unsigned long gfn = op->u.memory_mapping.first_gfn; +@@ -436,6 +464,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + goto domctl_out_unlock_domonly; + } + ++ case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: +@@ -777,31 +806,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + } + #endif + +- case XEN_DOMCTL_iomem_permission: +- { +- unsigned long mfn = op->u.iomem_permission.first_mfn; +- unsigned long nr_mfns = op->u.iomem_permission.nr_mfns; +- int allow = op->u.iomem_permission.allow_access; +- +- ret = -EINVAL; +- if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */ +- break; +- +- iocaps_double_lock(d, true); +- +- if ( !iomem_access_permitted(current->domain, +- mfn, mfn + nr_mfns - 1) || +- xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) ) +- ret = -EPERM; +- else if ( allow ) +- ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1); +- else +- ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); +- +- iocaps_double_unlock(d, true); +- break; +- } +- + case XEN_DOMCTL_settimeoffset: + domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds); + break; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -170,7 +170,9 @@ static XSM_INLINE int cf_check xsm_domct + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_mapping: ++ case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); +@@ -567,7 +569,7 @@ static XSM_INLINE int cf_check xsm_irq_p + static XSM_INLINE int cf_check xsm_iomem_permission( + XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, d); + } + +@@ -763,7 +765,7 @@ static XSM_INLINE int cf_check xsm_priv_ + static XSM_INLINE int cf_check xsm_ioport_permission( + XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, d); + } + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -686,7 +686,9 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_mapping: ++ case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); +@@ -695,14 +697,12 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_irq_permission: +- case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_set_target: + case XEN_DOMCTL_vm_event_op: + + #ifdef CONFIG_X86 + /* These have individual XSM hooks (arch/x86/domctl.c) */ + case XEN_DOMCTL_shadow_op: +- case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_gsi_permission: + #endif + #ifdef CONFIG_HAS_PASSTHROUGH diff --git a/xsa492-4.21-13.patch b/xsa492-4.21-13.patch new file mode 100644 index 0000000..91ce1ae --- /dev/null +++ b/xsa492-4.21-13.patch @@ -0,0 +1,163 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_{irq,gsi}_permission without acquiring domctl lock + +With dedicated locking added, the domctl lock isn't required here anymore. +As the GSI handling is in arch-specific code (x86 only), no code is being +moved there; the 2nd invocation of arch_do_domctl() is re-used. Move the +re-purposed (XSM_HOOK -> XSM_PRIV, as xsm_domctl() is now bypassed) +dedicated XSM checks as early as possible. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/x86/domctl.c ++++ b/xen/arch/x86/domctl.c +@@ -272,10 +272,13 @@ long arch_do_domctl( + break; + } + ++ ret = xsm_irq_permission(XSM_PRIV, d, irq, flags); ++ if ( ret ) ++ break; ++ + iocaps_double_lock(d, true); + +- if ( !irq_access_permitted(currd, irq) || +- xsm_irq_permission(XSM_HOOK, d, irq, flags) ) ++ if ( !irq_access_permitted(currd, irq) ) + ret = -EPERM; + else if ( flags ) + ret = irq_permit_access(d, irq); +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -464,8 +464,41 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + goto domctl_out_unlock_domonly; + } + ++#ifdef CONFIG_HAS_PIRQ ++ case XEN_DOMCTL_irq_permission: ++ { ++ unsigned int pirq = op->u.irq_permission.pirq, irq; ++ bool allow = op->u.irq_permission.allow_access; ++ ++ ret = -EINVAL; ++ if ( pirq >= current->domain->nr_pirqs ) ++ goto domctl_out_unlock_domonly; ++ ++ irq = domain_pirq_to_irq(current->domain, pirq); ++ ++ ret = -EPERM; ++ if ( irq ) ++ ret = xsm_irq_permission(XSM_PRIV, d, irq, allow); ++ if ( ret ) ++ goto domctl_out_unlock_domonly; ++ ++ iocaps_double_lock(d, true); ++ ++ if ( !irq_access_permitted(current->domain, irq) ) ++ ret = -EPERM; ++ else if ( allow ) ++ ret = irq_permit_access(d, irq); ++ else ++ ret = irq_deny_access(d, irq); ++ ++ iocaps_double_unlock(d, true); ++ goto domctl_out_unlock_domonly; ++ } ++#endif ++ + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_ioport_mapping: ++ case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + ret = arch_do_domctl(op, d, u_domctl); +@@ -779,33 +812,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + } + break; + +-#ifdef CONFIG_HAS_PIRQ +- case XEN_DOMCTL_irq_permission: +- { +- unsigned int pirq = op->u.irq_permission.pirq, irq; +- int allow = op->u.irq_permission.allow_access; +- +- if ( pirq >= current->domain->nr_pirqs ) +- { +- ret = -EINVAL; +- break; +- } +- +- iocaps_double_lock(d, true); +- +- irq = pirq_access_permitted(current->domain, pirq); +- if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) ) +- ret = -EPERM; +- else if ( allow ) +- ret = irq_permit_access(d, irq); +- else +- ret = irq_deny_access(d, irq); +- +- iocaps_double_unlock(d, true); +- break; +- } +-#endif +- + case XEN_DOMCTL_settimeoffset: + domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds); + break; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -170,9 +170,11 @@ static XSM_INLINE int cf_check xsm_domct + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_ioport_permission: ++ case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); +@@ -562,7 +564,7 @@ static XSM_INLINE int cf_check xsm_unmap + static XSM_INLINE int cf_check xsm_irq_permission( + XSM_DEFAULT_ARG struct domain *d, int pirq, uint8_t allow) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, d); + } + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -686,9 +686,11 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: ++ case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_ioport_permission: ++ case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); +@@ -696,14 +698,12 @@ static int cf_check flask_domctl(struct + + /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_scheduler_op: +- case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_set_target: + case XEN_DOMCTL_vm_event_op: + + #ifdef CONFIG_X86 + /* These have individual XSM hooks (arch/x86/domctl.c) */ + case XEN_DOMCTL_shadow_op: +- case XEN_DOMCTL_gsi_permission: + #endif + #ifdef CONFIG_HAS_PASSTHROUGH + /* diff --git a/xsa492-4.21-14.patch b/xsa492-4.21-14.patch new file mode 100644 index 0000000..2b13377 --- /dev/null +++ b/xsa492-4.21-14.patch @@ -0,0 +1,179 @@ +From: Jan Beulich +Subject: domctl/XSM: drop vm_event_control hook + +Integrate the checking with xsm_domctl(). Care needs to be taken with the +GET_VERSION sub-op, which may be invoked with DOMID_INVALID, and which has +been (and continues to be) bypassing XSM checking. + +Since the latter two parameters were unused, monitor_domctl() invoking the +hook was actually redundant with the earlier xsm_domctl() (as can be seen +nicely from the hunks changing xsm/flask/hooks.c). + +As a positive side effect, permissions are then checked at the same early +point with and without Flask. + +While folding XEN_DOMCTL_monitor_op and XEN_DOMCTL_vm_event_op in +flask_domctl(), also fold in XEN_DOMCTL_set_access_required. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -496,6 +496,23 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + } + #endif + ++ case XEN_DOMCTL_vm_event_op: ++ if ( op->u.vm_event_op.op == XEN_VM_EVENT_GET_VERSION ) ++ { ++ /* No XSM check (and potentially d == NULL) here. */ ++ ret = vm_event_domctl(d, &op->u.vm_event_op); ++ if ( !ret ) ++ copyback = true; ++ goto domctl_out_unlock_domonly; ++ } ++ if ( !d ) ++ { ++ ret = -ESRCH; ++ goto domctl_out_unlock_domonly; ++ } ++ /* Other sub-ops handled further down. */ ++ break; ++ + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_gsi_permission: +--- a/xen/common/monitor.c ++++ b/xen/common/monitor.c +@@ -30,16 +30,11 @@ + + int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop) + { +- int rc; + bool requested_status = false; + + if ( unlikely(current->domain == d) ) /* no domain_pause() */ + return -EPERM; + +- rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event); +- if ( unlikely(rc) ) +- return rc; +- + switch ( mop->op ) + { + case XEN_DOMCTL_MONITOR_OP_ENABLE: +--- a/xen/common/vm_event.c ++++ b/xen/common/vm_event.c +@@ -603,11 +603,10 @@ int vm_event_domctl(struct domain *d, st + + /* All other subops need to target a real domain. */ + if ( unlikely(d == NULL) ) +- return -ESRCH; +- +- rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op); +- if ( rc ) +- return rc; ++ { ++ ASSERT_UNREACHABLE(); ++ return -EILSEQ; ++ } + + if ( unlikely(d == current->domain) ) /* no domain_pause() */ + { +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -652,13 +652,6 @@ static XSM_INLINE int cf_check xsm_hvm_a + } + } + +-static XSM_INLINE int cf_check xsm_vm_event_control( +- XSM_DEFAULT_ARG struct domain *d, int mode, int op) +-{ +- XSM_ASSERT_ACTION(XSM_PRIV); +- return xsm_default_action(action, current->domain, d); +-} +- + #ifdef CONFIG_VM_EVENT + static XSM_INLINE int cf_check xsm_mem_access(XSM_DEFAULT_ARG struct domain *d) + { +--- a/xen/include/xsm/xsm.h ++++ b/xen/include/xsm/xsm.h +@@ -157,8 +157,6 @@ struct xsm_ops { + int (*hvm_altp2mhvm_op)(struct domain *d, uint64_t mode, uint32_t op); + int (*get_vnumainfo)(struct domain *d); + +- int (*vm_event_control)(struct domain *d, int mode, int op); +- + #ifdef CONFIG_VM_EVENT + int (*mem_access)(struct domain *d); + #endif +@@ -657,12 +655,6 @@ static inline int xsm_get_vnumainfo(xsm_ + return alternative_call(xsm_ops.get_vnumainfo, d); + } + +-static inline int xsm_vm_event_control( +- xsm_default_t def, struct domain *d, int mode, int op) +-{ +- return alternative_call(xsm_ops.vm_event_control, d, mode, op); +-} +- + #ifdef CONFIG_VM_EVENT + static inline int xsm_mem_access(xsm_default_t def, struct domain *d) + { +--- a/xen/xsm/dummy.c ++++ b/xen/xsm/dummy.c +@@ -116,8 +116,6 @@ static const struct xsm_ops __initconst_ + .remove_from_physmap = xsm_remove_from_physmap, + .map_gmfn_foreign = xsm_map_gmfn_foreign, + +- .vm_event_control = xsm_vm_event_control, +- + #ifdef CONFIG_VM_EVENT + .mem_access = xsm_mem_access, + #endif +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -699,7 +699,6 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_set_target: +- case XEN_DOMCTL_vm_event_op: + + #ifdef CONFIG_X86 + /* These have individual XSM hooks (arch/x86/domctl.c) */ +@@ -793,9 +792,8 @@ static int cf_check flask_domctl(struct + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__TRIGGER); + + case XEN_DOMCTL_set_access_required: +- return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT); +- + case XEN_DOMCTL_monitor_op: ++ case XEN_DOMCTL_vm_event_op: + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT); + + case XEN_DOMCTL_debug_op: +@@ -1368,11 +1366,6 @@ static int cf_check flask_hvm_altp2mhvm_ + return current_has_perm(d, SECCLASS_HVM, HVM__ALTP2MHVM_OP); + } + +-static int cf_check flask_vm_event_control(struct domain *d, int mode, int op) +-{ +- return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT); +-} +- + #ifdef CONFIG_VM_EVENT + static int cf_check flask_mem_access(struct domain *d) + { +@@ -1971,8 +1964,6 @@ static const struct xsm_ops __initconst_ + .do_xsm_op = do_flask_op, + .get_vnumainfo = flask_get_vnumainfo, + +- .vm_event_control = flask_vm_event_control, +- + #ifdef CONFIG_VM_EVENT + .mem_access = flask_mem_access, + #endif diff --git a/xsa492-4.21-15.patch b/xsa492-4.21-15.patch new file mode 100644 index 0000000..ac87f3b --- /dev/null +++ b/xsa492-4.21-15.patch @@ -0,0 +1,108 @@ +From: Jan Beulich +Subject: domctl/XSM: pass full struct xen_domctl to xsm_domctl() + +Subsequently some sub-ops will want to inspect their sub-sub-ops. Plus +this way we don't need to pass SSIDref separately anymore for +domain_create. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith + +--- a/xen/arch/x86/mm/paging.c ++++ b/xen/arch/x86/mm/paging.c +@@ -735,7 +735,7 @@ long do_paging_domctl_cont( + if ( d == NULL ) + return -ESRCH; + +- ret = xsm_domctl(XSM_OTHER, d, op.cmd, 0 /* SSIDref not applicable */); ++ ret = xsm_domctl(XSM_OTHER, d, &op); + if ( !ret ) + { + if ( domctl_lock_acquire() ) +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -526,9 +526,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + break; + } + +- ret = xsm_domctl(XSM_OTHER, d, op->cmd, +- /* SSIDRef only applicable for cmd == createdomain */ +- op->u.createdomain.ssidref); ++ ret = xsm_domctl(XSM_OTHER, d, op); + if ( ret ) + goto domctl_out_unlock_domonly; + +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -162,10 +162,10 @@ static XSM_INLINE int cf_check xsm_set_t + } + + static XSM_INLINE int cf_check xsm_domctl( +- XSM_DEFAULT_ARG struct domain *d, unsigned int cmd, uint32_t ssidref) ++ XSM_DEFAULT_ARG struct domain *d, struct xen_domctl *op) + { + XSM_ASSERT_ACTION(XSM_OTHER); +- switch ( cmd ) ++ switch ( op->cmd ) + { + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: +--- a/xen/include/xsm/xsm.h ++++ b/xen/include/xsm/xsm.h +@@ -61,7 +61,7 @@ struct xsm_ops { + int (*sysctl_scheduler_op)(int op); + #endif + int (*set_target)(struct domain *d, struct domain *e); +- int (*domctl)(struct domain *d, unsigned int cmd, uint32_t ssidref); ++ int (*domctl)(struct domain *d, struct xen_domctl *op); + int (*sysctl)(int cmd); + int (*readconsole)(uint32_t clear); + +@@ -260,9 +260,9 @@ static inline int xsm_set_target( + } + + static inline int xsm_domctl(xsm_default_t def, struct domain *d, +- unsigned int cmd, uint32_t ssidref) ++ struct xen_domctl *op) + { +- return alternative_call(xsm_ops.domctl, d, cmd, ssidref); ++ return alternative_call(xsm_ops.domctl, d, op); + } + + static inline int xsm_sysctl(xsm_default_t def, int cmd) +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -667,10 +667,9 @@ static int cf_check flask_set_target(str + return rc; + } + +-static int cf_check flask_domctl(struct domain *d, unsigned int cmd, +- uint32_t ssidref) ++static int cf_check flask_domctl(struct domain *d, struct xen_domctl *op) + { +- switch ( cmd ) ++ switch ( op->cmd ) + { + case XEN_DOMCTL_createdomain: + /* +@@ -680,7 +679,8 @@ static int cf_check flask_domctl(struct + * Note that d is NULL because we haven't even allocated memory for it + * this early in XEN_DOMCTL_createdomain. + */ +- return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL); ++ return avc_current_has_perm(op->u.createdomain.ssidref, SECCLASS_DOMAIN, ++ DOMAIN__CREATE, NULL); + + /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_bind_pt_irq: +@@ -855,7 +855,7 @@ static int cf_check flask_domctl(struct + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SET_LLC_COLORS); + + default: +- return avc_unknown_permission("domctl", cmd); ++ return avc_unknown_permission("domctl", op->cmd); + } + } + diff --git a/xsa492-4.21-16.patch b/xsa492-4.21-16.patch new file mode 100644 index 0000000..2cb8619 --- /dev/null +++ b/xsa492-4.21-16.patch @@ -0,0 +1,112 @@ +From: Jan Beulich +Subject: domctl/XSM: drop scheduler_op hook + +Integrate the checking with xsm_domctl(), now that it has the full op +struct passed. As a positive side effect, permissions are then checked at +the same early point with and without Flask. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Juergen Gross + +--- a/xen/common/sched/core.c ++++ b/xen/common/sched/core.c +@@ -2074,10 +2074,6 @@ long sched_adjust(struct domain *d, stru + { + long ret; + +- ret = xsm_domctl_scheduler_op(XSM_HOOK, d, op->cmd); +- if ( ret ) +- return ret; +- + if ( op->sched_id != dom_scheduler(d)->sched_id ) + return -EINVAL; + +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -141,13 +141,6 @@ static XSM_INLINE int cf_check xsm_getdo + return xsm_default_action(action, current->domain, d); + } + +-static XSM_INLINE int cf_check xsm_domctl_scheduler_op( +- XSM_DEFAULT_ARG struct domain *d, int cmd) +-{ +- XSM_ASSERT_ACTION(XSM_HOOK); +- return xsm_default_action(action, current->domain, d); +-} +- + static XSM_INLINE int cf_check xsm_sysctl_scheduler_op(XSM_DEFAULT_ARG int cmd) + { + XSM_ASSERT_ACTION(XSM_HOOK); +--- a/xen/include/xsm/xsm.h ++++ b/xen/include/xsm/xsm.h +@@ -56,7 +56,6 @@ struct xsm_ops { + struct xen_domctl_getdomaininfo *info); + int (*domain_create)(struct domain *d, uint32_t ssidref); + int (*getdomaininfo)(struct domain *d); +- int (*domctl_scheduler_op)(struct domain *d, int op); + #ifdef CONFIG_SYSCTL + int (*sysctl_scheduler_op)(int op); + #endif +@@ -240,12 +239,6 @@ static inline int xsm_get_domain_state(x + return alternative_call(xsm_ops.get_domain_state, d); + } + +-static inline int xsm_domctl_scheduler_op( +- xsm_default_t def, struct domain *d, int cmd) +-{ +- return alternative_call(xsm_ops.domctl_scheduler_op, d, cmd); +-} +- + #ifdef CONFIG_SYSCTL + static inline int xsm_sysctl_scheduler_op(xsm_default_t def, int cmd) + { +--- a/xen/xsm/dummy.c ++++ b/xen/xsm/dummy.c +@@ -18,7 +18,6 @@ static const struct xsm_ops __initconst_ + .security_domaininfo = xsm_security_domaininfo, + .domain_create = xsm_domain_create, + .getdomaininfo = xsm_getdomaininfo, +- .domctl_scheduler_op = xsm_domctl_scheduler_op, + #ifdef CONFIG_SYSCTL + .sysctl_scheduler_op = xsm_sysctl_scheduler_op, + #endif +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -609,7 +609,7 @@ static int cf_check flask_getdomaininfo( + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO); + } + +-static int cf_check flask_domctl_scheduler_op(struct domain *d, int op) ++static int flask_domctl_scheduler_op(struct domain *d, int op) + { + switch ( op ) + { +@@ -697,7 +697,6 @@ static int cf_check flask_domctl(struct + return -EILSEQ; + + /* These have individual XSM hooks (common/domctl.c) */ +- case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_set_target: + + #ifdef CONFIG_X86 +@@ -745,6 +744,9 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_setdomainhandle: + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE); + ++ case XEN_DOMCTL_scheduler_op: ++ return flask_domctl_scheduler_op(d, op->u.scheduler_op.cmd); ++ + case XEN_DOMCTL_set_ext_vcpucontext: + case XEN_DOMCTL_set_vcpu_msrs: + case XEN_DOMCTL_setvcpucontext: +@@ -1884,7 +1886,6 @@ static const struct xsm_ops __initconst_ + .security_domaininfo = flask_security_domaininfo, + .domain_create = flask_domain_create, + .getdomaininfo = flask_getdomaininfo, +- .domctl_scheduler_op = flask_domctl_scheduler_op, + #ifdef CONFIG_SYSCTL + .sysctl_scheduler_op = flask_sysctl_scheduler_op, + #endif diff --git a/xsa492-4.21-17.patch b/xsa492-4.21-17.patch new file mode 100644 index 0000000..99542df --- /dev/null +++ b/xsa492-4.21-17.patch @@ -0,0 +1,124 @@ +From: Jan Beulich +Subject: domctl/XSM: drop shadow_control_op hook + +Integrate the checking with xsm_domctl(), now that it has the full op +struct passed. As a positive side effect, permissions are then checked at +the same early point with and without Flask. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith + +--- a/xen/arch/x86/mm/paging.c ++++ b/xen/arch/x86/mm/paging.c +@@ -677,10 +677,6 @@ int paging_domctl(struct domain *d, stru + return -EBUSY; + } + +- rc = xsm_shadow_control(XSM_HOOK, d, sc->op); +- if ( rc ) +- return rc; +- + /* Code to handle log-dirty. Note that some log dirty operations + * piggy-back on shadow operations. For example, when + * XEN_DOMCTL_SHADOW_OP_OFF is called, it first checks whether log dirty +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -682,13 +682,6 @@ static XSM_INLINE int cf_check xsm_do_mc + return xsm_default_action(action, current->domain, NULL); + } + +-static XSM_INLINE int cf_check xsm_shadow_control( +- XSM_DEFAULT_ARG struct domain *d, uint32_t op) +-{ +- XSM_ASSERT_ACTION(XSM_HOOK); +- return xsm_default_action(action, current->domain, d); +-} +- + static XSM_INLINE int cf_check xsm_mem_sharing_op( + XSM_DEFAULT_ARG struct domain *d, struct domain *cd, int op) + { +--- a/xen/include/xsm/xsm.h ++++ b/xen/include/xsm/xsm.h +@@ -172,7 +172,6 @@ struct xsm_ops { + + #ifdef CONFIG_X86 + int (*do_mca)(void); +- int (*shadow_control)(struct domain *d, uint32_t op); + int (*mem_sharing_op)(struct domain *d, struct domain *cd, int op); + int (*apic)(struct domain *d, int cmd); + int (*machine_memory_map)(void); +@@ -680,12 +679,6 @@ static inline int xsm_do_mca(xsm_default + return alternative_call(xsm_ops.do_mca); + } + +-static inline int xsm_shadow_control( +- xsm_default_t def, struct domain *d, uint32_t op) +-{ +- return alternative_call(xsm_ops.shadow_control, d, op); +-} +- + static inline int xsm_mem_sharing_op( + xsm_default_t def, struct domain *d, struct domain *cd, int op) + { +--- a/xen/xsm/dummy.c ++++ b/xen/xsm/dummy.c +@@ -130,7 +130,6 @@ static const struct xsm_ops __initconst_ + .platform_op = xsm_platform_op, + #ifdef CONFIG_X86 + .do_mca = xsm_do_mca, +- .shadow_control = xsm_shadow_control, + .mem_sharing_op = xsm_mem_sharing_op, + .apic = xsm_apic, + .machine_memory_map = xsm_machine_memory_map, +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -40,6 +40,7 @@ + + #ifdef CONFIG_X86 + #include ++static int flask_shadow_control(struct domain *d, unsigned int op); + #else + #define pv_shim false + #endif +@@ -699,10 +700,6 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_set_target: + +-#ifdef CONFIG_X86 +- /* These have individual XSM hooks (arch/x86/domctl.c) */ +- case XEN_DOMCTL_shadow_op: +-#endif + #ifdef CONFIG_HAS_PASSTHROUGH + /* + * These have individual XSM hooks +@@ -787,6 +784,11 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_get_address_size: + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETADDRSIZE); + ++#ifdef CONFIG_X86 ++ case XEN_DOMCTL_shadow_op: ++ return flask_shadow_control(d, op->u.shadow_op.op); ++#endif ++ + case XEN_DOMCTL_mem_sharing_op: + return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING); + +@@ -1603,7 +1605,7 @@ static int cf_check flask_do_mca(void) + return domain_has_xen(current->domain, XEN__MCA_OP); + } + +-static int cf_check flask_shadow_control(struct domain *d, uint32_t op) ++static int flask_shadow_control(struct domain *d, unsigned int op) + { + uint32_t perm; + +@@ -1999,7 +2001,6 @@ static const struct xsm_ops __initconst_ + .platform_op = flask_platform_op, + #ifdef CONFIG_X86 + .do_mca = flask_do_mca, +- .shadow_control = flask_shadow_control, + .mem_sharing_op = flask_mem_sharing_op, + .apic = flask_apic, + .machine_memory_map = flask_machine_memory_map, diff --git a/xsa492-4.21-18.patch b/xsa492-4.21-18.patch new file mode 100644 index 0000000..1d82124 --- /dev/null +++ b/xsa492-4.21-18.patch @@ -0,0 +1,94 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_get_device_group without acquiring domctl lock + +iommu_get_device_group() uses its own locking. Thus, with caller side +locking irrelevant, it can as well be called with the domctl lock not +held. + +Move the handling not only ahead of acquiring the lock, but also ahead +of the XSM check, leveraging that the sub-op has its own hook. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -513,6 +513,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + /* Other sub-ops handled further down. */ + break; + ++ case XEN_DOMCTL_get_device_group: ++ ret = iommu_do_domctl(op, d, u_domctl); ++ goto domctl_out_unlock_domonly; ++ + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_gsi_permission: +@@ -918,7 +922,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + case XEN_DOMCTL_assign_device: + case XEN_DOMCTL_test_assign_device: + case XEN_DOMCTL_deassign_device: +- case XEN_DOMCTL_get_device_group: + ret = iommu_do_domctl(op, d, u_domctl); + break; + +--- a/xen/drivers/passthrough/pci.c ++++ b/xen/drivers/passthrough/pci.c +@@ -1620,7 +1620,7 @@ static int iommu_get_device_group( + if ( (pdev->seg != seg) || ((b == bus) && (df == devfn)) ) + continue; + +- if ( xsm_get_device_group(XSM_HOOK, (seg << 16) | (b << 8) | df) ) ++ if ( xsm_get_device_group(XSM_PRIV, (seg << 16) | (b << 8) | df) ) + continue; + + sdev_id = iommu_call(ops, get_device_group_id, seg, b, df); +@@ -1690,7 +1690,7 @@ int iommu_do_pci_domctl( + u32 max_sdevs; + XEN_GUEST_HANDLE_64(uint32) sdevs; + +- ret = xsm_get_device_group(XSM_HOOK, domctl->u.get_device_group.machine_sbdf); ++ ret = xsm_get_device_group(XSM_PRIV, domctl->u.get_device_group.machine_sbdf); + if ( ret ) + break; + +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -162,6 +162,7 @@ static XSM_INLINE int cf_check xsm_domct + { + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: ++ case XEN_DOMCTL_get_device_group: + case XEN_DOMCTL_get_domain_state: + case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_iomem_permission: +@@ -401,7 +402,7 @@ static XSM_INLINE int cf_check xsm_get_v + static XSM_INLINE int cf_check xsm_get_device_group( + XSM_DEFAULT_ARG uint32_t machine_bdf) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, NULL); + } + +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -686,6 +686,7 @@ static int cf_check flask_domctl(struct + /* These have individual XSM hooks and don't make it here. */ + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_getdomaininfo: ++ case XEN_DOMCTL_get_device_group: + case XEN_DOMCTL_get_domain_state: + case XEN_DOMCTL_gsi_permission: + case XEN_DOMCTL_iomem_permission: +@@ -705,7 +706,6 @@ static int cf_check flask_domctl(struct + * These have individual XSM hooks + * (drivers/passthrough/{pci,device_tree.c) + */ +- case XEN_DOMCTL_get_device_group: + case XEN_DOMCTL_test_assign_device: + case XEN_DOMCTL_assign_device: + case XEN_DOMCTL_deassign_device: diff --git a/xsa492-4.21-19.patch b/xsa492-4.21-19.patch new file mode 100644 index 0000000..54a1117 --- /dev/null +++ b/xsa492-4.21-19.patch @@ -0,0 +1,378 @@ +From: Jan Beulich +Subject: domctl/XSM: drop {,de}assign_{,dt}device hooks + +Integrate the checking with xsm_domctl(). As a positive side effect, +permissions are then checked at the same early point with and without +Flask. As the DT device path needs fetching earlier (but must not be +double fetched), cache it in a private field of the public interface +struct. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -325,6 +325,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + case XEN_DOMCTL_deassign_device: + if ( op->domain == DOMID_IO ) + { ++#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY ++ if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT ) ++ op->u.assign_device.u.dt.dev = NULL; ++#endif + d = dom_io; + break; + } +@@ -332,6 +336,11 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + return -ESRCH; + fallthrough; + case XEN_DOMCTL_test_assign_device: ++#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY ++ if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT ) ++ op->u.assign_device.u.dt.dev = NULL; ++ fallthrough; ++#endif + case XEN_DOMCTL_vm_event_op: + if ( op->domain == DOMID_INVALID ) + { +--- a/xen/drivers/passthrough/device_tree.c ++++ b/xen/drivers/passthrough/device_tree.c +@@ -340,15 +340,15 @@ int iommu_do_dt_domctl(struct xen_domctl + if ( (d && d->is_dying) || domctl->u.assign_device.flags ) + break; + +- ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, +- domctl->u.assign_device.u.dt.size, +- &dev); +- if ( ret ) +- break; +- +- ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev)); +- if ( ret ) +- break; ++ dev = domctl->u.assign_device.u.dt.dev; ++ if ( !dev ) ++ { ++ ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, ++ domctl->u.assign_device.u.dt.size, ++ &dev); ++ if ( ret ) ++ break; ++ } + + if ( domctl->cmd == XEN_DOMCTL_test_assign_device ) + { +@@ -396,15 +396,15 @@ int iommu_do_dt_domctl(struct xen_domctl + if ( domctl->u.assign_device.flags ) + break; + +- ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, +- domctl->u.assign_device.u.dt.size, +- &dev); +- if ( ret ) +- break; +- +- ret = xsm_deassign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev)); +- if ( ret ) +- break; ++ dev = domctl->u.assign_device.u.dt.dev; ++ if ( !dev ) ++ { ++ ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path, ++ domctl->u.assign_device.u.dt.size, ++ &dev); ++ if ( ret ) ++ break; ++ } + + if ( d == dom_io ) + { +--- a/xen/drivers/passthrough/pci.c ++++ b/xen/drivers/passthrough/pci.c +@@ -1740,10 +1740,6 @@ int iommu_do_pci_domctl( + + machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf; + +- ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf); +- if ( ret ) +- break; +- + seg = machine_sbdf >> 16; + bus = PCI_BUS(machine_sbdf); + devfn = PCI_DEVFN(machine_sbdf); +@@ -1785,10 +1781,6 @@ int iommu_do_pci_domctl( + + machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf; + +- ret = xsm_deassign_device(XSM_HOOK, d, machine_sbdf); +- if ( ret ) +- break; +- + seg = machine_sbdf >> 16; + bus = PCI_BUS(machine_sbdf); + devfn = PCI_DEVFN(machine_sbdf); +--- a/xen/include/public/domctl.h ++++ b/xen/include/public/domctl.h +@@ -575,7 +575,10 @@ struct xen_domctl_assign_device { + } pci; + struct { + uint32_t size; /* Length of the path */ +- XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */ ++ XEN_GUEST_HANDLE_64(char) path; /* Path to the device tree node */ ++#ifdef __XEN__ ++ struct dt_device_node *dev; /* Resolved device node of the above */ ++#endif + } dt; + } u; + }; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -405,40 +405,8 @@ static XSM_INLINE int cf_check xsm_get_d + XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, NULL); + } +- +-static XSM_INLINE int cf_check xsm_assign_device( +- XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf) +-{ +- XSM_ASSERT_ACTION(XSM_HOOK); +- return xsm_default_action(action, current->domain, d); +-} +- +-static XSM_INLINE int cf_check xsm_deassign_device( +- XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf) +-{ +- XSM_ASSERT_ACTION(XSM_HOOK); +- return xsm_default_action(action, current->domain, d); +-} +- + #endif /* HAS_PASSTHROUGH && HAS_PCI */ + +-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY) +-static XSM_INLINE int cf_check xsm_assign_dtdevice( +- XSM_DEFAULT_ARG struct domain *d, const char *dtpath) +-{ +- XSM_ASSERT_ACTION(XSM_HOOK); +- return xsm_default_action(action, current->domain, d); +-} +- +-static XSM_INLINE int cf_check xsm_deassign_dtdevice( +- XSM_DEFAULT_ARG struct domain *d, const char *dtpath) +-{ +- XSM_ASSERT_ACTION(XSM_HOOK); +- return xsm_default_action(action, current->domain, d); +-} +- +-#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE_DISCOVERY */ +- + static XSM_INLINE int cf_check xsm_resource_plug_core(XSM_DEFAULT_VOID) + { + XSM_ASSERT_ACTION(XSM_HOOK); +--- a/xen/include/xsm/xsm.h ++++ b/xen/include/xsm/xsm.h +@@ -124,13 +124,6 @@ struct xsm_ops { + + #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI) + int (*get_device_group)(uint32_t machine_bdf); +- int (*assign_device)(struct domain *d, uint32_t machine_bdf); +- int (*deassign_device)(struct domain *d, uint32_t machine_bdf); +-#endif +- +-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY) +- int (*assign_dtdevice)(struct domain *d, const char *dtpath); +- int (*deassign_dtdevice)(struct domain *d, const char *dtpath); + #endif + + int (*resource_plug_core)(void); +@@ -533,35 +526,8 @@ static inline int xsm_get_device_group(x + { + return alternative_call(xsm_ops.get_device_group, machine_bdf); + } +- +-static inline int xsm_assign_device( +- xsm_default_t def, struct domain *d, uint32_t machine_bdf) +-{ +- return alternative_call(xsm_ops.assign_device, d, machine_bdf); +-} +- +-static inline int xsm_deassign_device( +- xsm_default_t def, struct domain *d, uint32_t machine_bdf) +-{ +- return alternative_call(xsm_ops.deassign_device, d, machine_bdf); +-} + #endif /* HAS_PASSTHROUGH && HAS_PCI) */ + +-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY) +-static inline int xsm_assign_dtdevice( +- xsm_default_t def, struct domain *d, const char *dtpath) +-{ +- return alternative_call(xsm_ops.assign_dtdevice, d, dtpath); +-} +- +-static inline int xsm_deassign_dtdevice( +- xsm_default_t def, struct domain *d, const char *dtpath) +-{ +- return alternative_call(xsm_ops.deassign_dtdevice, d, dtpath); +-} +- +-#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE_DISCOVERY */ +- + static inline int xsm_resource_plug_pci(xsm_default_t def, uint32_t machine_bdf) + { + return alternative_call(xsm_ops.resource_plug_pci, machine_bdf); +--- a/xen/xsm/dummy.c ++++ b/xen/xsm/dummy.c +@@ -81,13 +81,6 @@ static const struct xsm_ops __initconst_ + + #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI) + .get_device_group = xsm_get_device_group, +- .assign_device = xsm_assign_device, +- .deassign_device = xsm_deassign_device, +-#endif +- +-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY) +- .assign_dtdevice = xsm_assign_dtdevice, +- .deassign_dtdevice = xsm_deassign_dtdevice, + #endif + + .resource_plug_core = xsm_resource_plug_core, +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -45,6 +45,17 @@ static int flask_shadow_control(struct d + #define pv_shim false + #endif + ++#ifdef CONFIG_HAS_PASSTHROUGH ++#ifdef CONFIG_HAS_PCI ++static int flask_assign_device(struct domain *d, unsigned int machine_bdf); ++static int flask_deassign_device(struct domain *d, unsigned int machine_bdf); ++#endif ++#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY ++static int flask_assign_dtdevice(struct domain *d, const char *dtpath); ++static int flask_deassign_dtdevice(struct domain *d, const char *dtpath); ++#endif ++#endif /* CONFIG_HAS_PASSTHROUGH */ ++ + static uint32_t domain_sid(const struct domain *dom) + { + struct domain_security_struct *dsec = dom->ssid; +@@ -700,16 +711,6 @@ static int cf_check flask_domctl(struct + + /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_set_target: +- +-#ifdef CONFIG_HAS_PASSTHROUGH +- /* +- * These have individual XSM hooks +- * (drivers/passthrough/{pci,device_tree.c) +- */ +- case XEN_DOMCTL_test_assign_device: +- case XEN_DOMCTL_assign_device: +- case XEN_DOMCTL_deassign_device: +-#endif + return 0; + + case XEN_DOMCTL_destroydomain: +@@ -789,6 +790,49 @@ static int cf_check flask_domctl(struct + return flask_shadow_control(d, op->u.shadow_op.op); + #endif + ++#ifdef CONFIG_HAS_PASSTHROUGH ++ ++ case XEN_DOMCTL_test_assign_device: ++ case XEN_DOMCTL_assign_device: ++ case XEN_DOMCTL_deassign_device: ++ switch ( op->u.assign_device.dev ) ++ { ++#ifdef CONFIG_HAS_PCI ++ case XEN_DOMCTL_DEV_PCI: ++ return op->cmd != XEN_DOMCTL_deassign_device ++ ? flask_assign_device( ++ d, op->u.assign_device.u.pci.machine_sbdf) ++ : flask_deassign_device( ++ d, op->u.assign_device.u.pci.machine_sbdf); ++#endif ++ ++#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY ++ case XEN_DOMCTL_DEV_DT: ++ { ++ struct dt_device_node *dev; ++ int ret = dt_find_node_by_gpath(op->u.assign_device.u.dt.path, ++ op->u.assign_device.u.dt.size, ++ &dev); ++ ++ if ( ret ) ++ return ret; ++ ++ op->u.assign_device.u.dt.dev = dev; ++ ++ return op->cmd != XEN_DOMCTL_deassign_device ++ ? flask_assign_dtdevice(d, dt_node_full_name(dev)) ++ : flask_deassign_dtdevice(d, dt_node_full_name(dev)); ++ } ++#endif ++ ++ default: ++ /* Unknown type. */ ++ break; ++ } ++ return avc_unknown_permission("assign_device", op->cmd); ++ ++#endif /* CONFIG_HAS_PASSTHROUGH */ ++ + case XEN_DOMCTL_mem_sharing_op: + return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING); + +@@ -1416,7 +1460,7 @@ static int flask_test_assign_device(uint + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL); + } + +-static int cf_check flask_assign_device(struct domain *d, uint32_t machine_bdf) ++static int flask_assign_device(struct domain *d, uint32_t machine_bdf) + { + uint32_t dsid, rsid; + int rc = -EPERM; +@@ -1446,7 +1490,7 @@ static int cf_check flask_assign_device( + return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad); + } + +-static int cf_check flask_deassign_device( ++static int flask_deassign_device( + struct domain *d, uint32_t machine_bdf) + { + uint32_t rsid; +@@ -1478,7 +1522,7 @@ static int flask_test_assign_dtdevice(co + NULL); + } + +-static int cf_check flask_assign_dtdevice(struct domain *d, const char *dtpath) ++static int flask_assign_dtdevice(struct domain *d, const char *dtpath) + { + uint32_t dsid, rsid; + int rc = -EPERM; +@@ -1508,7 +1552,7 @@ static int cf_check flask_assign_dtdevic + return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad); + } + +-static int cf_check flask_deassign_dtdevice( ++static int flask_deassign_dtdevice( + struct domain *d, const char *dtpath) + { + uint32_t rsid; +@@ -1989,13 +2033,6 @@ static const struct xsm_ops __initconst_ + + #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI) + .get_device_group = flask_get_device_group, +- .assign_device = flask_assign_device, +- .deassign_device = flask_deassign_device, +-#endif +- +-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY) +- .assign_dtdevice = flask_assign_dtdevice, +- .deassign_dtdevice = flask_deassign_dtdevice, + #endif + + .platform_op = flask_platform_op, diff --git a/xsa492-4.21-20.patch b/xsa492-4.21-20.patch new file mode 100644 index 0000000..bfd10a9 --- /dev/null +++ b/xsa492-4.21-20.patch @@ -0,0 +1,123 @@ +From: Jan Beulich +Subject: domctl: handle XEN_DOMCTL_set_target without acquiring domctl lock + +The only locking required here is that between checking d->target and +setting it. To avoid the need for an explicit lock, use cmpxchgptr() to +update d->target. + +Move the handling not only ahead of acquiring the lock, but also ahead +of the XSM check, leveraging that the sub-op has its own hook. + +This is part of XSA-492. + +Signed-off-by: Jan Beulich +Acked-by: Daniel P. Smith +Reviewed-by: Roger Pau Monné + +--- a/xen/common/domctl.c ++++ b/xen/common/domctl.c +@@ -505,6 +505,30 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + } + #endif + ++ case XEN_DOMCTL_set_target: ++ { ++ struct domain *e = get_domain_by_id(op->u.set_target.target); ++ ++ ret = -ESRCH; ++ if ( !e ) ++ goto domctl_out_unlock_domonly; ++ ++ if ( d == e ) ++ ret = -EINVAL; ++ else if ( !is_hvm_domain(e) ) ++ ret = -EOPNOTSUPP; ++ else ++ ret = xsm_set_target(XSM_PRIV, d, e); ++ ++ /* Hold reference on @e until we destroy @d. */ ++ if ( !ret && cmpxchgptr(&d->target, NULL, e) ) ++ ret = -EINVAL; ++ ++ if ( ret ) ++ put_domain(e); ++ goto domctl_out_unlock_domonly; ++ } ++ + case XEN_DOMCTL_vm_event_op: + if ( op->u.vm_event_op.op == XEN_VM_EVENT_GET_VERSION ) + { +@@ -844,36 +868,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe + domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds); + break; + +- case XEN_DOMCTL_set_target: +- { +- struct domain *e; +- +- ret = -ESRCH; +- e = get_domain_by_id(op->u.set_target.target); +- if ( e == NULL ) +- break; +- +- ret = -EINVAL; +- if ( (d == e) || (d->target != NULL) ) +- { +- put_domain(e); +- break; +- } +- +- ret = -EOPNOTSUPP; +- if ( is_hvm_domain(e) ) +- ret = xsm_set_target(XSM_HOOK, d, e); +- if ( ret ) +- { +- put_domain(e); +- break; +- } +- +- /* Hold reference on @e until we destroy @d. */ +- d->target = e; +- break; +- } +- + case XEN_DOMCTL_subscribe: + d->suspend_evtchn = op->u.subscribe.port; + break; +--- a/xen/include/xsm/dummy.h ++++ b/xen/include/xsm/dummy.h +@@ -150,7 +150,7 @@ static XSM_INLINE int cf_check xsm_sysct + static XSM_INLINE int cf_check xsm_set_target( + XSM_DEFAULT_ARG struct domain *d, struct domain *e) + { +- XSM_ASSERT_ACTION(XSM_HOOK); ++ XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, NULL); + } + +@@ -170,6 +170,7 @@ static XSM_INLINE int cf_check xsm_domct + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_memory_mapping: ++ case XEN_DOMCTL_set_target: + case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); + return -EILSEQ; +--- a/xen/xsm/flask/hooks.c ++++ b/xen/xsm/flask/hooks.c +@@ -705,14 +705,11 @@ static int cf_check flask_domctl(struct + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_memory_mapping: ++ case XEN_DOMCTL_set_target: + case XEN_DOMCTL_unbind_pt_irq: + ASSERT_UNREACHABLE(); + return -EILSEQ; + +- /* These have individual XSM hooks (common/domctl.c) */ +- case XEN_DOMCTL_set_target: +- return 0; +- + case XEN_DOMCTL_destroydomain: + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__DESTROY); + diff --git a/xsa493-4.21-01.patch b/xsa493-4.21-01.patch new file mode 100644 index 0000000..c06b9a5 --- /dev/null +++ b/xsa493-4.21-01.patch @@ -0,0 +1,311 @@ +From 2e21b5301765de353c06081eee953255bf327176 Mon Sep 17 00:00:00 2001 +From: Michal Orzel +Date: Tue, 14 Apr 2026 10:11:24 +0200 +Subject: xen/arm64: flushtlb: Optimize ARM64_WORKAROUND_REPEAT_TLBI + +The ARM64_WORKAROUND_REPEAT_TLBI workaround is used to mitigate several +errata where broadcast TLBI;DSB sequences don't provide all the +architecturally required synchronization. The workaround performs more +work than necessary, and can have significant overhead. This patch +optimizes the workaround, as explained below. + +1. All relevant errata only affect the ordering and/or completion of + memory accesses which have been translated by an invalidated TLB + entry. The actual invalidation of TLB entries is unaffected. + +2. The existing workaround is applied to both broadcast and local TLB + invalidation, whereas for all relevant errata it is only necessary to + apply a workaround for broadcast invalidation. + +3. The existing workaround replaces every TLBI with a TLBI;DSB;TLBI + sequence, whereas for all relevant errata it is only necessary to + execute a single additional TLBI;DSB sequence after any number of + TLBIs are completed by a DSB. + + For example, for a sequence of batched TLBIs: + + TLBI [, ] + TLBI [, ] + TLBI [, ] + DSB ISH + + ... the existing workaround will expand this to: + + TLBI [, ] + DSB ISH // additional + TLBI [, ] // additional + TLBI [, ] + DSB ISH // additional + TLBI [, ] // additional + TLBI [, ] + DSB ISH // additional + TLBI [, ] // additional + DSB ISH + + ... whereas it is sufficient to have: + + TLBI [, ] + TLBI [, ] + TLBI [, ] + DSB ISH + TLBI [, ] // additional + DSB ISH // additional + + Using a single additional TLBI and DSB at the end of the sequence can + have significantly lower overhead as each DSB which completes a TLBI + must synchronize with other PEs in the system, with potential + performance effects both locally and system-wide. + +4. The existing workaround repeats each specific TLBI operation, whereas + for all relevant errata it is sufficient for the additional TLBI to + use *any* operation which will be broadcast, regardless of which + translation regime or stage of translation the operation applies to. + + For example, for a single TLBI: + + TLBI ALLE2IS + DSB ISH + + ... the existing workaround will expand this to: + + TLBI ALLE2IS + DSB ISH + TLBI ALLE2IS // additional + DSB ISH // additional + + ... whereas it is sufficient to have: + + TLBI ALLE2IS + DSB ISH + TLBI VALE1IS, XZR // additional + DSB ISH // additional + + As the additional TLBI doesn't have to match a specific earlier TLBI, + the additional TLBI can be implemented in separate code, with no + memory of the earlier TLBIs. The additional TLBI can also use a + cheaper TLBI operation. + +5. The existing workaround is applied to both Stage-1 and Stage-2 TLB + invalidation, whereas for all relevant errata it is only necessary to + apply a workaround for Stage-1 invalidation. + + Architecturally, TLBI operations which invalidate only Stage-2 + information (e.g. IPAS2E1IS) are not required to invalidate TLB + entries which combine information from Stage-1 and Stage-2 + translation table entries, and consequently may not complete memory + accesses translated by those combined entries. In these cases, + completion of memory accesses is only guaranteed after subsequent + invalidation of Stage-1 information (e.g. VMALLE1IS). + +Rework the workaround logic as follows: + - add TLB_HELPER_LOCAL() to be used for local TLB ops without a + workaround, + - modify TLB_HELPER() workaround to use tlbi vale2is, xzr as a second + TLBI, + - drop TLB_HELPER_VA(). It's used only by __flush_xen_tlb_one_local + which is local and does not need workaround and by + __flush_xen_tlb_one. In the latter case, since it's used in a loop, + we don't need a workaround in the middle. Add __tlb_repeat_sync with + a workaround to be used at the end after DSB and before final ISB, + - TLBI VALE2IS passing XZR is used as an additional TLBI. While there is + an identity mapping there, it's used very rarely. The performance + impact is therefore negligible. If things change in the future, we + can revisit the decision. + +Signed-off-by: Michal Orzel +Reviewed-by: Luca Fancellu +Reviewed-by: Julien Grall +(cherry picked from commit 7c502d7591519135765b8041cbd1c70e56e5a0b9) + +diff --git a/xen/arch/arm/include/asm/arm32/flushtlb.h b/xen/arch/arm/include/asm/arm32/flushtlb.h +index 61c25a318998..5483be08fbbe 100644 +--- a/xen/arch/arm/include/asm/arm32/flushtlb.h ++++ b/xen/arch/arm/include/asm/arm32/flushtlb.h +@@ -57,6 +57,9 @@ static inline void __flush_xen_tlb_one(vaddr_t va) + asm volatile(STORE_CP32(0, TLBIMVAHIS) : : "r" (va) : "memory"); + } + ++/* Only for ARM64_WORKAROUND_REPEAT_TLBI */ ++static inline void __tlb_repeat_sync(void) {} ++ + #endif /* __ASM_ARM_ARM32_FLUSHTLB_H__ */ + /* + * Local variables: +diff --git a/xen/arch/arm/include/asm/arm64/flushtlb.h b/xen/arch/arm/include/asm/arm64/flushtlb.h +index 3b99c11b50d1..1606b26bf28a 100644 +--- a/xen/arch/arm/include/asm/arm64/flushtlb.h ++++ b/xen/arch/arm/include/asm/arm64/flushtlb.h +@@ -12,9 +12,14 @@ + * ARM64_WORKAROUND_REPEAT_TLBI: + * Modification of the translation table for a virtual address might lead to + * read-after-read ordering violation. +- * The workaround repeats TLBI+DSB ISH operation for all the TLB flush +- * operations. While this is strictly not necessary, we don't want to +- * take any risk. ++ * The workaround repeats TLBI+DSB ISH operation for broadcast TLB flush ++ * operations. The workaround is not needed for local operations. ++ * ++ * It is sufficient for the additional TLBI to use *any* operation which will ++ * be broadcast, regardless of which translation regime or stage of translation ++ * the operation applies to. TLBI VALE2IS is used passing XZR. While there is ++ * an identity mapping there, it's only used during suspend/resume, CPU on/off, ++ * so the impact (performance if any) is negligible. + * + * For Xen page-tables the ISB will discard any instructions fetched + * from the old mappings. +@@ -26,69 +31,90 @@ + * Note that for local TLB flush, using non-shareable (nsh) is sufficient + * (see D5-4929 in ARM DDI 0487H.a). Although, the memory barrier in + * for the workaround is left as inner-shareable to match with Linux +- * v6.1-rc8. ++ * v6.19. + */ +-#define TLB_HELPER(name, tlbop, sh) \ ++#define TLB_HELPER_LOCAL(name, tlbop) \ + static inline void name(void) \ + { \ + asm_inline volatile ( \ +- "dsb " # sh "st;" \ ++ "dsb nshst;" \ + "tlbi " # tlbop ";" \ +- ALTERNATIVE( \ +- "nop; nop;", \ +- "dsb ish;" \ +- "tlbi " # tlbop ";", \ +- ARM64_WORKAROUND_REPEAT_TLBI, \ +- CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ +- "dsb " # sh ";" \ ++ "dsb nsh;" \ + "isb;" \ + : : : "memory"); \ + } + +-/* +- * FLush TLB by VA. This will likely be used in a loop, so the caller +- * is responsible to use the appropriate memory barriers before/after +- * the sequence. +- * +- * See above about the ARM64_WORKAROUND_REPEAT_TLBI sequence. +- */ +-#define TLB_HELPER_VA(name, tlbop) \ +-static inline void name(vaddr_t va) \ +-{ \ +- asm_inline volatile ( \ +- "tlbi " # tlbop ", %0;" \ +- ALTERNATIVE( \ +- "nop; nop;", \ +- "dsb ish;" \ +- "tlbi " # tlbop ", %0;", \ +- ARM64_WORKAROUND_REPEAT_TLBI, \ +- CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ +- : : "r" (va >> PAGE_SHIFT) : "memory"); \ ++#define TLB_HELPER(name, tlbop) \ ++static inline void name(void) \ ++{ \ ++ asm_inline volatile ( \ ++ "dsb ishst;" \ ++ "tlbi " # tlbop ";" \ ++ ALTERNATIVE( \ ++ "nop; nop;", \ ++ "dsb ish;" \ ++ "tlbi vale2is, xzr;", \ ++ ARM64_WORKAROUND_REPEAT_TLBI, \ ++ CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ ++ "dsb ish;" \ ++ "isb;" \ ++ : : : "memory"); \ + } + + /* Flush local TLBs, current VMID only. */ +-TLB_HELPER(flush_guest_tlb_local, vmalls12e1, nsh) ++TLB_HELPER_LOCAL(flush_guest_tlb_local, vmalls12e1) + + /* Flush innershareable TLBs, current VMID only */ +-TLB_HELPER(flush_guest_tlb, vmalls12e1is, ish) ++TLB_HELPER(flush_guest_tlb, vmalls12e1is) + + /* Flush local TLBs, all VMIDs, non-hypervisor mode */ +-TLB_HELPER(flush_all_guests_tlb_local, alle1, nsh) ++TLB_HELPER_LOCAL(flush_all_guests_tlb_local, alle1) + + /* Flush innershareable TLBs, all VMIDs, non-hypervisor mode */ +-TLB_HELPER(flush_all_guests_tlb, alle1is, ish) ++TLB_HELPER(flush_all_guests_tlb, alle1is) + + /* Flush all hypervisor mappings from the TLB of the local processor. */ +-TLB_HELPER(flush_xen_tlb_local, alle2, nsh) ++TLB_HELPER_LOCAL(flush_xen_tlb_local, alle2) ++ ++#undef TLB_HELPER_LOCAL ++#undef TLB_HELPER ++ ++/* ++ * FLush TLB by VA. This will likely be used in a loop, so the caller ++ * is responsible to use the appropriate memory barriers before/after ++ * the sequence. ++ */ + + /* Flush TLB of local processor for address va. */ +-TLB_HELPER_VA(__flush_xen_tlb_one_local, vae2) ++static inline void __flush_xen_tlb_one_local(vaddr_t va) ++{ ++ asm_inline volatile ( ++ "tlbi vae2, %0" : : "r" (va >> PAGE_SHIFT) : "memory"); ++} + + /* Flush TLB of all processors in the inner-shareable domain for address va. */ +-TLB_HELPER_VA(__flush_xen_tlb_one, vae2is) ++static inline void __flush_xen_tlb_one(vaddr_t va) ++{ ++ asm_inline volatile ( ++ "tlbi vae2is, %0" : : "r" (va >> PAGE_SHIFT) : "memory"); ++} + +-#undef TLB_HELPER +-#undef TLB_HELPER_VA ++/* ++ * ARM64_WORKAROUND_REPEAT_TLBI: ++ * For all relevant erratas it is only necessary to execute a single ++ * additional TLBI;DSB sequence after any number of TLBIs are completed by DSB. ++ */ ++static inline void __tlb_repeat_sync(void) ++{ ++ asm_inline volatile ( ++ ALTERNATIVE( ++ "nop; nop;", ++ "tlbi vale2is, xzr;" ++ "dsb ish;", ++ ARM64_WORKAROUND_REPEAT_TLBI, ++ CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) ++ : : : "memory"); ++} + + #endif /* __ASM_ARM_ARM64_FLUSHTLB_H__ */ + /* +diff --git a/xen/arch/arm/include/asm/flushtlb.h b/xen/arch/arm/include/asm/flushtlb.h +index e45fb6d97b02..c292c3c00d29 100644 +--- a/xen/arch/arm/include/asm/flushtlb.h ++++ b/xen/arch/arm/include/asm/flushtlb.h +@@ -65,6 +65,7 @@ static inline void flush_xen_tlb_range_va(vaddr_t va, + va += PAGE_SIZE; + } + dsb(ish); /* Ensure the TLB invalidation has completed */ ++ __tlb_repeat_sync(); + isb(); + } + +diff --git a/xen/arch/arm/include/asm/mmu/layout.h b/xen/arch/arm/include/asm/mmu/layout.h +index 19c0ec63a59a..feafc14ebfda 100644 +--- a/xen/arch/arm/include/asm/mmu/layout.h ++++ b/xen/arch/arm/include/asm/mmu/layout.h +@@ -23,6 +23,10 @@ + * + * Reserved to identity map Xen + * ++ * Note: As part of ARM64_WORKAROUND_REPEAT_TLBI, VA 0 is used for an extra ++ * TLBI operation given its rare use (only identity mapping) and thus ++ * negligible performance impact. ++ * + * 0x00000a0000000000 - 0x00000a7fffffffff (512GB, L0 slot [20]) + * (Relative offsets) + * 0 - 2M Unmapped diff --git a/xsa493-4.21-02.patch b/xsa493-4.21-02.patch new file mode 100644 index 0000000..f80119c --- /dev/null +++ b/xsa493-4.21-02.patch @@ -0,0 +1,71 @@ +From 7e70b87512c966248b1e8453d9ac54c643c06f44 Mon Sep 17 00:00:00 2001 +From: Michal Orzel +Date: Fri, 22 May 2026 09:35:55 +0200 +Subject: xen/arm: Sync missing definitions for Arm CPUs with Linux + +Synchronize with Linux kernel 7.0 definitions for the following CPUs: + - Cortex-A76AE, + - Cortex-A78AE, + - Cortex-X1C, + - Cortex-X3, + - Neoverse-V2, + - Cortex-X4, + - Neoverse-V3AE, + - Neoverse-V3, + - Cortex-X925. + +These will be used for errata detection in subsequent patches. + +Signed-off-by: Michal Orzel +Reviewed-by: Julien Grall + +diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h +index ec23fd098b63..907778683b08 100644 +--- a/xen/arch/arm/include/asm/processor.h ++++ b/xen/arch/arm/include/asm/processor.h +@@ -89,13 +89,22 @@ + #define ARM_CPU_PART_CORTEX_A76 0xD0B + #define ARM_CPU_PART_NEOVERSE_N1 0xD0C + #define ARM_CPU_PART_CORTEX_A77 0xD0D ++#define ARM_CPU_PART_CORTEX_A76AE 0xD0E + #define ARM_CPU_PART_NEOVERSE_V1 0xD40 + #define ARM_CPU_PART_CORTEX_A78 0xD41 ++#define ARM_CPU_PART_CORTEX_A78AE 0xD42 + #define ARM_CPU_PART_CORTEX_X1 0xD44 + #define ARM_CPU_PART_CORTEX_A710 0xD47 + #define ARM_CPU_PART_CORTEX_X2 0xD48 + #define ARM_CPU_PART_NEOVERSE_N2 0xD49 + #define ARM_CPU_PART_CORTEX_A78C 0xD4B ++#define ARM_CPU_PART_CORTEX_X1C 0xD4C ++#define ARM_CPU_PART_CORTEX_X3 0xD4E ++#define ARM_CPU_PART_NEOVERSE_V2 0xD4F ++#define ARM_CPU_PART_CORTEX_X4 0xD82 ++#define ARM_CPU_PART_NEOVERSE_V3AE 0xD83 ++#define ARM_CPU_PART_NEOVERSE_V3 0xD84 ++#define ARM_CPU_PART_CORTEX_X925 0xD85 + + #define MIDR_CORTEX_A12 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A12) + #define MIDR_CORTEX_A17 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A17) +@@ -110,13 +119,22 @@ + #define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76) + #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1) + #define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77) ++#define MIDR_CORTEX_A76AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76AE) + #define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1) + #define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78) ++#define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE) + #define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1) + #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710) + #define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2) + #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2) + #define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C) ++#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C) ++#define MIDR_CORTEX_X3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X3) ++#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2) ++#define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4) ++#define MIDR_NEOVERSE_V3AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3AE) ++#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3) ++#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925) + + /* MPIDR Multiprocessor Affinity Register */ + #define _MPIDR_UP (30) diff --git a/xsa493-4.21-03.patch b/xsa493-4.21-03.patch new file mode 100644 index 0000000..86bae68 --- /dev/null +++ b/xsa493-4.21-03.patch @@ -0,0 +1,37 @@ +From c0f7b40fdbb986b3cf470ed51f3878261e33f9cb Mon Sep 17 00:00:00 2001 +From: Michal Orzel +Date: Fri, 22 May 2026 09:35:56 +0200 +Subject: xen/arm: Add C1-Ultra definitions + +Add processor definitions for C1-Ultra. These will be used for errata +detection in subsequent patches. + +These values can be found in the C1-Ultra TRM: + + https://developer.arm.com/documentation/108014/0100/ + +... in section A.5.1 ("MIDR_EL1, Main ID Register"). + +Signed-off-by: Michal Orzel +Reviewed-by: Julien Grall + +diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h +index 907778683b08..72745cca62bc 100644 +--- a/xen/arch/arm/include/asm/processor.h ++++ b/xen/arch/arm/include/asm/processor.h +@@ -105,6 +105,7 @@ + #define ARM_CPU_PART_NEOVERSE_V3AE 0xD83 + #define ARM_CPU_PART_NEOVERSE_V3 0xD84 + #define ARM_CPU_PART_CORTEX_X925 0xD85 ++#define ARM_CPU_PART_C1_ULTRA 0xD8C + + #define MIDR_CORTEX_A12 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A12) + #define MIDR_CORTEX_A17 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A17) +@@ -135,6 +136,7 @@ + #define MIDR_NEOVERSE_V3AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3AE) + #define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3) + #define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925) ++#define MIDR_C1_ULTRA MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_C1_ULTRA) + + /* MPIDR Multiprocessor Affinity Register */ + #define _MPIDR_UP (30) diff --git a/xsa493-4.21-04.patch b/xsa493-4.21-04.patch new file mode 100644 index 0000000..b59ee74 --- /dev/null +++ b/xsa493-4.21-04.patch @@ -0,0 +1,37 @@ +From 6af67aeca418bffb807424eb3415fab59e581733 Mon Sep 17 00:00:00 2001 +From: Michal Orzel +Date: Fri, 22 May 2026 09:35:57 +0200 +Subject: xen/arm: Add C1-Premium definitions + +Add processor definitions for C1-Premium. These will be used for errata +detection in subsequent patches. + +These values can be found in the C1-Premium TRM: + + https://developer.arm.com/documentation/109416/0100/ + +... in section A.5.1 ("MIDR_EL1, Main ID Register"). + +Signed-off-by: Michal Orzel +Reviewed-by: Julien Grall + +diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h +index 72745cca62bc..25c5762c6706 100644 +--- a/xen/arch/arm/include/asm/processor.h ++++ b/xen/arch/arm/include/asm/processor.h +@@ -106,6 +106,7 @@ + #define ARM_CPU_PART_NEOVERSE_V3 0xD84 + #define ARM_CPU_PART_CORTEX_X925 0xD85 + #define ARM_CPU_PART_C1_ULTRA 0xD8C ++#define ARM_CPU_PART_C1_PREMIUM 0xD90 + + #define MIDR_CORTEX_A12 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A12) + #define MIDR_CORTEX_A17 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A17) +@@ -137,6 +138,7 @@ + #define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3) + #define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925) + #define MIDR_C1_ULTRA MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_C1_ULTRA) ++#define MIDR_C1_PREMIUM MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_C1_PREMIUM) + + /* MPIDR Multiprocessor Affinity Register */ + #define _MPIDR_UP (30) diff --git a/xsa494-4.21.patch b/xsa494-4.21.patch new file mode 100644 index 0000000..d52a0f1 --- /dev/null +++ b/xsa494-4.21.patch @@ -0,0 +1,404 @@ +From 579016a359741044c9076bf0884e1dbab00ab080 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Mon, 16 Mar 2026 11:03:22 +0100 +Subject: [PATCH] x86/mm: accurately track which vCPU page-tables are loaded +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Neither current nor curr_vcpu per-CPU fields accurately track which +page-tables are loaded. There are corner cases when dealing with shadow +paging failures that switch to the idle vCPU page-tables without changing +current or curr_vcpu per-CPU fields. + +Introduce a new per-CPU field that attempts to track which vCPU page-tables +are loaded. Update such tracking when cr3 is changed, and do so in a +region with interrupts disabled, as to avoid handling interrupts with a +mismatch between the vCPU tracking field and the loaded page-tables. + +As a result of this newly more accurate tracking the mapcache override +functionality can be removed: the dom0 PV builder was the only user of it, +and it's updated here to properly signal which vCPU page-tables are loaded +in the calls to switch_cr3_cr4(). + +Note the EFI page-tables have the Xen owned L4 slots copied from the idle +page-tables, so for the effects of the mapcache the EFI page-tables could +use the idle mapcache if it had one. Pass the idle vCPU in the +switch_cr3_cr4() call that switches to the runtime EFI page-tables. + +There are known issues with the use of mapcache in NMI context.  This patch +does not alter the behaviour. + +This is CVE-2026-42488 / XSA-494. + +Fixes: fb0ff49fe9f7 ("x86/shadow: defer releasing of PV's top-level shadow reference") +Signed-off-by: Roger Pau Monné +Acked-by: Andrew Cooper +--- + xen/arch/x86/domain_page.c | 48 ++++++++++++---------------- + xen/arch/x86/flushtlb.c | 5 ++- + xen/arch/x86/include/asm/domain.h | 1 - + xen/arch/x86/include/asm/flushtlb.h | 2 +- + xen/arch/x86/include/asm/processor.h | 3 ++ + xen/arch/x86/mm.c | 4 +-- + xen/arch/x86/pv/dom0_build.c | 12 +++---- + xen/arch/x86/pv/domain.c | 13 ++++++-- + xen/arch/x86/smpboot.c | 1 + + xen/common/efi/common-stub.c | 5 --- + xen/common/efi/runtime.c | 21 +++++------- + xen/include/xen/efi.h | 1 - + 12 files changed, 54 insertions(+), 62 deletions(-) + +diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/domain_page.c +index eac5e3304fb8..72c00194f315 100644 +--- a/xen/arch/x86/domain_page.c ++++ b/xen/arch/x86/domain_page.c +@@ -18,48 +18,40 @@ + #include + #include + +-static DEFINE_PER_CPU(struct vcpu *, override); +- + static inline struct vcpu *mapcache_current_vcpu(void) + { +- /* In the common case we use the mapcache of the running VCPU. */ +- struct vcpu *v = this_cpu(override) ?: current; +- +- /* +- * When current isn't properly set up yet, this is equivalent to +- * running in an idle vCPU (callers must check for NULL). +- */ +- if ( !v ) +- return NULL; ++ struct vcpu *v = this_cpu(pgtable_vcpu); ++ struct vcpu *curr = current; + + /* +- * When using efi runtime page tables, we have the equivalent of the idle +- * domain's page tables but current may point at another domain's VCPU. +- * Return NULL as though current is not properly set up yet. ++ * During early boot pgtable_vcpu is not set, callers must handle NULL. ++ * Non-PV domains don't have a mapcache, the directmap covers all physical ++ * address space. + */ +- if ( efi_rs_using_pgtables() ) ++ if ( !v || !is_pv_vcpu(v) ) + return NULL; + + /* +- * If guest_table is NULL, and we are running a paravirtualised guest, +- * then it means we are running on the idle domain's page table and must +- * therefore use its mapcache. ++ * If we are in a lazy context-switch state from a PV vCPU do a full switch ++ * to the idle vCPU now, otherwise an incoming FLUSH_VCPU_STATE IPI would ++ * change the page tables under our feet an invalidate any in-use mapcache ++ * entries. + */ +- if ( unlikely(pagetable_is_null(v->arch.guest_table)) && is_pv_vcpu(v) ) ++ if ( unlikely(this_cpu(curr_vcpu) != curr) ) + { +- /* If we really are idling, perform lazy context switch now. */ +- if ( (v = idle_vcpu[smp_processor_id()]) == current ) +- sync_local_execstate(); ++ ASSERT(curr == idle_vcpu[smp_processor_id()]); ++ sync_local_execstate(); + /* We must now be running on the idle page table. */ + ASSERT(cr3_pa(read_cr3()) == __pa(idle_pg_table)); + } + +- return v; +-} +- +-void __init mapcache_override_current(struct vcpu *v) +-{ +- this_cpu(override) = v; ++ /* ++ * At this point we can guarantee Xen is not in lazy context switch: either ++ * the code above will have synced the state, or an incoming ++ * FLUSH_VCPU_STATE IPI has done so behind our back. Use ACCESS_ONCE to ++ * ensure the compiler never returns the locally cached pgtable_vcpu value. ++ */ ++ return ACCESS_ONCE(this_cpu(pgtable_vcpu)); + } + + #define mapcache_l2_entry(e) ((e) >> PAGETABLE_ORDER) +diff --git a/xen/arch/x86/flushtlb.c b/xen/arch/x86/flushtlb.c +index 09e676c151fa..928bca66b433 100644 +--- a/xen/arch/x86/flushtlb.c ++++ b/xen/arch/x86/flushtlb.c +@@ -111,7 +111,9 @@ static void do_tlb_flush(void) + local_irq_restore(flags); + } + +-void switch_cr3_cr4(unsigned long cr3, unsigned long cr4) ++DEFINE_PER_CPU(struct vcpu *, pgtable_vcpu); ++ ++void switch_cr3_cr4(struct vcpu *v, unsigned long cr3, unsigned long cr4) + { + unsigned long flags, old_cr4; + u32 t = 0; +@@ -155,6 +157,7 @@ void switch_cr3_cr4(unsigned long cr3, unsigned long cr4) + if ( (old_cr4 & X86_CR4_PCIDE) > (cr4 & X86_CR4_PCIDE) ) + cr3 |= X86_CR3_NOFLUSH; + write_cr3(cr3); ++ this_cpu(pgtable_vcpu) = v; + + if ( old_cr4 != cr4 ) + write_cr4(cr4); +diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h +index 828f42c3e448..10d2b9fe2546 100644 +--- a/xen/arch/x86/include/asm/domain.h ++++ b/xen/arch/x86/include/asm/domain.h +@@ -75,7 +75,6 @@ struct mapcache_domain { + + int mapcache_domain_init(struct domain *d); + int mapcache_vcpu_init(struct vcpu *v); +-void mapcache_override_current(struct vcpu *v); + + /* x86/64: toggle guest between kernel and user modes. */ + void toggle_guest_mode(struct vcpu *v); +diff --git a/xen/arch/x86/include/asm/flushtlb.h b/xen/arch/x86/include/asm/flushtlb.h +index 7bcbca2b7f31..345677eb72ae 100644 +--- a/xen/arch/x86/include/asm/flushtlb.h ++++ b/xen/arch/x86/include/asm/flushtlb.h +@@ -104,7 +104,7 @@ static inline void invlpg(const void *p) + } + + /* Write pagetable base and implicitly tick the tlbflush clock. */ +-void switch_cr3_cr4(unsigned long cr3, unsigned long cr4); ++void switch_cr3_cr4(struct vcpu *v, unsigned long cr3, unsigned long cr4); + + /* flush_* flag fields: */ + /* +diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h +index 2e087c625770..d2cacdfedb74 100644 +--- a/xen/arch/x86/include/asm/processor.h ++++ b/xen/arch/x86/include/asm/processor.h +@@ -328,6 +328,9 @@ DECLARE_PER_CPU(struct tss_page, tss_page); + + DECLARE_PER_CPU(root_pgentry_t *, root_pgt); + ++/* vCPU of the currently loaded page-tables. */ ++DECLARE_PER_CPU(struct vcpu *, pgtable_vcpu); ++ + extern void write_ptbase(struct vcpu *v); + + /* PAUSE (encoding: REP NOP) is a good thing to insert into busy-wait loops. */ +diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c +index 2b23bf2e7a75..d02c9862d387 100644 +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -535,7 +535,7 @@ void write_ptbase(struct vcpu *v) + cpu_info->pv_cr3 = __pa(this_cpu(root_pgt)); + if ( new_cr4 & X86_CR4_PCIDE ) + cpu_info->pv_cr3 |= get_pcid_bits(v, true); +- switch_cr3_cr4(v->arch.cr3, new_cr4); ++ switch_cr3_cr4(v, v->arch.cr3, new_cr4); + } + else + { +@@ -543,7 +543,7 @@ void write_ptbase(struct vcpu *v) + cpu_info->use_pv_cr3 = false; + cpu_info->xen_cr3 = 0; + /* switch_cr3_cr4() serializes. */ +- switch_cr3_cr4(v->arch.cr3, new_cr4); ++ switch_cr3_cr4(v, v->arch.cr3, new_cr4); + cpu_info->pv_cr3 = 0; + } + } +diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c +index 37729091dfaa..42bc530c0f0d 100644 +--- a/xen/arch/x86/pv/dom0_build.c ++++ b/xen/arch/x86/pv/dom0_build.c +@@ -828,8 +828,7 @@ static int __init dom0_construct(const struct boot_domain *bd) + update_cr3(v); + + /* We run on dom0's page tables for the final part of the build process. */ +- switch_cr3_cr4(cr3_pa(v->arch.cr3), read_cr4()); +- mapcache_override_current(v); ++ switch_cr3_cr4(v, cr3_pa(v->arch.cr3), read_cr4()); + + /* Copy the OS image and free temporary buffer. */ + elf.dest_base = (void*)vkern_start; +@@ -838,8 +837,7 @@ static int __init dom0_construct(const struct boot_domain *bd) + rc = elf_load_binary(&elf); + if ( rc < 0 ) + { +- mapcache_override_current(NULL); +- switch_cr3_cr4(current->arch.cr3, read_cr4()); ++ switch_cr3_cr4(current, current->arch.cr3, read_cr4()); + printk("Failed to load the kernel binary\n"); + goto out; + } +@@ -850,8 +848,7 @@ static int __init dom0_construct(const struct boot_domain *bd) + if ( (parms.virt_hypercall < v_start) || + (parms.virt_hypercall >= v_end) ) + { +- mapcache_override_current(NULL); +- switch_cr3_cr4(current->arch.cr3, read_cr4()); ++ switch_cr3_cr4(current, current->arch.cr3, read_cr4()); + printk("Invalid HYPERCALL_PAGE field in ELF notes.\n"); + return -EINVAL; + } +@@ -992,8 +989,7 @@ static int __init dom0_construct(const struct boot_domain *bd) + #endif + + /* Return to idle domain's page tables. */ +- mapcache_override_current(NULL); +- switch_cr3_cr4(current->arch.cr3, read_cr4()); ++ switch_cr3_cr4(current, current->arch.cr3, read_cr4()); + + update_domain_wallclock_time(d); + +diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c +index ef4f442e7332..d9e52f5f88f3 100644 +--- a/xen/arch/x86/pv/domain.c ++++ b/xen/arch/x86/pv/domain.c +@@ -451,6 +451,8 @@ static void _toggle_guest_pt(struct vcpu *v) + pagetable_t old_shadow; + unsigned long cr3; + ++ ASSERT(local_irq_is_enabled()); ++ + v->arch.flags ^= TF_kernel_mode; + guest_update = v->arch.flags & TF_kernel_mode; + old_shadow = update_cr3(v); +@@ -473,15 +475,22 @@ static void _toggle_guest_pt(struct vcpu *v) + { + cr3 &= ~X86_CR3_NOFLUSH; + ++ local_irq_disable(); + if ( unlikely(mfn_eq(pagetable_get_mfn(old_shadow), + maddr_to_mfn(cr3))) ) + { +- cr3 = idle_vcpu[v->processor]->arch.cr3; + /* Also suppress runstate/time area updates below. */ + guest_update = false; ++ ++ cr3 = idle_vcpu[v->processor]->arch.cr3; ++ this_cpu(pgtable_vcpu) = idle_vcpu[v->processor]; + } ++ ++ write_cr3(cr3); ++ local_irq_enable(); + } +- write_cr3(cr3); ++ else ++ write_cr3(cr3); + + if ( !pagetable_is_null(old_shadow) ) + shadow_put_top_level(v->domain, old_shadow); +diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c +index 27628800a821..b37feab3bef4 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -1063,6 +1063,7 @@ static int cpu_smpboot_alloc(unsigned int cpu) + + info->current_vcpu = idle_vcpu[cpu]; /* set_current() */ + per_cpu(curr_vcpu, cpu) = idle_vcpu[cpu]; ++ per_cpu(pgtable_vcpu, cpu) = idle_vcpu[cpu]; + + gdt = per_cpu(gdt, cpu) ?: alloc_xenheap_pages(0, memflags); + if ( gdt == NULL ) +diff --git a/xen/common/efi/common-stub.c b/xen/common/efi/common-stub.c +index 77f138a6c574..7b12005bea3f 100644 +--- a/xen/common/efi/common-stub.c ++++ b/xen/common/efi/common-stub.c +@@ -7,11 +7,6 @@ bool efi_enabled(unsigned int feature) + return false; + } + +-bool efi_rs_using_pgtables(void) +-{ +- return false; +-} +- + unsigned long efi_get_time(void) + { + BUG(); +diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c +index 30d649ca5c1b..feb09acf754c 100644 +--- a/xen/common/efi/runtime.c ++++ b/xen/common/efi/runtime.c +@@ -49,7 +49,6 @@ const CHAR16 *__read_mostly efi_fw_vendor; + const EFI_RUNTIME_SERVICES *__read_mostly efi_rs; + #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ + static DEFINE_SPINLOCK(efi_rs_lock); +-static unsigned int efi_rs_on_cpu = NR_CPUS; + #endif + + UINTN __read_mostly efi_memmap_size; +@@ -92,6 +91,11 @@ struct efi_rs_state efi_rs_enter(void) + if ( mfn_eq(efi_l4_mfn, INVALID_MFN) ) + return state; + ++ /* ++ * If in lazy idle context switch state sync now to avoid an incoming ++ * FLUSH_VCPU_STATE IPI changing the loaded page-tables. ++ */ ++ sync_local_execstate(); + state.cr3 = read_cr3(); + save_fpu_enable(); + asm volatile ( "fnclex; fldcw %0" :: "m" (fcw) ); +@@ -99,8 +103,6 @@ struct efi_rs_state efi_rs_enter(void) + + spin_lock(&efi_rs_lock); + +- efi_rs_on_cpu = smp_processor_id(); +- + /* prevent fixup_page_fault() from doing anything */ + irq_enter(); + +@@ -115,7 +117,8 @@ struct efi_rs_state efi_rs_enter(void) + lgdt(&gdt_desc); + } + +- switch_cr3_cr4(mfn_to_maddr(efi_l4_mfn), read_cr4()); ++ switch_cr3_cr4(idle_vcpu[smp_processor_id()], mfn_to_maddr(efi_l4_mfn), ++ read_cr4()); + + /* + * At the time of writing (2022), no UEFI firwmare is CET-IBT compatible. +@@ -143,7 +146,7 @@ void efi_rs_leave(struct efi_rs_state *state) + if ( state->msr_s_cet ) + wrmsrl(MSR_S_CET, state->msr_s_cet); + +- switch_cr3_cr4(state->cr3, read_cr4()); ++ switch_cr3_cr4(curr, state->cr3, read_cr4()); + if ( is_pv_vcpu(curr) && !is_idle_vcpu(curr) ) + { + struct desc_ptr gdt_desc = { +@@ -154,18 +157,10 @@ void efi_rs_leave(struct efi_rs_state *state) + lgdt(&gdt_desc); + } + irq_exit(); +- efi_rs_on_cpu = NR_CPUS; + spin_unlock(&efi_rs_lock); + vcpu_restore_fpu_nonlazy(curr, true); + } + +-bool efi_rs_using_pgtables(void) +-{ +- return !mfn_eq(efi_l4_mfn, INVALID_MFN) && +- (smp_processor_id() == efi_rs_on_cpu) && +- (read_cr3() == mfn_to_maddr(efi_l4_mfn)); +-} +- + unsigned long efi_get_time(void) + { + EFI_TIME time; +diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h +index 723cb8085270..9953197ee553 100644 +--- a/xen/include/xen/efi.h ++++ b/xen/include/xen/efi.h +@@ -40,7 +40,6 @@ extern bool efi_secure_boot; + + void efi_init_memory(void); + bool efi_boot_mem_unused(unsigned long *start, unsigned long *end); +-bool efi_rs_using_pgtables(void); + unsigned long efi_get_time(void); + void efi_halt_system(void); + void efi_reset_system(bool warm); +-- +2.53.0 + From 1e49e52adbc73af767fcb7be16d77f985daabbb6 Mon Sep 17 00:00:00 2001 From: Yaakov Selkowitz Date: Thu, 18 Jun 2026 16:36:54 -0400 Subject: [PATCH 96/99] Rebuilt for openssl 4.0 --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index a9bf097..9c859aa 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 6%{?dist} +Release: 7%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -882,6 +882,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Thu Jun 18 2026 Yaakov Selkowitz - 4.21.1-7 +- Rebuilt for openssl 4.0 + * Thu Jun 18 2026 Michael Young - 4.21.1-6 - x86 HVM I/O port list traversal [XSA-491, CVE-2026-42487] - domctl lock open to abuse [XSA-492, CVE-2026-42489, CVE-2026-42490] From 87e40ff1baa988d7407049254ba9504a5c327569 Mon Sep 17 00:00:00 2001 From: Jerry James Date: Thu, 9 Jul 2026 11:46:55 -0600 Subject: [PATCH 97/99] OCaml 5.5.0 rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 9c859aa..ece45a0 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 7%{?dist} +Release: 8%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -882,6 +882,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Thu Jul 09 2026 Jerry James - 4.21.1-8 +- OCaml 5.5.0 rebuild + * Thu Jun 18 2026 Yaakov Selkowitz - 4.21.1-7 - Rebuilt for openssl 4.0 From 5bd254f0062a21e3a9bb302a4dd674a3b2f6bb0d Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 17 Jul 2026 09:07:32 +0000 Subject: [PATCH 98/99] Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index ece45a0..3f9106e 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 8%{?dist} +Release: 9%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -882,6 +882,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Fri Jul 17 2026 Fedora Release Engineering - 4.21.1-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild + * Thu Jul 09 2026 Jerry James - 4.21.1-8 - OCaml 5.5.0 rebuild From c8af4d85b66f3c03fe405e620cda2e12a255d77a Mon Sep 17 00:00:00 2001 From: Python Maint Date: Wed, 22 Jul 2026 10:47:19 +0200 Subject: [PATCH 99/99] Rebuilt for Python 3.15.0b4 ABI change --- xen.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen.spec b/xen.spec index 3f9106e..1bea8ef 100644 --- a/xen.spec +++ b/xen.spec @@ -51,7 +51,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.21.1 -Release: 9%{?dist} +Release: 10%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -882,6 +882,9 @@ fi %{_libexecdir}/xen/tests/* %changelog +* Wed Jul 22 2026 Python Maint - 4.21.1-10 +- Rebuilt for Python 3.15.0b4 ABI change + * Fri Jul 17 2026 Fedora Release Engineering - 4.21.1-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild