/proc and chroot, again

Patrick Schaaf (phbof@bof.de)
Fri, 25 Jun 1999 21:11:29 +0200 (MEST)


Hi,

inspired by the recent discussion on chroot and /proc, I made the appended
patch to 2.3.8.

The first chunk of the patch adds a call to proc_permission to
proc_base_inode_ops, resulting in ENOENT when trying to lookup
/proc/<pid> processes that have their fs->root outside the
current->fs->root tree. The remainder of the patch hides those
processes from readdir(/proc).

A stat() or lstat() on "outside" /proc/<pid> stuff still works,
because fs/stat.c does not use 'permission' at all. Personally,
I don't consider that a security problem. I even see the readdir
hiding as cosmetics - it is cmdline and environ for "outside"
processes I'm concerned about.

regards
Patrick

diff -urN linux-2.3.8/fs/proc/base.c patch-linux/fs/proc/base.c
--- linux-2.3.8/fs/proc/base.c Sat Jun 19 20:45:28 1999
+++ patch-linux/fs/proc/base.c Fri Jun 25 12:18:40 1999
@@ -50,7 +50,7 @@
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
- NULL, /* permission */
+ proc_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
diff -urN linux-2.3.8/fs/proc/inode.c patch-linux/fs/proc/inode.c
--- linux-2.3.8/fs/proc/inode.c Tue Jun 8 19:47:58 1999
+++ patch-linux/fs/proc/inode.c Fri Jun 25 17:36:08 1999
@@ -175,6 +175,23 @@
*
* Jeremy Fitzhardinge <jeremy@zip.com.au>
*/
+
+int proc_is_under(struct dentry *base, struct dentry *de)
+{
+ if (base && de) {
+ /* XXX locking? */
+ for(;;) {
+ struct dentry *parent;
+ if (de == base) return 1;
+ de = de->d_covers;
+ parent = de->d_parent;
+ if (de == parent) break;
+ de = parent;
+ }
+ }
+ return 0;
+}
+
int proc_permission(struct inode *inode, int mask)
{
struct task_struct *p;
@@ -207,33 +224,7 @@
de = p->fs->root;
read_unlock(&tasklist_lock); /* FIXME! */

- if (p == NULL)
- return -EACCES; /* ENOENT? */
-
- if (de == NULL)
- {
- /* kswapd and bdflush don't have proper root or cwd... */
- return -EACCES;
- }
-
- /* XXX locking? */
- for(;;)
- {
- struct dentry *parent;
-
- if (de == base)
- return 0; /* already allowed */
-
- de = de->d_covers;
- parent = de->d_parent;
-
- if (de == parent)
- break;
-
- de = parent;
- }
-
- return -EACCES; /* incompatible roots */
+ return proc_is_under(base, de) ? 0 : -ENOENT;
}

struct inode * proc_get_inode(struct super_block * sb, int ino,
diff -urN linux-2.3.8/fs/proc/root.c patch-linux/fs/proc/root.c
--- linux-2.3.8/fs/proc/root.c Sat Jun 19 20:45:29 1999
+++ patch-linux/fs/proc/root.c Fri Jun 25 17:36:08 1999
@@ -945,6 +945,8 @@
#define PROC_NUMBUF 10
#define PROC_MAXPIDS 20

+extern int proc_is_under(struct dentry *base, struct dentry *de);
+
/*
* Get a few pid's to return for filldir - we need to hold the
* tasklist lock while doing this, and we must release it before
@@ -954,12 +956,16 @@
{
struct task_struct *p;
int nr_pids = 0;
+ struct dentry *base = current->fs ? current->fs->root : NULL;

index -= FIRST_PROCESS_ENTRY;
read_lock(&tasklist_lock);
for_each_task(p) {
int pid = p->pid;
+ struct dentry *de = p->fs ? p->fs->root : NULL;
if (!pid)
+ continue;
+ if (!proc_is_under(base, de))
continue;
if (--index >= 0)
continue;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/