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: Oleg 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
65450cebc6
commit
24336eaeec
@ -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);
|
||||||
|
|
||||||
|
21
kernel/pid.c
21
kernel/pid.c
@ -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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user