Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12:Update
xen
CVE-2015-8818-qemuu-OOB-access-in-address_space...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2015-8818-qemuu-OOB-access-in-address_space_rw-leads-to-segmentation-fault.patch of Package xen
References: bsc#969126 CVE-2015-8818 Subject: exec: skip MMIO regions correctly in cpu_physical_memory_write_rom_internal From: Paolo Bonzini pbonzini@redhat.com Sat Jul 4 00:24:51 2015 +0200 Date: Mon Jul 6 14:59:11 2015 +0200: Git: b242e0e0e2969c044a318e56f7988bbd84de1f63 Loading the BIOS in the mac99 machine is interesting, because there is a PROM in the middle of the BIOS region (from 16K to 32K). Before memory region accesses were clamped, when QEMU was asked to load a BIOS from 0xfff00000 to 0xffffffff it would put even those 16K from the BIOS file into the region. This is weird because those 16K were not actually visible between 0xfff04000 and 0xfff07fff. However, it worked. After clamping was added, this also worked. In this case, the cpu_physical_memory_write_rom_internal function split the write in three parts: the first 16K were copied, the PROM area (second 16K) were ignored, then the rest was copied. Problems then started with commit 965eb2f (exec: do not clamp accesses to MMIO regions, 2015-06-17). Clamping accesses is not done for MMIO regions because they can overlap wildly, and MMIO registers can be expected to perform full-width accesses based only on their address (with no respect for adjacent registers that could decode to completely different MemoryRegions). However, this lack of clamping also applied to the PROM area! cpu_physical_memory_write_rom_internal thus failed to copy the third range above, i.e. only copied the first 16K of the BIOS. In effect, address_space_translate is expecting _something else_ to do the clamping for MMIO regions if the incoming length is large. This "something else" is memory_access_size in the case of address_space_rw, so use the same logic in cpu_physical_memory_write_rom_internal. Reported-by: Alexander Graf <agraf@redhat.com> Reviewed-by: Laurent Vivier <lvivier@redhat.com> Tested-by: Laurent Vivier <lvivier@redhat.com> Fixes: 965eb2f Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Index: xen-4.4.4-testing/tools/qemu-xen-dir-remote/exec.c =================================================================== --- xen-4.4.4-testing.orig/tools/qemu-xen-dir-remote/exec.c +++ xen-4.4.4-testing/tools/qemu-xen-dir-remote/exec.c @@ -251,7 +251,8 @@ address_space_translate_internal(Address hwaddr *plen, bool resolve_subpage) { MemoryRegionSection *section; - Int128 diff, diff_page; + MemoryRegion *mr; + Int128 diff; section = address_space_lookup_region(d, addr, resolve_subpage); /* Compute offset within MemoryRegionSection */ @@ -260,10 +261,23 @@ address_space_translate_internal(Address /* Compute offset within MemoryRegion */ *xlat = addr + section->offset_within_region; - diff_page = int128_make64(((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr); - diff = int128_sub(section->mr->size, int128_make64(addr)); - diff = int128_min(diff, diff_page); - *plen = int128_get64(int128_min(diff, int128_make64(*plen))); + mr = section->mr; + + /* 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. + */ + if (memory_region_is_ram(mr)) { + diff = int128_sub(section->size, int128_make64(addr)); + *plen = int128_get64(int128_min(diff, int128_make64(*plen))); + } return section; } @@ -2070,7 +2084,7 @@ void cpu_physical_memory_write_rom(hwadd if (!(memory_region_is_ram(mr) || memory_region_is_romd(mr))) { - /* do nothing */ + l = memory_access_size(mr, l, addr1); } else { addr1 += memory_region_get_ram_addr(mr); /* ROM/RAM case */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor