public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] introduce get_task_pid() to fix unsafe get_pid()
@ 2006-09-11  2:25 Oleg Nesterov
  2006-09-11  3:58 ` Eric W. Biederman
  0 siblings, 1 reply; 4+ messages in thread
From: Oleg Nesterov @ 2006-09-11  2:25 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Andrew Morton, linux-kernel

(COMPILE TESTED, needs an ack from Eric)

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>

--- rc6-mm1/include/linux/pid.h~1_tgp	2006-09-09 22:34:50.000000000 +0400
+++ rc6-mm1/include/linux/pid.h	2006-09-11 05:46:14.000000000 +0400
@@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_
 extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid,
 						enum pid_type));
 
+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
  * write-held.
--- rc6-mm1/kernel/pid.c~1_tgp	2006-09-09 22:34:50.000000000 +0400
+++ rc6-mm1/kernel/pid.c	2006-09-11 05:39:23.000000000 +0400
@@ -305,6 +305,15 @@ struct task_struct *find_task_by_pid_typ
 
 EXPORT_SYMBOL(find_task_by_pid_type);
 
+struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
+{
+	struct pid *pid;
+	rcu_read_lock();
+	pid = get_pid(task->pids[type].pid);
+	rcu_read_unlock();
+	return pid;
+}
+
 struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type)
 {
 	struct task_struct *result;
--- rc6-mm1/fs/proc/base.c~1_tgp	2006-09-09 22:34:49.000000000 +0400
+++ rc6-mm1/fs/proc/base.c	2006-09-11 05:56:19.000000000 +0400
@@ -958,7 +958,7 @@ static struct inode *proc_pid_make_inode
 	/*
 	 * grab the reference to task.
 	 */
-	ei->pid = get_pid(task_pid(task));
+	ei->pid = get_task_pid(task, PIDTYPE_PID);
 	if (!ei->pid)
 		goto out_unlock;
 
@@ -1665,7 +1665,7 @@ static struct dentry *proc_base_instanti
 	/*
 	 * grab the reference to the task.
 	 */
-	ei->pid = get_pid(task_pid(task));
+	ei->pid = get_task_pid(task, PIDTYPE_PID);
 	if (!ei->pid)
 		goto out_iput;
 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] introduce get_task_pid() to fix unsafe get_pid()
  2006-09-11  2:25 [PATCH] introduce get_task_pid() to fix unsafe get_pid() Oleg Nesterov
@ 2006-09-11  3:58 ` Eric W. Biederman
  2006-09-11  4:37   ` Oleg Nesterov
  0 siblings, 1 reply; 4+ messages in thread
From: Eric W. Biederman @ 2006-09-11  3:58 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: Andrew Morton, linux-kernel

Oleg Nesterov <oleg@tv-sign.ru> writes:

> (COMPILE TESTED, needs an ack from Eric)
>
> 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.

Ugh.  I had forgotten that the pid of a task gets freed even if you
hold a reference to the task struct.  So the preemption case looks possible.

Your technique to handle this problem looks fine.

As for the functions can we build them in all 4 varieties.
struct pid *get_task_pid(struct task *);
struct pid *get_task_tgid(struct task *);
struct pid *get_task_pgrp(struct task *);
struct pid *get_task_session(struct task *);

Functions without a flag are less error prone to use, and clearer to read.

Either that or we can just drop in some rcu_read_lock() rcu_read_unlock()
into the call sites.

Eric

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] introduce get_task_pid() to fix unsafe get_pid()
  2006-09-11  3:58 ` Eric W. Biederman
@ 2006-09-11  4:37   ` Oleg Nesterov
  2006-09-11  4:59     ` Eric W. Biederman
  0 siblings, 1 reply; 4+ messages in thread
From: Oleg Nesterov @ 2006-09-11  4:37 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Andrew Morton, linux-kernel

On 09/10, Eric W. Biederman wrote:
> 
> As for the functions can we build them in all 4 varieties.
> struct pid *get_task_pid(struct task *);
> struct pid *get_task_tgid(struct task *);
> struct pid *get_task_pgrp(struct task *);
> struct pid *get_task_session(struct task *);

Something like the patch below?

> Either that or we can just drop in some rcu_read_lock() rcu_read_unlock()
> into the call sites.

Possible. I don't have a strong opinion, please feel free to send
a different patch.

[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>

--- rc6-mm1/include/linux/pid.h~1_tgp	2006-09-09 22:34:50.000000000 +0400
+++ rc6-mm1/include/linux/pid.h	2006-09-11 08:24:15.000000000 +0400
@@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_
 extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid,
 						enum pid_type));
 
+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
  * write-held.
--- rc6-mm1/kernel/pid.c~1_tgp	2006-09-09 22:34:50.000000000 +0400
+++ rc6-mm1/kernel/pid.c	2006-09-11 08:24:21.000000000 +0400
@@ -305,6 +305,15 @@ struct task_struct *find_task_by_pid_typ
 
 EXPORT_SYMBOL(find_task_by_pid_type);
 
+struct pid *__get_task_pid(struct task_struct *task, enum pid_type type)
+{
+	struct pid *pid;
+	rcu_read_lock();
+	pid = get_pid(task->pids[type].pid);
+	rcu_read_unlock();
+	return pid;
+}
+
 struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type)
 {
 	struct task_struct *result;
--- rc6-mm1/include/linux/sched.h~1_tgp	2006-09-09 22:34:50.000000000 +0400
+++ rc6-mm1/include/linux/sched.h	2006-09-11 08:26:29.000000000 +0400
@@ -1073,6 +1073,11 @@ static inline struct pid *task_session(s
 	return task->group_leader->pids[PIDTYPE_SID].pid;
 }
 
+static inline struct pid *get_task_pid(struct task_struct *task)
+{
+	return __get_task_pid(task, PIDTYPE_PID);
+}
+
 /**
  * pid_alive - check that a task structure is not stale
  * @p: Task structure to be checked.
--- rc6-mm1/fs/proc/base.c~1_tgp	2006-09-09 22:34:49.000000000 +0400
+++ rc6-mm1/fs/proc/base.c	2006-09-11 08:27:12.000000000 +0400
@@ -958,7 +958,7 @@ static struct inode *proc_pid_make_inode
 	/*
 	 * grab the reference to task.
 	 */
-	ei->pid = get_pid(task_pid(task));
+	ei->pid = get_task_pid(task);
 	if (!ei->pid)
 		goto out_unlock;
 
@@ -1665,7 +1665,7 @@ static struct dentry *proc_base_instanti
 	/*
 	 * grab the reference to the task.
 	 */
-	ei->pid = get_pid(task_pid(task));
+	ei->pid = get_task_pid(task);
 	if (!ei->pid)
 		goto out_iput;
 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] introduce get_task_pid() to fix unsafe get_pid()
  2006-09-11  4:37   ` Oleg Nesterov
@ 2006-09-11  4:59     ` Eric W. Biederman
  0 siblings, 0 replies; 4+ messages in thread
From: Eric W. Biederman @ 2006-09-11  4:59 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: Andrew Morton, linux-kernel

Oleg Nesterov <oleg@tv-sign.ru> writes:

> On 09/10, Eric W. Biederman wrote:
>> 
>> As for the functions can we build them in all 4 varieties.
>> struct pid *get_task_pid(struct task *);
>> struct pid *get_task_tgid(struct task *);
>> struct pid *get_task_pgrp(struct task *);
>> struct pid *get_task_session(struct task *);
>
> Something like the patch below?

Yes something like that.  Although it doesn't provide for the 
get_task_tgid case, and your patch only get_task_pid.

>> Either that or we can just drop in some rcu_read_lock() rcu_read_unlock()
>> into the call sites.
>
> Possible. I don't have a strong opinion, please feel free to send
> a different patch.

I just might.  Coming up with an idiom that is hard to get wrong,
is desirable here, or at least with an idiom that is consistent.

I need to sleep on it before I can answer which way we handle that.
The pain with a new idiom is that I will have to update all of the
users so all of the examples in the kernel are consistent.

I might just need to do that anyway, but...


Eric

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-09-11  5:00 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-11  2:25 [PATCH] introduce get_task_pid() to fix unsafe get_pid() Oleg Nesterov
2006-09-11  3:58 ` Eric W. Biederman
2006-09-11  4:37   ` Oleg Nesterov
2006-09-11  4:59     ` Eric W. Biederman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox