diff options
author | Andrey Vagin <avagin@openvz.org> | 2013-07-03 18:08:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:08:01 -0400 |
commit | 29000caecbe87b6b66f144f72111f0d02fbbf0c1 (patch) | |
tree | 91d178abd9543a49c087af857a3cfabececfd71e /kernel/ptrace.c | |
parent | 37f07655522042399db7a4b54aee830bdb52ce2c (diff) |
ptrace: add ability to get/set signal-blocked mask
crtools uses a parasite code for dumping processes. The parasite code is
injected into a process with help PTRACE_SEIZE.
Currently crtools blocks signals from a parasite code. If a process has
pending signals, crtools wait while a process handles these signals.
This method is not suitable for stopped tasks. A stopped task can have a
few pending signals, when we will try to execute a parasite code, we will
need to drop SIGSTOP, but all other signals must remain pending, because a
state of processes must not be changed during checkpointing.
This patch adds two ptrace commands to set/get signal-blocked mask.
I think gdb can use this commands too.
[akpm@linux-foundation.org: be consistent with brace layout]
Signed-off-by: Andrey Vagin <avagin@openvz.org>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 335a7ae697f5..ba5e6cea181a 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -844,6 +844,47 @@ int ptrace_request(struct task_struct *child, long request, | |||
844 | ret = ptrace_setsiginfo(child, &siginfo); | 844 | ret = ptrace_setsiginfo(child, &siginfo); |
845 | break; | 845 | break; |
846 | 846 | ||
847 | case PTRACE_GETSIGMASK: | ||
848 | if (addr != sizeof(sigset_t)) { | ||
849 | ret = -EINVAL; | ||
850 | break; | ||
851 | } | ||
852 | |||
853 | if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t))) | ||
854 | ret = -EFAULT; | ||
855 | else | ||
856 | ret = 0; | ||
857 | |||
858 | break; | ||
859 | |||
860 | case PTRACE_SETSIGMASK: { | ||
861 | sigset_t new_set; | ||
862 | |||
863 | if (addr != sizeof(sigset_t)) { | ||
864 | ret = -EINVAL; | ||
865 | break; | ||
866 | } | ||
867 | |||
868 | if (copy_from_user(&new_set, datavp, sizeof(sigset_t))) { | ||
869 | ret = -EFAULT; | ||
870 | break; | ||
871 | } | ||
872 | |||
873 | sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
874 | |||
875 | /* | ||
876 | * Every thread does recalc_sigpending() after resume, so | ||
877 | * retarget_shared_pending() and recalc_sigpending() are not | ||
878 | * called here. | ||
879 | */ | ||
880 | spin_lock_irq(&child->sighand->siglock); | ||
881 | child->blocked = new_set; | ||
882 | spin_unlock_irq(&child->sighand->siglock); | ||
883 | |||
884 | ret = 0; | ||
885 | break; | ||
886 | } | ||
887 | |||
847 | case PTRACE_INTERRUPT: | 888 | case PTRACE_INTERRUPT: |
848 | /* | 889 | /* |
849 | * Stop tracee without any side-effect on signal or job | 890 | * Stop tracee without any side-effect on signal or job |
@@ -948,8 +989,7 @@ int ptrace_request(struct task_struct *child, long request, | |||
948 | 989 | ||
949 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 990 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
950 | case PTRACE_GETREGSET: | 991 | case PTRACE_GETREGSET: |
951 | case PTRACE_SETREGSET: | 992 | case PTRACE_SETREGSET: { |
952 | { | ||
953 | struct iovec kiov; | 993 | struct iovec kiov; |
954 | struct iovec __user *uiov = datavp; | 994 | struct iovec __user *uiov = datavp; |
955 | 995 | ||