new file mode 100644
@@ -0,0 +1,35 @@
+/* Early initialization of libc.so.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef EARLY_INIT_H
+#define EARLY_INIT_H
+
+#include <ldsodefs.h>
+
+static __attribute__ ((unused)) void
+call_libc_early_init (Lmid_t nsid, struct link_map *new_object)
+{
+ if (!GL(dl_ns)[nsid].libc_initialized)
+ {
+#ifndef SHARED
+ GL(dl_ns)[nsid].libc_initialized = DL_STATIC_INIT (new_object);
+#endif
+ }
+}
+
+#endif /* EARLY_INIT_H */
@@ -33,6 +33,7 @@
#include <stap-probe.h>
#include <atomic.h>
#include <libc-internal.h>
+#include <dl-early-init.h>
#include <dl-dst.h>
#include <dl-prop.h>
@@ -502,9 +503,15 @@ TLS generation counter wrapped! Please report this."));
if (relocation_in_progress)
LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
-#ifndef SHARED
- DL_STATIC_INIT (new);
-#endif
+ /* Initialize libc.so early, before applying RELRO protection and
+ running ELF constructors. */
+ call_libc_early_init (args->nsid, new);
+
+ /* Apply RELRO protection after early initialization, which may have
+ updated RELRO data. */
+ for (unsigned int i = nmaps; i-- > 0; )
+ if (maps[i]->l_relro_size != 0)
+ _dl_protect_relro (maps[i]);
/* Run the initializer functions of new objects. */
_dl_init (new, args->argc, args->argv, args->env);
@@ -295,11 +295,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
textrels = textrels->next;
}
-
- /* In case we can protect the data now that the relocations are
- done, do it. */
- if (l->l_relro_size != 0)
- _dl_protect_relro (l);
}
@@ -43,6 +43,7 @@
#include <stap-probe.h>
#include <stackinfo.h>
#include <not-cancel.h>
+#include <dl-early-init.h>
#include <assert.h>
@@ -2209,8 +2210,6 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
for (struct link_map *l = main_map; l != NULL; l = l->l_next)
{
l->l_relocated = 1;
- if (l->l_relro_size)
- _dl_protect_relro (l);
/* Add object to slot information data if necessasy. */
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
@@ -2314,6 +2313,21 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
rtld_timer_accum (&relocate_time, start);
}
+ /* Perform early libc.so initialization before applying RELRO
+ protection. */
+ call_libc_early_init (LM_ID_BASE, main_map);
+
+ /* Apply RELRO protection to everything that requests it. */
+ {
+ unsigned i = main_map->l_searchlist.r_nlist;
+ while (i-- > 0)
+ {
+ struct link_map *l = main_map->l_initfini[i];
+ if (l->l_relro_size != 0)
+ _dl_protect_relro (l);
+ }
+ }
+
/* Do any necessary cleanups for the startup OS interface code.
We do these now so that no calls are made after rtld re-relocation
which might be resolved to different functions than we expect.
@@ -131,9 +131,11 @@ dl_symbol_visibility_binds_local_p (const ElfW(Sym) *sym)
#endif
/* By default we do not need special support to initialize DSOs loaded
- by statically linked binaries. */
+ by statically linked binaries. A true value indicates that
+ initialization happened (and that GL(dl_ns)[nsid].libc_initialized
+ should be updated). */
#ifndef DL_STATIC_INIT
-# define DL_STATIC_INIT(map)
+# define DL_STATIC_INIT(map) true
#endif
/* Reloc type classes as returned by elf_machine_type_class().
@@ -323,6 +325,11 @@ struct rtld_global
struct link_map *_ns_loaded;
/* Number of object in the _dl_loaded list. */
unsigned int _ns_nloaded;
+
+ /* Non-zero if libc has been found in the namespace and has been
+ initialized. */
+ bool libc_initialized;
+
/* Direct pointer to the searchlist of the main object. */
struct r_scope_elem *_ns_main_searchlist;
/* This is zero at program start to signal that the global scope map is
@@ -45,46 +45,23 @@ static void *variables[] =
&GLRO(dl_pagesize)
};
-static void
-_dl_unprotect_relro (struct link_map *l)
-{
- ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
- & ~(GLRO(dl_pagesize) - 1));
- ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
- & ~(GLRO(dl_pagesize) - 1));
-
- if (start != end)
- __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE);
-}
-
-void
+bool
_dl_static_init (struct link_map *l)
{
- struct link_map *rtld_map = l;
- struct r_scope_elem **scope;
const ElfW(Sym) *ref = NULL;
lookup_t loadbase;
void (*f) (void *[]);
- size_t i;
loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope,
NULL, 0, 1, NULL);
-
- for (scope = l->l_local_scope; *scope != NULL; scope++)
- for (i = 0; i < (*scope)->r_nlist; i++)
- if ((*scope)->r_list[i] == loadbase)
- {
- rtld_map = (*scope)->r_list[i];
- break;
- }
-
if (ref != NULL)
{
f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref);
- _dl_unprotect_relro (rtld_map);
f (variables);
- _dl_protect_relro (rtld_map);
+ return true;
}
+ else
+ return false;
}
#endif
@@ -26,7 +26,7 @@
/* We need special support to initialize DSO loaded for statically linked
binaries. */
-extern void _dl_static_init (struct link_map *map);
+extern bool _dl_static_init (struct link_map *map);
#undef DL_STATIC_INIT
#define DL_STATIC_INIT(map) _dl_static_init (map)
@@ -50,7 +50,7 @@ static void *variables[] =
&GLRO(dl_clktck)
};
-void
+bool
_dl_static_init (struct link_map *map)
{
const ElfW(Sym) *ref = NULL;
@@ -63,7 +63,10 @@ _dl_static_init (struct link_map *map)
{
f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref);
f (variables);
+ return true;
}
+ else
+ return false;
}
#endif
@@ -25,7 +25,7 @@
/* We need special support to initialize DSO loaded for statically linked
binaries. */
-extern void _dl_static_init (struct link_map *map);
+extern bool _dl_static_init (struct link_map *map);
#undef DL_STATIC_INIT
#define DL_STATIC_INIT(map) _dl_static_init (map)
@@ -45,46 +45,23 @@ static void *variables[] =
&GLRO(dl_pagesize)
};
-static void
-_dl_unprotect_relro (struct link_map *l)
-{
- ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
- & ~(GLRO(dl_pagesize) - 1));
- ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
- & ~(GLRO(dl_pagesize) - 1));
-
- if (start != end)
- __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE);
-}
-
-void
+bool
_dl_static_init (struct link_map *l)
{
- struct link_map *rtld_map = l;
- struct r_scope_elem **scope;
const ElfW(Sym) *ref = NULL;
lookup_t loadbase;
void (*f) (void *[]);
- size_t i;
loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope,
NULL, 0, 1, NULL);
-
- for (scope = l->l_local_scope; *scope != NULL; scope++)
- for (i = 0; i < (*scope)->r_nlist; i++)
- if ((*scope)->r_list[i] == loadbase)
- {
- rtld_map = (*scope)->r_list[i];
- break;
- }
-
if (ref != NULL)
{
f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref);
- _dl_unprotect_relro (rtld_map);
f (variables);
- _dl_protect_relro (rtld_map);
+ return true;
}
+ else
+ return false;
}
#endif
@@ -25,7 +25,7 @@
/* We need special support to initialize DSO loaded for statically linked
binaries. */
-extern void _dl_static_init (struct link_map *map);
+extern bool _dl_static_init (struct link_map *map);
#undef DL_STATIC_INIT
#define DL_STATIC_INIT(map) _dl_static_init (map)
@@ -45,46 +45,23 @@ static void *variables[] =
&GLRO(dl_pagesize)
};
-static void
-_dl_unprotect_relro (struct link_map *l)
-{
- ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
- & ~(GLRO(dl_pagesize) - 1));
- ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
- & ~(GLRO(dl_pagesize) - 1));
-
- if (start != end)
- __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE);
-}
-
-void
+bool
_dl_static_init (struct link_map *l)
{
- struct link_map *rtld_map = l;
- struct r_scope_elem **scope;
const ElfW(Sym) *ref = NULL;
lookup_t loadbase;
void (*f) (void *[]);
- size_t i;
loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope,
NULL, 0, 1, NULL);
-
- for (scope = l->l_local_scope; *scope != NULL; scope++)
- for (i = 0; i < (*scope)->r_nlist; i++)
- if ((*scope)->r_list[i] == loadbase)
- {
- rtld_map = (*scope)->r_list[i];
- break;
- }
-
if (ref != NULL)
{
f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref);
- _dl_unprotect_relro (rtld_map);
f (variables);
- _dl_protect_relro (rtld_map);
+ return true;
}
+ else
+ return false;
}
#endif
@@ -25,7 +25,7 @@
/* We need special support to initialize DSO loaded for statically linked
binaries. */
-extern void _dl_static_init (struct link_map *map);
+extern bool _dl_static_init (struct link_map *map);
#undef DL_STATIC_INIT
#define DL_STATIC_INIT(map) _dl_static_init (map)
@@ -45,46 +45,23 @@ static void *variables[] =
&GLRO(dl_pagesize)
};
-static void
-_dl_unprotect_relro (struct link_map *l)
-{
- ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
- & ~(GLRO(dl_pagesize) - 1));
- ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
- & ~(GLRO(dl_pagesize) - 1));
-
- if (start != end)
- __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE);
-}
-
-void
+bool
_dl_static_init (struct link_map *l)
{
- struct link_map *rtld_map = l;
- struct r_scope_elem **scope;
const ElfW(Sym) *ref = NULL;
lookup_t loadbase;
void (*f) (void *[]);
- size_t i;
loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope,
NULL, 0, 1, NULL);
-
- for (scope = l->l_local_scope; *scope != NULL; scope++)
- for (i = 0; i < (*scope)->r_nlist; i++)
- if ((*scope)->r_list[i] == loadbase)
- {
- rtld_map = (*scope)->r_list[i];
- break;
- }
-
if (ref != NULL)
{
f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref);
- _dl_unprotect_relro (rtld_map);
f (variables);
- _dl_protect_relro (rtld_map);
+ return true;
}
+ else
+ return false;
}
#endif
@@ -26,7 +26,7 @@
/* We need special support to initialize DSO loaded for statically linked
binaries. */
-extern void _dl_static_init (struct link_map *map);
+extern bool _dl_static_init (struct link_map *map);
#undef DL_STATIC_INIT
#define DL_STATIC_INIT(map) _dl_static_init (map)