diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index e93ff0a719a0..60d80ab2601c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/unistd.h> | 38 | #include <asm/unistd.h> |
39 | #include <asm/siginfo.h> | 39 | #include <asm/siginfo.h> |
40 | #include <asm/cacheflush.h> | ||
40 | #include "audit.h" /* audit_signal_info() */ | 41 | #include "audit.h" /* audit_signal_info() */ |
41 | 42 | ||
42 | /* | 43 | /* |
@@ -59,21 +60,20 @@ static int sig_handler_ignored(void __user *handler, int sig) | |||
59 | (handler == SIG_DFL && sig_kernel_ignore(sig)); | 60 | (handler == SIG_DFL && sig_kernel_ignore(sig)); |
60 | } | 61 | } |
61 | 62 | ||
62 | static int sig_task_ignored(struct task_struct *t, int sig, | 63 | static int sig_task_ignored(struct task_struct *t, int sig, bool force) |
63 | int from_ancestor_ns) | ||
64 | { | 64 | { |
65 | void __user *handler; | 65 | void __user *handler; |
66 | 66 | ||
67 | handler = sig_handler(t, sig); | 67 | handler = sig_handler(t, sig); |
68 | 68 | ||
69 | if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && | 69 | if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && |
70 | handler == SIG_DFL && !from_ancestor_ns) | 70 | handler == SIG_DFL && !force) |
71 | return 1; | 71 | return 1; |
72 | 72 | ||
73 | return sig_handler_ignored(handler, sig); | 73 | return sig_handler_ignored(handler, sig); |
74 | } | 74 | } |
75 | 75 | ||
76 | static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) | 76 | static int sig_ignored(struct task_struct *t, int sig, bool force) |
77 | { | 77 | { |
78 | /* | 78 | /* |
79 | * Blocked signals are never ignored, since the | 79 | * Blocked signals are never ignored, since the |
@@ -83,7 +83,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) | |||
83 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) | 83 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) |
84 | return 0; | 84 | return 0; |
85 | 85 | ||
86 | if (!sig_task_ignored(t, sig, from_ancestor_ns)) | 86 | if (!sig_task_ignored(t, sig, force)) |
87 | return 0; | 87 | return 0; |
88 | 88 | ||
89 | /* | 89 | /* |
@@ -856,7 +856,7 @@ static void ptrace_trap_notify(struct task_struct *t) | |||
856 | * Returns true if the signal should be actually delivered, otherwise | 856 | * Returns true if the signal should be actually delivered, otherwise |
857 | * it should be dropped. | 857 | * it should be dropped. |
858 | */ | 858 | */ |
859 | static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) | 859 | static int prepare_signal(int sig, struct task_struct *p, bool force) |
860 | { | 860 | { |
861 | struct signal_struct *signal = p->signal; | 861 | struct signal_struct *signal = p->signal; |
862 | struct task_struct *t; | 862 | struct task_struct *t; |
@@ -916,7 +916,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) | |||
916 | } | 916 | } |
917 | } | 917 | } |
918 | 918 | ||
919 | return !sig_ignored(p, sig, from_ancestor_ns); | 919 | return !sig_ignored(p, sig, force); |
920 | } | 920 | } |
921 | 921 | ||
922 | /* | 922 | /* |
@@ -1060,7 +1060,8 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
1060 | assert_spin_locked(&t->sighand->siglock); | 1060 | assert_spin_locked(&t->sighand->siglock); |
1061 | 1061 | ||
1062 | result = TRACE_SIGNAL_IGNORED; | 1062 | result = TRACE_SIGNAL_IGNORED; |
1063 | if (!prepare_signal(sig, t, from_ancestor_ns)) | 1063 | if (!prepare_signal(sig, t, |
1064 | from_ancestor_ns || (info == SEND_SIG_FORCED))) | ||
1064 | goto ret; | 1065 | goto ret; |
1065 | 1066 | ||
1066 | pending = group ? &t->signal->shared_pending : &t->pending; | 1067 | pending = group ? &t->signal->shared_pending : &t->pending; |
@@ -1602,7 +1603,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) | |||
1602 | 1603 | ||
1603 | ret = 1; /* the signal is ignored */ | 1604 | ret = 1; /* the signal is ignored */ |
1604 | result = TRACE_SIGNAL_IGNORED; | 1605 | result = TRACE_SIGNAL_IGNORED; |
1605 | if (!prepare_signal(sig, t, 0)) | 1606 | if (!prepare_signal(sig, t, false)) |
1606 | goto out; | 1607 | goto out; |
1607 | 1608 | ||
1608 | ret = 0; | 1609 | ret = 0; |
@@ -1653,6 +1654,15 @@ bool do_notify_parent(struct task_struct *tsk, int sig) | |||
1653 | BUG_ON(!tsk->ptrace && | 1654 | BUG_ON(!tsk->ptrace && |
1654 | (tsk->group_leader != tsk || !thread_group_empty(tsk))); | 1655 | (tsk->group_leader != tsk || !thread_group_empty(tsk))); |
1655 | 1656 | ||
1657 | if (sig != SIGCHLD) { | ||
1658 | /* | ||
1659 | * This is only possible if parent == real_parent. | ||
1660 | * Check if it has changed security domain. | ||
1661 | */ | ||
1662 | if (tsk->parent_exec_id != tsk->parent->self_exec_id) | ||
1663 | sig = SIGCHLD; | ||
1664 | } | ||
1665 | |||
1656 | info.si_signo = sig; | 1666 | info.si_signo = sig; |
1657 | info.si_errno = 0; | 1667 | info.si_errno = 0; |
1658 | /* | 1668 | /* |