diff options
| author | Roland McGrath <roland@redhat.com> | 2005-01-14 23:38:53 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-14 23:38:53 -0800 |
| commit | 040e3e09c0905972d58c290240e1f626a8692565 (patch) | |
| tree | dc3d0c342ead6fb96a75bcc9b5e44b8ba458262b /fs/exec.c | |
| parent | a6a3f14ce0d747c7dc7ba708cf9290f8c73909fb (diff) | |
[PATCH] fix race between core dumping and exec with shared mm
When threads are sharing mm via CLONE_VM (linuxthreads, vfork), there is a
race condition where one thread doing a core dump and synchronizing all
mm-sharing threads for it can deadlock waiting for another thread that just
did an exec and will never synchronize. This patch makes the exec_mmap
check for a pending core dump and punt the exec to synchronize with that,
as if the core dump had struck before entering the execve system call at
all.
Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/fs/exec.c b/fs/exec.c index e97370813755..24f873e55080 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -550,6 +550,21 @@ static int exec_mmap(struct mm_struct *mm) old_mm = current->mm; mm_release(tsk, old_mm); + if (old_mm) { + /* + * Make sure that if there is a core dump in progress + * for the old mm, we get out and die instead of going + * through with the exec. We must hold mmap_sem around + * checking core_waiters and changing tsk->mm. The + * core-inducing thread will increment core_waiters for + * each thread whose ->mm == old_mm. + */ + down_read(&old_mm->mmap_sem); + if (unlikely(old_mm->core_waiters)) { + up_read(&old_mm->mmap_sem); + return -EINTR; + } + } task_lock(tsk); active_mm = tsk->active_mm; tsk->mm = mm; @@ -558,6 +573,7 @@ static int exec_mmap(struct mm_struct *mm) task_unlock(tsk); arch_pick_mmap_layout(mm); if (old_mm) { + up_read(&old_mm->mmap_sem); if (active_mm != old_mm) BUG(); mmput(old_mm); return 0; |
