about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--NEWS2
-rw-r--r--elf/Makefile6
-rw-r--r--elf/dl-open.c11
-rw-r--r--elf/tst-nodelete-opened-lib.c19
-rw-r--r--elf/tst-nodelete-opened.c67
6 files changed, 106 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index b0eba065fd..7dd5e9a96d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2015-07-16  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	[BZ #18676]
+	* elf/tst-nodelete-opened.c: New test case.
+	* elf/tst-nodelete-opened-lib.c: New test case module.
+	* elf/Makefile (tests, modules-names): Use them.
+	* elf/dl-open.c (dl_open_worker): Set DF_1_NODELETE flag
+	early.
+
 2015-07-15  David S. Miller  <davem@davemloft.net>
 
 	* sysdeps/sparc/nptl/pthread_barrier_init.c: Include
diff --git a/NEWS b/NEWS
index f91edc7804..fc8456051b 100644
--- a/NEWS
+++ b/NEWS
@@ -27,7 +27,7 @@ Version 2.22
   18522, 18527, 18528, 18529, 18530, 18532, 18533, 18534, 18536, 18539,
   18540, 18542, 18544, 18545, 18546, 18547, 18549, 18553, 18557, 18558,
   18569, 18583, 18585, 18586, 18592, 18593, 18594, 18602, 18612, 18613,
-  18619, 18633, 18641, 18643, 18648.
+  18619, 18633, 18641, 18643, 18648, 18676.
 
 * Cache information can be queried via sysconf() function on s390 e.g. with
   _SC_LEVEL1_ICACHE_SIZE as argument.
diff --git a/elf/Makefile b/elf/Makefile
index 90d50588e1..4ceeaf89be 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -148,7 +148,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \
 	 tst-nodelete) \
 	 tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
-	 tst-ptrguard1 tst-tlsalign tst-tlsalign-extern
+	 tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened
 #	 reldep9
 ifeq ($(build-hardcoded-path-in-tests),yes)
 tests += tst-dlopen-aout
@@ -218,7 +218,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-initorder2d \
 		tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \
 		tst-array5dep tst-null-argv-lib \
-		tst-tlsalign-lib
+		tst-tlsalign-lib tst-nodelete-opened-lib
 ifeq (yes,$(have-protected-data))
 modules-names += tst-protected1moda tst-protected1modb
 tests += tst-protected1a tst-protected1b
@@ -525,6 +525,8 @@ $(objpfx)tst-initordera4.so: $(objpfx)tst-initordera3.so
 $(objpfx)tst-initorder: $(objpfx)tst-initordera4.so $(objpfx)tst-initordera1.so $(objpfx)tst-initorderb2.so
 $(objpfx)tst-null-argv: $(objpfx)tst-null-argv-lib.so
 $(objpfx)tst-tlsalign: $(objpfx)tst-tlsalign-lib.so
+$(objpfx)tst-nodelete-opened.out: $(objpfx)tst-nodelete-opened-lib.so
+$(objpfx)tst-nodelete-opened: $(libdl)
 
 $(objpfx)tst-tlsalign-extern: $(objpfx)tst-tlsalign-vars.o
 $(objpfx)tst-tlsalign-extern-static: $(objpfx)tst-tlsalign-vars.o
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 027c1e0eda..2db1c02148 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -226,6 +226,12 @@ dl_open_worker (void *a)
   args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
 				    mode | __RTLD_CALLMAP, args->nsid);
 
+  /* Mark the object as not deletable if the RTLD_NODELETE flags was passed.
+     Do this early so that we don't skip marking the object if it was
+     already loaded.  */
+  if (__glibc_unlikely (mode & RTLD_NODELETE))
+    new->l_flags_1 |= DF_1_NODELETE;
+
   /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
      set and the object is not already loaded.  */
   if (new == NULL)
@@ -564,11 +570,6 @@ TLS generation counter wrapped!  Please report this."));
       /* It failed.  */
       return;
 
-  /* Mark the object as not deletable if the RTLD_NODELETE flags was
-     passed.  */
-  if (__glibc_unlikely (mode & RTLD_NODELETE))
-    new->l_flags_1 |= DF_1_NODELETE;
-
 #ifndef SHARED
   /* We must be the static _dl_open in libc.a.  A static program that
      has loaded a dynamic object now has competition.  */
diff --git a/elf/tst-nodelete-opened-lib.c b/elf/tst-nodelete-opened-lib.c
new file mode 100644
index 0000000000..994702a9c5
--- /dev/null
+++ b/elf/tst-nodelete-opened-lib.c
@@ -0,0 +1,19 @@
+/* Verify that objects opened with RTLD_NODELETE are not unloaded - the DSO.
+   Copyright (C) 2015 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
+   <http://www.gnu.org/licenses/>.  */
+
+int foo_var = 42;
diff --git a/elf/tst-nodelete-opened.c b/elf/tst-nodelete-opened.c
new file mode 100644
index 0000000000..43b00fa16d
--- /dev/null
+++ b/elf/tst-nodelete-opened.c
@@ -0,0 +1,67 @@
+/* Verify that an already opened DSO opened agained with RTLD_NODELETE actually
+   sets the NODELETE flag.
+
+   Copyright (C) 2015 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+do_test (void)
+{
+  void *h1 = dlopen ("$ORIGIN/tst-nodelete-opened-lib.so", RTLD_LAZY);
+  if (h1 == NULL)
+    {
+      printf ("h1: failed to open DSO: %s\n", dlerror ());
+      return 1;
+    }
+
+  void *h2 = dlopen ("$ORIGIN/tst-nodelete-opened-lib.so",
+		     RTLD_LAZY | RTLD_NODELETE);
+  if (h2 == NULL)
+    {
+      printf ("h2: failed to open DSO: %s\n", dlerror ());
+      return 1;
+    }
+
+  int *foo = dlsym (h2, "foo_var");
+  if (foo == NULL)
+    {
+      printf ("failed to load symbol foo_var: %s\n", dlerror ());
+      return 1;
+    }
+
+  if (dlclose (h1) != 0)
+    {
+      printf ("h1: dlclose failed: %s\n", dlerror ());
+      return 1;
+    }
+
+  if (dlclose (h2) != 0)
+    {
+      printf ("h2: dlclose failed: %s\n", dlerror ());
+      return 1;
+    }
+
+  printf ("foo == %d\n", *foo);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"