diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/fd.c | 81 |
1 files changed, 44 insertions, 37 deletions
diff --git a/fs/proc/fd.c b/fs/proc/fd.c index d38845ecc408..f5de22a9e9e0 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -98,12 +98,27 @@ static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) return !!file; } +static void tid_fd_update_inode(struct task_struct *task, struct inode *inode, + fmode_t f_mode) +{ + task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); + + if (S_ISLNK(inode->i_mode)) { + unsigned i_mode = S_IFLNK; + if (f_mode & FMODE_READ) + i_mode |= S_IRUSR | S_IXUSR; + if (f_mode & FMODE_WRITE) + i_mode |= S_IWUSR | S_IXUSR; + inode->i_mode = i_mode; + } + security_task_to_inode(task, inode); +} + static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) { struct task_struct *task; struct inode *inode; unsigned int fd; - fmode_t f_mode; if (flags & LOOKUP_RCU) return -ECHILD; @@ -113,18 +128,9 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) fd = proc_fd(inode); if (task) { + fmode_t f_mode; if (tid_fd_mode(task, fd, &f_mode)) { - task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); - - if (S_ISLNK(inode->i_mode)) { - unsigned i_mode = S_IFLNK; - if (f_mode & FMODE_READ) - i_mode |= S_IRUSR | S_IXUSR; - if (f_mode & FMODE_WRITE) - i_mode |= S_IWUSR | S_IXUSR; - inode->i_mode = i_mode; - } - security_task_to_inode(task, inode); + tid_fd_update_inode(task, inode, f_mode); put_task_struct(task); return 1; } @@ -168,34 +174,35 @@ static int proc_fd_link(struct dentry *dentry, struct path *path) return ret; } +struct fd_data { + fmode_t mode; + unsigned fd; +}; + static int proc_fd_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { - unsigned fd = (unsigned long)ptr; + const struct fd_data *data = ptr; struct proc_inode *ei; struct inode *inode; inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK); if (!inode) - goto out; + return -ENOENT; ei = PROC_I(inode); - ei->fd = fd; + ei->fd = data->fd; inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; ei->op.proc_get_link = proc_fd_link; + tid_fd_update_inode(task, inode, data->mode); 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 */ - if (tid_fd_revalidate(dentry, 0)) - return 0; - out: - return -ENOENT; + return 0; } static struct dentry *proc_lookupfd_common(struct inode *dir, @@ -204,17 +211,16 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, { struct task_struct *task = get_proc_task(dir); int result = -ENOENT; - unsigned fd = name_to_int(&dentry->d_name); - fmode_t f_mode; + struct fd_data data = {.fd = name_to_int(&dentry->d_name)}; if (!task) goto out_no_task; - if (fd == ~0U) + if (data.fd == ~0U) goto out; - if (!tid_fd_mode(task, fd, &f_mode)) + if (!tid_fd_mode(task, data.fd, &data.mode)) goto out; - result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); + result = instantiate(dir, dentry, task, &data); out: put_task_struct(task); out_no_task: @@ -241,17 +247,22 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx, for (fd = ctx->pos - 2; fd < files_fdtable(files)->max_fds; fd++, ctx->pos++) { + struct file *f; + struct fd_data data; char name[10 + 1]; int len; - if (!fcheck_files(files, fd)) + f = fcheck_files(files, fd); + if (!f) continue; + data.mode = f->f_mode; rcu_read_unlock(); + data.fd = fd; len = snprintf(name, sizeof(name), "%u", fd); if (!proc_fill_cache(file, ctx, name, len, instantiate, p, - (void *)(unsigned long)fd)) + &data)) goto out_fd_loop; cond_resched(); rcu_read_lock(); @@ -313,27 +324,23 @@ static int proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { - unsigned fd = (unsigned long)ptr; + const struct fd_data *data = ptr; struct proc_inode *ei; struct inode *inode; inode = proc_pid_make_inode(dir->i_sb, task, S_IFREG | S_IRUSR); if (!inode) - goto out; + return -ENOENT; ei = PROC_I(inode); - ei->fd = fd; + ei->fd = data->fd; inode->i_fop = &proc_fdinfo_file_operations; + tid_fd_update_inode(task, inode, 0); 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 */ - if (tid_fd_revalidate(dentry, 0)) - return 0; - out: - return -ENOENT; + return 0; } static struct dentry * |