Commit 5e442a49 authored by Linus Torvalds's avatar Linus Torvalds

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

This reverts commit aa6afca5.

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: default avatarAlex Villacís Lasso <a_villacis@palosanto.com>
Requested-by: default avatarJames Morris <jmorris@namei.org>
Requested-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 19e0bafc
...@@ -1652,46 +1652,12 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b ...@@ -1652,46 +1652,12 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
return error; 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 = { static const struct inode_operations proc_pid_link_inode_operations = {
.readlink = proc_pid_readlink, .readlink = proc_pid_readlink,
.follow_link = proc_pid_follow_link, .follow_link = proc_pid_follow_link,
.setattr = proc_setattr, .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 */ /* building an inode */
...@@ -1923,61 +1889,49 @@ static unsigned name_to_int(struct dentry *dentry) ...@@ -1923,61 +1889,49 @@ static unsigned name_to_int(struct dentry *dentry)
static int proc_fd_info(struct inode *inode, struct path *path, char *info) static int proc_fd_info(struct inode *inode, struct path *path, char *info)
{ {
struct task_struct *task; struct task_struct *task = get_proc_task(inode);
struct files_struct *files; struct files_struct *files = NULL;
struct file *file; struct file *file;
int fd = proc_fd(inode); int fd = proc_fd(inode);
int rc;
task = get_proc_task(inode);
if (!task)
return -ENOENT;
rc = -EACCES;
if (lock_trace(task))
goto out_task;
rc = -ENOENT;
files = get_files_struct(task);
if (files == NULL)
goto out_unlock;
/* if (task) {
* We are not taking a ref to the file structure, so we must files = get_files_struct(task);
* hold ->file_lock. put_task_struct(task);
*/ }
spin_lock(&files->file_lock); if (files) {
file = fcheck_files(files, fd); /*
if (file) { * We are not taking a ref to the file structure, so we must
unsigned int f_flags; * hold ->file_lock.
struct fdtable *fdt; */
spin_lock(&files->file_lock);
fdt = files_fdtable(files); file = fcheck_files(files, fd);
f_flags = file->f_flags & ~O_CLOEXEC; if (file) {
if (FD_ISSET(fd, fdt->close_on_exec)) unsigned int f_flags;
f_flags |= O_CLOEXEC; struct fdtable *fdt;
if (path) { fdt = files_fdtable(files);
*path = file->f_path; f_flags = file->f_flags & ~O_CLOEXEC;
path_get(&file->f_path); if (FD_ISSET(fd, fdt->close_on_exec))
f_flags |= O_CLOEXEC;
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) spin_unlock(&files->file_lock);
snprintf(info, PROC_FDINFO_MAX, put_files_struct(files);
"pos:\t%lli\n" }
"flags:\t0%o\n", return -ENOENT;
(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;
} }
static int proc_fd_link(struct inode *inode, struct path *path) static int proc_fd_link(struct inode *inode, struct path *path)
...@@ -2072,7 +2026,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, ...@@ -2072,7 +2026,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
spin_unlock(&files->file_lock); spin_unlock(&files->file_lock);
put_files_struct(files); put_files_struct(files);
inode->i_op = &proc_fd_link_inode_operations; inode->i_op = &proc_pid_link_inode_operations;
inode->i_size = 64; inode->i_size = 64;
ei->op.proc_get_link = proc_fd_link; ei->op.proc_get_link = proc_fd_link;
d_set_d_op(dentry, &tid_fd_dentry_operations); d_set_d_op(dentry, &tid_fd_dentry_operations);
...@@ -2104,12 +2058,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, ...@@ -2104,12 +2058,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
if (fd == ~0U) if (fd == ~0U)
goto out; goto out;
result = ERR_PTR(-EACCES);
if (lock_trace(task))
goto out;
result = instantiate(dir, dentry, task, &fd); result = instantiate(dir, dentry, task, &fd);
unlock_trace(task);
out: out:
put_task_struct(task); put_task_struct(task);
out_no_task: out_no_task:
...@@ -2129,28 +2078,23 @@ static int proc_readfd_common(struct file * filp, void * dirent, ...@@ -2129,28 +2078,23 @@ static int proc_readfd_common(struct file * filp, void * dirent,
retval = -ENOENT; retval = -ENOENT;
if (!p) if (!p)
goto out_no_task; goto out_no_task;
retval = -EACCES;
if (lock_trace(p))
goto out;
retval = 0; retval = 0;
fd = filp->f_pos; fd = filp->f_pos;
switch (fd) { switch (fd) {
case 0: case 0:
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
goto out_unlock; goto out;
filp->f_pos++; filp->f_pos++;
case 1: case 1:
ino = parent_ino(dentry); ino = parent_ino(dentry);
if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
goto out_unlock; goto out;
filp->f_pos++; filp->f_pos++;
default: default:
files = get_files_struct(p); files = get_files_struct(p);
if (!files) if (!files)
goto out_unlock; goto out;
rcu_read_lock(); rcu_read_lock();
for (fd = filp->f_pos-2; for (fd = filp->f_pos-2;
fd < files_fdtable(files)->max_fds; fd < files_fdtable(files)->max_fds;
...@@ -2174,9 +2118,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, ...@@ -2174,9 +2118,6 @@ static int proc_readfd_common(struct file * filp, void * dirent,
rcu_read_unlock(); rcu_read_unlock();
put_files_struct(files); put_files_struct(files);
} }
out_unlock:
unlock_trace(p);
out: out:
put_task_struct(p); put_task_struct(p);
out_no_task: out_no_task:
...@@ -2254,7 +2195,6 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir, ...@@ -2254,7 +2195,6 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
ei->fd = fd; ei->fd = fd;
inode->i_mode = S_IFREG | S_IRUSR; inode->i_mode = S_IFREG | S_IRUSR;
inode->i_fop = &proc_fdinfo_file_operations; 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_set_d_op(dentry, &tid_fd_dentry_operations);
d_add(dentry, inode); d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */ /* Close the race of the process dying before we return the dentry */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment