Commit 0e2a5b5b authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'parisc-5.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc fixes from Helge Deller:

 - Prevent kernel panics by adding proper checking of register values
   injected via the ptrace interface

 - Wire up the new clone3 syscall

* 'parisc-5.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Wire up clone3 syscall
  parisc: Avoid kernel panic triggered by invalid kprobe
  parisc: Ensure userspace privilege for ptraced processes in regset functions
  parisc: Fix kernel panic due invalid values in IAOQ0 or IAOQ1
parents da0acd7c 45800fb4
......@@ -166,6 +166,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_CLONE3
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#ifdef CONFIG_64BIT
......
......@@ -1732,6 +1732,7 @@ ENDPROC_CFI(sys_\name\()_wrapper)
.endm
fork_like clone
fork_like clone3
fork_like fork
fork_like vfork
......
......@@ -133,6 +133,9 @@ int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
struct kprobe *p = kprobe_running();
if (!p)
return 0;
if (regs->iaoq[0] != (unsigned long)p->ainsn.insn+4)
return 0;
......
......@@ -167,6 +167,9 @@ long arch_ptrace(struct task_struct *child, long request,
if ((addr & (sizeof(unsigned long)-1)) ||
addr >= sizeof(struct pt_regs))
break;
if (addr == PT_IAOQ0 || addr == PT_IAOQ1) {
data |= 3; /* ensure userspace privilege */
}
if ((addr >= PT_GR1 && addr <= PT_GR31) ||
addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
......@@ -228,16 +231,18 @@ long arch_ptrace(struct task_struct *child, long request,
static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
{
if (offset < 0)
return sizeof(struct pt_regs);
else if (offset <= 32*4) /* gr[0..31] */
return offset * 2 + 4;
else if (offset <= 32*4+32*8) /* gr[0..31] + fr[0..31] */
return offset + 32*4;
else if (offset < sizeof(struct pt_regs)/2 + 32*4)
return offset * 2 + 4 - 32*8;
compat_ulong_t pos;
if (offset < 32*4) /* gr[0..31] */
pos = offset * 2 + 4;
else if (offset < 32*4+32*8) /* fr[0] ... fr[31] */
pos = (offset - 32*4) + PT_FR0;
else if (offset < sizeof(struct pt_regs)/2 + 32*4) /* sr[0] ... ipsw */
pos = (offset - 32*4 - 32*8) * 2 + PT_SR0 + 4;
else
return sizeof(struct pt_regs);
pos = sizeof(struct pt_regs);
return pos;
}
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
......@@ -281,9 +286,12 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
addr = translate_usr_offset(addr);
if (addr >= sizeof(struct pt_regs))
break;
if (addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4) {
data |= 3; /* ensure userspace privilege */
}
if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
/* Special case, fp regs are 64 bits anyway */
*(__u64 *) ((char *) task_regs(child) + addr) = data;
*(__u32 *) ((char *) task_regs(child) + addr) = data;
ret = 0;
}
else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
......@@ -496,7 +504,8 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val)
return;
case RI(iaoq[0]):
case RI(iaoq[1]):
regs->iaoq[num - RI(iaoq[0])] = val;
/* set 2 lowest bits to ensure userspace privilege: */
regs->iaoq[num - RI(iaoq[0])] = val | 3;
return;
case RI(sar): regs->sar = val;
return;
......
......@@ -431,4 +431,4 @@
432 common fsmount sys_fsmount
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
# 435 reserved for clone3
435 common clone3 sys_clone3_wrapper
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment