Merge branch 'for_paulus' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc
[pandora-kernel.git] / fs / proc / base.c
index cc578a3..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,
@@ -185,6 +187,9 @@ enum pid_directory_inos {
        PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
 };
 
+/* Worst case buffer size needed for holding an integer. */
+#define PROC_NUMBUF 10
+
 struct pid_entry {
        int type;
        int len;
@@ -288,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[] = {
@@ -296,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
@@ -304,12 +311,15 @@ static struct pid_entry tid_attr_stuff[] = {
 
 static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct task_struct *task = proc_task(inode);
-       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);
 
-       files = get_files_struct(task);
+       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
@@ -341,10 +351,29 @@ static struct fs_struct *get_fs_struct(struct task_struct *task)
        return fs;
 }
 
+static int get_nr_threads(struct task_struct *tsk)
+{
+       /* Must be called with the rcu_read_lock held */
+       unsigned long flags;
+       int count = 0;
+
+       if (lock_task_sighand(tsk, &flags)) {
+               count = atomic_read(&tsk->signal->count);
+               unlock_task_sighand(tsk, &flags);
+       }
+       return count;
+}
+
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct fs_struct *fs = get_fs_struct(proc_task(inode));
+       struct task_struct *task = get_proc_task(inode);
+       struct fs_struct *fs = NULL;
        int result = -ENOENT;
+
+       if (task) {
+               fs = get_fs_struct(task);
+               put_task_struct(task);
+       }
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->pwdmnt);
@@ -358,8 +387,14 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
 
 static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct fs_struct *fs = get_fs_struct(proc_task(inode));
+       struct task_struct *task = get_proc_task(inode);
+       struct fs_struct *fs = NULL;
        int result = -ENOENT;
+
+       if (task) {
+               fs = get_fs_struct(task);
+               put_task_struct(task);
+       }
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->rootmnt);
@@ -501,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;
@@ -547,16 +560,19 @@ struct proc_mounts {
 
 static int mounts_open(struct inode *inode, struct file *file)
 {
-       struct task_struct *task = proc_task(inode);
-       struct namespace *namespace;
+       struct task_struct *task = get_proc_task(inode);
+       struct namespace *namespace = NULL;
        struct proc_mounts *p;
        int ret = -EINVAL;
 
-       task_lock(task);
-       namespace = task->namespace;
-       if (namespace)
-               get_namespace(namespace);
-       task_unlock(task);
+       if (task) {
+               task_lock(task);
+               namespace = task->namespace;
+               if (namespace)
+                       get_namespace(namespace);
+               task_unlock(task);
+               put_task_struct(task);
+       }
 
        if (namespace) {
                ret = -ENOMEM;
@@ -613,17 +629,21 @@ static struct file_operations proc_mounts_operations = {
 extern struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-       struct task_struct *task = proc_task(inode);
        int ret = seq_open(file, &mountstats_op);
 
        if (!ret) {
                struct seq_file *m = file->private_data;
-               struct namespace *namespace;
-               task_lock(task);
-               namespace = task->namespace;
-               if (namespace)
-                       get_namespace(namespace);
-               task_unlock(task);
+               struct namespace *namespace = NULL;
+               struct task_struct *task = get_proc_task(inode);
+
+               if (task) {
+                       task_lock(task);
+                       namespace = task->namespace;
+                       if (namespace)
+                               get_namespace(namespace);
+                       task_unlock(task);
+                       put_task_struct(task);
+               }
 
                if (namespace)
                        m->private = namespace;
@@ -650,18 +670,27 @@ static ssize_t proc_info_read(struct file * file, char __user * buf,
        struct inode * inode = file->f_dentry->d_inode;
        unsigned long page;
        ssize_t length;
-       struct task_struct *task = proc_task(inode);
+       struct task_struct *task = get_proc_task(inode);
+
+       length = -ESRCH;
+       if (!task)
+               goto out_no_task;
 
        if (count > PROC_BLOCK_SIZE)
                count = PROC_BLOCK_SIZE;
+
+       length = -ENOMEM;
        if (!(page = __get_free_page(GFP_KERNEL)))
-               return -ENOMEM;
+               goto out;
 
        length = PROC_I(inode)->op.proc_read(task, (char*)page);
 
        if (length >= 0)
                length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
        free_page(page);
+out:
+       put_task_struct(task);
+out_no_task:
        return length;
 }
 
@@ -678,12 +707,15 @@ static int mem_open(struct inode* inode, struct file* file)
 static ssize_t mem_read(struct file * file, char __user * buf,
                        size_t count, loff_t *ppos)
 {
-       struct task_struct *task = proc_task(file->f_dentry->d_inode);
+       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
        char *page;
        unsigned long src = *ppos;
        int ret = -ESRCH;
        struct mm_struct *mm;
 
+       if (!task)
+               goto out_no_task;
+
        if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
                goto out;
 
@@ -733,6 +765,8 @@ out_put:
 out_free:
        free_page((unsigned long) page);
 out:
+       put_task_struct(task);
+out_no_task:
        return ret;
 }
 
@@ -745,15 +779,20 @@ static ssize_t mem_write(struct file * file, const char * buf,
 {
        int copied = 0;
        char *page;
-       struct task_struct *task = proc_task(file->f_dentry->d_inode);
+       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
        unsigned long dst = *ppos;
 
+       copied = -ESRCH;
+       if (!task)
+               goto out_no_task;
+
        if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
-               return -ESRCH;
+               goto out;
 
+       copied = -ENOMEM;
        page = (char *)__get_free_page(GFP_USER);
        if (!page)
-               return -ENOMEM;
+               goto out;
 
        while (count > 0) {
                int this_len, retval;
@@ -776,6 +815,9 @@ static ssize_t mem_write(struct file * file, const char * buf,
        }
        *ppos = dst;
        free_page((unsigned long) page);
+out:
+       put_task_struct(task);
+out_no_task:
        return copied;
 }
 #endif
@@ -806,13 +848,18 @@ static struct file_operations proc_mem_operations = {
 static ssize_t oom_adjust_read(struct file *file, char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct task_struct *task = proc_task(file->f_dentry->d_inode);
-       char buffer[8];
+       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+       char buffer[PROC_NUMBUF];
        size_t len;
-       int oom_adjust = task->oomkilladj;
+       int oom_adjust;
        loff_t __ppos = *ppos;
 
-       len = sprintf(buffer, "%i\n", oom_adjust);
+       if (!task)
+               return -ESRCH;
+       oom_adjust = task->oomkilladj;
+       put_task_struct(task);
+
+       len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
        if (__ppos >= len)
                return 0;
        if (count > len-__ppos)
@@ -826,15 +873,15 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
 static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct task_struct *task = proc_task(file->f_dentry->d_inode);
-       char buffer[8], *end;
+       struct task_struct *task;
+       char buffer[PROC_NUMBUF], *end;
        int oom_adjust;
 
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
-       memset(buffer, 0, 8);
-       if (count > 6)
-               count = 6;
+       memset(buffer, 0, sizeof(buffer));
+       if (count > sizeof(buffer) - 1)
+               count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
        oom_adjust = simple_strtol(buffer, &end, 0);
@@ -842,7 +889,11 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
                return -EINVAL;
        if (*end == '\n')
                end++;
+       task = get_proc_task(file->f_dentry->d_inode);
+       if (!task)
+               return -ESRCH;
        task->oomkilladj = oom_adjust;
+       put_task_struct(task);
        if (end - buffer == 0)
                return -EIO;
        return end - buffer;
@@ -859,12 +910,15 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
                                  size_t count, loff_t *ppos)
 {
        struct inode * inode = file->f_dentry->d_inode;
-       struct task_struct *task = proc_task(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_loginuid(task->audit_context));
+       put_task_struct(task);
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
@@ -874,13 +928,12 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
        struct inode * inode = file->f_dentry->d_inode;
        char *page, *tmp;
        ssize_t length;
-       struct task_struct *task = proc_task(inode);
        uid_t loginuid;
 
        if (!capable(CAP_AUDIT_CONTROL))
                return -EPERM;
 
-       if (current != task)
+       if (current != pid_task(proc_pid(inode), PIDTYPE_PID))
                return -EPERM;
 
        if (count >= PAGE_SIZE)
@@ -904,7 +957,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
                goto out_free_page;
 
        }
-       length = audit_set_loginuid(task, loginuid);
+       length = audit_set_loginuid(current, loginuid);
        if (likely(length == 0))
                length = count;
 
@@ -923,13 +976,16 @@ static struct file_operations proc_loginuid_operations = {
 static ssize_t seccomp_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
-       struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+       struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
        char __buf[20];
        loff_t __ppos = *ppos;
        size_t len;
 
+       if (!tsk)
+               return -ESRCH;
        /* 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)
@@ -943,29 +999,43 @@ static ssize_t seccomp_read(struct file *file, char __user *buf,
 static ssize_t seccomp_write(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+       struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
        char __buf[20], *end;
        unsigned int seccomp_mode;
+       ssize_t result;
+
+       result = -ESRCH;
+       if (!tsk)
+               goto out_no_task;
 
        /* can set it only once to be even more secure */
+       result = -EPERM;
        if (unlikely(tsk->seccomp.mode))
-               return -EPERM;
+               goto out;
 
+       result = -EFAULT;
        memset(__buf, 0, sizeof(__buf));
        count = min(count, sizeof(__buf) - 1);
        if (copy_from_user(__buf, buf, count))
-               return -EFAULT;
+               goto out;
+
        seccomp_mode = simple_strtoul(__buf, &end, 0);
        if (*end == '\n')
                end++;
+       result = -EINVAL;
        if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
                tsk->seccomp.mode = seccomp_mode;
                set_tsk_thread_flag(tsk, TIF_SECCOMP);
        } else
-               return -EINVAL;
+               goto out;
+       result = -EIO;
        if (unlikely(!(end - __buf)))
-               return -EIO;
-       return end - __buf;
+               goto out;
+       result = end - __buf;
+out:
+       put_task_struct(tsk);
+out_no_task:
+       return result;
 }
 
 static struct file_operations proc_seccomp_operations = {
@@ -974,48 +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;
-       struct files_struct *task_files, *files;
-       int error = -EACCES;
-
-       /* See if the the two tasks share a commone set of
-        * file descriptors.  If so everything is visible.
-        */
-       task = proc_task(inode);
-       if (!task)
-               goto out;
-       files = get_files_struct(current);
-       task_files = get_files_struct(task);
-       if (files && task_files && (files == task_files))
-               error = 0;
-       if (task_files)
-               put_files_struct(task_files);
-       if (files)
-               put_files_struct(files);
-       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;
@@ -1024,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);
 }
@@ -1073,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:
@@ -1099,22 +1115,20 @@ static struct inode_operations proc_pid_link_inode_operations = {
        .follow_link    = proc_pid_follow_link
 };
 
-#define NUMBUF 10
-
 static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
-       struct task_struct *p = proc_task(inode);
+       struct task_struct *p = get_proc_task(inode);
        unsigned int fd, tid, ino;
        int retval;
-       char buf[NUMBUF];
+       char buf[PROC_NUMBUF];
        struct files_struct * files;
        struct fdtable *fdt;
 
        retval = -ENOENT;
-       if (!pid_alive(p))
-               goto out;
+       if (!p)
+               goto out_no_task;
        retval = 0;
        tid = p->pid;
 
@@ -1144,7 +1158,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
                                        continue;
                                rcu_read_unlock();
 
-                               j = NUMBUF;
+                               j = PROC_NUMBUF;
                                i = fd;
                                do {
                                        j--;
@@ -1153,7 +1167,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
                                } while (i);
 
                                ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
-                               if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
+                               if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
                                        rcu_read_lock();
                                        break;
                                }
@@ -1163,6 +1177,8 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
                        put_files_struct(files);
        }
 out:
+       put_task_struct(p);
+out_no_task:
        return retval;
 }
 
@@ -1174,16 +1190,18 @@ static int proc_pident_readdir(struct file *filp,
        int pid;
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
        struct pid_entry *p;
        ino_t ino;
        int ret;
 
        ret = -ENOENT;
-       if (!pid_alive(proc_task(inode)))
+       if (!task)
                goto out;
 
        ret = 0;
-       pid = proc_task(inode)->pid;
+       pid = task->pid;
+       put_task_struct(task);
        i = filp->f_pos;
        switch (i) {
        case 0:
@@ -1269,14 +1287,13 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_ino = fake_ino(task->pid, ino);
 
-       if (!pid_alive(task))
-               goto out_unlock;
-
        /*
         * grab the reference to task.
         */
-       get_task_struct(task);
-       ei->task = task;
+       ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
+       if (!ei->pid)
+               goto out_unlock;
+
        inode->i_uid = 0;
        inode->i_gid = 0;
        if (task_dumpable(task)) {
@@ -1302,13 +1319,21 @@ out_unlock:
  *
  * Rewrite the inode's ownerships here because the owning task may have
  * performed a setuid(), etc.
+ *
+ * Before the /proc/pid/status file was created the only way to read
+ * the effective uid of a /process was to stat /proc/pid.  Reading
+ * /proc/pid/status is slow enough that procps and other packages
+ * kept stating /proc/pid.  To keep the rules in /proc simple I have
+ * made this apply to all per process world readable and executable
+ * directories.
  */
 static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
-       struct task_struct *task = proc_task(inode);
-       if (pid_alive(task)) {
-               if (task_dumpable(task)) {
+       struct task_struct *task = get_proc_task(inode);
+       if (task) {
+               if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+                   task_dumpable(task)) {
                        inode->i_uid = task->euid;
                        inode->i_gid = task->egid;
                } else {
@@ -1316,37 +1341,63 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
                        inode->i_gid = 0;
                }
                security_task_to_inode(task, inode);
+               put_task_struct(task);
                return 1;
        }
        d_drop(dentry);
        return 0;
 }
 
+static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task;
+       generic_fillattr(inode, stat);
+
+       rcu_read_lock();
+       stat->uid = 0;
+       stat->gid = 0;
+       task = pid_task(proc_pid(inode), PIDTYPE_PID);
+       if (task) {
+               if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+                   task_dumpable(task)) {
+                       stat->uid = task->euid;
+                       stat->gid = task->egid;
+               }
+       }
+       rcu_read_unlock();
+       return 0;
+}
+
 static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
-       struct task_struct *task = proc_task(inode);
+       struct task_struct *task = get_proc_task(inode);
        int fd = proc_fd(inode);
        struct files_struct *files;
 
-       files = get_files_struct(task);
-       if (files) {
-               rcu_read_lock();
-               if (fcheck_files(files, fd)) {
+       if (task) {
+               files = get_files_struct(task);
+               if (files) {
+                       rcu_read_lock();
+                       if (fcheck_files(files, fd)) {
+                               rcu_read_unlock();
+                               put_files_struct(files);
+                               if (task_dumpable(task)) {
+                                       inode->i_uid = task->euid;
+                                       inode->i_gid = task->egid;
+                               } else {
+                                       inode->i_uid = 0;
+                                       inode->i_gid = 0;
+                               }
+                               security_task_to_inode(task, inode);
+                               put_task_struct(task);
+                               return 1;
+                       }
                        rcu_read_unlock();
                        put_files_struct(files);
-                       if (task_dumpable(task)) {
-                               inode->i_uid = task->euid;
-                               inode->i_gid = task->egid;
-                       } else {
-                               inode->i_uid = 0;
-                               inode->i_gid = 0;
-                       }
-                       security_task_to_inode(task, inode);
-                       return 1;
                }
-               rcu_read_unlock();
-               put_files_struct(files);
+               put_task_struct(task);
        }
        d_drop(dentry);
        return 0;
@@ -1358,7 +1409,7 @@ static int pid_delete_dentry(struct dentry * dentry)
         * If so, then don't put the dentry on the lru list,
         * kill it immediately.
         */
-       return !pid_alive(proc_task(dentry->d_inode));
+       return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
 }
 
 static struct dentry_operations tid_fd_dentry_operations =
@@ -1400,7 +1451,7 @@ out:
 /* SMP-safe */
 static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
 {
-       struct task_struct *task = proc_task(dir);
+       struct task_struct *task = get_proc_task(dir);
        unsigned fd = name_to_int(dentry);
        struct dentry *result = ERR_PTR(-ENOENT);
        struct file * file;
@@ -1408,10 +1459,10 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        struct inode *inode;
        struct proc_inode *ei;
 
+       if (!task)
+               goto out_no_task;
        if (fd == ~0U)
                goto out;
-       if (!pid_alive(task))
-               goto out;
 
        inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
        if (!inode)
@@ -1446,6 +1497,8 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        if (tid_fd_revalidate(dentry, NULL))
                result = NULL;
 out:
+       put_task_struct(task);
+out_no_task:
        return result;
 
 out_unlock2:
@@ -1489,12 +1542,17 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
        struct inode * inode = file->f_dentry->d_inode;
        unsigned long page;
        ssize_t length;
-       struct task_struct *task = proc_task(inode);
+       struct task_struct *task = get_proc_task(inode);
+
+       length = -ESRCH;
+       if (!task)
+               goto out_no_task;
 
        if (count > PAGE_SIZE)
                count = PAGE_SIZE;
+       length = -ENOMEM;
        if (!(page = __get_free_page(GFP_KERNEL)))
-               return -ENOMEM;
+               goto out;
 
        length = security_getprocattr(task, 
                                      (char*)file->f_dentry->d_name.name, 
@@ -1502,6 +1560,9 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
        if (length >= 0)
                length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
        free_page(page);
+out:
+       put_task_struct(task);
+out_no_task:
        return length;
 }
 
@@ -1511,26 +1572,36 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
        struct inode * inode = file->f_dentry->d_inode;
        char *page; 
        ssize_t length; 
-       struct task_struct *task = proc_task(inode); 
+       struct task_struct *task = get_proc_task(inode);
 
+       length = -ESRCH;
+       if (!task)
+               goto out_no_task;
        if (count > PAGE_SIZE) 
                count = PAGE_SIZE; 
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
+
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
+               goto out;
+
+       length = -ENOMEM;
        page = (char*)__get_free_page(GFP_USER); 
        if (!page) 
-               return -ENOMEM;
+               goto out;
+
        length = -EFAULT; 
        if (copy_from_user(page, buf, count)) 
-               goto out;
+               goto out_free;
 
        length = security_setprocattr(task, 
                                      (char*)file->f_dentry->d_name.name, 
                                      (void*)page, count);
-out:
+out_free:
        free_page((unsigned long) page);
+out:
+       put_task_struct(task);
+out_no_task:
        return length;
 } 
 
@@ -1552,15 +1623,15 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
 {
        struct inode *inode;
        struct dentry *error;
-       struct task_struct *task = proc_task(dir);
+       struct task_struct *task = get_proc_task(dir);
        struct pid_entry *p;
        struct proc_inode *ei;
 
        error = ERR_PTR(-ENOENT);
        inode = NULL;
 
-       if (!pid_alive(task))
-               goto out;
+       if (!task)
+               goto out_no_task;
 
        for (p = ents; p->name; p++) {
                if (p->len != dentry->d_name.len)
@@ -1697,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
@@ -1747,6 +1820,8 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
        if (pid_revalidate(dentry, NULL))
                error = NULL;
 out:
+       put_task_struct(task);
+out_no_task:
        return error;
 }
 
@@ -1770,10 +1845,12 @@ static struct file_operations proc_tid_base_operations = {
 
 static struct inode_operations proc_tgid_base_inode_operations = {
        .lookup         = proc_tgid_base_lookup,
+       .getattr        = pid_getattr,
 };
 
 static struct inode_operations proc_tid_base_inode_operations = {
        .lookup         = proc_tid_base_lookup,
+       .getattr        = pid_getattr,
 };
 
 #ifdef CONFIG_SECURITY
@@ -1815,10 +1892,12 @@ static struct dentry *proc_tid_attr_lookup(struct inode *dir,
 
 static struct inode_operations proc_tgid_attr_inode_operations = {
        .lookup         = proc_tgid_attr_lookup,
+       .getattr        = pid_getattr,
 };
 
 static struct inode_operations proc_tid_attr_inode_operations = {
        .lookup         = proc_tid_attr_lookup,
+       .getattr        = pid_getattr,
 };
 #endif
 
@@ -1828,14 +1907,14 @@ static struct inode_operations proc_tid_attr_inode_operations = {
 static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
                              int buflen)
 {
-       char tmp[30];
+       char tmp[PROC_NUMBUF];
        sprintf(tmp, "%d", current->tgid);
        return vfs_readlink(dentry,buffer,buflen,tmp);
 }
 
 static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-       char tmp[30];
+       char tmp[PROC_NUMBUF];
        sprintf(tmp, "%d", current->tgid);
        return ERR_PTR(vfs_follow_link(nd,tmp));
 }      
@@ -1869,7 +1948,7 @@ static struct inode_operations proc_self_inode_operations = {
 void proc_flush_task(struct task_struct *task)
 {
        struct dentry *dentry, *leader, *dir;
-       char buf[30];
+       char buf[PROC_NUMBUF];
        struct qstr name;
 
        name.name = buf;
@@ -1940,11 +2019,11 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
        if (tgid == ~0U)
                goto out;
 
-       read_lock(&tasklist_lock);
+       rcu_read_lock();
        task = find_task_by_pid(tgid);
        if (task)
                get_task_struct(task);
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
        if (!task)
                goto out;
 
@@ -1980,19 +2059,22 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
 {
        struct dentry *result = ERR_PTR(-ENOENT);
        struct task_struct *task;
-       struct task_struct *leader = proc_task(dir);
+       struct task_struct *leader = get_proc_task(dir);
        struct inode *inode;
        unsigned tid;
 
+       if (!leader)
+               goto out_no_task;
+
        tid = name_to_int(dentry);
        if (tid == ~0U)
                goto out;
 
-       read_lock(&tasklist_lock);
+       rcu_read_lock();
        task = find_task_by_pid(tid);
        if (task)
                get_task_struct(task);
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
        if (!task)
                goto out;
        if (leader->tgid != task->tgid)
@@ -2023,11 +2105,11 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
 out_drop_task:
        put_task_struct(task);
 out:
+       put_task_struct(leader);
+out_no_task:
        return result;
 }
 
-#define PROC_NUMBUF 10
-
 /*
  * Find the first tgid to return to user space.
  *
@@ -2040,34 +2122,32 @@ out:
  * In the case of a seek we start with &init_task and walk nr
  * threads past it.
  */
-static struct task_struct *first_tgid(int tgid, int nr)
+static struct task_struct *first_tgid(int tgid, unsigned int nr)
 {
-       struct task_struct *pos = NULL;
+       struct task_struct *pos;
        rcu_read_lock();
        if (tgid && nr) {
                pos = find_task_by_pid(tgid);
-               if (pos && !thread_group_leader(pos))
-                       pos = NULL;
-               if (pos)
-                       nr = 0;
+               if (pos && thread_group_leader(pos))
+                       goto found;
        }
        /* If nr exceeds the number of processes get out quickly */
+       pos = NULL;
        if (nr && nr >= nr_processes())
                goto done;
 
        /* If we haven't found our starting place yet start with
         * the init_task and walk nr tasks forward.
         */
-       if (!pos && (nr >= 0))
-               pos = next_task(&init_task);
-
-       for (; pos && pid_alive(pos); pos = next_task(pos)) {
-               if (--nr > 0)
-                       continue;
-               get_task_struct(pos);
-               goto done;
+       for (pos = next_task(&init_task); nr > 0; --nr) {
+               pos = next_task(pos);
+               if (pos == &init_task) {
+                       pos = NULL;
+                       goto done;
+               }
        }
-       pos = NULL;
+found:
+       get_task_struct(pos);
 done:
        rcu_read_unlock();
        return pos;
@@ -2150,46 +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) {
-               int threads = 0;
-               task_lock(leader);
-               if (leader->signal)
-                       threads = atomic_read(&leader->signal->count);
-               task_unlock(leader);
-               if (nr >= threads)
-                       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;
 }
 
@@ -2201,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;
 }
@@ -2221,15 +2293,15 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
        char buf[PROC_NUMBUF];
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
-       struct task_struct *leader = proc_task(inode);
+       struct task_struct *leader = get_proc_task(inode);
        struct task_struct *task;
        int retval = -ENOENT;
        ino_t ino;
        int tid;
        unsigned long pos = filp->f_pos;  /* avoiding "long long" filp->f_pos */
 
-       if (!pid_alive(leader))
-               goto out;
+       if (!leader)
+               goto out_no_task;
        retval = 0;
 
        switch (pos) {
@@ -2269,20 +2341,22 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
        }
 out:
        filp->f_pos = pos;
+       put_task_struct(leader);
+out_no_task:
        return retval;
 }
 
 static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
        struct inode *inode = dentry->d_inode;
-       struct task_struct *p = proc_task(inode);
+       struct task_struct *p = get_proc_task(inode);
        generic_fillattr(inode, stat);
 
-       if (pid_alive(p)) {
-               task_lock(p);
-               if (p->signal)
-                       stat->nlink += atomic_read(&p->signal->count);
-               task_unlock(p);
+       if (p) {
+               rcu_read_lock();
+               stat->nlink += get_nr_threads(p);
+               rcu_read_unlock();
+               put_task_struct(p);
        }
 
        return 0;