Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e2a5b5b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -1732,6 +1732,7 @@ ENDPROC_CFI(sys_\name\()_wrapper)
	.endm

fork_like clone
fork_like clone3
fork_like fork
fork_like vfork

+3 −0
Original line number Diff line number Diff line
@@ -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;

+20 −11
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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