e9451d9
Author: Florian Weimer <fweimer@redhat.com>
e9451d9
Date:   Thu Dec 5 16:20:30 2019 +0100
e9451d9
e9451d9
    dlopen: Do not block signals
e9451d9
    
e9451d9
    Blocking signals causes issues with certain anti-malware solutions
e9451d9
    which rely on an unblocked SIGSYS signal for system calls they
e9451d9
    intercept.
e9451d9
    
e9451d9
    This reverts commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23
e9451d9
    ("Block signals during the initial part of dlopen") and adds
e9451d9
    comments related to async signal safety to active_nodelete and
e9451d9
    its caller.
e9451d9
    
e9451d9
    Note that this does not make lazy binding async-signal-safe with regards
e9451d9
    to dlopen.  It merely avoids introducing new async-signal-safety hazards
e9451d9
    as part of the NODELETE changes.
e9451d9
e9451d9
diff --git a/elf/dl-open.c b/elf/dl-open.c
e9451d9
index c23341be5892fb12..5a1c5b53269f1236 100644
e9451d9
--- a/elf/dl-open.c
e9451d9
+++ b/elf/dl-open.c
e9451d9
@@ -34,7 +34,6 @@
e9451d9
 #include <atomic.h>
e9451d9
 #include <libc-internal.h>
e9451d9
 #include <array_length.h>
e9451d9
-#include <internal-signals.h>
e9451d9
 
e9451d9
 #include <dl-dst.h>
e9451d9
 #include <dl-prop.h>
e9451d9
@@ -53,10 +52,6 @@ struct dl_open_args
e9451d9
   /* Namespace ID.  */
e9451d9
   Lmid_t nsid;
e9451d9
 
e9451d9
-  /* Original signal mask.  Used for unblocking signal handlers before
e9451d9
-     running ELF constructors.  */
e9451d9
-  sigset_t original_signal_mask;
e9451d9
-
e9451d9
   /* Original value of _ns_global_scope_pending_adds.  Set by
e9451d9
      dl_open_worker.  Only valid if nsid is a real namespace
e9451d9
      (non-negative).  */
e9451d9
@@ -446,6 +441,9 @@ activate_nodelete (struct link_map *new)
e9451d9
 	  _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
e9451d9
 			    l->l_name, l->l_ns);
e9451d9
 
e9451d9
+	/* The flag can already be true at this point, e.g. a signal
e9451d9
+	   handler may have triggered lazy binding and set NODELETE
e9451d9
+	   status immediately.  */
e9451d9
 	l->l_nodelete_active = true;
e9451d9
 
e9451d9
 	/* This is just a debugging aid, to indicate that
e9451d9
@@ -520,16 +518,12 @@ dl_open_worker (void *a)
e9451d9
   if (new == NULL)
e9451d9
     {
e9451d9
       assert (mode & RTLD_NOLOAD);
e9451d9
-      __libc_signal_restore_set (&args->original_signal_mask);
e9451d9
       return;
e9451d9
     }
e9451d9
 
e9451d9
   if (__glibc_unlikely (mode & __RTLD_SPROF))
e9451d9
-    {
e9451d9
-      /* This happens only if we load a DSO for 'sprof'.  */
e9451d9
-      __libc_signal_restore_set (&args->original_signal_mask);
e9451d9
-      return;
e9451d9
-    }
e9451d9
+    /* This happens only if we load a DSO for 'sprof'.  */
e9451d9
+    return;
e9451d9
 
e9451d9
   /* This object is directly loaded.  */
e9451d9
   ++new->l_direct_opencount;
e9451d9
@@ -565,7 +559,6 @@ dl_open_worker (void *a)
e9451d9
 
e9451d9
       assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
e9451d9
 
e9451d9
-      __libc_signal_restore_set (&args->original_signal_mask);
e9451d9
       return;
e9451d9
     }
e9451d9
 
e9451d9
@@ -712,6 +705,12 @@ dl_open_worker (void *a)
e9451d9
      All memory allocations for new objects must have happened
e9451d9
      before.  */
e9451d9
 
e9451d9
+  /* Finalize the NODELETE status first.  This comes before
e9451d9
+     update_scopes, so that lazy binding will not see pending NODELETE
e9451d9
+     state for newly loaded objects.  There is a compiler barrier in
e9451d9
+     update_scopes which ensures that the changes from
e9451d9
+     activate_nodelete are visible before new objects show up in the
e9451d9
+     local scope.  */
e9451d9
   activate_nodelete (new);
e9451d9
 
e9451d9
   /* Second stage after resize_scopes: Actually perform the scope
e9451d9
@@ -745,10 +744,6 @@ dl_open_worker (void *a)
e9451d9
   if (mode & RTLD_GLOBAL)
e9451d9
     add_to_global_resize (new);
e9451d9
 
e9451d9
-  /* Unblock signals.  Data structures are now consistent, and
e9451d9
-     application code may run.  */
e9451d9
-  __libc_signal_restore_set (&args->original_signal_mask);
e9451d9
-
e9451d9
   /* Run the initializer functions of new objects.  Temporarily
e9451d9
      disable the exception handler, so that lazy binding failures are
e9451d9
      fatal.  */
e9451d9
@@ -838,10 +833,6 @@ no more namespaces available for dlmopen()"));
e9451d9
   args.argv = argv;
e9451d9
   args.env = env;
e9451d9
 
e9451d9
-  /* Recursive lazy binding during manipulation of the dynamic loader
e9451d9
-     structures may result in incorrect behavior.  */
e9451d9
-  __libc_signal_block_all (&args.original_signal_mask);
e9451d9
-
e9451d9
   struct dl_exception exception;
e9451d9
   int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
e9451d9
 
e9451d9
@@ -882,16 +873,10 @@ no more namespaces available for dlmopen()"));
e9451d9
 
e9451d9
 	  _dl_close_worker (args.map, true);
e9451d9
 
e9451d9
-	  /* Restore the signal mask.  In the success case, this
e9451d9
-	     happens inside dl_open_worker.  */
e9451d9
-	  __libc_signal_restore_set (&args.original_signal_mask);
e9451d9
-
e9451d9
 	  /* All l_nodelete_pending objects should have been deleted
e9451d9
 	     at this point, which is why it is not necessary to reset
e9451d9
 	     the flag here.  */
e9451d9
 	}
e9451d9
-      else
e9451d9
-	__libc_signal_restore_set (&args.original_signal_mask);
e9451d9
 
e9451d9
       assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
e9451d9