]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - hurd/hurdsig.c
Break lines before not after operators, batch 4.
[thirdparty/glibc.git] / hurd / hurdsig.c
index 47f5fbf0a43edda22949b0916639b14f822a1275..1b511d1e8f9932322862c573b3a4c903c22c5f9e 100644 (file)
@@ -1,30 +1,39 @@
-/* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2019 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 Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   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
-   Library General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   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 <stdlib.h>
 #include <stdio.h>
-#include <hurd.h>
-#include <hurd/signal.h>
-#include <cthreads.h>          /* For `struct mutex'.  */
+#include <stdlib.h>
 #include <string.h>
+
+#include <cthreads.h>          /* For `struct mutex'.  */
+#include <pthreadP.h>
+#include <mach.h>
+#include <mach/thread_switch.h>
+#include <mach/mig_support.h>
+
+#include <hurd.h>
 #include <hurd/id.h>
+#include <hurd/signal.h>
+
 #include "hurdfault.h"
 #include "hurdmalloc.h"                /* XXX */
+#include "../locale/localeinfo.h"
+
+#include <libc-diag.h>
 
 const char *_hurdsig_getenv (const char *);
 
@@ -43,13 +52,12 @@ thread_t _hurd_sigthread;
 /* These are set up by _hurdsig_init.  */
 unsigned long int __hurd_sigthread_stack_base;
 unsigned long int __hurd_sigthread_stack_end;
-unsigned long int *__hurd_sigthread_variables;
 
 /* Linked-list of per-thread signal state.  */
 struct hurd_sigstate *_hurd_sigstates;
 
 /* Timeout for RPC's after interrupt_operation. */
-mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
+mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 60000;
 \f
 static void
 default_sigaction (struct sigaction actions[NSIG])
@@ -84,8 +92,9 @@ _hurd_thread_sigstate (thread_t thread)
       __sigemptyset (&ss->blocked);
       __sigemptyset (&ss->pending);
       memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
+      ss->sigaltstack.ss_flags |= SS_DISABLE;
       ss->preemptors = NULL;
-      ss->suspended = 0;
+      ss->suspended = MACH_PORT_NULL;
       ss->intr_port = MACH_PORT_NULL;
       ss->context = NULL;
 
@@ -115,23 +124,24 @@ _hurd_thread_sigstate (thread_t thread)
   __mutex_unlock (&_hurd_siglock);
   return ss;
 }
+libc_hidden_def (_hurd_thread_sigstate)
 \f
 /* Signal delivery itself is on this page.  */
 
 #include <hurd/fd.h>
 #include <hurd/crash.h>
+#include <hurd/resource.h>
 #include <hurd/paths.h>
 #include <setjmp.h>
 #include <fcntl.h>
 #include <sys/wait.h>
-#include "thread_state.h"
+#include <thread_state.h>
 #include <hurd/msg_server.h>
 #include <hurd/msg_reply.h>    /* For __msg_sig_post_reply.  */
 #include <hurd/interrupt.h>
 #include <assert.h>
 #include <unistd.h>
 
-int _hurd_core_limit;  /* XXX */
 
 /* Call the crash dump server to mummify us before we die.
    Returns nonzero if a core file was written.  */
@@ -143,6 +153,15 @@ write_corefile (int signo, const struct hurd_signal_detail *detail)
   file_t file, coredir;
   const char *name;
 
+  /* Don't bother locking since we just read the one word.  */
+  rlim_t corelimit = _hurd_rlimits[RLIMIT_CORE].rlim_cur;
+
+  if (corelimit == 0)
+    /* No core dumping, thank you very much.  Note that this makes
+       `ulimit -c 0' prevent crash-suspension too, which is probably
+       what the user wanted.  */
+    return 0;
+
   /* XXX RLIMIT_CORE:
      When we have a protocol to make the server return an error
      for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE
@@ -183,7 +202,7 @@ write_corefile (int signo, const struct hurd_signal_detail *detail)
   if (! err && file != MACH_PORT_NULL)
     /* The core dump into FILE succeeded, so now link it into the
        directory.  */
-    err = __dir_link (file, coredir, name, 1);
+    err = __dir_link (coredir, file, name, 1);
   __mach_port_deallocate (__mach_task_self (), file);
   __mach_port_deallocate (__mach_task_self (), coredir);
   return !err && file != MACH_PORT_NULL;
@@ -220,18 +239,24 @@ abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
    that this location can be set without faulting, or else return NULL.  */
 
 static mach_port_t *
-interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
+interrupted_reply_port_location (thread_t thread,
+                                struct machine_thread_all_state *thread_state,
                                 int sigthread)
 {
-  mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
-    (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
+  mach_port_t *portloc = &THREAD_TCB(thread, thread_state)->reply_port;
 
   if (sigthread && _hurdsig_catch_memory_fault (portloc))
-    /* Faulted trying to read the stack.  */
+    /* Faulted trying to read the TCB.  */
     return NULL;
 
+  DIAG_PUSH_NEEDS_COMMENT;
+  /* GCC 6 and before seem to be confused by the setjmp call inside
+     _hurdsig_catch_memory_fault and think that we may be returning a second
+     time to here with portloc uninitialized (but we never do). */
+  DIAG_IGNORE_NEEDS_COMMENT (6, "-Wmaybe-uninitialized");
   /* Fault now if this pointer is bogus.  */
   *(volatile mach_port_t *) portloc = *portloc;
+  DIAG_POP_NEEDS_COMMENT;
 
   if (sigthread)
     _hurdsig_end_catch_fault ();
@@ -240,7 +265,7 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
 }
 \f
 #include <hurd/sigpreempt.h>
-#include "intr-msg.h"
+#include <intr-msg.h>
 
 /* Timeout on interrupt_operation calls.  */
 mach_msg_timeout_t _hurdsig_interrupt_timeout = 1000;
@@ -268,6 +293,7 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
                     struct machine_thread_all_state *state, int *state_change,
                     void (*reply) (void))
 {
+  extern const void _hurd_intr_rpc_msg_about_to;
   extern const void _hurd_intr_rpc_msg_in_trap;
   mach_port_t rcv_port = MACH_PORT_NULL;
   mach_port_t intr_port;
@@ -283,7 +309,8 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
      receive completes immediately or aborts.  */
   abort_thread (ss, state, reply);
 
-  if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
+  if (state->basic.PC >= (natural_t) &_hurd_intr_rpc_msg_about_to
+      && state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
     {
       /* The thread is about to do the RPC, but hasn't yet entered
         mach_msg.  Mutate the thread's state so it knows not to try
@@ -294,11 +321,11 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
       state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
       *state_change = 1;
     }
-  else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
+  else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap
           /* The thread was blocked in the system call.  After thread_abort,
              the return value register indicates what state the RPC was in
              when interrupted.  */
-          state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
+          && state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
       {
        /* The RPC request message was sent and the thread was waiting for
           the reply message; now the message receive has been aborted, so
@@ -309,7 +336,8 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
           our nonzero return tells the trampoline code to finish the message
           receive operation before running the handler.  */
 
-       mach_port_t *reply = interrupted_reply_port_location (state,
+       mach_port_t *reply = interrupted_reply_port_location (ss->thread,
+                                                             state,
                                                              sigthread);
        error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout);
 
@@ -434,8 +462,8 @@ sigset_t _hurdsig_preempted_set;
 weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
 
 /* Mask of stop signals.  */
-#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) \
-                 sigmask (SIGSTOP) | sigmask (SIGTSTP))
+#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) \
+                 sigmask (SIGSTOP) | sigmask (SIGTSTP))
 
 /* Deliver a signal.  SS is not locked.  */
 void
@@ -510,8 +538,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       assert_perror (err);
       for (i = 0; i < nthreads; ++i)
        {
-         if (threads[i] != _hurd_msgport_thread &&
-             (act != handle || threads[i] != ss->thread))
+         if (threads[i] != _hurd_msgport_thread
+             && (act != handle || threads[i] != ss->thread))
            {
              err = __thread_resume (threads[i]);
              assert_perror (err);
@@ -573,7 +601,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
     handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
 
     /* If no thread-specific preemptor, check for a global one.  */
-    if (handler == SIG_ERR && (__sigmask (signo) & _hurdsig_preempted_set))
+    if (handler == SIG_ERR && __sigismember (&_hurdsig_preempted_set, signo))
       {
        __mutex_lock (&_hurd_siglock);
        handler = try_preemptor (_hurdsig_preemptors);
@@ -674,7 +702,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       if (__sigmask (signo) & STOPSIGS)
        /* Stop signals clear a pending SIGCONT even if they
           are handled or ignored (but not if preempted).  */
-       ss->pending &= ~sigmask (SIGCONT);
+       __sigdelset (&ss->pending, SIGCONT);
       else
        {
          if (signo == SIGCONT)
@@ -687,9 +715,9 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
        }
     }
 
-  if (_hurd_orphaned && act == stop &&
-      (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |
-                           __sigmask (SIGTSTP))))
+  if (_hurd_orphaned && act == stop
+      && (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU)
+                              | __sigmask (SIGTSTP))))
     {
       /* If we would ordinarily stop for a job control signal, but we are
         orphaned so noone would ever notice and continue us again, we just
@@ -700,9 +728,9 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
     }
 
   /* Handle receipt of a blocked signal, or any signal while stopped.  */
-  if (act != ignore &&         /* Signals ignored now are forgotten now.  */
-      __sigismember (&ss->blocked, signo) ||
-      (signo != SIGKILL && _hurd_stopped))
+  if (act != ignore            /* Signals ignored now are forgotten now.  */
+      && __sigismember (&ss->blocked, signo)
+      || (signo != SIGKILL && _hurd_stopped))
     {
       mark_pending ();
       act = ignore;
@@ -727,6 +755,11 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       break;
 
     case ignore:
+      if (detail->exc)
+       /* Blocking or ignoring a machine exception is fatal.
+          Otherwise we could just spin on the faulting instruction.  */
+       goto fatal;
+
       /* Nobody cares about this signal.  If there was a call to resume
         above in SIGCONT processing and we've left a thread suspended,
         now's the time to set it going. */
@@ -743,6 +776,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
         Nothing to do but die; BSD gets SIGILL in this case.  */
       detail->code = signo;    /* XXX ? */
       signo = SIGILL;
+
+    fatal:
       act = core;
       /* FALLTHROUGH */
 
@@ -814,7 +849,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 
            if (! machine_get_basic_state (ss->thread, &thread_state))
              goto sigbomb;
-           loc = interrupted_reply_port_location (&thread_state, 1);
+           loc = interrupted_reply_port_location (ss->thread,
+                                                  &thread_state, 1);
            if (loc && *loc != MACH_PORT_NULL)
              /* This is the reply port for the context which called
                 sigreturn.  Since we are abandoning that context entirely
@@ -880,7 +916,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
        {
          /* Fetch the thread variable for the MiG reply port,
             and set it to MACH_PORT_NULL.  */
-         mach_port_t *loc = interrupted_reply_port_location (&thread_state,
+         mach_port_t *loc = interrupted_reply_port_location (ss->thread,
+                                                             &thread_state,
                                                              1);
          if (loc)
            {
@@ -911,9 +948,20 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
        /* Backdoor extra argument to signal handler.  */
        scp->sc_error = detail->error;
 
-       /* Block SIGNO and requested signals while running the handler.  */
+       /* Block requested signals while running the handler.  */
        scp->sc_mask = ss->blocked;
-       ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
+       __sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
+
+       /* Also block SIGNO unless we're asked not to.  */
+       if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
+         __sigaddset (&ss->blocked, signo);
+
+       /* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
+           be automatically reset when delivered; the system silently
+           enforces this restriction.  */
+       if (ss->actions[signo].sa_flags & SA_RESETHAND
+           && signo != SIGILL && signo != SIGTRAP)
+         ss->actions[signo].sa_handler = SIG_DFL;
 
        /* Start the thread running the handler (or possibly waiting for an
           RPC reply before running the handler).  */
@@ -983,7 +1031,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
                      || ss->actions[signo].sa_handler == SIG_IGN
                      || ss->actions[signo].sa_handler == SIG_DFL))
                {
-                 mutex_unlock (&_hurd_siglock);
+                 __mutex_unlock (&_hurd_siglock);
                  goto deliver_pending;
                }
            __spin_unlock (&ss->lock);
@@ -999,16 +1047,11 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
            /* There is a sigsuspend waiting.  Tell it to wake up.  */
            error_t err;
            mach_msg_header_t msg;
-           err = __mach_port_insert_right (__mach_task_self (),
-                                           ss->suspended, ss->suspended,
-                                           MACH_MSG_TYPE_MAKE_SEND);
-           assert_perror (err);
-           msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_SEND, 0);
+           msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
            msg.msgh_remote_port = ss->suspended;
            msg.msgh_local_port = MACH_PORT_NULL;
            /* These values do not matter.  */
            msg.msgh_id = 8675309; /* Jenny, Jenny.  */
-           msg.msgh_seqno = 17; /* Random.  */
            ss->suspended = MACH_PORT_NULL;
            err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
                              MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
@@ -1105,6 +1148,7 @@ signal_allowed (int signo, mach_port_t refport)
              }
            _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
          }
+       __mutex_unlock (&_hurd_dtable_lock);
        /* If we found a lucky winner, we've set D to -1 in the loop.  */
        if (lucky)
          goto win;
@@ -1212,7 +1256,7 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
   if (intarraysize > INIT_SIGMASK)
     ss->blocked = intarray[INIT_SIGMASK];
   if (intarraysize > INIT_SIGPENDING)
-    ss->blocked = intarray[INIT_SIGPENDING];
+    ss->pending = intarray[INIT_SIGPENDING];
   if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
     {
       int signo;
@@ -1227,24 +1271,22 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
 
   /* Start the signal thread listening on the message port.  */
 
-  if (__hurd_threadvar_stack_mask == 0)
+#pragma weak __cthread_fork
+  if (!__cthread_fork)
     {
       err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
       assert_perror (err);
 
-      stacksize = ~__hurd_threadvar_stack_mask + 1;
       stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
       err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
                                 _hurd_msgport_receive,
                                 (vm_address_t *) &__hurd_sigthread_stack_base,
                                 &stacksize);
       assert_perror (err);
+      err = __mach_setup_tls (_hurd_msgport_thread);
+      assert_perror (err);
 
       __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
-      __hurd_sigthread_variables =
-       malloc (__hurd_threadvar_max * sizeof (unsigned long int));
-      if (__hurd_sigthread_variables == NULL)
-       __libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
 
       /* Reinitialize the MiG support routines so they will use a per-thread
         variable for the cached reply port.  */
@@ -1264,14 +1306,50 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
          we'll let the signal thread's per-thread variables be found as for
          any normal cthread, and just leave the magic __hurd_sigthread_*
          values all zero so they'll be ignored.  */
-#pragma weak cthread_fork
-#pragma weak cthread_detach
-      cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
+#pragma weak __cthread_detach
+#pragma weak __pthread_getattr_np
+#pragma weak __pthread_attr_getstack
+      __cthread_t thread = __cthread_fork (
+                            (cthread_fn_t) &_hurd_msgport_receive, 0);
+      __cthread_detach (thread);
+
+      if (__pthread_getattr_np)
+       {
+         /* Record signal thread stack layout for fork() */
+         pthread_attr_t attr;
+         void *addr;
+         size_t size;
+
+         __pthread_getattr_np ((pthread_t) thread, &attr);
+         __pthread_attr_getstack (&attr, &addr, &size);
+         __hurd_sigthread_stack_base = (uintptr_t) addr;
+         __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + size;
+       }
+
+      /* XXX We need the thread port for the signal thread further on
+         in this thread (see hurdfault.c:_hurdsigfault_init).
+         Therefore we block until _hurd_msgport_thread is initialized
+         by the newly created thread.  This really shouldn't be
+         necessary; we should be able to fetch the thread port for a
+         cthread from here.  */
+      while (_hurd_msgport_thread == 0)
+       __swtch_pri (0);
     }
 
   /* Receive exceptions on the signal port.  */
+#ifdef TASK_EXCEPTION_PORT
   __task_set_special_port (__mach_task_self (),
                           TASK_EXCEPTION_PORT, _hurd_msgport);
+#elif defined (EXC_MASK_ALL)
+  __task_set_exception_ports (__mach_task_self (),
+                             EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
+                                              | EXC_MASK_MACH_SYSCALL
+                                              | EXC_MASK_RPC_ALERT),
+                             _hurd_msgport,
+                             EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
+#else
+# error task_set_exception_port?
+#endif
 
   /* Sanity check.  Any pending, unblocked signals should have been
      taken by our predecessor incarnation (i.e. parent or pre-exec state)
@@ -1290,23 +1368,23 @@ reauth_proc (mach_port_t new)
   ref = __mach_reply_port ();
   if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
                       __proc_reauthenticate (port, ref,
-                                             MACH_MSG_TYPE_MAKE_SEND) ||
-                      __auth_user_authenticate (new, ref,
-                                                MACH_MSG_TYPE_MAKE_SEND,
-                                                &ignore))
+                                             MACH_MSG_TYPE_MAKE_SEND)
+                      || __auth_user_authenticate (new, ref,
+                                                   MACH_MSG_TYPE_MAKE_SEND,
+                                                   &ignore))
       && ignore != MACH_PORT_NULL)
     __mach_port_deallocate (__mach_task_self (), ignore);
   __mach_port_destroy (__mach_task_self (), ref);
 
   /* Set the owner of the process here too. */
-  mutex_lock (&_hurd_id.lock);
+  __mutex_lock (&_hurd_id.lock);
   if (!_hurd_check_ids ())
     HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
                   __proc_setowner (port,
                                    (_hurd_id.gen.nuids
                                     ? _hurd_id.gen.uids[0] : 0),
                                    !_hurd_id.gen.nuids));
-  mutex_unlock (&_hurd_id.lock);
+  __mutex_unlock (&_hurd_id.lock);
 
   (void) &reauth_proc;         /* Silence compiler warning.  */
 }
@@ -1318,6 +1396,9 @@ text_set_element (_hurd_reauth_hook, reauth_proc);
 const char *
 _hurdsig_getenv (const char *variable)
 {
+  if (__libc_enable_secure)
+    return NULL;
+
   if (_hurdsig_catch_memory_fault (__environ))
     /* We bombed in getenv.  */
     return NULL;
@@ -1333,7 +1414,6 @@ _hurdsig_getenv (const char *variable)
          _hurdsig_fault_preemptor.last = VM_MAX_ADDRESS;
          if (! strncmp (p, variable, len) && p[len] == '=')
            {
-             char *value;
              size_t valuelen;
              p += len + 1;
              valuelen = strlen (p);