Messages in this thread Patch in this message | | | Date | Sat, 17 Nov 2007 21:15:49 +0300 | From | Oleg Nesterov <> | Subject | [PATCH] task_pid_nr_ns() breaks proc_pid_readdir() |
| |
proc_pid_readdir:
for (...; ...; task = next_tgid(tgid + 1, ns)) { tgid = task_pid_nr_ns(task, ns); ... use tgid ...
The first problem is that task_pid_nr_ns() can race with RCU and read the freed memory.
However, rcu_read_lock() can't help. next_tgid() returns a pinned task_struct, but the task can be released (and it's pid detached) before task_pid_nr_ns() reads the pid_t value. In that case task_pid_nr_ns() returns 0 thus breaking the whole logic.
Make sure that task_pid_nr_ns() returns !0 before updating tgid. Note that next_tgid(tgid + 1) can find the same "struct pid" again, but we shouldn't go into the endless loop because pid_task(PIDTYPE_PID) must return NULL in this case, so next_tgid() can't return the same task.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
--- 24/fs/proc/base.c~pprd 2007-10-25 16:22:11.000000000 +0400 +++ 24/fs/proc/base.c 2007-11-17 20:58:14.000000000 +0300 @@ -2481,7 +2481,15 @@ int proc_pid_readdir(struct file * filp, for (task = next_tgid(tgid, ns); task; put_task_struct(task), task = next_tgid(tgid + 1, ns)) { - tgid = task_pid_nr_ns(task, ns); + int nr; + + rcu_read_lock(); + nr = task_pid_nr_ns(task, ns); + rcu_read_unlock(); + if (!nr) + continue; + + tgid = nr; filp->f_pos = tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) { put_task_struct(task); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |