Skip to content

Commit 9230738

Browse files
committed
coredump: Don't perform any cleanups before dumping core
Rename coredump_exit_mm to coredump_task_exit and call it from do_exit before PTRACE_EVENT_EXIT, and before any cleanup work for a task happens. This ensures that an accurate copy of the process can be captured in the coredump as no cleanup for the process happens before the coredump completes. This also ensures that PTRACE_EVENT_EXIT will not be visited by any thread until the coredump is complete. Add a new flag PF_POSTCOREDUMP so that tasks that have passed through coredump_task_exit can be recognized and ignored in zap_process. Now that all of the coredumping happens before exit_mm remove code to test for a coredump in progress from mm_release. Replace "may_ptrace_stop()" with a simple test of "current->ptrace". The other tests in may_ptrace_stop all concern avoiding stopping during a coredump. These tests are no longer necessary as it is now guaranteed that fatal_signal_pending will be set if the code enters ptrace_stop during a coredump. The code in ptrace_stop is guaranteed not to stop if fatal_signal_pending returns true. Until this change "ptrace_event(PTRACE_EVENT_EXIT)" could call ptrace_stop without fatal_signal_pending being true, as signals are dequeued in get_signal before calling do_exit. This is no longer an issue as "ptrace_event(PTRACE_EVENT_EXIT)" is no longer reached until after the coredump completes. Link: https://lkml.kernel.org/r/874kaax26c.fsf@disp2133 Reviewed-by: Kees Cook <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent d67e03e commit 9230738

File tree

6 files changed

+20
-40
lines changed

6 files changed

+20
-40
lines changed

fs/coredump.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ static int zap_process(struct task_struct *start, int exit_code, int flags)
359359

360360
for_each_thread(start, t) {
361361
task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK);
362-
if (t != current && t->mm) {
362+
if (t != current && !(t->flags & PF_POSTCOREDUMP)) {
363363
sigaddset(&t->pending.signal, SIGKILL);
364364
signal_wake_up(t, 1);
365365
nr++;
@@ -404,8 +404,8 @@ static int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
404404
*
405405
* do_exit:
406406
* The caller holds mm->mmap_lock. This means that the task which
407-
* uses this mm can't pass coredump_exit_mm(), so it can't exit or
408-
* clear its ->mm.
407+
* uses this mm can't pass coredump_task_exit(), so it can't exit
408+
* or clear its ->mm.
409409
*
410410
* de_thread:
411411
* It does list_replace_rcu(&leader->tasks, &current->tasks),
@@ -500,7 +500,7 @@ static void coredump_finish(struct mm_struct *mm, bool core_dumped)
500500
next = curr->next;
501501
task = curr->task;
502502
/*
503-
* see coredump_exit_mm(), curr->task must not see
503+
* see coredump_task_exit(), curr->task must not see
504504
* ->task == NULL before we read ->next.
505505
*/
506506
smp_mb();

include/linux/sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,7 @@ extern struct pid *cad_pid;
16641664
#define PF_VCPU 0x00000001 /* I'm a virtual CPU */
16651665
#define PF_IDLE 0x00000002 /* I am an IDLE thread */
16661666
#define PF_EXITING 0x00000004 /* Getting shut down */
1667+
#define PF_POSTCOREDUMP 0x00000008 /* Coredumps should ignore this task */
16671668
#define PF_IO_WORKER 0x00000010 /* Task is an IO worker */
16681669
#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */
16691670
#define PF_FORKNOEXEC 0x00000040 /* Forked but didn't exec */

kernel/exit.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -339,23 +339,29 @@ kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent)
339339
}
340340
}
341341

342-
static void coredump_exit_mm(struct mm_struct *mm)
342+
static void coredump_task_exit(struct task_struct *tsk)
343343
{
344344
struct core_state *core_state;
345+
struct mm_struct *mm;
346+
347+
mm = tsk->mm;
348+
if (!mm)
349+
return;
345350

346351
/*
347352
* Serialize with any possible pending coredump.
348353
* We must hold mmap_lock around checking core_state
349-
* and clearing tsk->mm. The core-inducing thread
354+
* and setting PF_POSTCOREDUMP. The core-inducing thread
350355
* will increment ->nr_threads for each thread in the
351-
* group with ->mm != NULL.
356+
* group without PF_POSTCOREDUMP set.
352357
*/
358+
mmap_read_lock(mm);
359+
tsk->flags |= PF_POSTCOREDUMP;
353360
core_state = mm->core_state;
361+
mmap_read_unlock(mm);
354362
if (core_state) {
355363
struct core_thread self;
356364

357-
mmap_read_unlock(mm);
358-
359365
self.task = current;
360366
if (self.task->flags & PF_SIGNALED)
361367
self.next = xchg(&core_state->dumper.next, &self);
@@ -375,7 +381,6 @@ static void coredump_exit_mm(struct mm_struct *mm)
375381
freezable_schedule();
376382
}
377383
__set_current_state(TASK_RUNNING);
378-
mmap_read_lock(mm);
379384
}
380385
}
381386

@@ -480,7 +485,6 @@ static void exit_mm(void)
480485
return;
481486
sync_mm_rss(mm);
482487
mmap_read_lock(mm);
483-
coredump_exit_mm(mm);
484488
mmgrab(mm);
485489
BUG_ON(mm != current->active_mm);
486490
/* more a memory barrier than a real lock */
@@ -768,6 +772,7 @@ void __noreturn do_exit(long code)
768772
profile_task_exit(tsk);
769773
kcov_task_exit(tsk);
770774

775+
coredump_task_exit(tsk);
771776
ptrace_event(PTRACE_EVENT_EXIT, code);
772777

773778
validate_creds_for_do_exit(tsk);

kernel/fork.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,8 +1392,7 @@ static void mm_release(struct task_struct *tsk, struct mm_struct *mm)
13921392
* purposes.
13931393
*/
13941394
if (tsk->clear_child_tid) {
1395-
if (!(tsk->signal->flags & SIGNAL_GROUP_COREDUMP) &&
1396-
atomic_read(&mm->mm_users) > 1) {
1395+
if (atomic_read(&mm->mm_users) > 1) {
13971396
/*
13981397
* We don't check the error code - if userspace has
13991398
* not set up a proper pointer then tough luck.

kernel/signal.c

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,31 +2158,6 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
21582158
spin_unlock_irqrestore(&sighand->siglock, flags);
21592159
}
21602160

2161-
static inline bool may_ptrace_stop(void)
2162-
{
2163-
if (!likely(current->ptrace))
2164-
return false;
2165-
/*
2166-
* Are we in the middle of do_coredump?
2167-
* If so and our tracer is also part of the coredump stopping
2168-
* is a deadlock situation, and pointless because our tracer
2169-
* is dead so don't allow us to stop.
2170-
* If SIGKILL was already sent before the caller unlocked
2171-
* ->siglock we must see ->core_state != NULL. Otherwise it
2172-
* is safe to enter schedule().
2173-
*
2174-
* This is almost outdated, a task with the pending SIGKILL can't
2175-
* block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported
2176-
* after SIGKILL was already dequeued.
2177-
*/
2178-
if (unlikely(current->mm->core_state) &&
2179-
unlikely(current->mm == current->parent->mm))
2180-
return false;
2181-
2182-
return true;
2183-
}
2184-
2185-
21862161
/*
21872162
* This must be called with current->sighand->siglock held.
21882163
*
@@ -2263,7 +2238,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
22632238

22642239
spin_unlock_irq(&current->sighand->siglock);
22652240
read_lock(&tasklist_lock);
2266-
if (may_ptrace_stop()) {
2241+
if (likely(current->ptrace)) {
22672242
/*
22682243
* Notify parents of the stop.
22692244
*

mm/oom_kill.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ static inline bool __task_will_free_mem(struct task_struct *task)
788788

789789
/*
790790
* A coredumping process may sleep for an extended period in
791-
* coredump_exit_mm(), so the oom killer cannot assume that
791+
* coredump_task_exit(), so the oom killer cannot assume that
792792
* the process will promptly exit and release memory.
793793
*/
794794
if (sig->flags & SIGNAL_GROUP_COREDUMP)

0 commit comments

Comments
 (0)