Also properly signal error for non-page aligned inputs and zero sized outputs.
Signed-off-by: Richard Henderson <r...@twiddle.net> --- linux-user/mmap.c | 44 ++++++++++++++++++++++++-------------------- 1 files changed, 24 insertions(+), 20 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index f4d44a8..463679d 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -657,37 +657,40 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_addr) { int prot; - void *host_addr; + void *host_addr = MAP_FAILED; - mmap_lock(); + if (new_size == 0 || (old_addr & ~TARGET_PAGE_MASK)) { + errno = EINVAL; + return -1; + } - if (flags & MREMAP_FIXED) - host_addr = (void *) syscall(__NR_mremap, g2h(old_addr), - old_size, new_size, - flags, - new_addr); - else if (flags & MREMAP_MAYMOVE) { - abi_ulong mmap_start; + mmap_lock(); - mmap_start = mmap_find_vma(0, new_size); + /* ??? If host page size > target page size, we can fail here + when we shouldn't. */ + if (flags & MREMAP_FIXED) { + if (new_addr & ~TARGET_PAGE_MASK) { + errno = EINVAL; + } else { + host_addr = (void *) syscall(__NR_mremap, g2h(old_addr), + old_size, new_size, flags, new_addr); + } + } else if (flags & MREMAP_MAYMOVE) { + abi_ulong mmap_start = mmap_find_vma(0, new_size); if (mmap_start == -1) { errno = ENOMEM; - host_addr = MAP_FAILED; - } else + } else { host_addr = (void *) syscall(__NR_mremap, g2h(old_addr), old_size, new_size, flags | MREMAP_FIXED, g2h(mmap_start)); - } else { - host_addr = mremap(g2h(old_addr), old_size, new_size, flags); - /* Check if address fits target address space */ - if ((unsigned long)host_addr + new_size > (abi_ulong)-1) { - /* Revert mremap() changes */ - host_addr = mremap(g2h(old_addr), new_size, old_size, flags); - errno = ENOMEM; - host_addr = MAP_FAILED; } + } else if (guest_start_len_valid(old_addr, new_size)) { + host_addr = mremap(g2h(old_addr), old_size, new_size, flags); + assert(host_addr == g2h(old_addr) || host_addr == MAP_FAILED); + } else { + errno = ENOMEM; } if (host_addr == MAP_FAILED) { @@ -698,6 +701,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); } + mmap_unlock(); return new_addr; } -- 1.6.6.1