]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/proc/base.c
procfs task exe symlink
[net-next-2.6.git] / fs / proc / base.c
index 770de444eba0b1cea185284f9b2f1760c7ddab30..b48ddb1199459530560a35cfeda4271cda3698b2 100644 (file)
@@ -502,17 +502,14 @@ static const struct inode_operations proc_def_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-extern const struct seq_operations mounts_op;
-struct proc_mounts {
-       struct seq_file m;
-       int event;
-};
-
-static int mounts_open(struct inode *inode, struct file *file)
+static int mounts_open_common(struct inode *inode, struct file *file,
+                             const struct seq_operations *op)
 {
        struct task_struct *task = get_proc_task(inode);
        struct nsproxy *nsp;
        struct mnt_namespace *ns = NULL;
+       struct fs_struct *fs = NULL;
+       struct path root;
        struct proc_mounts *p;
        int ret = -EINVAL;
 
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file)
                                get_mnt_ns(ns);
                }
                rcu_read_unlock();
-
+               if (ns)
+                       fs = get_fs_struct(task);
                put_task_struct(task);
        }
 
-       if (ns) {
-               ret = -ENOMEM;
-               p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
-               if (p) {
-                       file->private_data = &p->m;
-                       ret = seq_open(file, &mounts_op);
-                       if (!ret) {
-                               p->m.private = ns;
-                               p->event = ns->event;
-                               return 0;
-                       }
-                       kfree(p);
-               }
-               put_mnt_ns(ns);
-       }
+       if (!ns)
+               goto err;
+       if (!fs)
+               goto err_put_ns;
+
+       read_lock(&fs->lock);
+       root = fs->root;
+       path_get(&root);
+       read_unlock(&fs->lock);
+       put_fs_struct(fs);
+
+       ret = -ENOMEM;
+       p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
+       if (!p)
+               goto err_put_path;
+
+       file->private_data = &p->m;
+       ret = seq_open(file, op);
+       if (ret)
+               goto err_free;
+
+       p->m.private = p;
+       p->ns = ns;
+       p->root = root;
+       p->event = ns->event;
+
+       return 0;
+
+ err_free:
+       kfree(p);
+ err_put_path:
+       path_put(&root);
+ err_put_ns:
+       put_mnt_ns(ns);
+ err:
        return ret;
 }
 
 static int mounts_release(struct inode *inode, struct file *file)
 {
-       struct seq_file *m = file->private_data;
-       struct mnt_namespace *ns = m->private;
-       put_mnt_ns(ns);
+       struct proc_mounts *p = file->private_data;
+       path_put(&p->root);
+       put_mnt_ns(p->ns);
        return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
        struct proc_mounts *p = file->private_data;
-       struct mnt_namespace *ns = p->m.private;
+       struct mnt_namespace *ns = p->ns;
        unsigned res = 0;
 
        poll_wait(file, &ns->poll, wait);
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
        return res;
 }
 
+static int mounts_open(struct inode *inode, struct file *file)
+{
+       return mounts_open_common(inode, file, &mounts_op);
+}
+
 static const struct file_operations proc_mounts_operations = {
        .open           = mounts_open,
        .read           = seq_read,
@@ -581,38 +604,22 @@ static const struct file_operations proc_mounts_operations = {
        .poll           = mounts_poll,
 };
 
-extern const struct seq_operations mountstats_op;
-static int mountstats_open(struct inode *inode, struct file *file)
+static int mountinfo_open(struct inode *inode, struct file *file)
 {
-       int ret = seq_open(file, &mountstats_op);
-
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               struct nsproxy *nsp;
-               struct mnt_namespace *mnt_ns = NULL;
-               struct task_struct *task = get_proc_task(inode);
-
-               if (task) {
-                       rcu_read_lock();
-                       nsp = task_nsproxy(task);
-                       if (nsp) {
-                               mnt_ns = nsp->mnt_ns;
-                               if (mnt_ns)
-                                       get_mnt_ns(mnt_ns);
-                       }
-                       rcu_read_unlock();
+       return mounts_open_common(inode, file, &mountinfo_op);
+}
 
-                       put_task_struct(task);
-               }
+static const struct file_operations proc_mountinfo_operations = {
+       .open           = mountinfo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = mounts_release,
+       .poll           = mounts_poll,
+};
 
-               if (mnt_ns)
-                       m->private = mnt_ns;
-               else {
-                       seq_release(inode, file);
-                       ret = -EINVAL;
-               }
-       }
-       return ret;
+static int mountstats_open(struct inode *inode, struct file *file)
+{
+       return mounts_open_common(inode, file, &mountstats_op);
 }
 
 static const struct file_operations proc_mountstats_operations = {
@@ -1036,6 +1043,26 @@ static const struct file_operations proc_loginuid_operations = {
        .read           = proc_loginuid_read,
        .write          = proc_loginuid_write,
 };
+
+static ssize_t proc_sessionid_read(struct file * file, char __user * buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct inode * inode = file->f_path.dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       ssize_t length;
+       char tmpbuf[TMPBUFLEN];
+
+       if (!task)
+               return -ESRCH;
+       length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
+                               audit_get_sessionid(task));
+       put_task_struct(task);
+       return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+}
+
+static const struct file_operations proc_sessionid_operations = {
+       .read           = proc_sessionid_read,
+};
 #endif
 
 #ifdef CONFIG_FAULT_INJECTION
@@ -1154,6 +1181,81 @@ static const struct file_operations proc_pid_sched_operations = {
 
 #endif
 
+/*
+ * We added or removed a vma mapping the executable. The vmas are only mapped
+ * during exec and are not mapped with the mmap system call.
+ * Callers must hold down_write() on the mm's mmap_sem for these
+ */
+void added_exe_file_vma(struct mm_struct *mm)
+{
+       mm->num_exe_file_vmas++;
+}
+
+void removed_exe_file_vma(struct mm_struct *mm)
+{
+       mm->num_exe_file_vmas--;
+       if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
+               fput(mm->exe_file);
+               mm->exe_file = NULL;
+       }
+
+}
+
+void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
+{
+       if (new_exe_file)
+               get_file(new_exe_file);
+       if (mm->exe_file)
+               fput(mm->exe_file);
+       mm->exe_file = new_exe_file;
+       mm->num_exe_file_vmas = 0;
+}
+
+struct file *get_mm_exe_file(struct mm_struct *mm)
+{
+       struct file *exe_file;
+
+       /* We need mmap_sem to protect against races with removal of
+        * VM_EXECUTABLE vmas */
+       down_read(&mm->mmap_sem);
+       exe_file = mm->exe_file;
+       if (exe_file)
+               get_file(exe_file);
+       up_read(&mm->mmap_sem);
+       return exe_file;
+}
+
+void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
+{
+       /* It's safe to write the exe_file pointer without exe_file_lock because
+        * this is called during fork when the task is not yet in /proc */
+       newmm->exe_file = get_mm_exe_file(oldmm);
+}
+
+static int proc_exe_link(struct inode *inode, struct path *exe_path)
+{
+       struct task_struct *task;
+       struct mm_struct *mm;
+       struct file *exe_file;
+
+       task = get_proc_task(inode);
+       if (!task)
+               return -ENOENT;
+       mm = get_task_mm(task);
+       put_task_struct(task);
+       if (!mm)
+               return -ENOENT;
+       exe_file = get_mm_exe_file(mm);
+       mmput(mm);
+       if (exe_file) {
+               *exe_path = exe_file->f_path;
+               path_get(&exe_file->f_path);
+               fput(exe_file);
+               return 0;
+       } else
+               return -ENOENT;
+}
+
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
@@ -1606,7 +1708,6 @@ static int proc_readfd_common(struct file * filp, void * dirent,
        unsigned int fd, ino;
        int retval;
        struct files_struct * files;
-       struct fdtable *fdt;
 
        retval = -ENOENT;
        if (!p)
@@ -1629,9 +1730,8 @@ static int proc_readfd_common(struct file * filp, void * dirent,
                        if (!files)
                                goto out;
                        rcu_read_lock();
-                       fdt = files_fdtable(files);
                        for (fd = filp->f_pos-2;
-                            fd < fdt->max_fds;
+                            fd < files_fdtable(files)->max_fds;
                             fd++, filp->f_pos++) {
                                char name[PROC_NUMBUF];
                                int len;
@@ -2291,6 +2391,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        LNK("root",       root),
        LNK("exe",        exe),
        REG("mounts",     S_IRUGO, mounts),
+       REG("mountinfo",  S_IRUGO, mountinfo),
        REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
@@ -2319,6 +2420,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        REG("oom_adj",    S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
        REG("loginuid",   S_IWUSR|S_IRUGO, loginuid),
+       REG("sessionid",  S_IRUSR, sessionid),
 #endif
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
@@ -2622,6 +2724,7 @@ static const struct pid_entry tid_base_stuff[] = {
        LNK("root",      root),
        LNK("exe",       exe),
        REG("mounts",    S_IRUGO, mounts),
+       REG("mountinfo",  S_IRUGO, mountinfo),
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",     S_IRUGO, smaps),
@@ -2649,6 +2752,7 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("oom_adj",   S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
        REG("loginuid",  S_IWUSR|S_IRUGO, loginuid),
+       REG("sessionid",  S_IRUSR, sessionid),
 #endif
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),