[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-stable] [PATCH 023/113] linux-user: fix mmap/munmap/mprotect/mrema
From: |
Michael Roth |
Subject: |
[Qemu-stable] [PATCH 023/113] linux-user: fix mmap/munmap/mprotect/mremap/shmat |
Date: |
Mon, 18 Jun 2018 20:41:49 -0500 |
From: Max Filippov <address@hidden>
In linux-user QEMU that runs for a target with TARGET_ABI_BITS bigger
than L1_MAP_ADDR_SPACE_BITS an assertion in page_set_flags fires when
mmap, munmap, mprotect, mremap or shmat is called for an address outside
the guest address space. mmap and mprotect should return ENOMEM in such
case.
Change definition of GUEST_ADDR_MAX to always be the last valid guest
address. Account for this change in open_self_maps.
Add macro guest_addr_valid that verifies if the guest address is valid.
Add function guest_range_valid that verifies if address range is within
guest address space and does not wrap around. Use that macro in
mmap/munmap/mprotect/mremap/shmat for error checking.
Cc: address@hidden
Cc: Riku Voipio <address@hidden>
Cc: Laurent Vivier <address@hidden>
Signed-off-by: Max Filippov <address@hidden>
Reviewed-by: Laurent Vivier <address@hidden>
Message-Id: <address@hidden>
Signed-off-by: Laurent Vivier <address@hidden>
(cherry picked from commit ebf9a3630c911d0cfc9c20f7cafe9ba4f88cf583)
Signed-off-by: Michael Roth <address@hidden>
---
include/exec/cpu-all.h | 6 +++++-
include/exec/cpu_ldst.h | 16 +++++++---------
linux-user/mmap.c | 20 +++++++++++++++-----
linux-user/syscall.c | 5 ++++-
4 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 0b141683f0..f4fa94e966 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -159,8 +159,12 @@ extern unsigned long guest_base;
extern int have_guest_base;
extern unsigned long reserved_va;
-#define GUEST_ADDR_MAX (reserved_va ? reserved_va : \
+#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
+#define GUEST_ADDR_MAX (~0ul)
+#else
+#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : \
(1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
+#endif
#else
#include "exec/hwaddr.h"
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 191f2e962a..5de8c8a5af 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -51,15 +51,13 @@
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base))
-#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
-#define h2g_valid(x) 1
-#else
-#define h2g_valid(x) ({ \
- unsigned long __guest = (unsigned long)(x) - guest_base; \
- (__guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) && \
- (!reserved_va || (__guest < reserved_va)); \
-})
-#endif
+#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX)
+#define h2g_valid(x) guest_addr_valid((unsigned long)(x) - guest_base)
+
+static inline int guest_range_valid(unsigned long start, unsigned long len)
+{
+ return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1;
+}
#define h2g_nocheck(x) ({ \
unsigned long __ret = (unsigned long)(x) - guest_base; \
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 4888f53139..33a73cd29c 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -80,8 +80,9 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
- if (end < start)
- return -EINVAL;
+ if (!guest_range_valid(start, len)) {
+ return -ENOMEM;
+ }
prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
if (len == 0)
return 0;
@@ -481,8 +482,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int
prot,
* It can fail only on 64-bit host with 32-bit target.
* On any other target/host host mmap() handles this error correctly.
*/
- if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
- errno = EINVAL;
+ if (!guest_range_valid(start, len)) {
+ errno = ENOMEM;
goto fail;
}
@@ -622,8 +623,10 @@ int target_munmap(abi_ulong start, abi_ulong len)
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
- if (len == 0)
+ if (len == 0 || !guest_range_valid(start, len)) {
return -EINVAL;
+ }
+
mmap_lock();
end = start + len;
real_start = start & qemu_host_page_mask;
@@ -678,6 +681,13 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong
old_size,
int prot;
void *host_addr;
+ if (!guest_range_valid(old_addr, old_size) ||
+ ((flags & MREMAP_FIXED) &&
+ !guest_range_valid(new_addr, new_size))) {
+ errno = ENOMEM;
+ return -1;
+ }
+
mmap_lock();
if (flags & MREMAP_FIXED) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 11c9116c4a..9872de7221 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4871,6 +4871,9 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
return -TARGET_EINVAL;
}
}
+ if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
+ return -TARGET_EINVAL;
+ }
mmap_lock();
@@ -7430,7 +7433,7 @@ static int open_self_maps(void *cpu_env, int fd)
}
if (h2g_valid(min)) {
int flags = page_get_flags(h2g(min));
- max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
+ max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) +
1;
if (page_check_range(h2g(min), max - min, flags) == -1) {
continue;
}
--
2.11.0
- [Qemu-stable] [PATCH 015/113] spapr: register dummy ICPs later, (continued)
- [Qemu-stable] [PATCH 015/113] spapr: register dummy ICPs later, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 014/113] spapr: fix missing CPU core nodes in DT when running with TCG, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 016/113] spapr: make pseries-2.11 the default machine type, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 017/113] nbd: Honor server's advertised minimum block size, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 018/113] specs/qcow2: Fix documentation of the compressed cluster descriptor, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 019/113] rbd: Fix use after free in qemu_rbd_set_keypairs() error path, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 020/113] tpm: Set the flags of the CMD_INIT command to 0, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 001/113] block/ssh: fix possible segmentation fault when .desc is not null-terminated, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 021/113] loader: don't perform overlapping address check for memory region ROM images, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 022/113] target/xtensa: dump correct physical registers, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 023/113] linux-user: fix mmap/munmap/mprotect/mremap/shmat,
Michael Roth <=
- [Qemu-stable] [PATCH 024/113] linux-user: fix assertion in shmdt, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 025/113] linux-user: fix target_mprotect/target_munmap error return values, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 027/113] openpic_kvm: drop address_space_to_flatview call, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 026/113] sparc: fix leon3 casa instruction when MMU is disabled, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 028/113] memory: inline some performance-sensitive accessors, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 029/113] address_space_write: address_space_to_flatview needs RCU lock, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 002/113] pci-bridge/i82801b11: clear bridge registers on platform reset, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 031/113] address_space_access_valid: address_space_to_flatview needs RCU lock, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 030/113] address_space_read: address_space_to_flatview needs RCU lock, Michael Roth, 2018/06/18
- [Qemu-stable] [PATCH 032/113] address_space_map: address_space_to_flatview needs RCU lock, Michael Roth, 2018/06/18