This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Save reference to kernel provided envp in the linker


Hi,

A circular dependency between libpthread.so and libc.so ensures that
libpthread.so constructor is called first.  Due to this, libpthread.so
constructor does not have access to the environment variables, since a
relocation wipes out the __environ that the dynamic linker had, which
gets updated when the libc.so constructor is called.
    
A new reference within the dynamic linker saves the kernel-provided
envp, which getenv falls back to if the libc.so constructor has not
been called yet.

I have verified that this change does not cause any regressions.  I
have also verified using some dummy code within nptl that it
recognizes environment variables with this patch and not without it.

OK for 2.18?

Siddhesh

ChangeLog:

	* csu/init-first.c (__libc_environ_initialized): New flag.
	(_init): Set __LIBC_ENVIRON_INITIALIZED once __ENVIRON is
	initialized.
	* elf/dl-support.c (_dl_environ): New variable.
	* elf/dl-sysdep.c (_dl_sysdep_start): Set _DL_ENVIRON with the
	kernel provided ENVP.
	* elf/rtld.c (_rtld_global_ro): Initialize member _DL_ENVIRON.
	* stdlib/getenv.c (getenv): Fall back to dl_environ if
	__LIBC_ENVIRON_INITIALIZED is not set.
	* sysdeps/generic/ldsodefs.h (struct rtld_global_ro): New member
	_DL_ENVIRON.

diff --git a/csu/init-first.c b/csu/init-first.c
index 0cfabbc..f40c58c 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -33,6 +33,8 @@
    used in the process.  Safe assumption if initializer never runs.  */
 int __libc_multiple_libcs attribute_hidden = 1;
 
+int __libc_environ_initialized attribute_hidden = 0;
+
 /* Remember the command line argument and enviroment contents for
    later calls of initializers for dynamic libraries.  */
 int __libc_argc attribute_hidden;
@@ -74,6 +76,8 @@ _init (int argc, char **argv, char **envp)
   __libc_argv = argv;
   __environ = envp;
 
+  __libc_environ_initialized = 1;
+
 #ifndef SHARED
   __libc_init_secure ();
 
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 81e7172..62b6c8c 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -127,6 +127,10 @@ int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
 
 ElfW(auxv_t) *_dl_auxv;
 ElfW(Phdr) *_dl_phdr;
+
+/* This is the environ that the kernel gave us.  */
+char **_dl_environ;
+
 size_t _dl_phnum;
 uint64_t _dl_hwcap __attribute__ ((nocommon));
 
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index 65a9046..bfe6b42 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -108,8 +108,10 @@ _dl_sysdep_start (void **start_argptr,
 #endif
 
   __libc_stack_end = DL_STACK_END (start_argptr);
-  DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, INTUSE(_dl_argv), _environ,
-			  GLRO(dl_auxv));
+  DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, INTUSE(_dl_argv),
+			  GLRO(dl_environ), GLRO(dl_auxv));
+
+  _environ = GLRO(dl_environ);
 
   user_entry = (ElfW(Addr)) ENTRY_POINT;
   GLRO(dl_platform) = NULL; /* Default to nothing known about the platform.  */
diff --git a/elf/rtld.c b/elf/rtld.c
index b0126e5..72ddf5c 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -165,6 +165,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_pointer_guard = 1,
     ._dl_pagesize = EXEC_PAGESIZE,
     ._dl_inhibit_cache = 0,
+    ._dl_environ = NULL,
 
     /* Function pointers.  */
     ._dl_debug_printf = _dl_debug_printf,
diff --git a/stdlib/getenv.c b/stdlib/getenv.c
index 8398dab..08cb507 100644
--- a/stdlib/getenv.c
+++ b/stdlib/getenv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,94,96,98,99,2002,2005 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2012 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
@@ -21,7 +21,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <ldsodefs.h>
 
+extern int __libc_environ_initialized;
 
 /* Return the value of the environment variable NAME.  This implementation
    is tuned a bit in that it assumes no environment variable has an empty
@@ -36,8 +38,12 @@ getenv (name)
   size_t len = strlen (name);
   char **ep;
   uint16_t name_start;
+  char **cur_env = __environ;
 
-  if (__environ == NULL || name[0] == '\0')
+  if (__builtin_expect (__libc_environ_initialized == 0, 0))
+    cur_env = GLRO(dl_environ);
+
+  if (cur_env == NULL || name[0] == '\0')
     return NULL;
 
   if (name[1] == '\0')
@@ -54,7 +60,7 @@ getenv (name)
  #error "Funny byte order."
 # endif
 #endif
-      for (ep = __environ; *ep != NULL; ++ep)
+      for (ep = cur_env; *ep != NULL; ++ep)
 	{
 #if _STRING_ARCH_unaligned
 	  uint16_t ep_start = *(uint16_t *) *ep;
@@ -77,7 +83,7 @@ getenv (name)
       len -= 2;
       name += 2;
 
-      for (ep = __environ; *ep != NULL; ++ep)
+      for (ep = cur_env; *ep != NULL; ++ep)
 	{
 #if _STRING_ARCH_unaligned
 	  uint16_t ep_start = *(uint16_t *) *ep;
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index c667e34..45bdd74 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -498,6 +498,8 @@ struct rtld_global_ro
   /* Pointer to the auxv list supplied to the program at startup.  */
   EXTERN ElfW(auxv_t) *_dl_auxv;
 
+  EXTERN char **_dl_environ;
+
   /* Get architecture specific definitions.  */
 #define PROCINFO_DECL
 #ifndef PROCINFO_CLASS


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]