pids: introduce change_pid() helper
PATCH 2/4 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 <[email protected]>
include/linux/pid.h renamed from include/linux/pid.h~2_PID_CHANGE +4 -2
@@ -89,9 +89,11 @@ extern struct pid *get_task_pid(struct t* attach_pid() and detach_pid() must be called with the tasklist_lock * write-held. */ -extern int attach_pid (struct task_struct *task,enum pid_type type, -struct pid *pid); +extern void attach_pid (struct task_struct *task,enum pid_type type, +struct pid *pid);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,enum pid_type );
kernel/pid.c renamed from kernel/pid.c~2_PID_CHANGE +16 -5
@@ -317,7 +317,7 @@ EXPORT_SYMBOL_GPL(find_pid);/* * 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_link *link;
@@ -325,11 +325,10 @@ int attach_pid(struct task_struct *task, link = &task->pids[type]; link->pid = pid;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 *pid;
@@ -339,7 +338,7 @@ void detach_pid(struct task_struct *task pid = link->pid;hlist_del_rcu (&link->node); - link->pid =NULL ; + link->pid = new;for (tmp =PIDTYPE_MAX ; --tmp >=0 ; )if (!hlist_empty (&pid->tasks[tmp]))
@@ -348,6 +347,18 @@ void detach_pid(struct task_struct *taskfree_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) */ void transfer_pid (struct task_struct *old,struct task_struct *new,enum pid_type type)