diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-18 12:23:45 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-18 12:23:45 -0700 |
commit | 0e2a5b5bd9a6aaec85df347dd71432a1d2d10763 (patch) | |
tree | 31a1289a9c73c559cf848a2ea2528c3079b058f4 | |
parent | da0acd7c656c09b362b5095dc8595f8655dc1223 (diff) | |
parent | 45800fb45139284f0db4f5ac7fbbf5dad81e4172 (diff) |
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
-rw-r--r-- | arch/parisc/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/parisc/kernel/entry.S | 1 | ||||
-rw-r--r-- | arch/parisc/kernel/kprobes.c | 3 | ||||
-rw-r--r-- | arch/parisc/kernel/ptrace.c | 31 | ||||
-rw-r--r-- | arch/parisc/kernel/syscalls/syscall.tbl | 2 |
5 files changed, 26 insertions, 12 deletions
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index b0838dc4dfee..cd438e4150f6 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -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 diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 3e430590c1e1..d9d3387f7c47 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1732,6 +1732,7 @@ ENDPROC_CFI(sys_\name\()_wrapper) .endm fork_like clone +fork_like clone3 fork_like fork fork_like vfork diff --git a/arch/parisc/kernel/kprobes.c b/arch/parisc/kernel/kprobes.c index d58960b33bda..5d7f2692ac5a 100644 --- a/arch/parisc/kernel/kprobes.c +++ b/arch/parisc/kernel/kprobes.c @@ -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; diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index f642ba378ffa..9f6ff7bc06f9 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -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; diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index c7aadfef5386..670d1371aca1 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -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 |