diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 4 | ||||
-rw-r--r-- | fs/proc/base.c | 266 | ||||
-rw-r--r-- | fs/proc/generic.c | 13 | ||||
-rw-r--r-- | fs/proc/inode.c | 14 | ||||
-rw-r--r-- | fs/proc/internal.h | 2 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 10 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 7 | ||||
-rw-r--r-- | fs/proc/proc_tty.c | 3 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 17 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 7 |
10 files changed, 228 insertions, 115 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 07c9cdbcdcac..74f30e0c0381 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -410,9 +410,9 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) /* convert nsec -> ticks */ start_time = nsec_to_clock_t(start_time); - res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ + res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ -%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", +%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n", task->pid, tcomm, state, diff --git a/fs/proc/base.c b/fs/proc/base.c index ec158dd02b3a..3c41149dea88 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -61,9 +61,9 @@ #include <linux/namei.h> #include <linux/mnt_namespace.h> #include <linux/mm.h> -#include <linux/smp_lock.h> #include <linux/rcupdate.h> #include <linux/kallsyms.h> +#include <linux/module.h> #include <linux/mount.h> #include <linux/security.h> #include <linux/ptrace.h> @@ -90,8 +90,8 @@ #define PROC_NUMBUF 13 struct pid_entry { - int len; char *name; + int len; mode_t mode; const struct inode_operations *iop; const struct file_operations *fop; @@ -99,8 +99,8 @@ struct pid_entry { }; #define NOD(NAME, MODE, IOP, FOP, OP) { \ - .len = sizeof(NAME) - 1, \ .name = (NAME), \ + .len = sizeof(NAME) - 1, \ .mode = MODE, \ .iop = IOP, \ .fop = FOP, \ @@ -123,6 +123,9 @@ struct pid_entry { NULL, &proc_info_file_operations, \ { .proc_read = &proc_##OTYPE } ) +int maps_protect; +EXPORT_SYMBOL(maps_protect); + static struct fs_struct *get_fs_struct(struct task_struct *task) { struct fs_struct *fs; @@ -275,17 +278,15 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer) */ static int proc_pid_wchan(struct task_struct *task, char *buffer) { - char *modname; - const char *sym_name; - unsigned long wchan, size, offset; - char namebuf[KSYM_NAME_LEN+1]; + unsigned long wchan; + char symname[KSYM_NAME_LEN+1]; wchan = get_wchan(task); - sym_name = kallsyms_lookup(wchan, &size, &offset, &modname, namebuf); - if (sym_name) - return sprintf(buffer, "%s", sym_name); - return sprintf(buffer, "%lu", wchan); + if (lookup_symbol_name(wchan, symname) < 0) + return sprintf(buffer, "%lu", wchan); + else + return sprintf(buffer, "%s", symname); } #endif /* CONFIG_KALLSYMS */ @@ -310,7 +311,9 @@ static int proc_oom_score(struct task_struct *task, char *buffer) struct timespec uptime; do_posix_clock_monotonic_gettime(&uptime); + read_lock(&tasklist_lock); points = badness(task, uptime.tv_sec); + read_unlock(&tasklist_lock); return sprintf(buffer, "%lu\n", points); } @@ -344,11 +347,8 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr) return -EPERM; error = inode_change_ok(inode, attr); - if (!error) { - error = security_inode_setattr(dentry, attr); - if (!error) - error = inode_setattr(inode, attr); - } + if (!error) + error = inode_setattr(inode, attr); return error; } @@ -660,7 +660,6 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf, char buffer[PROC_NUMBUF]; size_t len; int oom_adjust; - loff_t __ppos = *ppos; if (!task) return -ESRCH; @@ -668,14 +667,8 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf, put_task_struct(task); len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); - if (__ppos >= len) - return 0; - if (count > len-__ppos) - count = len-__ppos; - if (copy_to_user(buf, buffer + __ppos, count)) - return -EFAULT; - *ppos = __ppos + count; - return count; + + return simple_read_from_buffer(buf, count, ppos, buffer, len); } static ssize_t oom_adjust_write(struct file *file, const char __user *buf, @@ -823,7 +816,6 @@ static ssize_t seccomp_read(struct file *file, char __user *buf, { struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); char __buf[20]; - loff_t __ppos = *ppos; size_t len; if (!tsk) @@ -831,14 +823,8 @@ static ssize_t seccomp_read(struct file *file, char __user *buf, /* no need to print the trailing zero, so use only len */ len = sprintf(__buf, "%u\n", tsk->seccomp.mode); put_task_struct(tsk); - if (__ppos >= len) - return 0; - if (count > len - __ppos) - count = len - __ppos; - if (copy_to_user(buf, __buf + __ppos, count)) - return -EFAULT; - *ppos = __ppos + count; - return count; + + return simple_read_from_buffer(buf, count, ppos, __buf, len); } static ssize_t seccomp_write(struct file *file, const char __user *buf, @@ -897,7 +883,6 @@ static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, char buffer[PROC_NUMBUF]; size_t len; int make_it_fail; - loff_t __ppos = *ppos; if (!task) return -ESRCH; @@ -905,14 +890,8 @@ static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, put_task_struct(task); len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail); - if (__ppos >= len) - return 0; - if (count > len-__ppos) - count = len-__ppos; - if (copy_to_user(buf, buffer + __ppos, count)) - return -EFAULT; - *ppos = __ppos + count; - return count; + + return simple_read_from_buffer(buf, count, ppos, buffer, len); } static ssize_t proc_fault_inject_write(struct file * file, @@ -975,7 +954,7 @@ static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, if (!tmp) return -ENOMEM; - + inode = dentry->d_inode; path = d_path(dentry, mnt, tmp, PAGE_SIZE); len = PTR_ERR(path); @@ -1155,7 +1134,8 @@ static struct dentry_operations pid_dentry_operations = /* Lookups */ -typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *); +typedef struct dentry *instantiate_t(struct inode *, struct dentry *, + struct task_struct *, const void *); /* * Fill a directory entry. @@ -1171,7 +1151,7 @@ typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct tas */ static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, char *name, int len, - instantiate_t instantiate, struct task_struct *task, void *ptr) + instantiate_t instantiate, struct task_struct *task, const void *ptr) { struct dentry *child, *dir = filp->f_path.dentry; struct inode *inode; @@ -1233,7 +1213,10 @@ out: return ~0U; } -static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) +#define PROC_FDINFO_MAX 64 + +static int proc_fd_info(struct inode *inode, struct dentry **dentry, + struct vfsmount **mnt, char *info) { struct task_struct *task = get_proc_task(inode); struct files_struct *files = NULL; @@ -1252,8 +1235,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (file) { - *mnt = mntget(file->f_path.mnt); - *dentry = dget(file->f_path.dentry); + if (mnt) + *mnt = mntget(file->f_path.mnt); + if (dentry) + *dentry = dget(file->f_path.dentry); + if (info) + snprintf(info, PROC_FDINFO_MAX, + "pos:\t%lli\n" + "flags:\t0%o\n", + (long long) file->f_pos, + file->f_flags); spin_unlock(&files->file_lock); put_files_struct(files); return 0; @@ -1264,6 +1255,12 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm return -ENOENT; } +static int proc_fd_link(struct inode *inode, struct dentry **dentry, + struct vfsmount **mnt) +{ + return proc_fd_info(inode, dentry, mnt, NULL); +} + static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; @@ -1306,9 +1303,9 @@ static struct dentry_operations tid_fd_dentry_operations = }; static struct dentry *proc_fd_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, void *ptr) + struct dentry *dentry, struct task_struct *task, const void *ptr) { - unsigned fd = *(unsigned *)ptr; + unsigned fd = *(const unsigned *)ptr; struct file *file; struct files_struct *files; struct inode *inode; @@ -1359,7 +1356,9 @@ out_iput: goto out; } -static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) +static struct dentry *proc_lookupfd_common(struct inode *dir, + struct dentry *dentry, + instantiate_t instantiate) { struct task_struct *task = get_proc_task(dir); unsigned fd = name_to_int(dentry); @@ -1370,23 +1369,15 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, if (fd == ~0U) goto out; - result = proc_fd_instantiate(dir, dentry, task, &fd); + result = instantiate(dir, dentry, task, &fd); out: put_task_struct(task); out_no_task: return result; } -static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - struct task_struct *task, int fd) -{ - char name[PROC_NUMBUF]; - int len = snprintf(name, sizeof(name), "%d", fd); - return proc_fill_cache(filp, dirent, filldir, name, len, - proc_fd_instantiate, task, &fd); -} - -static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) +static int proc_readfd_common(struct file * filp, void * dirent, + filldir_t filldir, instantiate_t instantiate) { struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; @@ -1422,12 +1413,17 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) for (fd = filp->f_pos-2; fd < fdt->max_fds; fd++, filp->f_pos++) { + char name[PROC_NUMBUF]; + int len; if (!fcheck_files(files, fd)) continue; rcu_read_unlock(); - if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) { + len = snprintf(name, sizeof(name), "%d", fd); + if (proc_fill_cache(filp, dirent, filldir, + name, len, instantiate, + p, &fd) < 0) { rcu_read_lock(); break; } @@ -1442,23 +1438,119 @@ out_no_task: return retval; } +static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); +} + +static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir) +{ + return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate); +} + +static ssize_t proc_fdinfo_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + char tmp[PROC_FDINFO_MAX]; + int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, NULL, tmp); + if (!err) + err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp)); + return err; +} + +static const struct file_operations proc_fdinfo_file_operations = { + .open = nonseekable_open, + .read = proc_fdinfo_read, +}; + static const struct file_operations proc_fd_operations = { .read = generic_read_dir, .readdir = proc_readfd, }; /* + * /proc/pid/fd needs a special permission handler so that a process can still + * access /proc/self/fd after it has executed a setuid(). + */ +static int proc_fd_permission(struct inode *inode, int mask, + struct nameidata *nd) +{ + int rv; + + rv = generic_permission(inode, mask, NULL); + if (rv == 0) + return 0; + if (task_pid(current) == proc_pid(inode)) + rv = 0; + return rv; +} + +/* * proc directories can do almost nothing.. */ static const struct inode_operations proc_fd_inode_operations = { .lookup = proc_lookupfd, + .permission = proc_fd_permission, .setattr = proc_setattr, }; +static struct dentry *proc_fdinfo_instantiate(struct inode *dir, + struct dentry *dentry, struct task_struct *task, const void *ptr) +{ + unsigned fd = *(unsigned *)ptr; + struct inode *inode; + struct proc_inode *ei; + struct dentry *error = ERR_PTR(-ENOENT); + + inode = proc_pid_make_inode(dir->i_sb, task); + if (!inode) + goto out; + ei = PROC_I(inode); + ei->fd = fd; + inode->i_mode = S_IFREG | S_IRUSR; + inode->i_fop = &proc_fdinfo_file_operations; + dentry->d_op = &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, NULL)) + error = NULL; + + out: + return error; +} + +static struct dentry *proc_lookupfdinfo(struct inode *dir, + struct dentry *dentry, + struct nameidata *nd) +{ + return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); +} + +static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir) +{ + return proc_readfd_common(filp, dirent, filldir, + proc_fdinfo_instantiate); +} + +static const struct file_operations proc_fdinfo_operations = { + .read = generic_read_dir, + .readdir = proc_readfdinfo, +}; + +/* + * proc directories can do almost nothing.. + */ +static const struct inode_operations proc_fdinfo_inode_operations = { + .lookup = proc_lookupfdinfo, + .setattr = proc_setattr, +}; + + static struct dentry *proc_pident_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, void *ptr) + struct dentry *dentry, struct task_struct *task, const void *ptr) { - struct pid_entry *p = ptr; + const struct pid_entry *p = ptr; struct inode *inode; struct proc_inode *ei; struct dentry *error = ERR_PTR(-EINVAL); @@ -1487,13 +1579,13 @@ out: static struct dentry *proc_pident_lookup(struct inode *dir, struct dentry *dentry, - struct pid_entry *ents, + const struct pid_entry *ents, unsigned int nents) { struct inode *inode; struct dentry *error; struct task_struct *task = get_proc_task(dir); - struct pid_entry *p, *last; + const struct pid_entry *p, *last; error = ERR_PTR(-ENOENT); inode = NULL; @@ -1522,8 +1614,8 @@ out_no_task: return error; } -static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - struct task_struct *task, struct pid_entry *p) +static int proc_pident_fill_cache(struct file *filp, void *dirent, + filldir_t filldir, struct task_struct *task, const struct pid_entry *p) { return proc_fill_cache(filp, dirent, filldir, p->name, p->len, proc_pident_instantiate, task, p); @@ -1531,14 +1623,14 @@ static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t fil static int proc_pident_readdir(struct file *filp, void *dirent, filldir_t filldir, - struct pid_entry *ents, unsigned int nents) + const struct pid_entry *ents, unsigned int nents) { int i; int pid; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct task_struct *task = get_proc_task(inode); - struct pid_entry *p, *last; + const struct pid_entry *p, *last; ino_t ino; int ret; @@ -1653,7 +1745,7 @@ static const struct file_operations proc_pid_attr_operations = { .write = proc_pid_attr_write, }; -static struct pid_entry attr_dir_stuff[] = { +static const struct pid_entry attr_dir_stuff[] = { REG("current", S_IRUGO|S_IWUGO, pid_attr), REG("prev", S_IRUGO, pid_attr), REG("exec", S_IRUGO|S_IWUGO, pid_attr), @@ -1719,7 +1811,7 @@ static const struct inode_operations proc_self_inode_operations = { * that properly belong to the /proc filesystem, as they describe * describe something that is process related. */ -static struct pid_entry proc_base_stuff[] = { +static const struct pid_entry proc_base_stuff[] = { NOD("self", S_IFLNK|S_IRWXUGO, &proc_self_inode_operations, NULL, {}), }; @@ -1748,9 +1840,9 @@ static struct dentry_operations proc_base_dentry_operations = }; static struct dentry *proc_base_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, void *ptr) + struct dentry *dentry, struct task_struct *task, const void *ptr) { - struct pid_entry *p = ptr; + const struct pid_entry *p = ptr; struct inode *inode; struct proc_inode *ei; struct dentry *error = ERR_PTR(-EINVAL); @@ -1798,7 +1890,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) { struct dentry *error; struct task_struct *task = get_proc_task(dir); - struct pid_entry *p, *last; + const struct pid_entry *p, *last; error = ERR_PTR(-ENOENT); @@ -1824,8 +1916,8 @@ out_no_task: return error; } -static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - struct task_struct *task, struct pid_entry *p) +static int proc_base_fill_cache(struct file *filp, void *dirent, + filldir_t filldir, struct task_struct *task, const struct pid_entry *p) { return proc_fill_cache(filp, dirent, filldir, p->name, p->len, proc_base_instantiate, task, p); @@ -1862,9 +1954,10 @@ static int proc_pid_io_accounting(struct task_struct *task, char *buffer) static const struct file_operations proc_task_operations; static const struct inode_operations proc_task_inode_operations; -static struct pid_entry tgid_base_stuff[] = { +static const struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, task), DIR("fd", S_IRUSR|S_IXUSR, fd), + DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), INF("environ", S_IRUSR, pid_environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), @@ -2005,7 +2098,7 @@ out: static struct dentry *proc_pid_instantiate(struct inode *dir, struct dentry * dentry, - struct task_struct *task, void *ptr) + struct task_struct *task, const void *ptr) { struct dentry *error = ERR_PTR(-ENOENT); struct inode *inode; @@ -2018,7 +2111,7 @@ static struct dentry *proc_pid_instantiate(struct inode *dir, inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; inode->i_flags|=S_IMMUTABLE; - inode->i_nlink = 4; + inode->i_nlink = 5; #ifdef CONFIG_SECURITY inode->i_nlink += 1; #endif @@ -2120,7 +2213,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) goto out_no_task; for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { - struct pid_entry *p = &proc_base_stuff[nr]; + const struct pid_entry *p = &proc_base_stuff[nr]; if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) goto out; } @@ -2146,8 +2239,9 @@ out_no_task: /* * Tasks */ -static struct pid_entry tid_base_stuff[] = { +static const struct pid_entry tid_base_stuff[] = { DIR("fd", S_IRUSR|S_IXUSR, fd), + DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), INF("environ", S_IRUSR, pid_environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), @@ -2216,7 +2310,7 @@ static const struct inode_operations proc_tid_base_inode_operations = { }; static struct dentry *proc_task_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, void *ptr) + struct dentry *dentry, struct task_struct *task, const void *ptr) { struct dentry *error = ERR_PTR(-ENOENT); struct inode *inode; @@ -2228,7 +2322,7 @@ static struct dentry *proc_task_instantiate(struct inode *dir, inode->i_op = &proc_tid_base_inode_operations; inode->i_fop = &proc_tid_base_operations; inode->i_flags|=S_IMMUTABLE; - inode->i_nlink = 3; + inode->i_nlink = 4; #ifdef CONFIG_SECURITY inode->i_nlink += 1; #endif diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 775fb21294d8..8a40e15f5ecb 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -398,6 +398,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { unsigned int ino = de->low_ino; + de_get(de); spin_unlock(&proc_subdir_lock); error = -EINVAL; inode = proc_get_inode(dir->i_sb, ino, de); @@ -414,6 +415,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam d_add(dentry, inode); return NULL; } + de_put(de); return ERR_PTR(error); } @@ -476,14 +478,21 @@ int proc_readdir(struct file * filp, } do { + struct proc_dir_entry *next; + /* filldir passes info to user space */ + de_get(de); spin_unlock(&proc_subdir_lock); if (filldir(dirent, de->name, de->namelen, filp->f_pos, - de->low_ino, de->mode >> 12) < 0) + de->low_ino, de->mode >> 12) < 0) { + de_put(de); goto out; + } spin_lock(&proc_subdir_lock); filp->f_pos++; - de = de->next; + next = de->next; + de_put(de); + de = next; } while (de); spin_unlock(&proc_subdir_lock); } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 22b1158389ae..b8171907c83b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -21,7 +21,7 @@ #include "internal.h" -static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de) +struct proc_dir_entry *de_get(struct proc_dir_entry *de) { if (de) atomic_inc(&de->count); @@ -31,7 +31,7 @@ static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de) /* * Decrements the use count and checks for deferred deletion. */ -static void de_put(struct proc_dir_entry *de) +void de_put(struct proc_dir_entry *de) { if (de) { lock_kernel(); @@ -146,13 +146,6 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, { struct inode * inode; - /* - * Increment the use count so the dir entry can't disappear. - */ - de_get(de); - - WARN_ON(de && de->deleted); - if (de != NULL && !try_module_get(de->owner)) goto out_mod; @@ -184,7 +177,6 @@ out_ino: if (de != NULL) module_put(de->owner); out_mod: - de_put(de); return NULL; } @@ -199,6 +191,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent) s->s_op = &proc_sops; s->s_time_gran = 1; + de_get(&proc_root); root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; @@ -212,6 +205,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent) out_no_root: printk("proc_read_super: get root inode failed\n"); iput(root_inode); + de_put(&proc_root); return -ENOMEM; } MODULE_LICENSE("GPL"); diff --git a/fs/proc/internal.h b/fs/proc/internal.h index f771889183c3..b215c3524fa6 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -37,6 +37,8 @@ do { \ extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); #endif +extern int maps_protect; + extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); extern int proc_tid_stat(struct task_struct *, char *); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 75ec6523d29a..5fd49e47f83a 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -35,7 +35,6 @@ #include <linux/signal.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/seq_file.h> #include <linux/times.h> #include <linux/profile.h> @@ -429,18 +428,11 @@ static int slabstats_open(struct inode *inode, struct file *file) return ret; } -static int slabstats_release(struct inode *inode, struct file *file) -{ - struct seq_file *m = file->private_data; - kfree(m->private); - return seq_release(inode, file); -} - static const struct file_operations proc_slabstats_operations = { .open = slabstats_open, .read = seq_read, .llseek = seq_lseek, - .release = slabstats_release, + .release = seq_release_private, }; #endif #endif diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 20e8cbb34364..680c429bfa22 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -429,11 +429,8 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) return -EPERM; error = inode_change_ok(inode, attr); - if (!error) { - error = security_inode_setattr(dentry, attr); - if (!error) - error = inode_setattr(inode, attr); - } + if (!error) + error = inode_setattr(inode, attr); return error; } diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index c1bbfbeb035e..b3a473b0a191 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -108,6 +108,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) { struct list_head *p; loff_t l = *pos; + + mutex_lock(&tty_mutex); list_for_each(p, &tty_drivers) if (!l--) return list_entry(p, struct tty_driver, tty_drivers); @@ -124,6 +126,7 @@ static void *t_next(struct seq_file *m, void *v, loff_t *pos) static void t_stop(struct seq_file *m, void *v) { + mutex_unlock(&tty_mutex); } static struct seq_operations tty_drivers_op = { diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 4008c060f7ef..c24d81a5a040 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -3,6 +3,7 @@ #include <linux/mount.h> #include <linux/seq_file.h> #include <linux/highmem.h> +#include <linux/ptrace.h> #include <linux/pagemap.h> #include <linux/mempolicy.h> @@ -142,6 +143,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats dev_t dev = 0; int len; + if (maps_protect && !ptrace_may_attach(task)) + return -EACCES; + if (file) { struct inode *inode = vma->vm_file->f_path.dentry->d_inode; dev = inode->i_sb->s_dev; @@ -512,11 +516,22 @@ const struct file_operations proc_maps_operations = { #ifdef CONFIG_NUMA extern int show_numa_map(struct seq_file *m, void *v); +static int show_numa_map_checked(struct seq_file *m, void *v) +{ + struct proc_maps_private *priv = m->private; + struct task_struct *task = priv->task; + + if (maps_protect && !ptrace_may_attach(task)) + return -EACCES; + + return show_numa_map(m, v); +} + static struct seq_operations proc_pid_numa_maps_op = { .start = m_start, .next = m_next, .stop = m_stop, - .show = show_numa_map + .show = show_numa_map_checked }; static int numa_maps_open(struct inode *inode, struct file *file) diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 7cddf6b8635a..d8b8c7183c24 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -2,6 +2,7 @@ #include <linux/mm.h> #include <linux/file.h> #include <linux/mount.h> +#include <linux/ptrace.h> #include <linux/seq_file.h> #include "internal.h" @@ -143,6 +144,12 @@ out: static int show_map(struct seq_file *m, void *_vml) { struct vm_list_struct *vml = _vml; + struct proc_maps_private *priv = m->private; + struct task_struct *task = priv->task; + + if (maps_protect && !ptrace_may_attach(task)) + return -EACCES; + return nommu_vma_show(m, vml->vma); } |