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?
Unified · Split
| @@ -2095,6 +2095,7 @@ SYSCALL_DEFINE6(io_pgetevents, · 2094 unmodified lines | ||
| 2095 | 2095 | struct __aio_sigset ksig = { NULL, }; |
| 2096 | 2096 | sigset_t ksigmask, sigsaved; |
| 2097 | 2097 | struct timespec64 ts; |
| 2098 | + bool interrupted; | |
| 2098 | 2099 | int ret; |
| 2099 | 2100 | |
| 2100 | 2101 | if (timeout && unlikely(get_timespec64(&ts, timeout))) |
| @@ -2108,8 +2109,10 @@ SYSCALL_DEFINE6(io_pgetevents, · 7 unmodified lines | ||
| 2108 | 2109 | return ret; |
| 2109 | 2110 | |
| 2110 | 2111 | ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL); |
| 2111 | − restore_user_sigmask(ksig.sigmask, &sigsaved); | |
| 2112 | − if (signal_pending(current) && !ret) | |
| 2112 | + | |
| 2113 | + interrupted = signal_pending(current); | |
| 2114 | + restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted); | |
| 2115 | + if (interrupted && !ret) | |
| 2113 | 2116 | ret = -ERESTARTNOHAND; |
| 2114 | 2117 | |
| 2115 | 2118 | return ret; |
| @@ -2128,6 +2131,7 @@ SYSCALL_DEFINE6(io_pgetevents_time32, · 12 unmodified lines | ||
| 2128 | 2131 | struct __aio_sigset ksig = { NULL, }; |
| 2129 | 2132 | sigset_t ksigmask, sigsaved; |
| 2130 | 2133 | struct timespec64 ts; |
| 2134 | + bool interrupted; | |
| 2131 | 2135 | int ret; |
| 2132 | 2136 | |
| 2133 | 2137 | if (timeout && unlikely(get_old_timespec32(&ts, timeout))) |
| @@ -2142,8 +2146,10 @@ SYSCALL_DEFINE6(io_pgetevents_time32, · 8 unmodified lines | ||
| 2142 | 2146 | return ret; |
| 2143 | 2147 | |
| 2144 | 2148 | ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL); |
| 2145 | − restore_user_sigmask(ksig.sigmask, &sigsaved); | |
| 2146 | − if (signal_pending(current) && !ret) | |
| 2149 | + | |
| 2150 | + interrupted = signal_pending(current); | |
| 2151 | + restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted); | |
| 2152 | + if (interrupted && !ret) | |
| 2147 | 2153 | ret = -ERESTARTNOHAND; |
| 2148 | 2154 | |
| 2149 | 2155 | return ret; |
| @@ -2193,6 +2199,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents, · 43 unmodified lines | ||
| 2193 | 2199 | struct __compat_aio_sigset ksig = { NULL, }; |
| 2194 | 2200 | sigset_t ksigmask, sigsaved; |
| 2195 | 2201 | struct timespec64 t; |
| 2202 | + bool interrupted; | |
| 2196 | 2203 | int ret; |
| 2197 | 2204 | |
| 2198 | 2205 | if (timeout && get_old_timespec32(&t, timeout)) |
| @@ -2206,8 +2213,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents, · 7 unmodified lines | ||
| 2206 | 2213 | return ret; |
| 2207 | 2214 | |
| 2208 | 2215 | ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); |
| 2209 | − restore_user_sigmask(ksig.sigmask, &sigsaved); | |
| 2210 | − if (signal_pending(current) && !ret) | |
| 2216 | + | |
| 2217 | + interrupted = signal_pending(current); | |
| 2218 | + restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted); | |
| 2219 | + if (interrupted && !ret) | |
| 2211 | 2220 | ret = -ERESTARTNOHAND; |
| 2212 | 2221 | |
| 2213 | 2222 | return ret; |
| @@ -2226,6 +2235,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64, · 12 unmodified lines | ||
| 2226 | 2235 | struct __compat_aio_sigset ksig = { NULL, }; |
| 2227 | 2236 | sigset_t ksigmask, sigsaved; |
| 2228 | 2237 | struct timespec64 t; |
| 2238 | + bool interrupted; | |
| 2229 | 2239 | int ret; |
| 2230 | 2240 | |
| 2231 | 2241 | if (timeout && get_timespec64(&t, timeout)) |
| @@ -2239,8 +2249,10 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64, · 7 unmodified lines | ||
| 2239 | 2249 | return ret; |
| 2240 | 2250 | |
| 2241 | 2251 | ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); |
| 2242 | − restore_user_sigmask(ksig.sigmask, &sigsaved); | |
| 2243 | − if (signal_pending(current) && !ret) | |
| 2252 | + | |
| 2253 | + interrupted = signal_pending(current); | |
| 2254 | + restore_user_sigmask(ksig.sigmask, &sigsaved, interrupted); | |
| 2255 | + if (interrupted && !ret) | |
| 2244 | 2256 | ret = -ERESTARTNOHAND; |
| 2245 | 2257 | |
| 2246 | 2258 | return ret; |
| @@ -2325,7 +2325,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, · 2324 unmodified lines | ||
| 2325 | 2325 | |
| 2326 | 2326 | error = do_epoll_wait(epfd, events, maxevents, timeout); |
| 2327 | 2327 | |
| 2328 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 2328 | + restore_user_sigmask(sigmask, &sigsaved, error == -EINTR); | |
| 2329 | 2329 | |
| 2330 | 2330 | return error; |
| 2331 | 2331 | } |
| @@ -2350,7 +2350,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, · 18 unmodified lines | ||
| 2350 | 2350 | |
| 2351 | 2351 | err = do_epoll_wait(epfd, events, maxevents, timeout); |
| 2352 | 2352 | |
| 2353 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 2353 | + restore_user_sigmask(sigmask, &sigsaved, err == -EINTR); | |
| 2354 | 2354 | |
| 2355 | 2355 | return err; |
| 2356 | 2356 | } |
| @@ -2201,11 +2201,12 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, · 2200 unmodified lines | ||
| 2201 | 2201 | } |
| 2202 | 2202 | |
| 2203 | 2203 | ret = wait_event_interruptible(ctx->wait, io_cqring_events(ring) >= min_events); |
| 2204 | − if (ret == -ERESTARTSYS) | |
| 2205 | − ret = -EINTR; | |
| 2206 | 2204 | |
| 2207 | 2205 | if (sig) |
| 2208 | − restore_user_sigmask(sig, &sigsaved); | |
| 2206 | + restore_user_sigmask(sig, &sigsaved, ret == -ERESTARTSYS); | |
| 2207 | + | |
| 2208 | + if (ret == -ERESTARTSYS) | |
| 2209 | + ret = -EINTR; | |
| 2209 | 2210 | |
| 2210 | 2211 | return READ_ONCE(ring->r.head) == READ_ONCE(ring->r.tail) ? ret : 0; |
| 2211 | 2212 | } |
| @@ -758,10 +758,9 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, · 757 unmodified lines | ||
| 758 | 758 | return ret; |
| 759 | 759 | |
| 760 | 760 | ret = core_sys_select(n, inp, outp, exp, to); |
| 761 | + restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND); | |
| 761 | 762 | ret = poll_select_copy_remaining(&end_time, tsp, type, ret); |
| 762 | 763 | |
| 763 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 764 | − | |
| 765 | 764 | return ret; |
| 766 | 765 | } |
| 767 | 766 | |
| @@ -1106,8 +1105,7 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, · 338 unmodified lines | ||
| 1106 | 1105 | |
| 1107 | 1106 | ret = do_sys_poll(ufds, nfds, to); |
| 1108 | 1107 | |
| 1109 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 1110 | − | |
| 1108 | + restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR); | |
| 1111 | 1109 | /* We can restart this syscall, usually */ |
| 1112 | 1110 | if (ret == -EINTR) |
| 1113 | 1111 | ret = -ERESTARTNOHAND; |
| @@ -1142,8 +1140,7 @@ SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, · 28 unmodified lines | ||
| 1142 | 1140 | |
| 1143 | 1141 | ret = do_sys_poll(ufds, nfds, to); |
| 1144 | 1142 | |
| 1145 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 1146 | − | |
| 1143 | + restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR); | |
| 1147 | 1144 | /* We can restart this syscall, usually */ |
| 1148 | 1145 | if (ret == -EINTR) |
| 1149 | 1146 | ret = -ERESTARTNOHAND; |
| @@ -1350,10 +1347,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp, · 200 unmodified lines | ||
| 1350 | 1347 | return ret; |
| 1351 | 1348 | |
| 1352 | 1349 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
| 1350 | + restore_user_sigmask(sigmask, &sigsaved, ret == -ERESTARTNOHAND); | |
| 1353 | 1351 | ret = poll_select_copy_remaining(&end_time, tsp, type, ret); |
| 1354 | 1352 | |
| 1355 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 1356 | − | |
| 1357 | 1353 | return ret; |
| 1358 | 1354 | } |
| 1359 | 1355 | |
| @@ -1425,8 +1421,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, · 65 unmodified lines | ||
| 1425 | 1421 | |
| 1426 | 1422 | ret = do_sys_poll(ufds, nfds, to); |
| 1427 | 1423 | |
| 1428 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 1429 | − | |
| 1424 | + restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR); | |
| 1430 | 1425 | /* We can restart this syscall, usually */ |
| 1431 | 1426 | if (ret == -EINTR) |
| 1432 | 1427 | ret = -ERESTARTNOHAND; |
| @@ -1461,8 +1456,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, · 28 unmodified lines | ||
| 1461 | 1456 | |
| 1462 | 1457 | ret = do_sys_poll(ufds, nfds, to); |
| 1463 | 1458 | |
| 1464 | − restore_user_sigmask(sigmask, &sigsaved); | |
| 1465 | − | |
| 1459 | + restore_user_sigmask(sigmask, &sigsaved, ret == -EINTR); | |
| 1466 | 1460 | /* We can restart this syscall, usually */ |
| 1467 | 1461 | if (ret == -EINTR) |
| 1468 | 1462 | ret = -ERESTARTNOHAND; |
| @@ -276,7 +276,7 @@ extern int sigprocmask(int, sigset_t *, sigset_t *); · 275 unmodified lines | ||
| 276 | 276 | extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set, |
| 277 | 277 | sigset_t *oldset, size_t sigsetsize); |
| 278 | 278 | extern void restore_user_sigmask(const void __user *usigmask, |
| 279 | − sigset_t *sigsaved); | |
| 279 | + sigset_t *sigsaved, bool interrupted); | |
| 280 | 280 | extern void set_current_blocked(sigset_t *); |
| 281 | 281 | extern void __set_current_blocked(const sigset_t *); |
| 282 | 282 | extern int show_unhandled_signals; |
| @@ -2912,7 +2912,8 @@ EXPORT_SYMBOL(set_compat_user_sigmask); · 2911 unmodified lines | ||
| 2912 | 2912 | * This is useful for syscalls such as ppoll, pselect, io_pgetevents and |
| 2913 | 2913 | * epoll_pwait where a new sigmask is passed in from userland for the syscalls. |
| 2914 | 2914 | */ |
| 2915 | −void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved) | |
| 2915 | +void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved, | |
| 2916 | + bool interrupted) | |
| 2916 | 2917 | { |
| 2917 | 2918 | |
| 2918 | 2919 | if (!usigmask) |
| @@ -2922,7 +2923,7 @@ void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved) · 3 unmodified lines | ||
| 2922 | 2923 | * Restoring sigmask here can lead to delivering signals that the above |
| 2923 | 2924 | * syscalls are intended to block because of the sigmask passed in. |
| 2924 | 2925 | */ |
| 2925 | − if (signal_pending(current)) { | |
| 2926 | + if (interrupted) { | |
| 2926 | 2927 | current->saved_sigmask = *sigsaved; |
| 2927 | 2928 | set_restore_sigmask(); |
| 2928 | 2929 | return; |