summaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2018-01-30 13:36:15 -0800
committerMax Filippov <jcmvbkbc@gmail.com>2018-03-13 11:30:22 -0700
commite530acd7de8178ca1eb30ac4c19508e6f68a172d (patch)
tree3e5d749c22a97be7b72c4f7cb24d06157d1ee7ea /linux-user
parent9fb40342d4b32152cedf32efe28b59ec3b932bd8 (diff)
downloadqemu-e530acd7de8178ca1eb30ac4c19508e6f68a172d.tar.gz
linux-user: fix mmap/munmap/mprotect/mremap/shmat
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: qemu-stable@nongnu.org Cc: Riku Voipio <riku.voipio@iki.fi> Cc: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/mmap.c20
-rw-r--r--linux-user/syscall.c5
2 files changed, 19 insertions, 6 deletions
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 0fbfd6dff2..df81f9b803 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 b4f7b14fbe..9cba25dc88 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4900,6 +4900,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();
@@ -7468,7 +7471,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;
}