Commit 66dcca06 authored by Sripathi Kodi's avatar Sripathi Kodi Committed by Linus Torvalds
Browse files

[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: default avatarSripathi Kodi <sripathik@in.ibm.com>
Acked-by: default avatarAl Viro <viro@ftp.linux.org.uk>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d79e743e
Loading
Loading
Loading
Loading
+77 −7
Original line number Diff line number Diff line
@@ -340,6 +340,52 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
	return result;
}


/* Same as proc_root_link, but this addionally tries to get fs from other
 * threads in the group */
static int proc_task_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
{
	struct fs_struct *fs;
	int result = -ENOENT;
	struct task_struct *leader = proc_task(inode);

	task_lock(leader);
	fs = leader->fs;
	if (fs) {
		atomic_inc(&fs->count);
		task_unlock(leader);
	} else {
		/* Try to get fs from other threads */
		task_unlock(leader);
		struct task_struct *task = leader;
		read_lock(&tasklist_lock);
		if (pid_alive(task)) {
			while ((task = next_thread(task)) != leader) {
				task_lock(task);
				fs = task->fs;
				if (fs) {
					atomic_inc(&fs->count);
					task_unlock(task);
					break;
				}
				task_unlock(task);
			}
		}
		read_unlock(&tasklist_lock);
	}

	if (fs) {
		read_lock(&fs->lock);
		*mnt = mntget(fs->rootmnt);
		*dentry = dget(fs->root);
		read_unlock(&fs->lock);
		result = 0;
		put_fs_struct(fs);
	}
	return result;
}


#define MAY_PTRACE(task) \
	(task == current || \
	(task->parent == current && \
@@ -471,14 +517,14 @@ static int proc_oom_score(struct task_struct *task, char *buffer)

/* permission checks */

static int proc_check_root(struct inode *inode)
/* If the process being read is separated by chroot from the reading process,
 * don't let the reader access the threads.
 */
static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
{
	struct dentry *de, *base, *root;
	struct vfsmount *our_vfsmnt, *vfsmnt, *mnt;
	struct dentry *de, *base;
	struct vfsmount *our_vfsmnt, *mnt;
	int res = 0;

	if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
		return -ENOENT;
	read_lock(&current->fs->lock);
	our_vfsmnt = mntget(current->fs->rootmnt);
	base = dget(current->fs->root);
@@ -511,6 +557,16 @@ out:
	goto exit;
}

static int proc_check_root(struct inode *inode)
{
	struct dentry *root;
	struct vfsmount *vfsmnt;

	if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
		return -ENOENT;
	return proc_check_chroot(root, vfsmnt);
}

static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
{
	if (generic_permission(inode, mask, NULL) != 0)
@@ -518,6 +574,20 @@ static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
	return proc_check_root(inode);
}

static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd)
{
	struct dentry *root;
	struct vfsmount *vfsmnt;

	if (generic_permission(inode, mask, NULL) != 0)
		return -EACCES;

	if (proc_task_root_link(inode, &root, &vfsmnt))
		return -ENOENT;

	return proc_check_chroot(root, vfsmnt);
}

extern struct seq_operations proc_pid_maps_op;
static int maps_open(struct inode *inode, struct file *file)
{
@@ -1419,7 +1489,7 @@ static struct inode_operations proc_fd_inode_operations = {

static struct inode_operations proc_task_inode_operations = {
	.lookup		= proc_task_lookup,
	.permission	= proc_permission,
	.permission	= proc_task_permission,
};

#ifdef CONFIG_SECURITY