Patchwork [4/7] linux-user: Use guest_start_len_valid in mremap.

login
register
mail settings
Submitter Richard Henderson
Date March 30, 2010, 6:52 p.m.
Message ID <3a524a7b48fad38a52c6df21a332374983f86a68.1270488612.git.rth@twiddle.net>
Download mbox | patch
Permalink /patch/49417/
State New
Headers show

Comments

Richard Henderson - March 30, 2010, 6:52 p.m.
Also properly signal error for non-page aligned inputs
and zero sized outputs.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/mmap.c |   44 ++++++++++++++++++++++++--------------------
 1 files changed, 24 insertions(+), 20 deletions(-)

Patch

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;
 }