Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / proc / base.c
index 1fc1dca..51be1ce 100644 (file)
@@ -216,7 +216,7 @@ static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
 
 struct mm_struct *mm_for_maps(struct task_struct *task)
 {
-       return mm_access(task, PTRACE_MODE_READ);
+       return mm_access(task, PTRACE_MODE_READ_FSCREDS);
 }
 
 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
@@ -288,7 +288,7 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
        wchan = get_wchan(task);
 
        if (lookup_symbol_name(wchan, symname) < 0)
-               if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
                        return 0;
                else
                        return sprintf(buffer, "%lu", wchan);
@@ -302,7 +302,7 @@ static int lock_trace(struct task_struct *task)
        int err = mutex_lock_killable(&task->signal->cred_guard_mutex);
        if (err)
                return err;
-       if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
+       if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
                mutex_unlock(&task->signal->cred_guard_mutex);
                return -EPERM;
        }
@@ -544,7 +544,7 @@ static int proc_fd_access_allowed(struct inode *inode)
         */
        task = get_proc_task(inode);
        if (task) {
-               allowed = ptrace_may_access(task, PTRACE_MODE_READ);
+               allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
                put_task_struct(task);
        }
        return allowed;
@@ -558,7 +558,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
        if (attr->ia_valid & ATTR_MODE)
                return -EPERM;
 
-       error = inode_change_ok(inode, attr);
+       error = setattr_prepare(dentry, attr);
        if (error)
                return error;
 
@@ -769,12 +769,19 @@ static int mem_open(struct inode* inode, struct file* file)
        if (!task)
                return -ESRCH;
 
-       mm = mm_access(task, PTRACE_MODE_ATTACH);
+       mm = mm_access(task, PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS);
        put_task_struct(task);
 
        if (IS_ERR(mm))
                return PTR_ERR(mm);
 
+       if (mm) {
+               /* ensure this mm_struct can't be freed */
+               atomic_inc(&mm->mm_count);
+               /* but do not pin its memory */
+               mmput(mm);
+       }
+
        /* OK to pass negative loff_t, we can catch out-of-range */
        file->f_mode |= FMODE_UNSIGNED_OFFSET;
        file->private_data = mm;
@@ -782,57 +789,13 @@ static int mem_open(struct inode* inode, struct file* file)
        return 0;
 }
 
-static ssize_t mem_read(struct file * file, char __user * buf,
-                       size_t count, loff_t *ppos)
+static ssize_t mem_rw(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos, int write)
 {
-       int ret;
-       char *page;
-       unsigned long src = *ppos;
        struct mm_struct *mm = file->private_data;
-
-       if (!mm)
-               return 0;
-
-       page = (char *)__get_free_page(GFP_TEMPORARY);
-       if (!page)
-               return -ENOMEM;
-
-       ret = 0;
-       while (count > 0) {
-               int this_len, retval;
-
-               this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-               retval = access_remote_vm(mm, src, page, this_len, 0);
-               if (!retval) {
-                       if (!ret)
-                               ret = -EIO;
-                       break;
-               }
-
-               if (copy_to_user(buf, page, retval)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               ret += retval;
-               src += retval;
-               buf += retval;
-               count -= retval;
-       }
-       *ppos = src;
-
-       free_page((unsigned long) page);
-       return ret;
-}
-
-static ssize_t mem_write(struct file * file, const char __user *buf,
-                        size_t count, loff_t *ppos)
-{
-       int copied;
+       unsigned long addr = *ppos;
+       ssize_t copied;
        char *page;
-       unsigned long dst = *ppos;
-       struct mm_struct *mm = file->private_data;
 
        if (!mm)
                return 0;
@@ -842,31 +805,54 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
                return -ENOMEM;
 
        copied = 0;
+       if (!atomic_inc_not_zero(&mm->mm_users))
+               goto free;
+
        while (count > 0) {
-               int this_len, retval;
+               int this_len = min_t(int, count, PAGE_SIZE);
 
-               this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-               if (copy_from_user(page, buf, this_len)) {
+               if (write && copy_from_user(page, buf, this_len)) {
                        copied = -EFAULT;
                        break;
                }
-               retval = access_remote_vm(mm, dst, page, this_len, 1);
-               if (!retval) {
+
+               this_len = access_remote_vm(mm, addr, page, this_len, write);
+               if (!this_len) {
                        if (!copied)
                                copied = -EIO;
                        break;
                }
-               copied += retval;
-               buf += retval;
-               dst += retval;
-               count -= retval;                        
+
+               if (!write && copy_to_user(buf, page, this_len)) {
+                       copied = -EFAULT;
+                       break;
+               }
+
+               buf += this_len;
+               addr += this_len;
+               copied += this_len;
+               count -= this_len;
        }
-       *ppos = dst;
+       *ppos = addr;
 
+       mmput(mm);
+free:
        free_page((unsigned long) page);
        return copied;
 }
 
+static ssize_t mem_read(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       return mem_rw(file, buf, count, ppos, 0);
+}
+
+static ssize_t mem_write(struct file *file, const char __user *buf,
+                        size_t count, loff_t *ppos)
+{
+       return mem_rw(file, (char __user*)buf, count, ppos, 1);
+}
+
 loff_t mem_lseek(struct file *file, loff_t offset, int orig)
 {
        switch (orig) {
@@ -886,8 +872,8 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)
 static int mem_release(struct inode *inode, struct file *file)
 {
        struct mm_struct *mm = file->private_data;
-
-       mmput(mm);
+       if (mm)
+               mmdrop(mm);
        return 0;
 }
 
@@ -919,7 +905,8 @@ static ssize_t environ_read(struct file *file, char __user *buf,
 
        mm = mm_for_maps(task);
        ret = PTR_ERR(mm);
-       if (!mm || IS_ERR(mm))
+       /* Ensure the process spawned far enough to have an environment. */
+       if (!mm || IS_ERR(mm) || !mm->env_end)
                goto out_free;
 
        ret = 0;
@@ -1844,7 +1831,7 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info)
 
                        fdt = files_fdtable(files);
                        f_flags = file->f_flags & ~O_CLOEXEC;
-                       if (FD_ISSET(fd, fdt->close_on_exec))
+                       if (close_on_exec(fd, fdt))
                                f_flags |= O_CLOEXEC;
 
                        if (path) {
@@ -2640,7 +2627,7 @@ static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
        if (result)
                return result;
 
-       if (!ptrace_may_access(task, PTRACE_MODE_READ)) {
+       if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
                result = -EACCES;
                goto out_unlock;
        }
@@ -2729,6 +2716,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        ONE("stat",       S_IRUGO, proc_tgid_stat),
        ONE("statm",      S_IRUGO, proc_pid_statm),
        REG("maps",       S_IRUGO, proc_maps_operations),
+       REG("arm_maps",   S_IRUGO, proc_armv7_maps_operations),
 #ifdef CONFIG_NUMA
        REG("numa_maps",  S_IRUGO, proc_numa_maps_operations),
 #endif
@@ -3075,6 +3063,7 @@ static const struct pid_entry tid_base_stuff[] = {
        ONE("stat",      S_IRUGO, proc_tid_stat),
        ONE("statm",     S_IRUGO, proc_pid_statm),
        REG("maps",      S_IRUGO, proc_maps_operations),
+       REG("arm_maps",  S_IRUGO, proc_armv7_maps_operations),
 #ifdef CONFIG_NUMA
        REG("numa_maps", S_IRUGO, proc_numa_maps_operations),
 #endif