Patchwork [RFC,1/1] linux-user: Probe the guest base for shared objects when needed

login
register
mail settings
Submitter Meador Inge
Date June 28, 2012, 12:32 a.m.
Message ID <4FEBA613.3010009@codesourcery.com>
Download mbox | patch
Permalink /patch/167764/
State New
Headers show

Comments

Meador Inge - June 28, 2012, 12:32 a.m.
On 06/27/2012 12:32 PM, Richard Henderson wrote:

> On 06/27/2012 08:51 AM, Meador Inge wrote:
>> To solve this issue I experimented with performing a similar probing in 'main'
>> as in 'probe_guest_base' so that we can find a reserved VA region that also
>> passes validation.  If a region isn't found that can be validated, then QEMU
>> gives up.  Does this approach seem reasonable?
> 
> I guess so, depending on how you adjust the hint each time.

What I am currently experimenting with is essentially the same as what is in
'probe_guest_base'.  So something like (not an actually patch submission, just
listing this here for discussion):


> I do wonder if it wouldn't be better to rearrange things such that
> for 64-bit hosts and 32-bit guests we *always* reserve 4G so that
> there's zero possibility of the guest stomping on host memory.  That
> would also solve your problem.

I am seeing problems with 32-on-32 where the ARM commpage check wraps around
(incidentally I also ran into problems with -B because for some values of
guest_base it is easy for guest_base >= min_mmap_addr and guest_base +
kernel_helper_addr < min_mmap_addr to hold).

Patch

Index: linux-user/main.c
===================================================================
--- linux-user/main.c	(revision 376549)
+++ linux-user/main.c	(working copy)
@@ -3486,35 +3486,53 @@  int main(int argc, char **argv, char **e
     guest_base = HOST_PAGE_ALIGN(guest_base);

     if (reserved_va) {
-        void *p;
+        unsigned long host_start, real_start, first_start, host_size;
         int flags;

         flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
         if (have_guest_base) {
             flags |= MAP_FIXED;
         }
-        p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0);
-        if (p == MAP_FAILED) {
-            fprintf(stderr, "Unable to reserve guest address space\n");
-            exit(1);
-        }
-        guest_base = (unsigned long)p;
-        /* Make sure the address is properly aligned.  */
-        if (guest_base & ~qemu_host_page_mask) {
-            munmap(p, reserved_va);
-            p = mmap((void *)guest_base, reserved_va + qemu_host_page_size,
-                     PROT_NONE, flags, -1, 0);
-            if (p == MAP_FAILED) {
+
+	first_start = host_start = HOST_PAGE_ALIGN(guest_base);
+	while (1) {
+            host_size = reserved_va;
+            real_start = (unsigned long) mmap((void *)host_start, host_size,
+                                              PROT_NONE, flags, -1, 0);
+            if (real_start == (unsigned long)-1) {
+                fprintf(stderr, "Unable to reserve guest address space\n");
+                exit(1);
+            }
+            guest_base = host_start;
+            /* Make sure the address is properly aligned.  */
+            if (guest_base & ~qemu_host_page_mask) {
+                munmap((void*)real_start, host_size);
+                host_size += qemu_host_page_size;
+                real_start = (unsigned long) mmap((void *)guest_base,
+                                                  host_size,
+                                                  PROT_NONE, flags, -1, 0);
+                if (real_start == (unsigned long)-1) {
+                    fprintf(stderr, "Unable to reserve guest address space\n");
+                    exit(1);
+                }
+                guest_base = HOST_PAGE_ALIGN(real_start);
+            }
+
+            if (guest_validate_base(guest_base))
+                break;
+
+            munmap((void *)real_start, host_size);
+            host_start += qemu_host_page_size;
+            if (host_start == first_start) {
                 fprintf(stderr, "Unable to reserve guest address space\n");
                 exit(1);
             }
-            guest_base = HOST_PAGE_ALIGN((unsigned long)p);
         }
         qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
         mmap_next_start = reserved_va;
     }

-    if (reserved_va || have_guest_base) {
+    if (have_guest_base) {
         if (!guest_validate_base(guest_base)) {
             fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
             exit(1);