diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-04-30 18:28:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 20:04:06 -0400 |
commit | 403bad72b67d8b3f5a0240af5023adfa48132a65 (patch) | |
tree | d240a287cf7e64824dc6441f397b0290aa79738b /fs | |
parent | 66e5b7e1948cdbdca2b0cc6ddc6d69ee84583fb4 (diff) |
coredump: only SIGKILL should interrupt the coredumping task
There are 2 well known and ancient problems with coredump/signals, and a
lot of related bug reports:
- do_coredump() clears TIF_SIGPENDING but of course this can't help
if, say, SIGCHLD comes after that.
In this case the coredump can fail unexpectedly. See for example
wait_for_dump_helper()->signal_pending() check but there are other
reasons.
- At the same time, dumping a huge core on the slow media can take a
lot of time/resources and there is no way to kill the coredumping
task reliably. In particular this is not oom_kill-friendly.
This patch tries to fix the 1st problem, and makes the preparation for the
next changes.
We add the new SIGNAL_GROUP_COREDUMP flag set by zap_threads() to indicate
that this process dumps the core. prepare_signal() checks this flag and
nacks any signal except SIGKILL.
Note that this check tries to be conservative, in the long term we should
probably treat the SIGNAL_GROUP_EXIT case equally but this needs more
discussion. See marc.info/?l=linux-kernel&m=120508897917439
Notes:
- recalc_sigpending() doesn't check SIGNAL_GROUP_COREDUMP.
The patch assumes that dump_write/etc paths should never
call it, but we can change it as well.
- There is another source of TIF_SIGPENDING, freezer. This
will be addressed separately.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Tested-by: Mandeep Singh Baines <msb@chromium.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Neil Horman <nhorman@redhat.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Roland McGrath <roland@hack.frob.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/coredump.c | 13 |
1 files changed, 5 insertions, 8 deletions
diff --git a/fs/coredump.c b/fs/coredump.c index d52f6bd5ad8e..f91cfd8cd5f2 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
@@ -280,8 +280,8 @@ static int zap_process(struct task_struct *start, int exit_code) | |||
280 | return nr; | 280 | return nr; |
281 | } | 281 | } |
282 | 282 | ||
283 | static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | 283 | static int zap_threads(struct task_struct *tsk, struct mm_struct *mm, |
284 | struct core_state *core_state, int exit_code) | 284 | struct core_state *core_state, int exit_code) |
285 | { | 285 | { |
286 | struct task_struct *g, *p; | 286 | struct task_struct *g, *p; |
287 | unsigned long flags; | 287 | unsigned long flags; |
@@ -291,6 +291,9 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | |||
291 | if (!signal_group_exit(tsk->signal)) { | 291 | if (!signal_group_exit(tsk->signal)) { |
292 | mm->core_state = core_state; | 292 | mm->core_state = core_state; |
293 | nr = zap_process(tsk, exit_code); | 293 | nr = zap_process(tsk, exit_code); |
294 | /* ignore all signals except SIGKILL, see prepare_signal() */ | ||
295 | tsk->signal->flags |= SIGNAL_GROUP_COREDUMP; | ||
296 | clear_tsk_thread_flag(tsk, TIF_SIGPENDING); | ||
294 | } | 297 | } |
295 | spin_unlock_irq(&tsk->sighand->siglock); | 298 | spin_unlock_irq(&tsk->sighand->siglock); |
296 | if (unlikely(nr < 0)) | 299 | if (unlikely(nr < 0)) |
@@ -514,12 +517,6 @@ void do_coredump(siginfo_t *siginfo) | |||
514 | 517 | ||
515 | old_cred = override_creds(cred); | 518 | old_cred = override_creds(cred); |
516 | 519 | ||
517 | /* | ||
518 | * Clear any false indication of pending signals that might | ||
519 | * be seen by the filesystem code called to write the core file. | ||
520 | */ | ||
521 | clear_thread_flag(TIF_SIGPENDING); | ||
522 | |||
523 | ispipe = format_corename(&cn, &cprm); | 520 | ispipe = format_corename(&cn, &cprm); |
524 | 521 | ||
525 | if (ispipe) { | 522 | if (ispipe) { |