Revert "proc: fix races against execve() of /proc/PID/fd**"

This reverts commit aa6afca5bc.

It escalates of some of the google-chrome SELinux problems with ptrace
("Check failed: pid_ > 0.  Did not find zygote process"), and Andrew
says that it is also causing mystery lockdep reports.

Reported-by: Alex Villacís Lasso <a_villacis@palosanto.com>
Requested-by: James Morris <jmorris@namei.org>
Requested-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2011-11-09 18:16:00 -05:00
parent 19e0bafc36
commit 5e442a493f
1 changed files with 41 additions and 101 deletions

View File

@ -1652,46 +1652,12 @@ out:
return error;
}
static int proc_pid_fd_link_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
int rc;
if (task == NULL)
return -ESRCH;
rc = -EACCES;
if (lock_trace(task))
goto out_task;
generic_fillattr(inode, stat);
unlock_trace(task);
rc = 0;
out_task:
put_task_struct(task);
return rc;
}
static const struct inode_operations proc_pid_link_inode_operations = {
.readlink = proc_pid_readlink,
.follow_link = proc_pid_follow_link,
.setattr = proc_setattr,
};
static const struct inode_operations proc_fdinfo_link_inode_operations = {
.setattr = proc_setattr,
.getattr = proc_pid_fd_link_getattr,
};
static const struct inode_operations proc_fd_link_inode_operations = {
.readlink = proc_pid_readlink,
.follow_link = proc_pid_follow_link,
.setattr = proc_setattr,
.getattr = proc_pid_fd_link_getattr,
};
/* building an inode */
@ -1923,61 +1889,49 @@ out:
static int proc_fd_info(struct inode *inode, struct path *path, char *info)
{
struct task_struct *task;
struct files_struct *files;
struct task_struct *task = get_proc_task(inode);
struct files_struct *files = NULL;
struct file *file;
int fd = proc_fd(inode);
int rc;
task = get_proc_task(inode);
if (!task)
return -ENOENT;
if (task) {
files = get_files_struct(task);
put_task_struct(task);
}
if (files) {
/*
* We are not taking a ref to the file structure, so we must
* hold ->file_lock.
*/
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
unsigned int f_flags;
struct fdtable *fdt;
rc = -EACCES;
if (lock_trace(task))
goto out_task;
fdt = files_fdtable(files);
f_flags = file->f_flags & ~O_CLOEXEC;
if (FD_ISSET(fd, fdt->close_on_exec))
f_flags |= O_CLOEXEC;
rc = -ENOENT;
files = get_files_struct(task);
if (files == NULL)
goto out_unlock;
/*
* We are not taking a ref to the file structure, so we must
* hold ->file_lock.
*/
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
unsigned int f_flags;
struct fdtable *fdt;
fdt = files_fdtable(files);
f_flags = file->f_flags & ~O_CLOEXEC;
if (FD_ISSET(fd, fdt->close_on_exec))
f_flags |= O_CLOEXEC;
if (path) {
*path = file->f_path;
path_get(&file->f_path);
if (path) {
*path = file->f_path;
path_get(&file->f_path);
}
if (info)
snprintf(info, PROC_FDINFO_MAX,
"pos:\t%lli\n"
"flags:\t0%o\n",
(long long) file->f_pos,
f_flags);
spin_unlock(&files->file_lock);
put_files_struct(files);
return 0;
}
if (info)
snprintf(info, PROC_FDINFO_MAX,
"pos:\t%lli\n"
"flags:\t0%o\n",
(long long) file->f_pos,
f_flags);
rc = 0;
} else
rc = -ENOENT;
spin_unlock(&files->file_lock);
put_files_struct(files);
out_unlock:
unlock_trace(task);
out_task:
put_task_struct(task);
return rc;
spin_unlock(&files->file_lock);
put_files_struct(files);
}
return -ENOENT;
}
static int proc_fd_link(struct inode *inode, struct path *path)
@ -2072,7 +2026,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
spin_unlock(&files->file_lock);
put_files_struct(files);
inode->i_op = &proc_fd_link_inode_operations;
inode->i_op = &proc_pid_link_inode_operations;
inode->i_size = 64;
ei->op.proc_get_link = proc_fd_link;
d_set_d_op(dentry, &tid_fd_dentry_operations);
@ -2104,12 +2058,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
if (fd == ~0U)
goto out;
result = ERR_PTR(-EACCES);
if (lock_trace(task))
goto out;
result = instantiate(dir, dentry, task, &fd);
unlock_trace(task);
out:
put_task_struct(task);
out_no_task:
@ -2129,28 +2078,23 @@ static int proc_readfd_common(struct file * filp, void * dirent,
retval = -ENOENT;
if (!p)
goto out_no_task;
retval = -EACCES;
if (lock_trace(p))
goto out;
retval = 0;
fd = filp->f_pos;
switch (fd) {
case 0:
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
goto out_unlock;
goto out;
filp->f_pos++;
case 1:
ino = parent_ino(dentry);
if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
goto out_unlock;
goto out;
filp->f_pos++;
default:
files = get_files_struct(p);
if (!files)
goto out_unlock;
goto out;
rcu_read_lock();
for (fd = filp->f_pos-2;
fd < files_fdtable(files)->max_fds;
@ -2174,9 +2118,6 @@ static int proc_readfd_common(struct file * filp, void * dirent,
rcu_read_unlock();
put_files_struct(files);
}
out_unlock:
unlock_trace(p);
out:
put_task_struct(p);
out_no_task:
@ -2254,7 +2195,6 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
ei->fd = fd;
inode->i_mode = S_IFREG | S_IRUSR;
inode->i_fop = &proc_fdinfo_file_operations;
inode->i_op = &proc_fdinfo_link_inode_operations;
d_set_d_op(dentry, &tid_fd_dentry_operations);
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */