Hi,

I recently tried to run qemu, and it failed with SIGABRT and dmesg
contains:

map stack 0x86277000-0x86378000 of map 0xd5343afc failed: bad protection
map stack for pid 43079 failed

I initially think about missing MAP_STACK. And effectively, the flag is
missing on the port (function qemu_alloc_stack() in util/oslib-posix.c).
But in fact, it seems it isn't underline problem of my failure: even
with MAP_STACK, the program is still aborted at the same place.

The real problem is qemu implements a stackguard protection

from qemu, util/oslib-posix.c (with manually added MAP_STACK):
   540      ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE,
   541                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
   542      if (ptr == MAP_FAILED) {
   543          perror("failed to allocate memory for stack");
   544          abort();
   545      }
   546
   547  #if defined(HOST_IA64)
   548      /* separate register stack */
   549      guardpage = ptr + (((*sz - pagesz) / 2) & ~pagesz);
   550  #elif defined(HOST_HPPA)
   551      /* stack grows up */
   552      guardpage = ptr + *sz - pagesz;
   553  #else
   554      /* stack grows down */
   555      guardpage = ptr;
   556  #endif
   557
   558      if (mprotect(guardpage, pagesz, PROT_NONE) != 0) {
   559          perror("failed to set up stack guard page");
   560          abort();
   561      }
   562

and the kernel doesn't like it: in uvm_map_is_stack_remappable(), the
protection check is done by only allowing PROT_READ | PROT_WRITE:

sys/uvm/uvm_map.c
  1852                  if (iter->protection != (PROT_READ | PROT_WRITE)) {
  1853                          printf("map stack 0x%lx-0x%lx of map %p failed: 
"
  1854                              "bad protection\n", addr, end, map);
  1855                          return FALSE;
  1856                  }

and the guardpage segment is PROT_NONE, resulting an error, and qemu
abort.

If I remove the mprotect(2) call from qemu, the program starts fine (I
didn't test it deeply).

Assuming the check on protection is a bit too restrictive, and it is
fine to have some chunks with PROT_NONE, I think we want something like:

Index: uvm/uvm_map.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.c,v
retrieving revision 1.234
diff -u -p -r1.234 uvm_map.c
--- uvm/uvm_map.c       12 Apr 2018 17:13:44 -0000      1.234
+++ uvm/uvm_map.c       16 Apr 2018 15:20:30 -0000
@@ -1849,7 +1849,11 @@ uvm_map_is_stack_remappable(struct vm_ma
 #if 0
                printf("iter prot: 0x%x\n", iter->protection);
 #endif
-               if (iter->protection != (PROT_READ | PROT_WRITE)) {
+               switch (iter->protection) {
+               case PROT_READ|PROT_WRITE:
+               case PROT_NONE:
+                       break;
+               default:
                        printf("map stack 0x%lx-0x%lx of map %p failed: "
                            "bad protection\n", addr, end, map);
                        return FALSE;


I will send a diff for emulators/qemu to add MAP_STACK after this part
is resolved.

Thanks.
-- 
Sebastien Marie

Reply via email to