On i386 don't attempt to map shared libraries in low memory when
authorkurt <kurt@openbsd.org>
Tue, 16 Mar 2021 18:03:06 +0000 (18:03 +0000)
committerkurt <kurt@openbsd.org>
Tue, 16 Mar 2021 18:03:06 +0000 (18:03 +0000)
a large executable's .text section crosses the 512MB exec line.

Executables that have MAXTSIZ > 64MB can map above the default
512MB exec line. When this happens, shared libs that attempt to map
into low memory will find their .data section can not be mapped. ld.so
will attempt to remap the share lib at higher addresses until it can be
mapped. For very large executables like chrome this process is very
time consuming. This change detects how much of the executable's
.text section exceeds 512MB and uses that as the initial hint for
shared libs to map into which avoids attempting to map into blocked
memory.

okay deraadt@

libexec/ld.so/library_mquery.c
libexec/ld.so/loader.c
libexec/ld.so/resolve.h

index 426b4da..c6b1f15 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: library_mquery.c,v 1.64 2019/12/09 23:15:03 bluhm Exp $ */
+/*     $OpenBSD: library_mquery.c,v 1.65 2021/03/16 18:03:06 kurt Exp $ */
 
 /*
  * Copyright (c) 2002 Dale Rahn
@@ -256,6 +256,8 @@ retry:
                         * EXEC region unless it is writable.
                         */
                        int exec = (ld->prot & PROT_WRITE) ? 0 : PROT_EXEC;
+                       if (exec && lowld->start == NULL)
+                               lowld->start = _dl_exec_hint;
                        res = _dl_mquery((void *)(LOFF + ld->moff),
                            ROUND_PG(ld->size), ld->prot | exec, flags,
                            fd, foff);
index f63825f..18bd30a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: loader.c,v 1.190 2019/12/17 03:16:07 guenther Exp $ */
+/*     $OpenBSD: loader.c,v 1.191 2021/03/16 18:03:06 kurt Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -32,6 +32,7 @@
 #include <sys/mman.h>
 #include <sys/exec.h>
 #include <sys/sysctl.h>
+#include <machine/vmparam.h>
 #include <nlist.h>
 #include <string.h>
 #include <link.h>
@@ -73,6 +74,7 @@ char *_dl_preload __boot_data = NULL;
 char *_dl_tracefmt1 __boot_data = NULL;
 char *_dl_tracefmt2 __boot_data = NULL;
 char *_dl_traceprog __boot_data = NULL;
+void *_dl_exec_hint __boot_data = NULL;
 
 char **environ = NULL;
 char *__progname = NULL;
@@ -461,7 +463,7 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
        unsigned int loop;
        int failed;
        struct dep_node *n;
-       Elf_Addr minva, maxva, exe_loff;
+       Elf_Addr minva, maxva, exe_loff, exec_end, cur_exec_end;
        Elf_Phdr *ptls = NULL;
        int align;
 
@@ -499,7 +501,7 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
        _dl_loading_object = NULL;
 
        minva = ELF_NO_ADDR;
-       maxva = exe_loff = 0;
+       maxva = exe_loff = exec_end = 0;
 
        /*
         * Examine the user application and set up object information.
@@ -539,6 +541,10 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
                        next_load->start = (char *)TRUNC_PG(phdp->p_vaddr) + exe_loff;
                        next_load->size = (phdp->p_vaddr & align) + phdp->p_filesz;
                        next_load->prot = PFLAGS(phdp->p_flags);
+                       cur_exec_end = (Elf_Addr)next_load->start + next_load->size;
+                       if ((next_load->prot & PROT_EXEC) != 0 &&
+                           cur_exec_end > exec_end)
+                               exec_end = cur_exec_end;
                        break;
                case PT_TLS:
                        if (phdp->p_filesz > phdp->p_memsz)
@@ -557,6 +563,12 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
        exe_obj->load_size = maxva - minva;
        _dl_set_sod(exe_obj->load_name, &exe_obj->sod);
 
+#ifdef __i386__
+       if (exec_end > I386_MAX_EXE_ADDR)
+               _dl_exec_hint = (void *)ROUND_PG(exec_end-I386_MAX_EXE_ADDR);
+       DL_DEB(("_dl_exec_hint:  0x%lx\n", _dl_exec_hint));
+#endif
+
        /* TLS bits in the base executable */
        if (ptls != NULL && ptls->p_memsz)
                _dl_set_tls(exe_obj, ptls, exe_loff, NULL);
index 1bad5d6..6c7380f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: resolve.h,v 1.96 2019/10/04 17:42:16 guenther Exp $ */
+/*     $OpenBSD: resolve.h,v 1.97 2021/03/16 18:03:06 kurt Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -350,6 +350,8 @@ extern char *_dl_tracefmt1;
 extern char *_dl_tracefmt2;
 extern char *_dl_traceprog;
 
+extern void *_dl_exec_hint;
+
 extern int _dl_trust;
 
 #define DL_DEB(P) do { if (_dl_debug) _dl_printf P ; } while (0)