diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-10-02 05:18:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:25 -0400 |
commit | 1a657f78dcc8ea7c53eaa1f2a45ea2315738c15f (patch) | |
tree | a19972027792082fed505c8d540f7d877e37c0ab | |
parent | 1c0d04c9e44f4a248335c33d2be7c7f7b06ff359 (diff) |
[PATCH] introduce get_task_pid() to fix unsafe get_pid()
proc_pid_make_inode:
ei->pid = get_pid(task_pid(task));
I think this is not safe. get_pid() can be preempted after checking "pid
!= NULL". Then the task exits, does detach_pid(), and RCU frees the pid.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/proc/base.c | 4 | ||||
-rw-r--r-- | include/linux/pid.h | 2 | ||||
-rw-r--r-- | kernel/pid.c | 9 |
3 files changed, 13 insertions, 2 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index a317eb2c4442..82da55b5cffe 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -958,7 +958,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st | |||
958 | /* | 958 | /* |
959 | * grab the reference to task. | 959 | * grab the reference to task. |
960 | */ | 960 | */ |
961 | ei->pid = get_pid(task_pid(task)); | 961 | ei->pid = get_task_pid(task, PIDTYPE_PID); |
962 | if (!ei->pid) | 962 | if (!ei->pid) |
963 | goto out_unlock; | 963 | goto out_unlock; |
964 | 964 | ||
@@ -1677,7 +1677,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir, | |||
1677 | /* | 1677 | /* |
1678 | * grab the reference to the task. | 1678 | * grab the reference to the task. |
1679 | */ | 1679 | */ |
1680 | ei->pid = get_pid(task_pid(task)); | 1680 | ei->pid = get_task_pid(task, PIDTYPE_PID); |
1681 | if (!ei->pid) | 1681 | if (!ei->pid) |
1682 | goto out_iput; | 1682 | goto out_iput; |
1683 | 1683 | ||
diff --git a/include/linux/pid.h b/include/linux/pid.h index 7e39767b4c60..17b9e04d3586 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h | |||
@@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_task(struct pid *pid, enum pid_type)); | |||
68 | extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid, | 68 | extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid, |
69 | enum pid_type)); | 69 | enum pid_type)); |
70 | 70 | ||
71 | extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); | ||
72 | |||
71 | /* | 73 | /* |
72 | * attach_pid() and detach_pid() must be called with the tasklist_lock | 74 | * attach_pid() and detach_pid() must be called with the tasklist_lock |
73 | * write-held. | 75 | * write-held. |
diff --git a/kernel/pid.c b/kernel/pid.c index e4779bbb2058..b914392085f9 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -304,6 +304,15 @@ struct task_struct *find_task_by_pid_type(int type, int nr) | |||
304 | 304 | ||
305 | EXPORT_SYMBOL(find_task_by_pid_type); | 305 | EXPORT_SYMBOL(find_task_by_pid_type); |
306 | 306 | ||
307 | struct pid *get_task_pid(struct task_struct *task, enum pid_type type) | ||
308 | { | ||
309 | struct pid *pid; | ||
310 | rcu_read_lock(); | ||
311 | pid = get_pid(task->pids[type].pid); | ||
312 | rcu_read_unlock(); | ||
313 | return pid; | ||
314 | } | ||
315 | |||
307 | struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) | 316 | struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) |
308 | { | 317 | { |
309 | struct task_struct *result; | 318 | struct task_struct *result; |