summaryrefslogtreecommitdiff
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorDeepa Dinamani <deepa.kernel@gmail.com>2018-09-19 21:41:05 -0700
committerArnd Bergmann <arnd@arndb.de>2018-12-06 17:22:53 +0100
commit854a6ed56839a40f6b5d02a2962f48841482eec4 (patch)
treeffe7666e31be2add4dfe7a8e4eadfbe015f94621 /kernel/signal.c
parentded653ccbec0335a78fa7a7aff3ec9870349fafb (diff)
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 <deepa.kernel@gmail.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 811b5d440617..3c8ea7a328e0 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2780,6 +2780,39 @@ int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
EXPORT_SYMBOL(set_compat_user_sigmask);
#endif
+/*
+ * restore_user_sigmask:
+ * usigmask: sigmask passed in from userland.
+ * sigsaved: saved sigmask when the syscall started and changed the sigmask to
+ * usigmask.
+ *
+ * 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)
+{
+
+ if (!usigmask)
+ return;
+ /*
+ * When signals are pending, do not restore them here.
+ * 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)) {
+ current->saved_sigmask = *sigsaved;
+ set_restore_sigmask();
+ return;
+ }
+
+ /*
+ * This is needed because the fast syscall return path does not restore
+ * saved_sigmask when signals are not pending.
+ */
+ set_current_blocked(sigsaved);
+}
+EXPORT_SYMBOL(restore_user_sigmask);
+
/**
* sys_rt_sigprocmask - change the list of currently blocked signals
* @how: whether to add, remove, or set signals