1feee8
commit 536ddc5c02f1ee82483319863a893ccb381beece
1feee8
Author: Florian Weimer <fweimer@redhat.com>
1feee8
Date:   Fri Aug 26 21:15:43 2022 +0200
1feee8
1feee8
    elf: Call __libc_early_init for reused namespaces (bug 29528)
1feee8
    
1feee8
    libc_map is never reset to NULL, neither during dlclose nor on a
1feee8
    dlopen call which reuses the namespace structure.  As a result, if a
1feee8
    namespace is reused, its libc is not initialized properly.  The most
1feee8
    visible result is a crash in the <ctype.h> functions.
1feee8
    
1feee8
    To prevent similar bugs on namespace reuse from surfacing,
1feee8
    unconditionally initialize the chosen namespace to zero using memset.
1feee8
    
1feee8
    (cherry picked from commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe)
1feee8
1feee8
Conflicts:
1feee8
	elf/Makefile
1feee8
	  (usual test differences)
1feee8
1feee8
diff --git a/elf/Makefile b/elf/Makefile
1feee8
index 2b547d5b58f1759b..feec365e4e5fe9b3 100644
1feee8
--- a/elf/Makefile
1feee8
+++ b/elf/Makefile
1feee8
@@ -399,6 +399,7 @@ tests += \
1feee8
   tst-dlmopen3 \
1feee8
   tst-dlmopen-dlerror \
1feee8
   tst-dlmopen-gethostbyname \
1feee8
+  tst-dlmopen-twice \
1feee8
   tst-dlopenfail \
1feee8
   tst-dlopenfail-2 \
1feee8
   tst-dlopenrpath \
1feee8
@@ -744,6 +745,8 @@ modules-names = \
1feee8
   tst-dlmopen1mod \
1feee8
   tst-dlmopen-dlerror-mod \
1feee8
   tst-dlmopen-gethostbyname-mod \
1feee8
+  tst-dlmopen-twice-mod1 \
1feee8
+  tst-dlmopen-twice-mod2 \
1feee8
   tst-dlopenfaillinkmod \
1feee8
   tst-dlopenfailmod1 \
1feee8
   tst-dlopenfailmod2 \
1feee8
@@ -2665,3 +2668,7 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
1feee8
 tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
1feee8
 $(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
1feee8
 tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
1feee8
+
1feee8
+$(objpfx)tst-dlmopen-twice.out: \
1feee8
+  $(objpfx)tst-dlmopen-twice-mod1.so \
1feee8
+  $(objpfx)tst-dlmopen-twice-mod2.so
1feee8
diff --git a/elf/dl-open.c b/elf/dl-open.c
1feee8
index bc6872632880634e..1ab3c7b5ac2fbc45 100644
1feee8
--- a/elf/dl-open.c
1feee8
+++ b/elf/dl-open.c
1feee8
@@ -839,11 +839,14 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
1feee8
 	  _dl_signal_error (EINVAL, file, NULL, N_("\
1feee8
 no more namespaces available for dlmopen()"));
1feee8
 	}
1feee8
-      else if (nsid == GL(dl_nns))
1feee8
-	{
1feee8
-	  __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
1feee8
-	  ++GL(dl_nns);
1feee8
-	}
1feee8
+
1feee8
+      if (nsid == GL(dl_nns))
1feee8
+	++GL(dl_nns);
1feee8
+
1feee8
+      /* Initialize the new namespace.  Most members are
1feee8
+	 zero-initialized, only the lock needs special treatment.  */
1feee8
+      memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
1feee8
+      __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
1feee8
 
1feee8
       _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
1feee8
     }
1feee8
diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
1feee8
new file mode 100644
1feee8
index 0000000000000000..0eaf04948ce5263e
1feee8
--- /dev/null
1feee8
+++ b/elf/tst-dlmopen-twice-mod1.c
1feee8
@@ -0,0 +1,37 @@
1feee8
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528).  Module 1.
1feee8
+   Copyright (C) 2022 Free Software Foundation, Inc.
1feee8
+   This file is part of the GNU C Library.
1feee8
+
1feee8
+   The GNU C Library is free software; you can redistribute it and/or
1feee8
+   modify it under the terms of the GNU Lesser General Public
1feee8
+   License as published by the Free Software Foundation; either
1feee8
+   version 2.1 of the License, or (at your option) any later version.
1feee8
+
1feee8
+   The GNU C Library is distributed in the hope that it will be useful,
1feee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
1feee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1feee8
+   Lesser General Public License for more details.
1feee8
+
1feee8
+   You should have received a copy of the GNU Lesser General Public
1feee8
+   License along with the GNU C Library; if not, see
1feee8
+   <https://www.gnu.org/licenses/>.  */
1feee8
+
1feee8
+#include <stdio.h>
1feee8
+
1feee8
+static void __attribute__ ((constructor))
1feee8
+init (void)
1feee8
+{
1feee8
+  puts ("info: tst-dlmopen-twice-mod1.so loaded");
1feee8
+  fflush (stdout);
1feee8
+}
1feee8
+
1feee8
+static void __attribute__ ((destructor))
1feee8
+fini (void)
1feee8
+{
1feee8
+  puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
1feee8
+  fflush (stdout);
1feee8
+}
1feee8
+
1feee8
+/* Large allocation.  The second module does not have this, so it
1feee8
+   should load libc at a different address.  */
1feee8
+char large_allocate[16 * 1024 * 1024];
1feee8
diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
1feee8
new file mode 100644
1feee8
index 0000000000000000..40c6c01f9625e188
1feee8
--- /dev/null
1feee8
+++ b/elf/tst-dlmopen-twice-mod2.c
1feee8
@@ -0,0 +1,50 @@
1feee8
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528).  Module 2.
1feee8
+   Copyright (C) 2022 Free Software Foundation, Inc.
1feee8
+   This file is part of the GNU C Library.
1feee8
+
1feee8
+   The GNU C Library is free software; you can redistribute it and/or
1feee8
+   modify it under the terms of the GNU Lesser General Public
1feee8
+   License as published by the Free Software Foundation; either
1feee8
+   version 2.1 of the License, or (at your option) any later version.
1feee8
+
1feee8
+   The GNU C Library is distributed in the hope that it will be useful,
1feee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
1feee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1feee8
+   Lesser General Public License for more details.
1feee8
+
1feee8
+   You should have received a copy of the GNU Lesser General Public
1feee8
+   License along with the GNU C Library; if not, see
1feee8
+   <https://www.gnu.org/licenses/>.  */
1feee8
+
1feee8
+#include <ctype.h>
1feee8
+#include <stdio.h>
1feee8
+
1feee8
+static void __attribute__ ((constructor))
1feee8
+init (void)
1feee8
+{
1feee8
+  puts ("info: tst-dlmopen-twice-mod2.so loaded");
1feee8
+  fflush (stdout);
1feee8
+}
1feee8
+
1feee8
+static void __attribute__ ((destructor))
1feee8
+fini (void)
1feee8
+{
1feee8
+  puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
1feee8
+  fflush (stdout);
1feee8
+}
1feee8
+
1feee8
+int
1feee8
+run_check (void)
1feee8
+{
1feee8
+  puts ("info: about to call isalpha");
1feee8
+  fflush (stdout);
1feee8
+
1feee8
+  volatile char ch = 'a';
1feee8
+  if (!isalpha (ch))
1feee8
+    {
1feee8
+      puts ("error: isalpha ('a') is not true");
1feee8
+      fflush (stdout);
1feee8
+      return 1;
1feee8
+    }
1feee8
+  return 0;
1feee8
+}
1feee8
diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
1feee8
new file mode 100644
1feee8
index 0000000000000000..449f3c8fa9f2aa01
1feee8
--- /dev/null
1feee8
+++ b/elf/tst-dlmopen-twice.c
1feee8
@@ -0,0 +1,34 @@
1feee8
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528).  Main.
1feee8
+   Copyright (C) 2022 Free Software Foundation, Inc.
1feee8
+   This file is part of the GNU C Library.
1feee8
+
1feee8
+   The GNU C Library is free software; you can redistribute it and/or
1feee8
+   modify it under the terms of the GNU Lesser General Public
1feee8
+   License as published by the Free Software Foundation; either
1feee8
+   version 2.1 of the License, or (at your option) any later version.
1feee8
+
1feee8
+   The GNU C Library is distributed in the hope that it will be useful,
1feee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
1feee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1feee8
+   Lesser General Public License for more details.
1feee8
+
1feee8
+   You should have received a copy of the GNU Lesser General Public
1feee8
+   License along with the GNU C Library; if not, see
1feee8
+   <https://www.gnu.org/licenses/>.  */
1feee8
+
1feee8
+#include <support/xdlfcn.h>
1feee8
+#include <support/check.h>
1feee8
+
1feee8
+static int
1feee8
+do_test (void)
1feee8
+{
1feee8
+  void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
1feee8
+  xdlclose (handle);
1feee8
+  handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
1feee8
+  int (*run_check) (void) = xdlsym (handle, "run_check");
1feee8
+  TEST_COMPARE (run_check (), 0);
1feee8
+  xdlclose (handle);
1feee8
+  return 0;
1feee8
+}
1feee8
+
1feee8
+#include <support/test-driver.c>