From 343a901c216405ca8ebe8c7b3ce21eafb7b5c495 Mon Sep 17 00:00:00 2001 From: Michael Young Date: Dec 13 2023 17:39:02 +0000 Subject: arm32: The cache may not be properly cleaned/invalidated (take two) [XSA-447, CVE-2023-46837] rebuild for OCaml-5.1.1 --- diff --git a/xen.spec b/xen.spec index 07bb3d2..c0bd413 100644 --- a/xen.spec +++ b/xen.spec @@ -55,7 +55,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.18.0 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ Source0: https://downloads.xenproject.org/release/xen/%{version}/xen-%{version}.tar.gz @@ -112,6 +112,7 @@ Patch46: xen.efi.build.patch Patch47: xen.gcc13.fixes.patch Patch49: xen.python3.12.patch Patch50: xen.ocaml5.fixes.patch +Patch51: xsa447.patch %if %build_qemutrad @@ -328,6 +329,7 @@ manage Xen virtual machines. %if "%dist" != ".fc38" %patch 50 -p1 %endif +%patch 51 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -934,6 +936,11 @@ fi %endif %changelog +* Wed Dec 13 2023 Michael Young - 4.18.0-2 +- arm32: The cache may not be properly cleaned/invalidated (take two) + [XSA-447, CVE-2023-46837] +- rebuild for OCaml-5.1.1 + * Wed Nov 29 2023 Michael Young - 4.18.0-1 - update to xen-4.18.0 rebase xen.canonicalize.patch and xen.ocaml5.fixes.patch diff --git a/xsa447.patch b/xsa447.patch new file mode 100644 index 0000000..2e26396 --- /dev/null +++ b/xsa447.patch @@ -0,0 +1,117 @@ +From 084c7312fa6c1d4a7fa343efa1d7d73693dafff4 Mon Sep 17 00:00:00 2001 +From: Michal Orzel +Date: Thu, 23 Nov 2023 15:53:02 +0100 +Subject: [PATCH] xen/arm: page: Avoid pointer overflow on cache clean & + invalidate + +On Arm32, after cleaning and invalidating the last dcache line of the top +domheap page i.e. VA = 0xfffff000 (as a result of flushing the page to +RAM), we end up adding the value of a dcache line size to the pointer +once again, which results in a pointer arithmetic overflow (with 64B line +size, operation 0xffffffc0 + 0x40 overflows to 0x0). Such behavior is +undefined and given the wide range of compiler versions we support, it is +difficult to determine what could happen in such scenario. + +Modify clean_and_invalidate_dcache_va_range() as well as +clean_dcache_va_range() and invalidate_dcache_va_range() due to similarity +of handling to prevent pointer arithmetic overflow. Modify the loops to +use an additional variable to store the index of the next cacheline. +Add an assert to prevent passing a region that wraps around which is +illegal and would end up in a page fault anyway (region 0-2MB is +unmapped). Lastly, return early if size passed is 0. + +Note that on Arm64, we don't have this problem given that the max VA +space we support is 48-bits. + +This is XSA-447 / CVE-2023-46837. + +Signed-off-by: Michal Orzel +Reviewed-by: Julien Grall +--- + xen/arch/arm/include/asm/page.h | 35 ++++++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 7 deletions(-) + +diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h +index ebaf5964f114..69f817d1e68a 100644 +--- a/xen/arch/arm/include/asm/page.h ++++ b/xen/arch/arm/include/asm/page.h +@@ -162,6 +162,13 @@ static inline size_t read_dcache_line_bytes(void) + static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + { + size_t cacheline_mask = dcache_line_bytes - 1; ++ unsigned long idx = 0; ++ ++ if ( !size ) ++ return 0; ++ ++ /* Passing a region that wraps around is illegal */ ++ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); + + dsb(sy); /* So the CPU issues all writes to the range */ + +@@ -174,11 +181,11 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + } + + for ( ; size >= dcache_line_bytes; +- p += dcache_line_bytes, size -= dcache_line_bytes ) +- asm volatile (__invalidate_dcache_one(0) : : "r" (p)); ++ idx += dcache_line_bytes, size -= dcache_line_bytes ) ++ asm volatile (__invalidate_dcache_one(0) : : "r" (p + idx)); + + if ( size > 0 ) +- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); ++ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); + + dsb(sy); /* So we know the flushes happen before continuing */ + +@@ -188,14 +195,21 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size) + static inline int clean_dcache_va_range(const void *p, unsigned long size) + { + size_t cacheline_mask = dcache_line_bytes - 1; ++ unsigned long idx = 0; ++ ++ if ( !size ) ++ return 0; ++ ++ /* Passing a region that wraps around is illegal */ ++ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); + + dsb(sy); /* So the CPU issues all writes to the range */ + size += (uintptr_t)p & cacheline_mask; + size = (size + cacheline_mask) & ~cacheline_mask; + p = (void *)((uintptr_t)p & ~cacheline_mask); + for ( ; size >= dcache_line_bytes; +- p += dcache_line_bytes, size -= dcache_line_bytes ) +- asm volatile (__clean_dcache_one(0) : : "r" (p)); ++ idx += dcache_line_bytes, size -= dcache_line_bytes ) ++ asm volatile (__clean_dcache_one(0) : : "r" (p + idx)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ + return 0; +@@ -205,14 +219,21 @@ static inline int clean_and_invalidate_dcache_va_range + (const void *p, unsigned long size) + { + size_t cacheline_mask = dcache_line_bytes - 1; ++ unsigned long idx = 0; ++ ++ if ( !size ) ++ return 0; ++ ++ /* Passing a region that wraps around is illegal */ ++ ASSERT(((uintptr_t)p + size - 1) >= (uintptr_t)p); + + dsb(sy); /* So the CPU issues all writes to the range */ + size += (uintptr_t)p & cacheline_mask; + size = (size + cacheline_mask) & ~cacheline_mask; + p = (void *)((uintptr_t)p & ~cacheline_mask); + for ( ; size >= dcache_line_bytes; +- p += dcache_line_bytes, size -= dcache_line_bytes ) +- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p)); ++ idx += dcache_line_bytes, size -= dcache_line_bytes ) ++ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p + idx)); + dsb(sy); /* So we know the flushes happen before continuing */ + /* ARM callers assume that dcache_* functions cannot fail. */ + return 0; +-- +2.40.1 +