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