]> sourceware.org Git - glibc.git/commitdiff
Set NODELETE flag when opening already open objects with RTLD_NODELETE
authorSiddhesh Poyarekar <siddhesh@redhat.com>
Thu, 16 Jul 2015 03:23:28 +0000 (08:53 +0530)
committerSiddhesh Poyarekar <siddhesh@redhat.com>
Thu, 16 Jul 2015 03:23:28 +0000 (08:53 +0530)
The DF_1_NODELETE flag is set too late when opening a DSO, due to
which, if a DSO is already open, subsequently opening it with
RTLD_NODELETE fails to set the DF_1_NODELETE flag.  This patch fixes
this by setting the flag immediately after bumping the opencount.

Verified on x86_64.

[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.

ChangeLog
NEWS
elf/Makefile
elf/dl-open.c
elf/tst-nodelete-opened-lib.c [new file with mode: 0644]
elf/tst-nodelete-opened.c [new file with mode: 0644]

index b0eba065fd3d90fe92eff908446de86dba8660bb..7dd5e9a96dbce679ccfb355859697311563267b5 100644 (file)
--- 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 f91edc7804beff32233aeb61465a829d0619c715..fc8456051b4e4a1cfa42bf5daae24a78fd0ecc0a 100644 (file)
--- 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.
index 90d50588e1104f90d451d36d8f701b447db7998a..4ceeaf89be65b47ab2bbba2214d2feff4895a7cd 100644 (file)
@@ -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
index 027c1e0edaa2841f229d51dc7ebbcb486cd33da2..2db1c021485763fbdc49cb7fb2e07e2ac87b0c29 100644 (file)
@@ -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 (file)
index 0000000..994702a
--- /dev/null
@@ -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 (file)
index 0000000..43b00fa
--- /dev/null
@@ -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"
This page took 0.12565 seconds and 5 git commands to generate.