aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
authorSripathi Kodi <sripathik@in.ibm.com>2005-09-19 19:26:12 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-21 12:15:34 -0400
commit66dcca062847bcd261ebb3ac96d51101f31a8630 (patch)
tree12f23a499ae0af8107d0c4a3afcff75e6697fa3b /fs/proc/base.c
parentd79e743e9fcf03f521300a970eb1ab69641910ba (diff)
[PATCH] Fix invisible threads problem
When the main thread of a thread group has done pthread_exit() and died, the other threads are still happily running, but will not be visible under /proc because their leader is no longer accessible. This fixes the access control so that we can see the sub-threads again. Signed-off-by: Sripathi Kodi <sripathik@in.ibm.com> Acked-by: Al Viro <viro@ftp.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c84
1 files changed, 77 insertions, 7 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 23db452ab428..fb34f88a4a74 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -340,6 +340,52 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
340 return result; 340 return result;
341} 341}
342 342
343
344/* Same as proc_root_link, but this addionally tries to get fs from other
345 * threads in the group */
346static int proc_task_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
347{
348 struct fs_struct *fs;
349 int result = -ENOENT;
350 struct task_struct *leader = proc_task(inode);
351
352 task_lock(leader);
353 fs = leader->fs;
354 if (fs) {
355 atomic_inc(&fs->count);
356 task_unlock(leader);
357 } else {
358 /* Try to get fs from other threads */
359 task_unlock(leader);
360 struct task_struct *task = leader;
361 read_lock(&tasklist_lock);
362 if (pid_alive(task)) {
363 while ((task = next_thread(task)) != leader) {
364 task_lock(task);
365 fs = task->fs;
366 if (fs) {
367 atomic_inc(&fs->count);
368 task_unlock(task);
369 break;
370 }
371 task_unlock(task);
372 }
373 }
374 read_unlock(&tasklist_lock);
375 }
376
377 if (fs) {
378 read_lock(&fs->lock);
379 *mnt = mntget(fs->rootmnt);
380 *dentry = dget(fs->root);
381 read_unlock(&fs->lock);
382 result = 0;
383 put_fs_struct(fs);
384 }
385 return result;
386}
387
388
343#define MAY_PTRACE(task) \ 389#define MAY_PTRACE(task) \
344 (task == current || \ 390 (task == current || \
345 (task->parent == current && \ 391 (task->parent == current && \
@@ -471,14 +517,14 @@ static int proc_oom_score(struct task_struct *task, char *buffer)
471 517
472/* permission checks */ 518/* permission checks */
473 519
474static int proc_check_root(struct inode *inode) 520/* If the process being read is separated by chroot from the reading process,
521 * don't let the reader access the threads.
522 */
523static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
475{ 524{
476 struct dentry *de, *base, *root; 525 struct dentry *de, *base;
477 struct vfsmount *our_vfsmnt, *vfsmnt, *mnt; 526 struct vfsmount *our_vfsmnt, *mnt;
478 int res = 0; 527 int res = 0;
479
480 if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
481 return -ENOENT;
482 read_lock(&current->fs->lock); 528 read_lock(&current->fs->lock);
483 our_vfsmnt = mntget(current->fs->rootmnt); 529 our_vfsmnt = mntget(current->fs->rootmnt);
484 base = dget(current->fs->root); 530 base = dget(current->fs->root);
@@ -511,6 +557,16 @@ out:
511 goto exit; 557 goto exit;
512} 558}
513 559
560static int proc_check_root(struct inode *inode)
561{
562 struct dentry *root;
563 struct vfsmount *vfsmnt;
564
565 if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
566 return -ENOENT;
567 return proc_check_chroot(root, vfsmnt);
568}
569
514static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) 570static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
515{ 571{
516 if (generic_permission(inode, mask, NULL) != 0) 572 if (generic_permission(inode, mask, NULL) != 0)
@@ -518,6 +574,20 @@ static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
518 return proc_check_root(inode); 574 return proc_check_root(inode);
519} 575}
520 576
577static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd)
578{
579 struct dentry *root;
580 struct vfsmount *vfsmnt;
581
582 if (generic_permission(inode, mask, NULL) != 0)
583 return -EACCES;
584
585 if (proc_task_root_link(inode, &root, &vfsmnt))
586 return -ENOENT;
587
588 return proc_check_chroot(root, vfsmnt);
589}
590
521extern struct seq_operations proc_pid_maps_op; 591extern struct seq_operations proc_pid_maps_op;
522static int maps_open(struct inode *inode, struct file *file) 592static int maps_open(struct inode *inode, struct file *file)
523{ 593{
@@ -1419,7 +1489,7 @@ static struct inode_operations proc_fd_inode_operations = {
1419 1489
1420static struct inode_operations proc_task_inode_operations = { 1490static struct inode_operations proc_task_inode_operations = {
1421 .lookup = proc_task_lookup, 1491 .lookup = proc_task_lookup,
1422 .permission = proc_permission, 1492 .permission = proc_task_permission,
1423}; 1493};
1424 1494
1425#ifdef CONFIG_SECURITY 1495#ifdef CONFIG_SECURITY