Bug 18778 - ld.so crashes if failed dlopen causes libpthread to be forced unloaded
Summary: ld.so crashes if failed dlopen causes libpthread to be forced unloaded
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: 2.22
: P2 critical
Target Milestone: 2.23
Assignee: Not yet assigned to anyone
URL:
Keywords: glibc_2.22
Depends on:
Blocks: 17833
  Show dependency treegraph
 
Reported: 2015-08-06 14:28 UTC by Andreas Schwab
Modified: 2015-10-29 16:40 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas Schwab 2015-08-06 14:28:38 UTC
If dlopen fails to load an object that has triggered loading libpthread it causes ld.so to unload libpthread because its DF_1_NODELETE flags has been forcefully cleared.  The next call to __rtdl_unlock_lock_recursive will crash since pthread_mutex_unlock no longer exists.
Comment 1 Pavel Kopyl 2015-08-06 16:38:59 UTC
Andreas,

Could you provide reprocase for this?
Comment 2 Andreas Schwab 2015-08-06 17:09:28 UTC
diff --git a/elf/tst-nodelete.cc b/elf/tst-nodelete.cc
index 176cb68..24bb4c0 100644
--- a/elf/tst-nodelete.cc
+++ b/elf/tst-nodelete.cc
@@ -1,12 +1,15 @@
 #include "../dlfcn/dlfcn.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <gnu/lib-names.h>
 
 static int
 do_test (void)
 {
   int result = 0;
 
+  void *pthread = dlopen (LIBPTHREAD_SO, RTLD_LAZY);
+
   /* This is a test for correct handling of dlopen failures for library that
      is loaded with RTLD_NODELETE flag.  The first dlopen should fail because
      of undefined symbols in shared library.  The second dlopen then verifies
@@ -18,6 +21,9 @@ do_test (void)
       result = 1;
     }
 
+  if (pthread)
+    dlclose (pthread);
+
   /* This is a test for correct handling of dlopen failures for library that
      is linked with '-z nodelete' option and hence has DF_1_NODELETE flag.
      The first dlopen should fail because of undefined symbols in shared
Comment 3 cvs-commit@gcc.gnu.org 2015-08-11 08:21:54 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  f25238ffe0455013174438376b3ee88df496f9d1 (commit)
      from  dc8a7ff24dfd1fd97a50b4b83a715958b31e4b92 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=f25238ffe0455013174438376b3ee88df496f9d1

commit f25238ffe0455013174438376b3ee88df496f9d1
Author: Maxim Ostapenko <m.ostapenko@partner.samsung.com>
Date:   Mon Aug 10 10:47:54 2015 +0300

    Clear DF_1_NODELETE flag only for failed to load library.
    
    https://sourceware.org/bugzilla/show_bug.cgi?id=18778
    
    If dlopen fails to load an object that has triggered loading libpthread it
    causes ld.so to unload libpthread because its DF_1_NODELETE flags has been
    forcefully cleared. The next call to __rtdl_unlock_lock_recursive will crash
    since pthread_mutex_unlock no longer exists.
    
    This patch moves l->l_flags_1 &= ~DF_1_NODELETE out of loop through all loaded
    libraries and performs the action only on inconsistent one.
    
    	[BZ #18778]
    	* elf/Makefile (tests): Add Add tst-nodelete2.
    	(modules-names): Add tst-nodelete2mod.
    	(tst-nodelete2mod.so-no-z-defs): New.
    	($(objpfx)tst-nodelete2): Likewise.
    	($(objpfx)tst-nodelete2.out): Likewise.
    	(LDFLAGS-tst-nodelete2): Likewise.
    	* elf/dl-close.c (_dl_close_worker): Move DF_1_NODELETE clearing
    	out of loop through all loaded libraries.
    	* elf/tst-nodelete2.c: New file.
    	* elf/tst-nodelete2mod.c: Likewise.

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                         |   14 ++++++++
 NEWS                                              |    2 +-
 elf/Makefile                                      |   11 +++++-
 elf/dl-close.c                                    |   15 ++++----
 elf/tst-nodelete2.c                               |   37 +++++++++++++++++++++
 elf/{tst-znodelete-zlib.cc => tst-nodelete2mod.c} |    3 +-
 6 files changed, 71 insertions(+), 11 deletions(-)
 create mode 100644 elf/tst-nodelete2.c
 rename elf/{tst-znodelete-zlib.cc => tst-nodelete2mod.c} (50%)
Comment 4 cvs-commit@gcc.gnu.org 2015-08-11 08:56:11 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, release/2.22/master has been updated
       via  a34d1c6afc86521d6ad17662a3b5362d8481514c (commit)
      from  561a9f11a974a447acb3dd03550a05df701a900e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=a34d1c6afc86521d6ad17662a3b5362d8481514c

commit a34d1c6afc86521d6ad17662a3b5362d8481514c
Author: Maxim Ostapenko <m.ostapenko@partner.samsung.com>
Date:   Mon Aug 10 10:47:54 2015 +0300

    Clear DF_1_NODELETE flag only for failed to load library.
    
    https://sourceware.org/bugzilla/show_bug.cgi?id=18778
    
    If dlopen fails to load an object that has triggered loading libpthread it
    causes ld.so to unload libpthread because its DF_1_NODELETE flags has been
    forcefully cleared. The next call to __rtdl_unlock_lock_recursive will crash
    since pthread_mutex_unlock no longer exists.
    
    This patch moves l->l_flags_1 &= ~DF_1_NODELETE out of loop through all loaded
    libraries and performs the action only on inconsistent one.
    
    	[BZ #18778]
    	* elf/Makefile (tests): Add Add tst-nodelete2.
    	(modules-names): Add tst-nodelete2mod.
    	(tst-nodelete2mod.so-no-z-defs): New.
    	($(objpfx)tst-nodelete2): Likewise.
    	($(objpfx)tst-nodelete2.out): Likewise.
    	(LDFLAGS-tst-nodelete2): Likewise.
    	* elf/dl-close.c (_dl_close_worker): Move DF_1_NODELETE clearing
    	out of loop through all loaded libraries.
    	* elf/tst-nodelete2.c: New file.
    	* elf/tst-nodelete2mod.c: Likewise.
    
    (cherry picked from commit f25238ffe0455013174438376b3ee88df496f9d1)

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                         |   14 ++++++++
 NEWS                                              |    2 +-
 elf/Makefile                                      |   11 +++++-
 elf/dl-close.c                                    |   15 ++++----
 elf/tst-nodelete2.c                               |   37 +++++++++++++++++++++
 elf/{tst-znodelete-zlib.cc => tst-nodelete2mod.c} |    3 +-
 6 files changed, 71 insertions(+), 11 deletions(-)
 create mode 100644 elf/tst-nodelete2.c
 rename elf/{tst-znodelete-zlib.cc => tst-nodelete2mod.c} (50%)
Comment 5 Andreas Schwab 2015-08-11 08:57:03 UTC
Fixed in 2.22.1.
Comment 6 cvs-commit@gcc.gnu.org 2015-08-12 04:51:52 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, gentoo/2.22 has been updated
       via  969fb008f467a27b7cf6cc3cb08f80a3072daf77 (commit)
       via  6f9b62ae8465ec6cb6561f309a2393899091f1c7 (commit)
      from  078cee5a65f59943e2d72e36ba6635d059c38426 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=969fb008f467a27b7cf6cc3cb08f80a3072daf77

commit 969fb008f467a27b7cf6cc3cb08f80a3072daf77
Author: Maxim Ostapenko <m.ostapenko@partner.samsung.com>
Date:   Mon Aug 10 10:47:54 2015 +0300

    Clear DF_1_NODELETE flag only for failed to load library.
    
    https://sourceware.org/bugzilla/show_bug.cgi?id=18778
    
    If dlopen fails to load an object that has triggered loading libpthread it
    causes ld.so to unload libpthread because its DF_1_NODELETE flags has been
    forcefully cleared. The next call to __rtdl_unlock_lock_recursive will crash
    since pthread_mutex_unlock no longer exists.
    
    This patch moves l->l_flags_1 &= ~DF_1_NODELETE out of loop through all loaded
    libraries and performs the action only on inconsistent one.
    
    	[BZ #18778]
    	* elf/Makefile (tests): Add Add tst-nodelete2.
    	(modules-names): Add tst-nodelete2mod.
    	(tst-nodelete2mod.so-no-z-defs): New.
    	($(objpfx)tst-nodelete2): Likewise.
    	($(objpfx)tst-nodelete2.out): Likewise.
    	(LDFLAGS-tst-nodelete2): Likewise.
    	* elf/dl-close.c (_dl_close_worker): Move DF_1_NODELETE clearing
    	out of loop through all loaded libraries.
    	* elf/tst-nodelete2.c: New file.
    	* elf/tst-nodelete2mod.c: Likewise.
    
    (cherry picked from commit f25238ffe0455013174438376b3ee88df496f9d1)
    (cherry picked from commit a34d1c6afc86521d6ad17662a3b5362d8481514c)

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=6f9b62ae8465ec6cb6561f309a2393899091f1c7

commit 6f9b62ae8465ec6cb6561f309a2393899091f1c7
Author: Andreas Schwab <schwab@suse.de>
Date:   Mon Aug 10 14:12:47 2015 +0200

    Readd O_LARGEFILE flag for openat64 (bug 18781)
    
    (cherry picked from commit eb32b0d40308166c4d8f6330cc2958cb1e545075)
    (cherry picked from commit 561a9f11a974a447acb3dd03550a05df701a900e)

-----------------------------------------------------------------------

Summary of changes:
 elf/Makefile                                      |   11 +++++-
 elf/dl-close.c                                    |   15 ++++----
 elf/tst-nodelete2.c                               |   37 +++++++++++++++++++++
 elf/{tst-znodelete-zlib.cc => tst-nodelete2mod.c} |    3 +-
 io/test-lfs.c                                     |   21 +++++++++++-
 sysdeps/unix/sysv/linux/openat.c                  |    5 +++
 6 files changed, 81 insertions(+), 11 deletions(-)
 create mode 100644 elf/tst-nodelete2.c
 rename elf/{tst-znodelete-zlib.cc => tst-nodelete2mod.c} (50%)