Merge branch 'for_paulus' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc
[pandora-kernel.git] / fs / proc / base.c
index f0db7f6..6ba7785 100644 (file)
@@ -132,6 +132,7 @@ enum pid_directory_inos {
        PROC_TGID_ATTR_EXEC,
        PROC_TGID_ATTR_FSCREATE,
        PROC_TGID_ATTR_KEYCREATE,
+       PROC_TGID_ATTR_SOCKCREATE,
 #endif
 #ifdef CONFIG_AUDITSYSCALL
        PROC_TGID_LOGINUID,
@@ -174,6 +175,7 @@ enum pid_directory_inos {
        PROC_TID_ATTR_EXEC,
        PROC_TID_ATTR_FSCREATE,
        PROC_TID_ATTR_KEYCREATE,
+       PROC_TID_ATTR_SOCKCREATE,
 #endif
 #ifdef CONFIG_AUDITSYSCALL
        PROC_TID_LOGINUID,
@@ -291,6 +293,7 @@ static struct pid_entry tgid_attr_stuff[] = {
        E(PROC_TGID_ATTR_EXEC,     "exec",     S_IFREG|S_IRUGO|S_IWUGO),
        E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
        E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
+       E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
        {0,0,NULL,0}
 };
 static struct pid_entry tid_attr_stuff[] = {
@@ -299,6 +302,7 @@ static struct pid_entry tid_attr_stuff[] = {
        E(PROC_TID_ATTR_EXEC,      "exec",     S_IFREG|S_IRUGO|S_IWUGO),
        E(PROC_TID_ATTR_FSCREATE,  "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
        E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
+       E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
        {0,0,NULL,0}
 };
 #endif
@@ -532,42 +536,20 @@ static int proc_oom_score(struct task_struct *task, char *buffer)
 /************************************************************************/
 
 /* permission checks */
-
-/* If the process being read is separated by chroot from the reading process,
- * don't let the reader access the threads.
- */
-static int proc_check_chroot(struct dentry *de, struct vfsmount *mnt)
+static int proc_fd_access_allowed(struct inode *inode)
 {
-       struct dentry *base;
-       struct vfsmount *our_vfsmnt;
-       int res = 0;
-
-       read_lock(&current->fs->lock);
-       our_vfsmnt = mntget(current->fs->rootmnt);
-       base = dget(current->fs->root);
-       read_unlock(&current->fs->lock);
-
-       spin_lock(&vfsmount_lock);
-
-       while (mnt != our_vfsmnt) {
-               if (mnt == mnt->mnt_parent)
-                       goto out;
-               de = mnt->mnt_mountpoint;
-               mnt = mnt->mnt_parent;
+       struct task_struct *task;
+       int allowed = 0;
+       /* Allow access to a task's file descriptors if it is us or we
+        * may use ptrace attach to the process and find out that
+        * information.
+        */
+       task = get_proc_task(inode);
+       if (task) {
+               allowed = ptrace_may_attach(task);
+               put_task_struct(task);
        }
-
-       if (!is_subdir(de, base))
-               goto out;
-       spin_unlock(&vfsmount_lock);
-
-exit:
-       dput(base);
-       mntput(our_vfsmnt);
-       return res;
-out:
-       spin_unlock(&vfsmount_lock);
-       res = -EACCES;
-       goto exit;
+       return allowed;
 }
 
 extern struct seq_operations mounts_op;
@@ -1062,52 +1044,6 @@ static struct file_operations proc_seccomp_operations = {
 };
 #endif /* CONFIG_SECCOMP */
 
-static int proc_check_dentry_visible(struct inode *inode,
-       struct dentry *dentry, struct vfsmount *mnt)
-{
-       /* Verify that the current process can already see the
-        * file pointed at by the file descriptor.
-        * This prevents /proc from being an accidental information leak.
-        *
-        * This prevents access to files that are not visible do to
-        * being on the otherside of a chroot, in a different
-        * namespace, or are simply process local (like pipes).
-        */
-       struct task_struct *task;
-       int error = -EACCES;
-
-       /* See if the the two tasks share a commone set of
-        * file descriptors.  If so everything is visible.
-        */
-       rcu_read_lock();
-       task = tref_task(proc_tref(inode));
-       if (task) {
-               struct files_struct *task_files, *files;
-               /* This test answeres the question:
-                * Is there a point in time since we looked up the
-                * file descriptor where the two tasks share the
-                * same files struct?
-                */
-               rmb();
-               files = current->files;
-               task_files = task->files;
-               if (files && (files == task_files))
-                       error = 0;
-       }
-       rcu_read_unlock();
-       if (!error)
-               goto out;
-
-       /* If the two tasks don't share a common set of file
-        * descriptors see if the destination dentry is already
-        * visible in the current tasks filesystem namespace.
-        */
-       error = proc_check_chroot(dentry, mnt);
-out:
-       return error;
-
-}
-
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
@@ -1116,18 +1052,12 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
        /* We don't need a base pointer in the /proc filesystem */
        path_release(nd);
 
-       if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
+       /* Are we allowed to snoop on the tasks file descriptors? */
+       if (!proc_fd_access_allowed(inode))
                goto out;
 
        error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
        nd->last_type = LAST_BIND;
-       if (error)
-               goto out;
-
-       /* Only return files this task can already see */
-       error = proc_check_dentry_visible(inode, nd->dentry, nd->mnt);
-       if (error)
-               path_release(nd);
 out:
        return ERR_PTR(error);
 }
@@ -1165,21 +1095,15 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
        struct dentry *de;
        struct vfsmount *mnt = NULL;
 
-
-       if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
+       /* Are we allowed to snoop on the tasks file descriptors? */
+       if (!proc_fd_access_allowed(inode))
                goto out;
 
        error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt);
        if (error)
                goto out;
 
-       /* Only return files this task can already see */
-       error = proc_check_dentry_visible(inode, de, mnt);
-       if (error)
-               goto out_put;
-
        error = do_proc_readlink(de, mnt, buffer, buflen);
-out_put:
        dput(de);
        mntput(mnt);
 out:
@@ -1844,6 +1768,8 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                case PROC_TGID_ATTR_FSCREATE:
                case PROC_TID_ATTR_KEYCREATE:
                case PROC_TGID_ATTR_KEYCREATE:
+               case PROC_TID_ATTR_SOCKCREATE:
+               case PROC_TGID_ATTR_SOCKCREATE:
                        inode->i_fop = &proc_pid_attr_operations;
                        break;
 #endif
@@ -2304,41 +2230,38 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
  * In the case of a seek we start with the leader and walk nr
  * threads past it.
  */
-static struct task_struct *first_tid(struct task_struct *leader, int tid, int nr)
+static struct task_struct *first_tid(struct task_struct *leader,
+                                       int tid, int nr)
 {
-       struct task_struct *pos = NULL;
-       read_lock(&tasklist_lock);
+       struct task_struct *pos;
 
+       rcu_read_lock();
        /* Attempt to start with the pid of a thread */
        if (tid && (nr > 0)) {
                pos = find_task_by_pid(tid);
-               if (pos && (pos->group_leader != leader))
-                       pos = NULL;
-               if (pos)
-                       nr = 0;
+               if (pos && (pos->group_leader == leader))
+                       goto found;
        }
 
        /* If nr exceeds the number of threads there is nothing todo */
-       if (nr) {
-               if (nr >= get_nr_threads(leader))
-                       goto done;
-       }
+       pos = NULL;
+       if (nr && nr >= get_nr_threads(leader))
+               goto out;
 
-       /* If we haven't found our starting place yet start with the
-        * leader and walk nr threads forward.
+       /* If we haven't found our starting place yet start
+        * with the leader and walk nr threads forward.
         */
-       if (!pos && (nr >= 0))
-               pos = leader;
-
-       for (; pos && pid_alive(pos); pos = next_thread(pos)) {
-               if (--nr > 0)
-                       continue;
-               get_task_struct(pos);
-               goto done;
+       for (pos = leader; nr > 0; --nr) {
+               pos = next_thread(pos);
+               if (pos == leader) {
+                       pos = NULL;
+                       goto out;
+               }
        }
-       pos = NULL;
-done:
-       read_unlock(&tasklist_lock);
+found:
+       get_task_struct(pos);
+out:
+       rcu_read_unlock();
        return pos;
 }
 
@@ -2350,16 +2273,16 @@ done:
  */
 static struct task_struct *next_tid(struct task_struct *start)
 {
-       struct task_struct *pos;
-       read_lock(&tasklist_lock);
-       pos = start;
-       if (pid_alive(start))
+       struct task_struct *pos = NULL;
+       rcu_read_lock();
+       if (pid_alive(start)) {
                pos = next_thread(start);
-       if (pid_alive(pos) && (pos != start->group_leader))
-               get_task_struct(pos);
-       else
-               pos = NULL;
-       read_unlock(&tasklist_lock);
+               if (thread_group_leader(pos))
+                       pos = NULL;
+               else
+                       get_task_struct(pos);
+       }
+       rcu_read_unlock();
        put_task_struct(start);
        return pos;
 }