Skip to content

Commit 854a6ed

Browse files
deepa-hubarndb
authored andcommitted
signal: Add restore_user_sigmask()
Refactor the logic to restore the sigmask before the syscall returns into an api. This is useful for versions of syscalls that pass in the sigmask and expect the current->sigmask to be changed during the execution and restored after the execution of the syscall. With the advent of new y2038 syscalls in the subsequent patches, we add two more new versions of the syscalls (for pselect, ppoll and io_pgetevents) in addition to the existing native and compat versions. Adding such an api reduces the logic that would need to be replicated otherwise. Signed-off-by: Deepa Dinamani <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
1 parent ded653c commit 854a6ed

File tree

5 files changed

+51
-103
lines changed

5 files changed

+51
-103
lines changed

fs/aio.c

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,18 +2110,9 @@ SYSCALL_DEFINE6(io_pgetevents,
21102110
return ret;
21112111

21122112
ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
2113-
if (signal_pending(current)) {
2114-
if (ksig.sigmask) {
2115-
current->saved_sigmask = sigsaved;
2116-
set_restore_sigmask();
2117-
}
2118-
2119-
if (!ret)
2120-
ret = -ERESTARTNOHAND;
2121-
} else {
2122-
if (ksig.sigmask)
2123-
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
2124-
}
2113+
restore_user_sigmask(ksig.sigmask, &sigsaved);
2114+
if (signal_pending(current) && !ret)
2115+
ret = -ERESTARTNOHAND;
21252116

21262117
return ret;
21272118
}
@@ -2175,17 +2166,9 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
21752166
return ret;
21762167

21772168
ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
2178-
if (signal_pending(current)) {
2179-
if (ksig.sigmask) {
2180-
current->saved_sigmask = sigsaved;
2181-
set_restore_sigmask();
2182-
}
2183-
if (!ret)
2184-
ret = -ERESTARTNOHAND;
2185-
} else {
2186-
if (ksig.sigmask)
2187-
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
2188-
}
2169+
restore_user_sigmask(ksig.sigmask, &sigsaved);
2170+
if (signal_pending(current) && !ret)
2171+
ret = -ERESTARTNOHAND;
21892172

21902173
return ret;
21912174
}

fs/eventpoll.c

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,20 +2229,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
22292229

22302230
error = do_epoll_wait(epfd, events, maxevents, timeout);
22312231

2232-
/*
2233-
* If we changed the signal mask, we need to restore the original one.
2234-
* In case we've got a signal while waiting, we do not restore the
2235-
* signal mask yet, and we allow do_signal() to deliver the signal on
2236-
* the way back to userspace, before the signal mask is restored.
2237-
*/
2238-
if (sigmask) {
2239-
if (error == -EINTR) {
2240-
memcpy(&current->saved_sigmask, &sigsaved,
2241-
sizeof(sigsaved));
2242-
set_restore_sigmask();
2243-
} else
2244-
set_current_blocked(&sigsaved);
2245-
}
2232+
restore_user_sigmask(sigmask, &sigsaved);
22462233

22472234
return error;
22482235
}
@@ -2267,20 +2254,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
22672254

22682255
err = do_epoll_wait(epfd, events, maxevents, timeout);
22692256

2270-
/*
2271-
* If we changed the signal mask, we need to restore the original one.
2272-
* In case we've got a signal while waiting, we do not restore the
2273-
* signal mask yet, and we allow do_signal() to deliver the signal on
2274-
* the way back to userspace, before the signal mask is restored.
2275-
*/
2276-
if (sigmask) {
2277-
if (err == -EINTR) {
2278-
memcpy(&current->saved_sigmask, &sigsaved,
2279-
sizeof(sigsaved));
2280-
set_restore_sigmask();
2281-
} else
2282-
set_current_blocked(&sigsaved);
2283-
}
2257+
restore_user_sigmask(sigmask, &sigsaved);
22842258

22852259
return err;
22862260
}

fs/select.c

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -724,19 +724,7 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
724724
ret = core_sys_select(n, inp, outp, exp, to);
725725
ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
726726

727-
if (ret == -ERESTARTNOHAND) {
728-
/*
729-
* Don't restore the signal mask yet. Let do_signal() deliver
730-
* the signal on the way back to userspace, before the signal
731-
* mask is restored.
732-
*/
733-
if (sigmask) {
734-
memcpy(&current->saved_sigmask, &sigsaved,
735-
sizeof(sigsaved));
736-
set_restore_sigmask();
737-
}
738-
} else if (sigmask)
739-
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
727+
restore_user_sigmask(sigmask, &sigsaved);
740728

741729
return ret;
742730
}
@@ -1060,21 +1048,11 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
10601048

10611049
ret = do_sys_poll(ufds, nfds, to);
10621050

1051+
restore_user_sigmask(sigmask, &sigsaved);
1052+
10631053
/* We can restart this syscall, usually */
1064-
if (ret == -EINTR) {
1065-
/*
1066-
* Don't restore the signal mask yet. Let do_signal() deliver
1067-
* the signal on the way back to userspace, before the signal
1068-
* mask is restored.
1069-
*/
1070-
if (sigmask) {
1071-
memcpy(&current->saved_sigmask, &sigsaved,
1072-
sizeof(sigsaved));
1073-
set_restore_sigmask();
1074-
}
1054+
if (ret == -EINTR)
10751055
ret = -ERESTARTNOHAND;
1076-
} else if (sigmask)
1077-
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
10781056

10791057
ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
10801058

@@ -1316,19 +1294,7 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
13161294
ret = compat_core_sys_select(n, inp, outp, exp, to);
13171295
ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret);
13181296

1319-
if (ret == -ERESTARTNOHAND) {
1320-
/*
1321-
* Don't restore the signal mask yet. Let do_signal() deliver
1322-
* the signal on the way back to userspace, before the signal
1323-
* mask is restored.
1324-
*/
1325-
if (sigmask) {
1326-
memcpy(&current->saved_sigmask, &sigsaved,
1327-
sizeof(sigsaved));
1328-
set_restore_sigmask();
1329-
}
1330-
} else if (sigmask)
1331-
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
1297+
restore_user_sigmask(sigmask, &sigsaved);
13321298

13331299
return ret;
13341300
}
@@ -1375,21 +1341,11 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
13751341

13761342
ret = do_sys_poll(ufds, nfds, to);
13771343

1344+
restore_user_sigmask(sigmask, &sigsaved);
1345+
13781346
/* We can restart this syscall, usually */
1379-
if (ret == -EINTR) {
1380-
/*
1381-
* Don't restore the signal mask yet. Let do_signal() deliver
1382-
* the signal on the way back to userspace, before the signal
1383-
* mask is restored.
1384-
*/
1385-
if (sigmask) {
1386-
memcpy(&current->saved_sigmask, &sigsaved,
1387-
sizeof(sigsaved));
1388-
set_restore_sigmask();
1389-
}
1347+
if (ret == -EINTR)
13901348
ret = -ERESTARTNOHAND;
1391-
} else if (sigmask)
1392-
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
13931349

13941350
ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret);
13951351

include/linux/signal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struc
275275
extern int sigprocmask(int, sigset_t *, sigset_t *);
276276
extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
277277
sigset_t *oldset, size_t sigsetsize);
278+
extern void restore_user_sigmask(const void __user *usigmask,
279+
sigset_t *sigsaved);
278280
extern void set_current_blocked(sigset_t *);
279281
extern void __set_current_blocked(const sigset_t *);
280282
extern int show_unhandled_signals;

kernel/signal.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,6 +2780,39 @@ int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
27802780
EXPORT_SYMBOL(set_compat_user_sigmask);
27812781
#endif
27822782

2783+
/*
2784+
* restore_user_sigmask:
2785+
* usigmask: sigmask passed in from userland.
2786+
* sigsaved: saved sigmask when the syscall started and changed the sigmask to
2787+
* usigmask.
2788+
*
2789+
* This is useful for syscalls such as ppoll, pselect, io_pgetevents and
2790+
* epoll_pwait where a new sigmask is passed in from userland for the syscalls.
2791+
*/
2792+
void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
2793+
{
2794+
2795+
if (!usigmask)
2796+
return;
2797+
/*
2798+
* When signals are pending, do not restore them here.
2799+
* Restoring sigmask here can lead to delivering signals that the above
2800+
* syscalls are intended to block because of the sigmask passed in.
2801+
*/
2802+
if (signal_pending(current)) {
2803+
current->saved_sigmask = *sigsaved;
2804+
set_restore_sigmask();
2805+
return;
2806+
}
2807+
2808+
/*
2809+
* This is needed because the fast syscall return path does not restore
2810+
* saved_sigmask when signals are not pending.
2811+
*/
2812+
set_current_blocked(sigsaved);
2813+
}
2814+
EXPORT_SYMBOL(restore_user_sigmask);
2815+
27832816
/**
27842817
* sys_rt_sigprocmask - change the list of currently blocked signals
27852818
* @how: whether to add, remove, or set signals

0 commit comments

Comments
 (0)