public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] filp->f_pos not correctly updated in proc_task_readdir
@ 2009-03-16  6:44 Zhang Le
  2009-03-16  8:34 ` Al Viro
  2009-03-17 18:12 ` Eric W. Biederman
  0 siblings, 2 replies; 13+ messages in thread
From: Zhang Le @ 2009-03-16  6:44 UTC (permalink / raw)
  To: linux-kernel; +Cc: torvalds, alan, Zhang Le

filp->f_pos only get updated at the end of the function. Thus d_off of those
dirents who are in the middle will be 0, and this will cause a problem in
glibc's readdir implementation, specifically endless loop. Because when overflow
occurs, f_pos will be set to next dirent to read, however it will be 0, unless
the next one is the last one. So it will start over again and again.

There is a sample program in man 2 gendents. This is the output of the program
running on a multithread program's task dir before this patch is applied:

$ ./a.out /proc/3807/task
--------------- nread=128 ---------------
i-node#  file type  d_reclen  d_off   d_name
  506442  directory    16          1  .
  506441  directory    16          0  ..
  506443  directory    16          0  3807
  506444  directory    16          0  3809
  506445  directory    16          0  3812
  506446  directory    16          0  3861
  506447  directory    16          0  3862
  506448  directory    16          8  3863

This is the output after this patch is applied

$ ./a.out /proc/3807/task
--------------- nread=128 ---------------
i-node#  file type  d_reclen  d_off   d_name
  506442  directory    16          1  .
  506441  directory    16          2  ..
  506443  directory    16          3  3807
  506444  directory    16          4  3809
  506445  directory    16          5  3812
  506446  directory    16          6  3861
  506447  directory    16          7  3862
  506448  directory    16          8  3863

Signed-off-by: Zhang Le <r0bertz@gentoo.org>
---
 fs/proc/base.c |   16 +++++++---------
 1 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 0c9de19..cc6ea23 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3066,7 +3066,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
 	int retval = -ENOENT;
 	ino_t ino;
 	int tid;
-	unsigned long pos = filp->f_pos;  /* avoiding "long long" filp->f_pos */
 	struct pid_namespace *ns;
 
 	task = get_proc_task(inode);
@@ -3083,18 +3082,18 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
 		goto out_no_task;
 	retval = 0;
 
-	switch (pos) {
+	switch (filp->f_pos) {
 	case 0:
 		ino = inode->i_ino;
-		if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
+		if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
 			goto out;
-		pos++;
+		filp->f_pos++;
 		/* fall through */
 	case 1:
 		ino = parent_ino(dentry);
-		if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
+		if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) < 0)
 			goto out;
-		pos++;
+		filp->f_pos++;
 		/* fall through */
 	}
 
@@ -3104,9 +3103,9 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
 	ns = filp->f_dentry->d_sb->s_fs_info;
 	tid = (int)filp->f_version;
 	filp->f_version = 0;
-	for (task = first_tid(leader, tid, pos - 2, ns);
+	for (task = first_tid(leader, tid, filp->f_pos - 2, ns);
 	     task;
-	     task = next_tid(task), pos++) {
+	     task = next_tid(task), filp->f_pos++) {
 		tid = task_pid_nr_ns(task, ns);
 		if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
 			/* returning this tgid failed, save it as the first
@@ -3117,7 +3116,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
 		}
 	}
 out:
-	filp->f_pos = pos;
 	put_task_struct(leader);
 out_no_task:
 	return retval;
-- 
1.6.2


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

end of thread, other threads:[~2009-03-19  3:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-16  6:44 [PATCH] filp->f_pos not correctly updated in proc_task_readdir Zhang Le
2009-03-16  8:34 ` Al Viro
2009-03-16 16:27   ` Zhang Le
2009-03-17 10:37   ` Alexey Dobriyan
2009-03-17 12:53     ` Zhang Le
2009-03-17 13:48       ` Alexey Dobriyan
2009-03-17 18:11       ` Al Viro
2009-03-17 18:12 ` Eric W. Biederman
2009-03-18  7:27   ` Zhang Le
2009-03-18 10:36     ` Eric W. Biederman
2009-03-18 13:39       ` [PATCH] proc: Fix proc_tid_readdir so it handles the weird cases Eric W. Biederman
2009-03-18 13:57         ` Louis Rilling
2009-03-19  3:40           ` 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