Browse Source

librt: fix broken posix_spawn

Fix iteration over signals, synced with GNU C library code and
pending patches. Issues found when running dhcpcd with hook
scripts. (exit status 127)

Reported-By: kapeka <kapeka@bering-uclibc.de>
Waldemar Brodkorb 6 years ago
parent
commit
71b3a63b64

+ 8 - 13
libpthread/nptl/sysdeps/unix/sysv/linux/nptl-signals.h → libc/sysdeps/linux/common/internal-signals.h

@@ -1,6 +1,4 @@
-/* Special use of signals in NPTL internals.  Linux version.
-   Copyright (C) 2014-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
+/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -21,27 +19,24 @@
 /* The signal used for asynchronous cancelation.  */
 #define SIGCANCEL       __SIGRTMIN
 
-
 /* Signal needed for the kernel-supported POSIX timer implementation.
    We can reuse the cancellation signal since we can distinguish
    cancellation from timer expirations.  */
 #define SIGTIMER        SIGCANCEL
 
-
 /* Signal used to implement the setuid et.al. functions.  */
 #define SIGSETXID       (__SIGRTMIN + 1)
 
-
-/* Return is sig is used internally.  */
+/* Return if sig is used internally.  */
 static inline int
-__nptl_is_internal_signal (int sig)
+__is_internal_signal (int sig)
 {
   return (sig == SIGCANCEL) || (sig == SIGTIMER) || (sig == SIGSETXID);
 }
 
-/* Remove internal glibc signal from the mask.  */
+/* Remove internal signal from the mask.  */
 static inline void
-__nptl_clear_internal_signals (sigset_t *set)
+__clear_internal_signals (sigset_t *set)
 {
   __sigdelset (set, SIGCANCEL);
   __sigdelset (set, SIGTIMER);
@@ -51,7 +46,7 @@ __nptl_clear_internal_signals (sigset_t *set)
 #define SIGALL_SET \
   ((__sigset_t) { .__val = {[0 ...  _SIGSET_NWORDS-1 ] =  -1 } })
 
-/* Block all signals, including internal glibc ones.  */
+/* Block all signals, including internal ones.  */
 static inline int
 __libc_signal_block_all (sigset_t *set)
 {
@@ -60,12 +55,12 @@ __libc_signal_block_all (sigset_t *set)
 			   set, _NSIG / 8);
 }
 
-/* Block all application signals (excluding internal glibc ones).  */
+/* Block all application signals (excluding internal ones).  */
 static inline int
 __libc_signal_block_app (sigset_t *set)
 {
   sigset_t allset = SIGALL_SET;
-  __nptl_clear_internal_signals (&allset);
+  __clear_internal_signals (&allset);
   INTERNAL_SYSCALL_DECL (err);
   return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &allset, set,
 			   _NSIG / 8);

+ 1 - 2
libpthread/nptl/pthreadP.h

@@ -1,5 +1,4 @@
 /* Copyright (C) 2002-2007, 2009 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -31,7 +30,7 @@
 #include <atomic.h>
 #include <bits/kernel-features.h>
 #include <errno.h>
-#include <nptl-signals.h>
+#include <internal-signals.h>
 
 
 /* Atomic operations on TLS memory.  */

+ 1 - 2
libpthread/nptl/sysdeps/unix/sysv/linux/raise.c

@@ -1,5 +1,4 @@
 /* Copyright (C) 2002-2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -20,7 +19,7 @@
 #include <limits.h>
 #include <signal.h>
 #include <sysdep.h>
-#include <nptl-signals.h>
+#include <internal-signals.h>
 
 int
 raise (int sig)

+ 26 - 6
librt/spawn.c

@@ -25,6 +25,7 @@
 
 #include <sys/resource.h>
 #include <not-cancel.h>
+#include <internal-signals.h>
 
 #include <spawn.h>
 #include "spawn_int.h"
@@ -153,13 +154,32 @@ __spawni(pid_t *pid, const char *file,
 		int sig;
 
 		memset(&sa, 0, sizeof(sa));
-		sa.sa_handler = SIG_DFL;
 
-		for (sig = 1; sig <= _NSIG; ++sig) {
-			if (sigismember(&attrp->__sd, sig)) {
-				if (sigaction(sig, &sa, NULL) != 0)
-					goto error;
-			}
+		sigset_t hset;
+		sigprocmask (SIG_BLOCK, 0, &hset);
+
+		for (int sig = 1; sig < _NSIG; ++sig) {
+		  if ((flags & POSIX_SPAWN_SETSIGDEF)
+		  && sigismember (&attrp->__sd, sig))
+		  {
+		    sa.sa_handler = SIG_DFL;
+		  }
+	          else if (sigismember (&hset, sig))
+		  {
+		    if (__is_internal_signal (sig))
+		      sa.sa_handler = SIG_IGN;
+		    else
+		    {
+		      __libc_sigaction (sig, 0, &sa);
+		      if (sa.sa_handler == SIG_IGN)
+			continue;
+		      sa.sa_handler = SIG_DFL;
+		    }
+		  }
+	        else
+		  continue;
+
+		__libc_sigaction (sig, &sa, 0);
 		}
 	}