Skip to content

Commit

Permalink
[PATCH] cpuset: fork hook fix
Browse files Browse the repository at this point in the history
Fix obscure, never seen in real life, cpuset fork race.  The cpuset_fork()
call in fork.c was setting up the correct task->cpuset pointer after the
tasklist_lock was dropped, which briefly exposed the newly forked process with
an unsafe (copied from parent without locks or usage counter increment) cpuset
pointer.

In theory, that exposed cpuset pointer could have been pointing at a cpuset
that was already freed and removed, and in theory another task that had been
sitting on the tasklist_lock waiting to scan the task list could have raced
down the entire tasklist, found our new child at the far end, and dereferenced
that bogus cpuset pointer.

To fix, setup up the correct cpuset pointer in the new child by calling
cpuset_fork() before the new task is linked into the tasklist, and with that,
add a fork failure case, to dereference that cpuset, if the fork fails along
the way, after cpuset_fork() was called.

Had to remove a BUG_ON() from cpuset_exit(), because it was no longer valid -
the call to cpuset_exit() from a failed fork would not have PF_EXITING set.

Signed-off-by: Paul Jackson <pj@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Paul Jackson authored and Linus Torvalds committed Jan 9, 2006
1 parent 59dac16 commit b4b2641
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 5 deletions.
4 changes: 1 addition & 3 deletions kernel/cpuset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1821,15 +1821,13 @@ void cpuset_fork(struct task_struct *child)
*
* We don't need to task_lock() this reference to tsk->cpuset,
* because tsk is already marked PF_EXITING, so attach_task() won't
* mess with it.
* mess with it, or task is a failed fork, never visible to attach_task.
**/

void cpuset_exit(struct task_struct *tsk)
{
struct cpuset *cs;

BUG_ON(!(tsk->flags & PF_EXITING));

cs = tsk->cpuset;
tsk->cpuset = NULL;

Expand Down
6 changes: 4 additions & 2 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -972,12 +972,13 @@ static task_t *copy_process(unsigned long clone_flags,
p->io_context = NULL;
p->io_wait = NULL;
p->audit_context = NULL;
cpuset_fork(p);
#ifdef CONFIG_NUMA
p->mempolicy = mpol_copy(p->mempolicy);
if (IS_ERR(p->mempolicy)) {
retval = PTR_ERR(p->mempolicy);
p->mempolicy = NULL;
goto bad_fork_cleanup;
goto bad_fork_cleanup_cpuset;
}
#endif

Expand Down Expand Up @@ -1148,7 +1149,6 @@ static task_t *copy_process(unsigned long clone_flags,
total_forks++;
write_unlock_irq(&tasklist_lock);
proc_fork_connector(p);
cpuset_fork(p);
retval = 0;

fork_out:
Expand Down Expand Up @@ -1180,7 +1180,9 @@ static task_t *copy_process(unsigned long clone_flags,
bad_fork_cleanup_policy:
#ifdef CONFIG_NUMA
mpol_free(p->mempolicy);
bad_fork_cleanup_cpuset:
#endif
cpuset_exit(p);
bad_fork_cleanup:
if (p->binfmt)
module_put(p->binfmt->module);
Expand Down

0 comments on commit b4b2641

Please sign in to comment.