git: 0143078248bb - stable/15 - linux(4): Fix signal mask restoration in epoll_pwait(2)/epoll_pwait2(2)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 04 Oct 2026 00:34:22 UTC
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=0143078248bb4caf39f23c9075b2afbede52e70d

commit 0143078248bb4caf39f23c9075b2afbede52e70d
Author:     Grzegorz Junka <list1@gjunka.com>
AuthorDate: 2026-09-27 19:22:20 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-10-04 00:33:40 +0000

    linux(4): Fix signal mask restoration in epoll_pwait(2)/epoll_pwait2(2)
    
    PR:             298878
    
    (cherry picked from commit 16a284b1cdfd45ba99c2723e7f88497e76b235ad)
---
 sys/compat/linux/linux_event.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/sys/compat/linux/linux_event.c b/sys/compat/linux/linux_event.c
index fc3ef7c3e90a..de313aefff97 100644
--- a/sys/compat/linux/linux_event.c
+++ b/sys/compat/linux/linux_event.c
@@ -376,7 +376,6 @@ linux_epoll_wait_ts(struct thread *td, int epfd, struct epoll_event *events,
 					NULL};
 	cap_rights_t rights;
 	struct file *epfp;
-	sigset_t omask;
 	int error;
 
 	if (maxevents <= 0 || maxevents > LINUX_MAX_EVENTS)
@@ -392,16 +391,10 @@ linux_epoll_wait_ts(struct thread *td, int epfd, struct epoll_event *events,
 	}
 	if (uset != NULL) {
 		error = kern_sigprocmask(td, SIG_SETMASK, uset,
-		    &omask, 0);
+		    &td->td_oldsigmask, 0);
 		if (error != 0)
 			goto leave;
 		td->td_pflags |= TDP_OLDMASK;
-		/*
-		 * Make sure that ast() is called on return to
-		 * usermode and TDP_OLDMASK is cleared, restoring old
-		 * sigmask.
-		 */
-		ast_sched(td, TDA_SIGSUSPEND);
 	}
 
 	coargs.leventlist = events;
@@ -420,9 +413,19 @@ linux_epoll_wait_ts(struct thread *td, int epfd, struct epoll_event *events,
 	if (error == 0)
 		td->td_retval[0] = coargs.count;
 
-	if (uset != NULL)
-		error = kern_sigprocmask(td, SIG_SETMASK, &omask,
-		    NULL, 0);
+	if (uset != NULL) {
+		/*
+		 * Make sure that ast() is called on return to usermode and
+		 * TDP_OLDMASK is cleared, restoring the old sigmask from
+		 * td_oldsigmask.  As on Linux, if we were interrupted, deliver
+		 * the signal with the temporary mask in place; otherwise
+		 * restore the old mask before any signal can be delivered.
+		 */
+		if (error == EINTR)
+			ast_sched(td, TDA_SIGSUSPEND);
+		else
+			ast_sched(td, TDA_PSELECT);
+	}
 leave:
 	fdrop(epfp, td);
 	return (error);