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:
parent
19e0bafc36
commit
5e442a493f
1 changed files with 41 additions and 101 deletions
142
fs/proc/base.c
142
fs/proc/base.c
|
@ -1652,46 +1652,12 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
|
|||
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 @@ static unsigned name_to_int(struct dentry *dentry)
|
|||
|
||||
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 */
|
||||
|
|
Loading…
Reference in a new issue