(root)/
glibc-2.38/
hurd/
catch-signal.c
       1  /* Convenience function to catch expected signals during an operation.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <hurd/signal.h>
      20  #include <hurd/sigpreempt.h>
      21  #include <string.h>
      22  #include <assert.h>
      23  
      24  error_t
      25  __hurd_catch_signal (sigset_t sigset,
      26  		     unsigned long int first, unsigned long int last,
      27  		     error_t (*operate) (struct hurd_signal_preemptor *),
      28  		     sighandler_t handler)
      29  {
      30    /* We need to restore the signal mask, because otherwise the
      31       signal-handling code will have blocked the caught signal and for
      32       instance calling hurd_catch_signal again would then dump core.  */
      33    sigjmp_buf buf;
      34    void throw (int signo, long int sigcode, struct sigcontext *scp)
      35      { siglongjmp (buf, scp->sc_error ?: EGRATUITOUS); }
      36  
      37    struct hurd_signal_preemptor preemptor =
      38      {
      39        sigset, first, last,
      40        NULL, handler == SIG_ERR ? (sighandler_t) &throw : handler,
      41      };
      42  
      43    struct hurd_sigstate *const ss = _hurd_self_sigstate ();
      44    error_t error;
      45  
      46    if (handler != SIG_ERR)
      47      /* Not our handler; don't bother saving state.  */
      48      error = 0;
      49    else
      50      /* This returns again with nonzero value when we preempt a signal.  */
      51      error = sigsetjmp (buf, 1);
      52  
      53    if (error == 0)
      54      {
      55        /* Install a signal preemptor for the thread.  */
      56        __spin_lock (&ss->lock);
      57        preemptor.next = ss->preemptors;
      58        ss->preemptors = &preemptor;
      59        __spin_unlock (&ss->lock);
      60  
      61        /* Try the operation that might crash.  */
      62        (*operate) (&preemptor);
      63      }
      64  
      65    /* Either FUNCTION completed happily and ERROR is still zero, or it hit
      66       an expected signal and `throw' made setjmp return the signal error
      67       code in ERROR.  Now we can remove the preemptor and return.  */
      68  
      69    __spin_lock (&ss->lock);
      70    assert (ss->preemptors == &preemptor);
      71    ss->preemptors = preemptor.next;
      72    __spin_unlock (&ss->lock);
      73  
      74    return error;
      75  }
      76  strong_alias (__hurd_catch_signal, hurd_catch_signal)
      77  
      78  
      79  error_t
      80  hurd_safe_memset (void *dest, int byte, size_t nbytes)
      81  {
      82    error_t operate (struct hurd_signal_preemptor *preemptor)
      83      {
      84        memset (dest, byte, nbytes);
      85        return 0;
      86      }
      87    return __hurd_catch_signal (__sigmask (SIGBUS) | __sigmask (SIGSEGV),
      88  			      (vm_address_t) dest, (vm_address_t) dest + nbytes,
      89  			      &operate, SIG_ERR);
      90  }
      91  
      92  
      93  error_t
      94  hurd_safe_copyout (void *dest, const void *src, size_t nbytes)
      95  {
      96    error_t operate (struct hurd_signal_preemptor *preemptor)
      97      {
      98        memcpy (dest, src, nbytes);
      99        return 0;
     100      }
     101    return __hurd_catch_signal (__sigmask (SIGBUS) | __sigmask (SIGSEGV),
     102  			      (vm_address_t) dest, (vm_address_t) dest + nbytes,
     103  			      &operate, SIG_ERR);
     104  }
     105  
     106  error_t
     107  hurd_safe_copyin (void *dest, const void *src, size_t nbytes)
     108  {
     109    error_t operate (struct hurd_signal_preemptor *preemptor)
     110      {
     111        memcpy (dest, src, nbytes);
     112        return 0;
     113      }
     114    return __hurd_catch_signal (__sigmask (SIGBUS) | __sigmask (SIGSEGV),
     115  			      (vm_address_t) src, (vm_address_t) src + nbytes,
     116  			      &operate, SIG_ERR);
     117  }
     118  
     119  error_t
     120  hurd_safe_memmove (void *dest, const void *src, size_t nbytes)
     121  {
     122    jmp_buf buf;
     123    void throw (int signo, long int sigcode, struct sigcontext *scp)
     124      { longjmp (buf, scp->sc_error ?: EGRATUITOUS); }
     125  
     126    struct hurd_signal_preemptor src_preemptor =
     127      {
     128        __sigmask (SIGBUS) | __sigmask (SIGSEGV),
     129        (vm_address_t) src, (vm_address_t) src + nbytes,
     130        NULL, (sighandler_t) &throw,
     131      };
     132    struct hurd_signal_preemptor dest_preemptor =
     133      {
     134        __sigmask (SIGBUS) | __sigmask (SIGSEGV),
     135        (vm_address_t) dest, (vm_address_t) dest + nbytes,
     136        NULL, (sighandler_t) &throw,
     137        &src_preemptor
     138      };
     139  
     140    struct hurd_sigstate *const ss = _hurd_self_sigstate ();
     141    error_t error;
     142  
     143    /* This returns again with nonzero value when we preempt a signal.  */
     144    error = setjmp (buf);
     145  
     146    if (error == 0)
     147      {
     148        /* Install a signal preemptor for the thread.  */
     149        __spin_lock (&ss->lock);
     150        src_preemptor.next = ss->preemptors;
     151        ss->preemptors = &dest_preemptor;
     152        __spin_unlock (&ss->lock);
     153  
     154        /* Do the copy; it might fault.  */
     155        memmove (dest, src, nbytes);
     156      }
     157  
     158    /* Either memmove completed happily and ERROR is still zero, or it hit
     159       an expected signal and `throw' made setjmp return the signal error
     160       code in ERROR.  Now we can remove the preemptor and return.  */
     161  
     162    __spin_lock (&ss->lock);
     163    assert (ss->preemptors == &dest_preemptor);
     164    ss->preemptors = src_preemptor.next;
     165    __spin_unlock (&ss->lock);
     166  
     167    return error;
     168  }