1From 3ab6fdc91b72e156da22848f0003ff4225690ced Mon Sep 17 00:00:00 2001 2From: =?utf8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@redhat.com> 3Date: Wed, 15 Dec 2021 19:24:21 +0100 4Subject: [PATCH] softmmu/physmem: Introduce MemTxAttrs::memory field and 5 MEMTX_ACCESS_ERROR 6MIME-Version: 1.0 7Content-Type: text/plain; charset=utf8 8Content-Transfer-Encoding: 8bit 9 10Add the 'memory' bit to the memory attributes to restrict bus 11controller accesses to memories. 12 13Introduce flatview_access_allowed() to check bus permission 14before running any bus transaction. 15 16Have read/write accessors return MEMTX_ACCESS_ERROR if an access is 17restricted. 18 19There is no change for the default case where 'memory' is not set. 20 21Signed-off-by: Philippe Mathieu-DaudÃf© <philmd@redhat.com> 22Message-Id: <20211215182421.418374-4-philmd@redhat.com> 23Reviewed-by: Richard Henderson <richard.henderson@linaro.org> 24Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> 25[thuth: Replaced MEMTX_BUS_ERROR with MEMTX_ACCESS_ERROR, remove "inline"] 26Signed-off-by: Thomas Huth <thuth@redhat.com> 27Signed-off-by: Virendra Thakur <virendra.thakur@kpit.com> 28 29CVE: CVE-2021-3750 30 31Upstream-Status: Backport [https://git.qemu.org/?p=qemu.git;a=commit;h=3ab6fdc91b72e156da22848f0003ff4225690ced] 32--- 33 include/exec/memattrs.h | 9 +++++++++ 34 softmmu/physmem.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 35 2 files changed, 51 insertions(+), 2 deletions(-) 36 37diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h 38index 95f2d20..9fb98bc 100644 39--- a/include/exec/memattrs.h 40+++ b/include/exec/memattrs.h 41@@ -35,6 +35,14 @@ typedef struct MemTxAttrs { 42 unsigned int secure:1; 43 /* Memory access is usermode (unprivileged) */ 44 unsigned int user:1; 45+ /* 46+ * Bus interconnect and peripherals can access anything (memories, 47+ * devices) by default. By setting the 'memory' bit, bus transaction 48+ * are restricted to "normal" memories (per the AMBA documentation) 49+ * versus devices. Access to devices will be logged and rejected 50+ * (see MEMTX_ACCESS_ERROR). 51+ */ 52+ unsigned int memory:1; 53 /* Requester ID (for MSI for example) */ 54 unsigned int requester_id:16; 55 /* Invert endianness for this page */ 56@@ -66,6 +74,7 @@ typedef struct MemTxAttrs { 57 #define MEMTX_OK 0 58 #define MEMTX_ERROR (1U << 0) /* device returned an error */ 59 #define MEMTX_DECODE_ERROR (1U << 1) /* nothing at that address */ 60+#define MEMTX_ACCESS_ERROR (1U << 2) /* access denied */ 61 typedef uint32_t MemTxResult; 62 63 #endif 64diff --git a/softmmu/physmem.c b/softmmu/physmem.c 65index 3d968ca..4e1b27a 100644 66--- a/softmmu/physmem.c 67+++ b/softmmu/physmem.c 68@@ -41,6 +41,7 @@ 69 #include "qemu/config-file.h" 70 #include "qemu/error-report.h" 71 #include "qemu/qemu-print.h" 72+#include "qemu/log.h" 73 #include "exec/memory.h" 74 #include "exec/ioport.h" 75 #include "sysemu/dma.h" 76@@ -2759,6 +2760,33 @@ static bool prepare_mmio_access(MemoryRe 77 return release_lock; 78 } 79 80+/** 81+ * flatview_access_allowed 82+ * @mr: #MemoryRegion to be accessed 83+ * @attrs: memory transaction attributes 84+ * @addr: address within that memory region 85+ * @len: the number of bytes to access 86+ * 87+ * Check if a memory transaction is allowed. 88+ * 89+ * Returns: true if transaction is allowed, false if denied. 90+ */ 91+static bool flatview_access_allowed(MemoryRegion *mr, MemTxAttrs attrs, 92+ hwaddr addr, hwaddr len) 93+{ 94+ if (likely(!attrs.memory)) { 95+ return true; 96+ } 97+ if (memory_region_is_ram(mr)) { 98+ return true; 99+ } 100+ qemu_log_mask(LOG_GUEST_ERROR, 101+ "Invalid access to non-RAM device at " 102+ "addr 0x%" HWADDR_PRIX ", size %" HWADDR_PRIu ", " 103+ "region '%s'\n", addr, len, memory_region_name(mr)); 104+ return false; 105+} 106+ 107 /* Called within RCU critical section. */ 108 static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, 109 MemTxAttrs attrs, 110@@ -2773,7 +2801,10 @@ static MemTxResult flatview_write_contin 111 const uint8_t *buf = ptr; 112 113 for (;;) { 114- if (!memory_access_is_direct(mr, true)) { 115+ if (!flatview_access_allowed(mr, attrs, addr1, l)) { 116+ result |= MEMTX_ACCESS_ERROR; 117+ /* Keep going. */ 118+ } else if (!memory_access_is_direct(mr, true)) { 119 release_lock |= prepare_mmio_access(mr); 120 l = memory_access_size(mr, l, addr1); 121 /* XXX: could force current_cpu to NULL to avoid 122@@ -2818,6 +2849,9 @@ static MemTxResult flatview_write(FlatVi 123 124 l = len; 125 mr = flatview_translate(fv, addr, &addr1, &l, true, attrs); 126+ if (!flatview_access_allowed(mr, attrs, addr, len)) { 127+ return MEMTX_ACCESS_ERROR; 128+ } 129 return flatview_write_continue(fv, addr, attrs, buf, len, 130 addr1, l, mr); 131 } 132@@ -2836,7 +2870,10 @@ MemTxResult flatview_read_continue(FlatV 133 134 fuzz_dma_read_cb(addr, len, mr); 135 for (;;) { 136- if (!memory_access_is_direct(mr, false)) { 137+ if (!flatview_access_allowed(mr, attrs, addr1, l)) { 138+ result |= MEMTX_ACCESS_ERROR; 139+ /* Keep going. */ 140+ } else if (!memory_access_is_direct(mr, false)) { 141 /* I/O case */ 142 release_lock |= prepare_mmio_access(mr); 143 l = memory_access_size(mr, l, addr1); 144@@ -2879,6 +2916,9 @@ static MemTxResult flatview_read(FlatVie 145 146 l = len; 147 mr = flatview_translate(fv, addr, &addr1, &l, false, attrs); 148+ if (!flatview_access_allowed(mr, attrs, addr, len)) { 149+ return MEMTX_ACCESS_ERROR; 150+ } 151 return flatview_read_continue(fv, addr, attrs, buf, len, 152 addr1, l, mr); 153 } 154-- 1551.8.3.1 156 157