FAILED: patch "[PATCH] signal: remove the wrong signal_pending() check in" failed to apply to 5.1-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 97abc889ee296faf95ca0e978340fb7b942a3e32 Mon Sep 17 00:00:00 2001
From: Oleg Nesterov <[email protected]>
Date: Fri, 28 Jun 2019 12:06:50 -0700
Subject: [PATCH] signal: remove the wrong signal_pending() check in
restore_user_sigmask()
This is the minimal fix for stable, I'll send cleanups later.
Commit 854a6ed56839 ("signal: Add restore_user_sigmask()") introduced the visible change which breaks user-space: a signal temporary unblocked by set_user_sigmask() can be delivered even if the caller returns success or timeout.
Change restore_user_sigmask() to accept the additional "interrupted" argument which should be used instead of signal_pending() check, and update the callers.
Eric said:
: For clarity. I don't think this is required by posix, or fundamentally to : remove the races in select. It is what linux has always done and we have : applications who care so I agree this fix is needed.
:
: Further in any case where the semantic change that this patch rolls back : (aka where allowing a signal to be delivered and the select like call to : complete) would be advantage we can do as well if not better by using : signalfd.
:
: Michael is there any chance we can get this guarantee of the linux : implementation of pselect and friends clearly documented. The guarantee : that if the system call completes successfully we are guaranteed that no : signal that is unblocked by using sigmask will be delivered?
fs/aio.c +20 -8
@@ -2095,6 +2095,7 @@ SYSCALL_DEFINE6(io_pgetevents,struct __aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 ts; +bool interrupted;int ret;if (timeout &&unlikely (get_timespec64 (&ts, timeout)))
@@ -2108,8 +2109,10 @@ SYSCALL_DEFINE6(io_pgetevents,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &ts :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
@@ -2128,6 +2131,7 @@ SYSCALL_DEFINE6(io_pgetevents_time32,struct __aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 ts; +bool interrupted;int ret;if (timeout &&unlikely (get_old_timespec32 (&ts, timeout)))
@@ -2142,8 +2146,10 @@ SYSCALL_DEFINE6(io_pgetevents_time32,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &ts :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
@@ -2193,6 +2199,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,struct __compat_aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 t; +bool interrupted;int ret;if (timeout &&get_old_timespec32 (&t, timeout))
@@ -2206,8 +2213,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &t :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
@@ -2226,6 +2235,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,struct __compat_aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 t; +bool interrupted;int ret;if (timeout &&get_timespec64 (&t, timeout))
@@ -2239,8 +2249,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &t :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
fs/eventpoll.c +2 -2
@@ -2325,7 +2325,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, error =do_epoll_wait (epfd, events, maxevents, timeout); -restore_user_sigmask (sigmask, &sigsaved); +restore_user_sigmask (sigmask, &sigsaved, error == -EINTR );return error; }
@@ -2350,7 +2350,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, err =do_epoll_wait (epfd, events, maxevents, timeout); -restore_user_sigmask (sigmask, &sigsaved); +restore_user_sigmask (sigmask, &sigsaved, err == -EINTR );return err; }
fs/io_uring.c +4 -3
@@ -2201,11 +2201,12 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, } ret =wait_event_interruptible (ctx->wait,io_cqring_events (ring) >= min_events); -if (ret == -ERESTARTSYS ) - ret = -EINTR ;if (sig) -restore_user_sigmask (sig, &sigsaved); +restore_user_sigmask (sig, &sigsaved, ret == -ERESTARTSYS ); + +if (ret == -ERESTARTSYS ) + ret = -EINTR ;return READ_ONCE (ring->r.head) ==READ_ONCE (ring->r.tail) ? ret :0 ; }
fs/select.c +6 -12
@@ -758,10 +758,9 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,return ret; ret =core_sys_select (n, inp, outp, exp, to); +restore_user_sigmask (sigmask, &sigsaved, ret == -ERESTARTNOHAND ); ret =poll_select_copy_remaining (&end_time, tsp, type, ret); -restore_user_sigmask (sigmask, &sigsaved); -return ret; }
@@ -1106,8 +1105,7 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
@@ -1142,8 +1140,7 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
@@ -1350,10 +1347,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,return ret; ret =compat_core_sys_select (n, inp, outp, exp, to); +restore_user_sigmask (sigmask, &sigsaved, ret == -ERESTARTNOHAND ); ret =poll_select_copy_remaining (&end_time, tsp, type, ret); -restore_user_sigmask (sigmask, &sigsaved); -return ret; }
@@ -1425,8 +1421,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
@@ -1461,8 +1456,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
include/linux/signal.h +1 -1
@@ -276,7 +276,7 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);extern int set_user_sigmask (const sigset_t __user *usigmask,sigset_t *set,sigset_t *oldset,size_t sigsetsize);extern void restore_user_sigmask (const void __user *usigmask, -sigset_t *sigsaved); +sigset_t *sigsaved,bool interrupted);extern void set_current_blocked (sigset_t *);extern void __set_current_blocked (const sigset_t *);extern int show_unhandled_signals;
kernel/signal.c +3 -2
@@ -2912,7 +2912,8 @@ EXPORT_SYMBOL(set_compat_user_sigmask);* This is useful for syscalls such as ppoll, pselect, io_pgetevents and * epoll_pwait where a new sigmask is passed in from userland for the syscalls. */ -void restore_user_sigmask (const void __user *usigmask,sigset_t *sigsaved) +void restore_user_sigmask (const void __user *usigmask,sigset_t *sigsaved, +bool interrupted) {if (!usigmask)
@@ -2922,7 +2923,7 @@ void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)* Restoring sigmask here can lead to delivering signals that the above * syscalls are intended to block because of the sigmask passed in. */ -if (signal_pending (current)) { +if (interrupted) { current->saved_sigmask = *sigsaved;set_restore_sigmask ();return ;
Oleg Nesterov
Tested-by Eric Wong Acked-by Eric W. Biederman Acked-by Arnd Bergmann Acked-by Deepa DinamaniQuoted 2 lines · On 07/01, [email protected] wrote:
The patch below does not apply to the 5.1-stable tree.
...
Quoted 7 lines
------------------ original commit in Linus's tree ------------------
From
97abc889ee296faf95ca0e978340fb7b942a3e32Mon Sep 17 00:00:00 2001
From: Oleg Nesterov <[email protected]>
Date: Fri, 28 Jun 2019 12:06:50 -0700
Subject: [PATCH] signal: remove the wrongsignal_pending()check in
restore_user_sigmask()
because 5.1 doesn't have fdb288a679cd ("io_uring: use wait_event_interruptible for cq_wait conditional wait").
Please see the updated patch below. Compile tested...
---------------------------------------------------------------------
From 63fe93147d254350d473203f0bce8dacf08a1fbd Mon Sep 17 00:00:00 2001
From: Oleg Nesterov <[email protected]>
Date: Tue, 2 Jul 2019 19:18:45 +0200
Subject: [PATCH] signal: remove the wrong signal_pending() check in
restore_user_sigmask()
This is the minimal fix for stable, I'll send cleanups later.
Commit 854a6ed56839 ("signal: Add restore_user_sigmask()") introduced the visible change which breaks user-space: a signal temporary unblocked by set_user_sigmask() can be delivered even if the caller returns success or timeout.
Change restore_user_sigmask() to accept the additional "interrupted" argument which should be used instead of signal_pending() check, and update the callers.
Eric said:
: For clarity. I don't think this is required by posix, or fundamentally to : remove the races in select. It is what linux has always done and we have : applications who care so I agree this fix is needed.
:
: Further in any case where the semantic change that this patch rolls back : (aka where allowing a signal to be delivered and the select like call to : complete) would be advantage we can do as well if not better by using : signalfd.
:
: Michael is there any chance we can get this guarantee of the linux : implementation of pselect and friends clearly documented. The guarantee : that if the system call completes successfully we are guaranteed that no : signal that is unblocked by using sigmask will be delivered?
--- fs/aio.c | 28 ++++++++++++++++++++-------- fs/eventpoll.c | 4 ++-- fs/io_uring.c | 2 +- fs/select.c | 18 ++++++------------ include/linux/signal.h | 2 +- kernel/signal.c | 5 +++-- 6 files changed, 33 insertions(+), 26 deletions(-)
fs/aio.c +20 -8
@@ -2095,6 +2095,7 @@ SYSCALL_DEFINE6(io_pgetevents,struct __aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 ts; +bool interrupted;int ret;if (timeout &&unlikely (get_timespec64 (&ts, timeout)))
@@ -2108,8 +2109,10 @@ SYSCALL_DEFINE6(io_pgetevents,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &ts :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
@@ -2128,6 +2131,7 @@ SYSCALL_DEFINE6(io_pgetevents_time32,struct __aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 ts; +bool interrupted;int ret;if (timeout &&unlikely (get_old_timespec32 (&ts, timeout)))
@@ -2142,8 +2146,10 @@ SYSCALL_DEFINE6(io_pgetevents_time32,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &ts :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
@@ -2193,6 +2199,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,struct __compat_aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 t; +bool interrupted;int ret;if (timeout &&get_old_timespec32 (&t, timeout))
@@ -2206,8 +2213,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &t :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
@@ -2226,6 +2235,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,struct __compat_aio_sigset ksig = {NULL , };sigset_t ksigmask, sigsaved;struct timespec64 t; +bool interrupted;int ret;if (timeout &&get_timespec64 (&t, timeout))
@@ -2239,8 +2249,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,return ret; ret =do_io_getevents (ctx_id, min_nr, nr, events, timeout ? &t :NULL ); -restore_user_sigmask (ksig.sigmask, &sigsaved); -if (signal_pending (current) && !ret) + + interrupted =signal_pending (current); +restore_user_sigmask (ksig.sigmask, &sigsaved, interrupted); +if (interrupted && !ret) ret = -ERESTARTNOHAND ;return ret;
fs/eventpoll.c +2 -2
@@ -2330,7 +2330,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, error =do_epoll_wait (epfd, events, maxevents, timeout); -restore_user_sigmask (sigmask, &sigsaved); +restore_user_sigmask (sigmask, &sigsaved, error == -EINTR );return error; }
@@ -2355,7 +2355,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, err =do_epoll_wait (epfd, events, maxevents, timeout); -restore_user_sigmask (sigmask, &sigsaved); +restore_user_sigmask (sigmask, &sigsaved, err == -EINTR );return err; }
fs/io_uring.c +1 -1
@@ -2097,7 +2097,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,finish_wait (&ctx->wait, &wait);if (sig) -restore_user_sigmask (sig, &sigsaved); +restore_user_sigmask (sig, &sigsaved, ret == -EINTR );return READ_ONCE (ring->r.head) ==READ_ONCE (ring->r.tail) ? ret :0 ; }
fs/select.c +6 -12
@@ -758,10 +758,9 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,return ret; ret =core_sys_select (n, inp, outp, exp, to); +restore_user_sigmask (sigmask, &sigsaved, ret == -ERESTARTNOHAND ); ret =poll_select_copy_remaining (&end_time, tsp, type, ret); -restore_user_sigmask (sigmask, &sigsaved); -return ret; }
@@ -1106,8 +1105,7 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
@@ -1142,8 +1140,7 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
@@ -1350,10 +1347,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,return ret; ret =compat_core_sys_select (n, inp, outp, exp, to); +restore_user_sigmask (sigmask, &sigsaved, ret == -ERESTARTNOHAND ); ret =poll_select_copy_remaining (&end_time, tsp, type, ret); -restore_user_sigmask (sigmask, &sigsaved); -return ret; }
@@ -1425,8 +1421,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
@@ -1461,8 +1456,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, ret =do_sys_poll (ufds, nfds, to); -restore_user_sigmask (sigmask, &sigsaved); - +restore_user_sigmask (sigmask, &sigsaved, ret == -EINTR );/* We can restart this syscall, usually */ if (ret == -EINTR ) ret = -ERESTARTNOHAND ;
include/linux/signal.h +1 -1
@@ -276,7 +276,7 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);extern int set_user_sigmask (const sigset_t __user *usigmask,sigset_t *set,sigset_t *oldset,size_t sigsetsize);extern void restore_user_sigmask (const void __user *usigmask, -sigset_t *sigsaved); +sigset_t *sigsaved,bool interrupted);extern void set_current_blocked (sigset_t *);extern void __set_current_blocked (const sigset_t *);extern int show_unhandled_signals;
kernel/signal.c +3 -2
@@ -2849,7 +2849,8 @@ EXPORT_SYMBOL(set_compat_user_sigmask);* This is useful for syscalls such as ppoll, pselect, io_pgetevents and * epoll_pwait where a new sigmask is passed in from userland for the syscalls. */ -void restore_user_sigmask (const void __user *usigmask,sigset_t *sigsaved) +void restore_user_sigmask (const void __user *usigmask,sigset_t *sigsaved, +bool interrupted) {if (!usigmask)
@@ -2859,7 +2860,7 @@ void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)* Restoring sigmask here can lead to delivering signals that the above * syscalls are intended to block because of the sigmask passed in. */ -if (signal_pending (current)) { +if (interrupted) { current->saved_sigmask = *sigsaved;set_restore_sigmask ();return ;
Signature · 1 line
2.5.0
Greg KH
maintainerQuoted 12 lines · Oleg Nesterov
Quoted 2 lines · On 07/01, [email protected] wrote:
The patch below does not apply to the 5.1-stable tree.
...
Quoted 7 lines
------------------ original commit in Linus's tree ------------------
From
97abc889ee296faf95ca0e978340fb7b942a3e32Mon Sep 17 00:00:00 2001
From: Oleg Nesterov <[email protected]>
Date: Fri, 28 Jun 2019 12:06:50 -0700
Subject: [PATCH] signal: remove the wrongsignal_pending()check in
restore_user_sigmask()
Quoted 4 lines
because 5.1 doesn't have
fdb288a679cd("io_uring: usewait_event_interruptibleforcq_waitconditional wait").Please see the updated patch below. Compile tested...
Thanks for this, now queued up.
greg k-h