Browse Source

[Pal/Linux] Load forked executable at the same address as parent

During fork emulation, the first exec file must be mapped at the same
address as the parent process.
In previous implementation if ASLR was enabled, the address could be
different from the parent, which could result in a corrupted state.
Pass the address for exec file to be mapped from parent process
to the child process and use that address.
At the same time, fix a problem with file handle not being
fully initialized in pal_linux_main().
Isaku Yamahata 5 years ago
parent
commit
b8031c4224

+ 11 - 0
Pal/src/host/Linux/db_files.c

@@ -65,6 +65,7 @@ static int file_open (PAL_HANDLE * handle, const char * type, const char * uri,
     hdl->file.offset = 0;
     hdl->file.append = 0;
     hdl->file.pass = 0;
+    hdl->file.map_start = NULL;
     char * path = (void *) hdl + HANDLE_SIZE(file);
     memcpy(path, uri, len + 1);
     hdl->file.realpath = (PAL_STR) path;
@@ -156,6 +157,16 @@ static int file_map (PAL_HANDLE handle, void ** addr, int prot,
 {
     int fd = handle->file.fd;
     void * mem = *addr;
+    /*
+     * work around for fork emulation
+     * the first exec image to be loaded has to be at same address
+     * as parent.
+     */
+    if (mem == NULL && handle->file.map_start != NULL) {
+        mem = (PAL_PTR)handle->file.map_start;
+        /* this address is used. don't over-map it later */
+        handle->file.map_start = NULL;
+    }
     int flags = MAP_FILE|HOST_FLAGS(0, prot)|(mem ? MAP_FIXED : 0);
     prot = HOST_PROT(prot);
 

+ 4 - 0
Pal/src/host/Linux/db_main.c

@@ -289,6 +289,10 @@ void pal_linux_main (void * args)
     SET_HANDLE_TYPE(file, file);
     HANDLE_HDR(file)->flags |= RFD(0)|WFD(0)|WRITEABLE(0);
     file->file.fd = fd;
+    file->file.offset = 0;
+    file->file.append = false;
+    file->file.pass = false;
+    file->file.map_start = NULL;
     char * path = (void *) file + HANDLE_SIZE(file);
     get_norm_path(argv[0], path, 0, len + 1);
     file->file.realpath = path;

+ 15 - 0
Pal/src/host/Linux/db_process.c

@@ -36,6 +36,7 @@
 #include "pal_debug.h"
 #include "pal_error.h"
 #include "pal_security.h"
+#include "pal_rtld.h"
 #include "graphene.h"
 #include "graphene-ipc.h"
 #include "api.h"
@@ -183,6 +184,20 @@ int _DkProcessCreate (PAL_HANDLE * handle, const char * uri, const char ** args)
             ret = -PAL_ERROR_INVAL;
             goto out;
         }
+
+        /* If this process creation is for fork emulation,
+         * map address of executable is already determined.
+         * tell its address to forked process.
+         */
+        size_t len;
+        const char * file_uri = "file:";
+        if (exec_map && exec_map->l_name &&
+            (len = strlen(uri)) >= 5 && !memcmp(uri, file_uri, 5) &&
+            /* skip "file:"*/
+            strlen(exec_map->l_name) == len - 5 &&
+            /* + 1 for lasting * NUL */
+            !memcmp(exec_map->l_name, uri + 5, len - 5 + 1))
+            exec->file.map_start = (PAL_PTR)exec_map->l_map_start;
     }
 
     /* step 2: create parant and child process handle */

+ 6 - 0
Pal/src/host/Linux/pal_host.h

@@ -90,6 +90,12 @@ typedef struct pal_handle
             PAL_BOL append;
             PAL_BOL pass;
             PAL_STR realpath;
+            /*
+             * map_start is to request this file should be mapped to this
+             * address. When fork is emulated, the address is already
+             * determined by parent process.
+             */
+            PAL_PTR map_start;
         } file;
         
         struct {