Commit 24336eae authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

pids: introduce change_pid() helper

Based on Eric W. Biederman's idea.

Without tasklist_lock held task_session()/task_pgrp() can return NULL if the
caller races with setprgp()/setsid() which does detach_pid() + attach_pid().
This can happen even if task == current.

Intoduce the new helper, change_pid(), which should be used instead.  This way
the caller always sees the special pid != NULL, either old or new.

Also change the prototype of attach_pid(), it always returns 0 and nobody
check the returned value.
Signed-off-by: default avatarOleg Nesterov <oleg@tv-sign.ru>
Cc:  "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 65450ceb
...@@ -89,9 +89,11 @@ extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); ...@@ -89,9 +89,11 @@ extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
* attach_pid() and detach_pid() must be called with the tasklist_lock * attach_pid() and detach_pid() must be called with the tasklist_lock
* write-held. * write-held.
*/ */
extern int attach_pid(struct task_struct *task, enum pid_type type, extern void attach_pid(struct task_struct *task, enum pid_type type,
struct pid *pid); struct pid *pid);
extern void detach_pid(struct task_struct *task, enum pid_type); extern void detach_pid(struct task_struct *task, enum pid_type);
extern void change_pid(struct task_struct *task, enum pid_type,
struct pid *pid);
extern void transfer_pid(struct task_struct *old, struct task_struct *new, extern void transfer_pid(struct task_struct *old, struct task_struct *new,
enum pid_type); enum pid_type);
......
...@@ -317,7 +317,7 @@ EXPORT_SYMBOL_GPL(find_pid); ...@@ -317,7 +317,7 @@ EXPORT_SYMBOL_GPL(find_pid);
/* /*
* attach_pid() must be called with the tasklist_lock write-held. * attach_pid() must be called with the tasklist_lock write-held.
*/ */
int attach_pid(struct task_struct *task, enum pid_type type, void attach_pid(struct task_struct *task, enum pid_type type,
struct pid *pid) struct pid *pid)
{ {
struct pid_link *link; struct pid_link *link;
...@@ -325,11 +325,10 @@ int attach_pid(struct task_struct *task, enum pid_type type, ...@@ -325,11 +325,10 @@ int attach_pid(struct task_struct *task, enum pid_type type,
link = &task->pids[type]; link = &task->pids[type];
link->pid = pid; link->pid = pid;
hlist_add_head_rcu(&link->node, &pid->tasks[type]); hlist_add_head_rcu(&link->node, &pid->tasks[type]);
return 0;
} }
void detach_pid(struct task_struct *task, enum pid_type type) static void __change_pid(struct task_struct *task, enum pid_type type,
struct pid *new)
{ {
struct pid_link *link; struct pid_link *link;
struct pid *pid; struct pid *pid;
...@@ -339,7 +338,7 @@ void detach_pid(struct task_struct *task, enum pid_type type) ...@@ -339,7 +338,7 @@ void detach_pid(struct task_struct *task, enum pid_type type)
pid = link->pid; pid = link->pid;
hlist_del_rcu(&link->node); hlist_del_rcu(&link->node);
link->pid = NULL; link->pid = new;
for (tmp = PIDTYPE_MAX; --tmp >= 0; ) for (tmp = PIDTYPE_MAX; --tmp >= 0; )
if (!hlist_empty(&pid->tasks[tmp])) if (!hlist_empty(&pid->tasks[tmp]))
...@@ -348,6 +347,18 @@ void detach_pid(struct task_struct *task, enum pid_type type) ...@@ -348,6 +347,18 @@ void detach_pid(struct task_struct *task, enum pid_type type)
free_pid(pid); free_pid(pid);
} }
void detach_pid(struct task_struct *task, enum pid_type type)
{
__change_pid(task, type, NULL);
}
void change_pid(struct task_struct *task, enum pid_type type,
struct pid *pid)
{
__change_pid(task, type, pid);
attach_pid(task, type, pid);
}
/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ /* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
void transfer_pid(struct task_struct *old, struct task_struct *new, void transfer_pid(struct task_struct *old, struct task_struct *new,
enum pid_type type) enum pid_type type)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment