Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorDavid S. Miller <davem@davemloft.net>
Wed, 3 Jun 2020 01:46:55 +0000 (18:46 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 3 Jun 2020 01:46:55 +0000 (18:46 -0700)
Some ptrace fixes from Al.

Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/kernel/ptrace_32.c
arch/sparc/kernel/ptrace_64.c

index 16b50af..60f7205 100644 (file)
@@ -46,82 +46,79 @@ enum sparc_regset {
        REGSET_FP,
 };
 
+static int regwindow32_get(struct task_struct *target,
+                          const struct pt_regs *regs,
+                          u32 *uregs)
+{
+       unsigned long reg_window = regs->u_regs[UREG_I6];
+       int size = 16 * sizeof(u32);
+
+       if (target == current) {
+               if (copy_from_user(uregs, (void __user *)reg_window, size))
+                       return -EFAULT;
+       } else {
+               if (access_process_vm(target, reg_window, uregs, size,
+                                     FOLL_FORCE) != size)
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+static int regwindow32_set(struct task_struct *target,
+                          const struct pt_regs *regs,
+                          u32 *uregs)
+{
+       unsigned long reg_window = regs->u_regs[UREG_I6];
+       int size = 16 * sizeof(u32);
+
+       if (target == current) {
+               if (copy_to_user((void __user *)reg_window, uregs, size))
+                       return -EFAULT;
+       } else {
+               if (access_process_vm(target, reg_window, uregs, size,
+                                     FOLL_FORCE | FOLL_WRITE) != size)
+                       return -EFAULT;
+       }
+       return 0;
+}
+
 static int genregs32_get(struct task_struct *target,
                         const struct user_regset *regset,
                         unsigned int pos, unsigned int count,
                         void *kbuf, void __user *ubuf)
 {
        const struct pt_regs *regs = target->thread.kregs;
-       unsigned long __user *reg_window;
-       unsigned long *k = kbuf;
-       unsigned long __user *u = ubuf;
-       unsigned long reg;
+       u32 uregs[16];
+       int ret;
 
        if (target == current)
                flush_user_windows();
 
-       pos /= sizeof(reg);
-       count /= sizeof(reg);
-
-       if (kbuf) {
-               for (; count > 0 && pos < 16; count--)
-                       *k++ = regs->u_regs[pos++];
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               reg_window -= 16;
-               for (; count > 0 && pos < 32; count--) {
-                       if (get_user(*k++, &reg_window[pos++]))
-                               return -EFAULT;
-               }
-       } else {
-               for (; count > 0 && pos < 16; count--) {
-                       if (put_user(regs->u_regs[pos++], u++))
-                               return -EFAULT;
-               }
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               reg_window -= 16;
-               for (; count > 0 && pos < 32; count--) {
-                       if (get_user(reg, &reg_window[pos++]) ||
-                           put_user(reg, u++))
-                               return -EFAULT;
-               }
-       }
-       while (count > 0) {
-               switch (pos) {
-               case 32: /* PSR */
-                       reg = regs->psr;
-                       break;
-               case 33: /* PC */
-                       reg = regs->pc;
-                       break;
-               case 34: /* NPC */
-                       reg = regs->npc;
-                       break;
-               case 35: /* Y */
-                       reg = regs->y;
-                       break;
-               case 36: /* WIM */
-               case 37: /* TBR */
-                       reg = 0;
-                       break;
-               default:
-                       goto finish;
-               }
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 regs->u_regs,
+                                 0, 16 * sizeof(u32));
+       if (ret || !count)
+               return ret;
 
-               if (kbuf)
-                       *k++ = reg;
-               else if (put_user(reg, u++))
+       if (pos < 32 * sizeof(u32)) {
+               if (regwindow32_get(target, regs, uregs))
                        return -EFAULT;
-               pos++;
-               count--;
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         uregs,
+                                         16 * sizeof(u32), 32 * sizeof(u32));
+               if (ret || !count)
+                       return ret;
        }
-finish:
-       pos *= sizeof(reg);
-       count *= sizeof(reg);
 
-       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
-                                       38 * sizeof(reg), -1);
+       uregs[0] = regs->psr;
+       uregs[1] = regs->pc;
+       uregs[2] = regs->npc;
+       uregs[3] = regs->y;
+       uregs[4] = 0;   /* WIM */
+       uregs[5] = 0;   /* TBR */
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 uregs,
+                                 32 * sizeof(u32), 38 * sizeof(u32));
 }
 
 static int genregs32_set(struct task_struct *target,
@@ -130,82 +127,53 @@ static int genregs32_set(struct task_struct *target,
                         const void *kbuf, const void __user *ubuf)
 {
        struct pt_regs *regs = target->thread.kregs;
-       unsigned long __user *reg_window;
-       const unsigned long *k = kbuf;
-       const unsigned long __user *u = ubuf;
-       unsigned long reg;
+       u32 uregs[16];
+       u32 psr;
+       int ret;
 
        if (target == current)
                flush_user_windows();
 
-       pos /= sizeof(reg);
-       count /= sizeof(reg);
-
-       if (kbuf) {
-               for (; count > 0 && pos < 16; count--)
-                       regs->u_regs[pos++] = *k++;
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               reg_window -= 16;
-               for (; count > 0 && pos < 32; count--) {
-                       if (put_user(*k++, &reg_window[pos++]))
-                               return -EFAULT;
-               }
-       } else {
-               for (; count > 0 && pos < 16; count--) {
-                       if (get_user(reg, u++))
-                               return -EFAULT;
-                       regs->u_regs[pos++] = reg;
-               }
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               reg_window -= 16;
-               for (; count > 0 && pos < 32; count--) {
-                       if (get_user(reg, u++) ||
-                           put_user(reg, &reg_window[pos++]))
-                               return -EFAULT;
-               }
-       }
-       while (count > 0) {
-               unsigned long psr;
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                regs->u_regs,
+                                0, 16 * sizeof(u32));
+       if (ret || !count)
+               return ret;
 
-               if (kbuf)
-                       reg = *k++;
-               else if (get_user(reg, u++))
+       if (pos < 32 * sizeof(u32)) {
+               if (regwindow32_get(target, regs, uregs))
                        return -EFAULT;
-
-               switch (pos) {
-               case 32: /* PSR */
-                       psr = regs->psr;
-                       psr &= ~(PSR_ICC | PSR_SYSCALL);
-                       psr |= (reg & (PSR_ICC | PSR_SYSCALL));
-                       regs->psr = psr;
-                       break;
-               case 33: /* PC */
-                       regs->pc = reg;
-                       break;
-               case 34: /* NPC */
-                       regs->npc = reg;
-                       break;
-               case 35: /* Y */
-                       regs->y = reg;
-                       break;
-               case 36: /* WIM */
-               case 37: /* TBR */
-                       break;
-               default:
-                       goto finish;
-               }
-
-               pos++;
-               count--;
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                        uregs,
+                                        16 * sizeof(u32), 32 * sizeof(u32));
+               if (ret)
+                       return ret;
+               if (regwindow32_set(target, regs, uregs))
+                       return -EFAULT;
+               if (!count)
+                       return 0;
        }
-finish:
-       pos *= sizeof(reg);
-       count *= sizeof(reg);
-
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &psr,
+                                32 * sizeof(u32), 33 * sizeof(u32));
+       if (ret)
+               return ret;
+       regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
+                   (psr & (PSR_ICC | PSR_SYSCALL));
+       if (!count)
+               return 0;
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs->pc,
+                                33 * sizeof(u32), 34 * sizeof(u32));
+       if (ret || !count)
+               return ret;
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs->y,
+                                34 * sizeof(u32), 35 * sizeof(u32));
+       if (ret || !count)
+               return ret;
        return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-                                        38 * sizeof(reg), -1);
+                                        35 * sizeof(u32), 38 * sizeof(u32));
 }
 
 static int fpregs32_get(struct task_struct *target,
index c9d41a9..3f5930b 100644 (file)
@@ -572,19 +572,13 @@ static int genregs32_get(struct task_struct *target,
                        for (; count > 0 && pos < 32; count--) {
                                if (access_process_vm(target,
                                                      (unsigned long)
-                                                     &reg_window[pos],
+                                                     &reg_window[pos++],
                                                      &reg, sizeof(reg),
                                                      FOLL_FORCE)
                                    != sizeof(reg))
                                        return -EFAULT;
-                               if (access_process_vm(target,
-                                                     (unsigned long) u,
-                                                     &reg, sizeof(reg),
-                                                     FOLL_FORCE | FOLL_WRITE)
-                                   != sizeof(reg))
+                               if (put_user(reg, u++))
                                        return -EFAULT;
-                               pos++;
-                               u++;
                        }
                }
        }
@@ -684,12 +678,7 @@ static int genregs32_set(struct task_struct *target,
                        }
                } else {
                        for (; count > 0 && pos < 32; count--) {
-                               if (access_process_vm(target,
-                                                     (unsigned long)
-                                                     u,
-                                                     &reg, sizeof(reg),
-                                                     FOLL_FORCE)
-                                   != sizeof(reg))
+                               if (get_user(reg, u++))
                                        return -EFAULT;
                                if (access_process_vm(target,
                                                      (unsigned long)