[newlib-cygwin/cygwin-3_5-branch] Cygwin: sigtimedwait: Fix segfault when timeout is used

Takashi Yano tyan0@sourceware.org
Fri Nov 22 10:28:58 GMT 2024


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=46474ecf5773bcfa216fe4943b8348f3aeb2bfcc

commit 46474ecf5773bcfa216fe4943b8348f3aeb2bfcc
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
Date:   Mon Nov 18 00:07:12 2024 +0900

    Cygwin: sigtimedwait: Fix segfault when timeout is used
    
    Previously, two bugs exist in sigtimedwait(). One is, that since
    _my_tls.sigwait_mask was left non-zero if the signal arrives after
    the timeout, sigpacket::process() would wrongly try to handle it.
    The other is if a timeout occurs after sigpacket::process() is
    called, but not completed yet, the signal handler can be called
    accidentally. If the signal handler is set to SIG_DFL or SIG_IGN,
    access violation will occur in both cases.
    
    With this patch, in sigwait_common(), check if sigwait_mask == 0
    to confirm that sigpacket::process() cleared it. In this case,
    do not treat WAIT_TIMEOUT, but call cygwait() again to retrieve
    the signal. Furthermore, sigpacket::process() checks whether
    timeout occurs in sigwait_common() and if timeout already happens,
    do not treat the signal as waited. In both cases, to avoid race
    issues, the code is guarded by cygtls::lock().
    
    Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html
    Fixes: 24ff42d79aab ("Cygwin: Implement sigtimedwait")
    Reported-by: Christian Franke <Christian.Franke@t-online.de>
    Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
    Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
    (cherry picked from commit 26144e4008cd8f7288f3387eea697bba4006e16f)

Diff:
---
 winsup/cygwin/exceptions.cc |  5 ++++-
 winsup/cygwin/release/3.5.5 |  3 +++
 winsup/cygwin/signal.cc     | 12 ++++++++++++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 3195d5719..60c1f594f 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1527,11 +1527,14 @@ sigpacket::process ()
   if ((HANDLE) *tls)
     tls->signal_debugger (si);
 
-  if (issig_wait)
+  tls->lock ();
+  if (issig_wait && tls->sigwait_mask != 0)
     {
       tls->sigwait_mask = 0;
+      tls->unlock ();
       goto dosig;
     }
+  tls->unlock ();
 
   if (handler == SIG_IGN)
     {
diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5
index b70b91ed8..d91f2b92c 100644
--- a/winsup/cygwin/release/3.5.5
+++ b/winsup/cygwin/release/3.5.5
@@ -42,3 +42,6 @@ Fixes:
 
 - Fix NtCreateEvent() error in create_lock_ob() called from flock().
   Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html
+
+- Fix segfault in sigtimedwait() when using timeout.
+  Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index 77152910b..9ee6cf995 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -615,6 +615,7 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
       set_signal_mask (_my_tls.sigwait_mask, *set);
       sig_dispatch_pending (true);
 
+do_wait:
       switch (cygwait (NULL, waittime,
 		       cw_sig_eintr | cw_cancel | cw_cancel_self))
 	{
@@ -640,6 +641,17 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
 	    }
 	  break;
 	case WAIT_TIMEOUT:
+	  _my_tls.lock ();
+	  if (_my_tls.sigwait_mask == 0)
+	    {
+	      /* sigpacket::process() already started.
+	         Will surely be signalled soon. */
+	      waittime = cw_infinite;
+	      _my_tls.unlock ();
+	      goto do_wait;
+	    }
+	  _my_tls.sigwait_mask = 0;
+	  _my_tls.unlock ();
 	  set_errno (EAGAIN);
 	  break;
 	default:


More information about the Cygwin-cvs mailing list