Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Some ptrace fixes from Al.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-06-02 18:46:55 -07:00
commit 824c874abc
2 changed files with 101 additions and 144 deletions

View File

@ -46,82 +46,79 @@ enum sparc_regset {
REGSET_FP, 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, static int genregs32_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf) void *kbuf, void __user *ubuf)
{ {
const struct pt_regs *regs = target->thread.kregs; const struct pt_regs *regs = target->thread.kregs;
unsigned long __user *reg_window; u32 uregs[16];
unsigned long *k = kbuf; int ret;
unsigned long __user *u = ubuf;
unsigned long reg;
if (target == current) if (target == current)
flush_user_windows(); flush_user_windows();
pos /= sizeof(reg); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
count /= sizeof(reg); regs->u_regs,
0, 16 * sizeof(u32));
if (ret || !count)
return ret;
if (kbuf) { if (pos < 32 * sizeof(u32)) {
for (; count > 0 && pos < 16; count--) if (regwindow32_get(target, regs, uregs))
*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; return -EFAULT;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
uregs,
16 * sizeof(u32), 32 * sizeof(u32));
if (ret || !count)
return ret;
} }
reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; uregs[0] = regs->psr;
reg_window -= 16; uregs[1] = regs->pc;
for (; count > 0 && pos < 32; count--) { uregs[2] = regs->npc;
if (get_user(reg, &reg_window[pos++]) || uregs[3] = regs->y;
put_user(reg, u++)) uregs[4] = 0; /* WIM */
return -EFAULT; uregs[5] = 0; /* TBR */
} return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
} uregs,
while (count > 0) { 32 * sizeof(u32), 38 * sizeof(u32));
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;
}
if (kbuf)
*k++ = reg;
else if (put_user(reg, u++))
return -EFAULT;
pos++;
count--;
}
finish:
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
38 * sizeof(reg), -1);
} }
static int genregs32_set(struct task_struct *target, 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) const void *kbuf, const void __user *ubuf)
{ {
struct pt_regs *regs = target->thread.kregs; struct pt_regs *regs = target->thread.kregs;
unsigned long __user *reg_window; u32 uregs[16];
const unsigned long *k = kbuf; u32 psr;
const unsigned long __user *u = ubuf; int ret;
unsigned long reg;
if (target == current) if (target == current)
flush_user_windows(); flush_user_windows();
pos /= sizeof(reg); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
count /= sizeof(reg); regs->u_regs,
0, 16 * sizeof(u32));
if (ret || !count)
return ret;
if (kbuf) { if (pos < 32 * sizeof(u32)) {
for (; count > 0 && pos < 16; count--) if (regwindow32_get(target, regs, uregs))
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; return -EFAULT;
} ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
} else { uregs,
for (; count > 0 && pos < 16; count--) { 16 * sizeof(u32), 32 * sizeof(u32));
if (get_user(reg, u++)) if (ret)
return ret;
if (regwindow32_set(target, regs, uregs))
return -EFAULT; return -EFAULT;
regs->u_regs[pos++] = reg; if (!count)
return 0;
} }
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; &psr,
reg_window -= 16; 32 * sizeof(u32), 33 * sizeof(u32));
for (; count > 0 && pos < 32; count--) { if (ret)
if (get_user(reg, u++) || return ret;
put_user(reg, &reg_window[pos++])) regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
return -EFAULT; (psr & (PSR_ICC | PSR_SYSCALL));
} if (!count)
} return 0;
while (count > 0) { ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
unsigned long psr; &regs->pc,
33 * sizeof(u32), 34 * sizeof(u32));
if (kbuf) if (ret || !count)
reg = *k++; return ret;
else if (get_user(reg, u++)) ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
return -EFAULT; &regs->y,
34 * sizeof(u32), 35 * sizeof(u32));
switch (pos) { if (ret || !count)
case 32: /* PSR */ return ret;
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--;
}
finish:
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 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, static int fpregs32_get(struct task_struct *target,

View File

@ -572,19 +572,13 @@ static int genregs32_get(struct task_struct *target,
for (; count > 0 && pos < 32; count--) { for (; count > 0 && pos < 32; count--) {
if (access_process_vm(target, if (access_process_vm(target,
(unsigned long) (unsigned long)
&reg_window[pos], &reg_window[pos++],
&reg, sizeof(reg), &reg, sizeof(reg),
FOLL_FORCE) FOLL_FORCE)
!= sizeof(reg)) != sizeof(reg))
return -EFAULT; return -EFAULT;
if (access_process_vm(target, if (put_user(reg, u++))
(unsigned long) u,
&reg, sizeof(reg),
FOLL_FORCE | FOLL_WRITE)
!= sizeof(reg))
return -EFAULT; return -EFAULT;
pos++;
u++;
} }
} }
} }
@ -684,12 +678,7 @@ static int genregs32_set(struct task_struct *target,
} }
} else { } else {
for (; count > 0 && pos < 32; count--) { for (; count > 0 && pos < 32; count--) {
if (access_process_vm(target, if (get_user(reg, u++))
(unsigned long)
u,
&reg, sizeof(reg),
FOLL_FORCE)
!= sizeof(reg))
return -EFAULT; return -EFAULT;
if (access_process_vm(target, if (access_process_vm(target,
(unsigned long) (unsigned long)