Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03ebe9389d | ||
|
|
4ed173cf08 | ||
|
|
3a216622ed | ||
|
|
1354ce6c4e | ||
|
|
3a033ad9a5 | ||
|
|
7a62e2da8f | ||
|
|
dba13fcb89 | ||
|
|
4334201f89 | ||
|
|
2060a2ec84 |
35 changed files with 73 additions and 4546 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -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.21.0.tar.xz
|
||||
/xen-4.21.1.tar.xz
|
||||
/mini-os-4.20.0.tar.xz
|
||||
/xen-4.20.4.tar.gz
|
||||
|
|
|
|||
4
sources
4
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.21.0.tar.xz) = 7543774d15da84476d93d04154990923c82209cb3fa125574c0383652c5a310957200f54b63b34502161f9c3afce4907e0060d9036f3eaf3a7cb6b1b3119b546
|
||||
SHA512 (xen-4.21.1.tar.xz) = 8dfe65255e202b3dacf9d0d7265636bc1f97627c11b08babc13a5b8e74c7c65e7e2c6a1513e28b3c713fe512edb6702a73b2bf667e2a8f2ce825b196a2cd5aab
|
||||
SHA512 (mini-os-4.20.0.tar.xz) = 52d5d0985e1b4c26b761c94a3f7ca543bc388a96f69710524ebf34dd5b01d8f774fd5a3f6a50739c8b7c7edfdf07b594f5d44de8f389ea4138a62f9c5884c4e6
|
||||
SHA512 (xen-4.20.4.tar.gz) = a4d92677f8dff486ae094bf9d74d15606217945012482fd43323c9b86891169be367b80aef2d711d686df478046649fa003ebc038b82ecaffdeff505195179af
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
From 90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3 Mon Sep 17 00:00:00 2001
|
||||
From c403cf9e742a20e0aadbe04c1ab0ce9621184037 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Date: Fri, 10 Apr 2026 21:55:46 +0100
|
||||
Subject: [PATCH] x86/amd: Mitigate AMD-SN-7053 / FP-DSS
|
||||
|
|
@ -17,10 +17,10 @@ Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
|||
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
|
||||
index d5069a7ec1..43883e04db 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)
|
||||
@@ -982,6 +982,42 @@ void amd_init_de_cfg(const struct cpuinfo_x86 *c)
|
||||
wrmsrl(MSR_AMD64_DE_CFG, val | new);
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ index 8c55d233f3..1bb0766ebf 100644
|
|||
+ * 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() )
|
||||
+ if ( c->x86 == 0x17 && is_zen1_uarch() )
|
||||
+ new |= 1 << 9;
|
||||
+
|
||||
+ /*
|
||||
|
|
@ -46,7 +46,7 @@ index 8c55d233f3..1bb0766ebf 100644
|
|||
+ if ( !new )
|
||||
+ return;
|
||||
+
|
||||
+ val = rdmsr(MSR_AMD64_FP_CFG);
|
||||
+ rdmsrl(MSR_AMD64_FP_CFG, val);
|
||||
+
|
||||
+ if ( (val & new) == new )
|
||||
+ return;
|
||||
|
|
@ -57,14 +57,14 @@ index 8c55d233f3..1bb0766ebf 100644
|
|||
+ * consistent across CPUs and unrelated to the old value, so the result
|
||||
+ * should be consistent.
|
||||
+ */
|
||||
+ wrmsr(MSR_AMD64_FP_CFG, val | new);
|
||||
+ wrmsrl(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;
|
||||
@@ -1055,6 +1091,7 @@ static void cf_check init_amd(struct cpuinfo_x86 *c)
|
||||
unsigned long long value;
|
||||
|
||||
amd_init_de_cfg(c);
|
||||
+ amd_init_fp_cfg(c);
|
||||
|
|
@ -72,10 +72,10 @@ index 8c55d233f3..1bb0766ebf 100644
|
|||
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
|
||||
index 6f2c3147e3..70e5f09a2d 100644
|
||||
--- a/xen/arch/x86/include/asm/msr-index.h
|
||||
+++ b/xen/arch/x86/include/asm/msr-index.h
|
||||
@@ -428,6 +428,7 @@
|
||||
@@ -411,6 +411,7 @@
|
||||
#define MSR_AMD64_LS_CFG 0xc0011020U
|
||||
#define MSR_AMD64_IC_CFG 0xc0011021U
|
||||
#define MSR_AMD64_DC_CFG 0xc0011022U
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
--- 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,
|
||||
211
xen.spec
211
xen.spec
|
|
@ -46,16 +46,16 @@
|
|||
%endif
|
||||
|
||||
# Hypervisor ABI
|
||||
%define hv_abi 4.21
|
||||
%define hv_abi 4.20
|
||||
|
||||
Summary: Xen is a virtual machine monitor
|
||||
Name: xen
|
||||
Version: 4.21.1
|
||||
Release: 10%{?dist}
|
||||
Version: 4.20.4
|
||||
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.xz
|
||||
Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz
|
||||
Source2: %{name}.logrotate
|
||||
# used by stubdoms
|
||||
Source10: lwip-1.3.0.tar.gz
|
||||
|
|
@ -66,50 +66,18 @@ 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.21.0 with .git and .gitignore stripped
|
||||
Source22: mini-os-4.21.0.tar.xz
|
||||
# mini-os xen-RELEASE-4.20.0 with .git and .gitignore stripped
|
||||
Source22: mini-os-4.20.0.tar.xz
|
||||
|
||||
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
|
||||
Patch11: xen.json.nocpuid.patch
|
||||
Patch12: xsa483.patch
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
# build using Fedora seabios and ipxe packages for roms
|
||||
|
|
@ -133,10 +101,8 @@ BuildRequires: acpica-tools
|
|||
BuildRequires: bzip2-devel xz-devel libzstd-devel
|
||||
# libfsimage
|
||||
BuildRequires: e2fsprogs-devel
|
||||
# tools now require wget
|
||||
BuildRequires: wget
|
||||
# use json-c instead of yajl
|
||||
BuildRequires: json-c-devel
|
||||
# tools now require yajl and wget
|
||||
BuildRequires: yajl-devel wget
|
||||
# remus support now needs libnl3
|
||||
BuildRequires: libnl3-devel
|
||||
%if %with_xsm
|
||||
|
|
@ -279,54 +245,17 @@ 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 7 -p1
|
||||
%patch 8 -p1
|
||||
%patch 9 -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 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
|
||||
%patch 43 -p1
|
||||
%patch 45 -p1
|
||||
%patch 46 -p1
|
||||
|
||||
# stubdom sources
|
||||
cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom
|
||||
|
|
@ -373,7 +302,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
|
||||
|
|
@ -666,7 +595,7 @@ fi
|
|||
%{_libdir}/libxenlight.so.4.*
|
||||
%{_libdir}/libxenstat.so.4.*
|
||||
%{_libdir}/libxenstore.so.4
|
||||
%{_libdir}/libxenstore.so.4.1
|
||||
%{_libdir}/libxenstore.so.4.0
|
||||
%{_libdir}/libxentoolcore.so.1
|
||||
%{_libdir}/libxentoolcore.so.1.0
|
||||
%{_libdir}/libxentoollog.so.1
|
||||
|
|
@ -676,8 +605,6 @@ 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
|
||||
|
|
@ -695,8 +622,7 @@ fi
|
|||
%{_unitdir}/xen-watchdog.service
|
||||
%{_unitdir}/xen-qemu-dom0-disk-backend.service
|
||||
%{_unitdir}/xendriverdomain.service
|
||||
%{_modulesloaddir}/xen.conf
|
||||
%{_systemd_util_dir}/system-sleep/xen-watchdog-sleep.sh
|
||||
/usr/lib/modules-load.d/xen.conf
|
||||
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/xencommons
|
||||
%config(noreplace) %{_sysconfdir}/xen/xl.conf
|
||||
|
|
@ -878,94 +804,71 @@ fi
|
|||
%{_libexecdir}/xen/ocaml/xsd_glue/xenctrl_plugin/domain_getinfo_v1.cmxs
|
||||
%endif
|
||||
|
||||
%files test
|
||||
%{_libexecdir}/xen/tests/*
|
||||
|
||||
%changelog
|
||||
* Wed Jul 22 2026 Python Maint <python-maint@redhat.com> - 4.21.1-10
|
||||
- Rebuilt for Python 3.15.0b4 ABI change
|
||||
* Thu Jul 30 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.4-1
|
||||
- update to xen 4.20.4
|
||||
- includes security fixes
|
||||
x86 shadow paging is deprecated [XSA-495, CVE-2026-42493]
|
||||
vIRQ event channel binding may break Xenstore [XSA-496, CVE-2026-42492]
|
||||
buffer overruns in libfsimage iso9660 handling [XSA-497, CVE-2026-42494,
|
||||
CVE-2026-42495, CVE-2026-62423, CVE-2026-62424, CVE-2026-62425]
|
||||
sysctl and platform-op locks open to abuse [XSA-499, CVE-2026-62426,
|
||||
CVE-2026-62427]
|
||||
grant-table: type confusion in grant-copy [XSA-500, CVE-2026-62428]
|
||||
grant-table: version change racing with other operations [XSA-501,
|
||||
CVE-2026-62435, CVE-2026-62436]
|
||||
vNUMA domain cleanup may race other operations [XSA-502, CVE-2026-62429]
|
||||
x86: Out-of-bounds read in vRTC emulation [XSA-503, CVE-2026-62430]
|
||||
Viridian STIMER division by zero [XSA-504, CVE-2026-62431]
|
||||
evtchn: Race between FIFO expand and reset [XSA-505, CVE-2026-62432]
|
||||
correct buffer checks for DM_OP hypercalls [XSA-506, CVE-2026-62433]
|
||||
PoD: Don't try to reclaim special pages [XSA-507, CVE-2026-62434]
|
||||
pygrub is only supported in de-privileged mode [XSA-508]
|
||||
|
||||
* Fri Jul 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 4.21.1-9
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
|
||||
|
||||
* Thu Jul 09 2026 Jerry James <loganjerry@gmail.com> - 4.21.1-8
|
||||
- OCaml 5.5.0 rebuild
|
||||
|
||||
* Thu Jun 18 2026 Yaakov Selkowitz <yselkowi@redhat.com> - 4.21.1-7
|
||||
- Rebuilt for openssl 4.0
|
||||
|
||||
* Thu Jun 18 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.1-6
|
||||
* Thu Jun 18 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.3-4
|
||||
[ never submitted as update ]
|
||||
- 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 <yselkowi@redhat.com> - 4.21.1-5
|
||||
- Rebuilt for openssl 4.0
|
||||
|
||||
* Wed Jun 03 2026 Python Maint <python-maint@redhat.com> - 4.21.1-4
|
||||
- Rebuilt for Python 3.15
|
||||
|
||||
* Tue May 12 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.1-3
|
||||
* Tue May 12 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.3-3
|
||||
- x86: CPU Opcode Cache corruption [XSA-490,CVE-2025-54518]
|
||||
|
||||
* Tue Apr 28 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.1-2
|
||||
* Wed Apr 29 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.3-2
|
||||
- oxenstored keeps quota related use counts across domain destruction
|
||||
[XSA-483, CVE-2026-23556]
|
||||
[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 <m.a.young@durham.ac.uk> - 4.21.1-1
|
||||
- update to xen 4.21.1
|
||||
* Fri Mar 27 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.3-1
|
||||
- update to xen 4.20.3
|
||||
remove patches now included or superceded upstream
|
||||
|
||||
* Tue Mar 17 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.0-5
|
||||
* Wed Mar 18 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.2-4
|
||||
- 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 <rjones@redhat.com> - 4.21.0-4
|
||||
- OCaml 5.4.1 rebuild
|
||||
|
||||
* Wed Jan 28 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.0-3
|
||||
* Thu Jan 29 2026 Michael Young <m.a.young@durham.ac.uk> - 4.20.2-3
|
||||
x86: buffer overrun with shadow paging + tracing [XSA-477, CVE-2025-58150]
|
||||
(#2434046)
|
||||
x86: incomplete IBPB for vCPU isolation [XSA-479, CVE-2026-23553]
|
||||
(#2434048)
|
||||
|
||||
* Sat Jan 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 4.21.0-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
|
||||
|
||||
* Wed Jan 07 2026 Michael Young <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 4.20.2-2.fc44
|
||||
* Fri Nov 14 2025 Michael Young <m.a.young@durham.ac.uk> - 4.20.2-1.fc43
|
||||
- update to xen 4.20.2
|
||||
remove patches now included or superceded upstream
|
||||
|
||||
* Sun Oct 26 2025 Michael Young <m.a.young@durham.ac.uk> - 4.20.1-9
|
||||
- teecr32_el1 and teehbr32_el1 support dropped in binutils 2.45.50-5.fc44
|
||||
|
||||
* Fri Oct 24 2025 Michael Young <m.a.young@durham.ac.uk>
|
||||
* Fri Oct 24 2025 Michael Young <m.a.young@durham.ac.uk> - 4.20.1-8
|
||||
- Incorrect removal of permissions on PCI device unplug [XSA-476,
|
||||
CVE-2025-58149]
|
||||
|
||||
* Tue Oct 21 2025 Michael Young <m.a.young@durham.ac.uk>
|
||||
* Tue Oct 21 2025 Michael Young <m.a.young@durham.ac.uk> - 4.20.1-7
|
||||
- x86: Incorrect input sanitisation in Viridian hypercalls [XSA-475,
|
||||
CVE-2025-58147, CVE-2025-58148]
|
||||
|
||||
* Wed Oct 15 2025 Richard W.M. Jones <rjones@redhat.com> - 4.20.1-7
|
||||
- OCaml 5.4.0 rebuild
|
||||
|
||||
* Fri Sep 19 2025 Python Maint <python-maint@redhat.com> - 4.20.1-6
|
||||
- Rebuilt for Python 3.14.0rc3 bytecode
|
||||
|
||||
|
|
@ -999,7 +902,7 @@ fi
|
|||
x86: Transitive Scheduler Attacks [XSA-471, CVE-2024-36350,
|
||||
CVE-2024-36357]
|
||||
|
||||
* Fri Jul 11 2025 Jerry James <loganjerry@gmail.com> - 4.19.2-6
|
||||
* Fri Jul 11 2025 Jerry James <loganjerry@gmail.com> - 4.19.2-6
|
||||
- Rebuild to fix OCaml dependencies
|
||||
|
||||
* Mon Jun 02 2025 Python Maint <python-maint@redhat.com> - 4.19.2-5
|
||||
|
|
|
|||
30
xsa483.patch
30
xsa483.patch
|
|
@ -1,30 +0,0 @@
|
|||
From: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
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 <andriy.sultanov@vates.tech>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
|
||||
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;
|
||||
89
xsa484.patch
89
xsa484.patch
|
|
@ -1,89 +0,0 @@
|
|||
From 3d0d19ad17f29c64dde4a7baf392da4fd58f3654 Mon Sep 17 00:00:00 2001
|
||||
From: Juergen Gross <jgross@suse.com>
|
||||
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 <andriy.sultanov@vates.tech>
|
||||
Fixes: 1f9d04fb021c ("xenstored: allow guest to shutdown all its watches/transactions")
|
||||
Signed-off-by: Juergen Gross <jgross@suse.com>
|
||||
---
|
||||
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
|
||||
|
||||
181
xsa486.patch
181
xsa486.patch
|
|
@ -1,181 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <rafal.wojtczuk@7bulls.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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)
|
||||
{
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/amd: Mitigate AMD-SN-7052
|
||||
|
||||
This is XSA-490 / CVE-2025-54518.
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
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
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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 {
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Juergen Gross <jgross@suse.com>
|
||||
|
||||
--- 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 <xen/radix-tree.h>
|
||||
#include <xen/multicall.h>
|
||||
#include <xen/nospec.h>
|
||||
+#include <xen/seqcount.h>
|
||||
#include <xen/tasklet.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/smp.h>
|
||||
@@ -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 <xen/lib.h>
|
||||
+#include <xen/nospec.h>
|
||||
+
|
||||
+#include <asm/atomic.h>
|
||||
+#include <asm/system.h>
|
||||
+
|
||||
+/*
|
||||
+ * 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:
|
||||
+ */
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- 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:
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
From: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
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 <dpsmith@apertussolutions.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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) )
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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:
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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 <asm/iocap.h>
|
||||
#include <asm/p2m.h>
|
||||
|
||||
+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;
|
||||
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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(),
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Julien Grall <julien@xen.org>
|
||||
|
||||
--- 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
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- 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,
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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:
|
||||
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- 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
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Acked-by: Julien Grall <julien@xen.org>
|
||||
|
||||
--- 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:
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- 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
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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
|
||||
/*
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Juergen Gross <jgross@suse.com>
|
||||
|
||||
--- 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
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- 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 <asm/pv/shim.h>
|
||||
+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,
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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:
|
||||
|
|
@ -1,378 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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,
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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);
|
||||
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
From 2e21b5301765de353c06081eee953255bf327176 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Orzel <michal.orzel@amd.com>
|
||||
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 <op1>[, <arg1>]
|
||||
TLBI <op2>[, <arg2>]
|
||||
TLBI <op3>[, <arg3>]
|
||||
DSB ISH
|
||||
|
||||
... the existing workaround will expand this to:
|
||||
|
||||
TLBI <op1>[, <arg1>]
|
||||
DSB ISH // additional
|
||||
TLBI <op1>[, <arg1>] // additional
|
||||
TLBI <op2>[, <arg2>]
|
||||
DSB ISH // additional
|
||||
TLBI <op2>[, <arg2>] // additional
|
||||
TLBI <op3>[, <arg3>]
|
||||
DSB ISH // additional
|
||||
TLBI <op3>[, <arg3>] // additional
|
||||
DSB ISH
|
||||
|
||||
... whereas it is sufficient to have:
|
||||
|
||||
TLBI <op1>[, <arg1>]
|
||||
TLBI <op2>[, <arg2>]
|
||||
TLBI <op3>[, <arg3>]
|
||||
DSB ISH
|
||||
TLBI <opX>[, <argX>] // 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 <michal.orzel@amd.com>
|
||||
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
|
||||
Reviewed-by: Julien Grall <jgrall@amazon.com>
|
||||
(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
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
From 7e70b87512c966248b1e8453d9ac54c643c06f44 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Orzel <michal.orzel@amd.com>
|
||||
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 <michal.orzel@amd.com>
|
||||
Reviewed-by: Julien Grall <julien@xen.org>
|
||||
|
||||
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)
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From c0f7b40fdbb986b3cf470ed51f3878261e33f9cb Mon Sep 17 00:00:00 2001
|
||||
From: Michal Orzel <michal.orzel@amd.com>
|
||||
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 <michal.orzel@amd.com>
|
||||
Reviewed-by: Julien Grall <julien@xen.org>
|
||||
|
||||
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)
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From 6af67aeca418bffb807424eb3415fab59e581733 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Orzel <michal.orzel@amd.com>
|
||||
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 <michal.orzel@amd.com>
|
||||
Reviewed-by: Julien Grall <julien@xen.org>
|
||||
|
||||
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)
|
||||
|
|
@ -1,404 +0,0 @@
|
|||
From 579016a359741044c9076bf0884e1dbab00ab080 Mon Sep 17 00:00:00 2001
|
||||
From: Roger Pau Monne <roger.pau@citrix.com>
|
||||
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é <roger.pau@citrix.com>
|
||||
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
---
|
||||
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 <asm/hardirq.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
-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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue