diff options
| author | Andrew Morton <akpm@osdl.org> | 2004-02-18 04:55:08 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-02-18 04:55:08 -0800 |
| commit | 9b6722edafc3be41d21a1cf0efc98cef3d2bed88 (patch) | |
| tree | a98ce3110220a55fe33bc839c9a2e21930babeff /fs/proc | |
| parent | 8bbb25c3087995d66d6c0c0cd111b5b8bdd50837 (diff) | |
[PATCH] /proc thread visibility fixes
From: Kingsley Cheung <kingsley@aurema.com>
Is is possible to examine the data of tasks currently existing in the system
which are not threads of the same thread group.
For example, the only task in the group where init is group leader is itself:
gen2 02:50:44 ~: ls /proc/1/task
1
However, I can then read the contents of 'stat' for any other task in the
system:
gen2 02:49:45 ~: cat /proc/1/task/$$/stat
1669 (bash) S 1668 1669 1669 34816 1730 256 1480 6479 12 4 8 5 5 17 15 0 1 0
+8065 3252224 451 4294967295 134512640 134955932 3221225104 3221222840
+4294960144 0 65536 3686404 1266761467 3222442959 0 0 17 0 0 0
I had a look at fs/proc/base.c and found that the 'lookup' functions for
these directories were checking that the task in question existed, but
overlooked the following:
1. In the function proc_pid_lookup, a check is required to ensure that
the task in question is a thread group leader. Without the check, any
task can have its data retrieved accordingly. Consider the following.
There is a multithreaded process 1777.
gen2 23:22:47 /proc/1777: ls task
1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
However, I can read the stat file for its thread 1778 as follows:
gen2 23:22:50 /proc/1777: cat /proc/1778/stat
1778 (multithreadtest) T 1777 1777 1672 34816 1672 64 0 0 0 0 14 17 0 0 15 0 12 0 8871 24727552 104 4294967295 134512640 134515104 3221222496 1077365276 4294960144 0 0 0 0 3222479248 0 0 -1 1 0 0
But 1778 is not meant to show up in /proc/, as intended right?:
gen2 23:22:56 /proc/1777: ls /proc/
1 1365 1661 1793 881 dma kcore scsi
10 1371 1662 18 9 driver kmsg self
1014 1372 1663 2 909 execdomains loadavg slabinfo
1032 14 1664 3 963 fb locks stat
1062 15 1665 4 966 filesystems mdstat swaps
1066 16 1666 5 buddyinfo fs meminfo sys
1067 1605 1669 6 bus ide misc sysrq-trigger
1087 1610 1670 7 cmdline interrupts modules sysvipc
1095 1611 1671 736 cpuinfo iomem mounts tty
11 1641 1672 8 crypto ioports mtrr uptime
12 1658 17 807 devices irq net version
13 1660 1777 810 diskstats kallsyms partitions vmstat
2. The other part of the bug is in the function proc_task_lookup. Here
there needs to be a check that the task X is indeed a thread of the
thread group Y when we read /proc/<Y>/task/<X>.
Right now, this check does not exist, which allows for any existing
task to have its data read from another thread group directory. The
following reads the stat directory of my bash shell from the thread
group 1.
gen2 23:28:07 ~: cd /proc/1
gen2 23:28:10 /proc/1: ls
auxv cwd exe maps mounts stat status wchan
cmdline environ fd mem root statm task
gen2 23:28:11 /proc/1: ls task
1
gen2 23:28:27 /proc/1: cat task/$$/stat
1671 (bash) S 1670 1671 1671 34817 1802 256 1953 8101 12 4 10 6 9 26 15 0 1 0 5789 3252224 454 4294967295 134512640 134955932 3221225104 3221222840 4294960144 0 65536 3686404 1266761467 3222442959 0 0 17 0 0 0
Diffstat (limited to 'fs/proc')
| -rw-r--r-- | fs/proc/base.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 7f2ab96dfd95..23550fef0c47 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1582,14 +1582,13 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct read_unlock(&tasklist_lock); if (!task) goto out; + if (!thread_group_leader(task)) + goto out_drop_task; inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); - - if (!inode) { - put_task_struct(task); - goto out; - } + if (!inode) + goto out_drop_task; inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; @@ -1614,6 +1613,8 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct goto out; } return NULL; +out_drop_task: + put_task_struct(task); out: return ERR_PTR(-ENOENT); } @@ -1622,6 +1623,7 @@ out: static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { struct task_struct *task; + struct task_struct *leader = proc_task(dir); struct inode *inode; unsigned tid; @@ -1636,14 +1638,14 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry read_unlock(&tasklist_lock); if (!task) goto out; + if (leader->tgid != task->tgid) + goto out_drop_task; inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); - if (!inode) { - put_task_struct(task); - goto out; - } + if (!inode) + goto out_drop_task; inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tid_base_inode_operations; inode->i_fop = &proc_tid_base_operations; @@ -1656,6 +1658,8 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry put_task_struct(task); return NULL; +out_drop_task: + put_task_struct(task); out: return ERR_PTR(-ENOENT); } |
