From 354946f1e5fee0a69282bdf284c969b03a78a53e Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Wed, 13 Jan 2021 00:42:23 -0500 Subject: [PATCH 15/17] memory: clamp cached translation in case it points to an MMIO region RH-Author: Jon Maloy Message-id: <20210113004223.871394-2-jmaloy@redhat.com> Patchwork-id: 100618 O-Subject: [RHEL-8.4.0 qemu-kvm PATCH 1/1] memory: clamp cached translation in case it points to an MMIO region Bugzilla: 1904393 RH-Acked-by: Paolo Bonzini RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: Thomas Huth From: Paolo Bonzini In using the address_space_translate_internal API, address_space_cache_init forgot one piece of advice that can be found in the code for address_space_translate_internal: /* MMIO registers can be expected to perform full-width accesses based only * on their address, without considering adjacent registers that could * decode to completely different MemoryRegions. When such registers * exist (e.g. I/O ports 0xcf8 and 0xcf9 on most PC chipsets), MMIO * regions overlap wildly. For this reason we cannot clamp the accesses * here. * * If the length is small (as is the case for address_space_ldl/stl), * everything works fine. If the incoming length is large, however, * the caller really has to do the clamping through memory_access_size. */ address_space_cache_init is exactly one such case where "the incoming length is large", therefore we need to clamp the resulting length---not to memory_access_size though, since we are not doing an access yet, but to the size of the resulting section. This ensures that subsequent accesses to the cached MemoryRegionSection will be in range. With this patch, the enclosed testcase notices that the used ring does not fit into the MSI-X table and prints a "qemu-system-x86_64: Cannot map used" error. Signed-off-by: Paolo Bonzini (cherry picked from 4bfb024bc76973d40a359476dc0291f46e435442) - Manually applied to file exec.c, where the code to correct is located in this version. - Skipped the fuzzing test part, which is hard to apply on this code. Signed-off-by: Jon Maloy Signed-off-by: Danilo C. L. de Paula --- exec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/exec.c b/exec.c index ffdb5185353..09ed0cfc756 100644 --- a/exec.c +++ b/exec.c @@ -3620,6 +3620,7 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, AddressSpaceDispatch *d; hwaddr l; MemoryRegion *mr; + Int128 diff; assert(len > 0); @@ -3628,6 +3629,15 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, d = flatview_to_dispatch(cache->fv); cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true); + /* + * cache->xlat is now relative to cache->mrs.mr, not to the section itself. + * Take that into account to compute how many bytes are there between + * cache->xlat and the end of the section. + */ + diff = int128_sub(cache->mrs.size, + int128_make64(cache->xlat - cache->mrs.offset_within_region)); + l = int128_get64(int128_min(diff, int128_make64(l))); + mr = cache->mrs.mr; memory_region_ref(mr); if (memory_access_is_direct(mr, is_write)) { -- 2.27.0