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

Commit 31267feb authored by James Morse's avatar James Morse Committed by Sami Tolvanen
Browse files

BACKPORT: arm64: kernel: Save and restore UAO and addr_limit on exception entry



If we take an exception while at EL1, the exception handler inherits
the original context's addr_limit and PSTATE.UAO values. To be consistent
always reset addr_limit and PSTATE.UAO on (re-)entry to EL1. This
prevents accidental re-use of the original context's addr_limit.

Based on a similar patch for arm from Russell King.

Cc: <stable@vger.kernel.org> # 4.6-
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Reviewed-by: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>

Bug: 31432001
Change-Id: Iab453201c6e08bc6e22500b7c5570dd0fe2d1b74
(cherry picked from commit e19a6ee2460bdd0d0055a6029383422773f9999a)
Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
parent 8d38c6a7
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -116,6 +116,8 @@ struct pt_regs {
	};
	};
	u64 orig_x0;
	u64 orig_x0;
	u64 syscallno;
	u64 syscallno;
	u64 orig_addr_limit;
	u64 unused;	// maintain 16 byte alignment
};
};


#define arch_has_single_step()	(1)
#define arch_has_single_step()	(1)
+1 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ int main(void)
  DEFINE(S_PC,			offsetof(struct pt_regs, pc));
  DEFINE(S_PC,			offsetof(struct pt_regs, pc));
  DEFINE(S_ORIG_X0,		offsetof(struct pt_regs, orig_x0));
  DEFINE(S_ORIG_X0,		offsetof(struct pt_regs, orig_x0));
  DEFINE(S_SYSCALLNO,		offsetof(struct pt_regs, syscallno));
  DEFINE(S_SYSCALLNO,		offsetof(struct pt_regs, syscallno));
  DEFINE(S_ORIG_ADDR_LIMIT,	offsetof(struct pt_regs, orig_addr_limit));
  DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
  DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
  BLANK();
  BLANK();
  DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id.counter));
  DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id.counter));
+17 −1
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@
#include <asm/cpufeature.h>
#include <asm/cpufeature.h>
#include <asm/errno.h>
#include <asm/errno.h>
#include <asm/esr.h>
#include <asm/esr.h>
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#include <asm/unistd.h>


@@ -93,7 +94,14 @@
	disable_step_tsk x19, x20		// exceptions when scheduling.
	disable_step_tsk x19, x20		// exceptions when scheduling.
	.else
	.else
	add	x21, sp, #S_FRAME_SIZE
	add	x21, sp, #S_FRAME_SIZE
	.endif
	get_thread_info tsk
	/* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
	ldr	x20, [tsk, #TI_ADDR_LIMIT]
	str	x20, [sp, #S_ORIG_ADDR_LIMIT]
	mov	x20, #TASK_SIZE_64
	str	x20, [tsk, #TI_ADDR_LIMIT]
	ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO)
	.endif /* \el == 0 */
	mrs	x22, elr_el1
	mrs	x22, elr_el1
	mrs	x23, spsr_el1
	mrs	x23, spsr_el1
	stp	lr, x21, [sp, #S_LR]
	stp	lr, x21, [sp, #S_LR]
@@ -117,6 +125,14 @@
	.endm
	.endm


	.macro	kernel_exit, el
	.macro	kernel_exit, el
	.if	\el != 0
	/* Restore the task's original addr_limit. */
	ldr	x20, [sp, #S_ORIG_ADDR_LIMIT]
	str	x20, [tsk, #TI_ADDR_LIMIT]

	/* No need to restore UAO, it will be restored from SPSR_EL1 */
	.endif

	ldp	x21, x22, [sp, #S_PC]		// load ELR, SPSR
	ldp	x21, x22, [sp, #S_PC]		// load ELR, SPSR
	.if	\el == 0
	.if	\el == 0
	ct_user_enter
	ct_user_enter
+3 −2
Original line number Original line Diff line number Diff line
@@ -238,8 +238,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
	}
	}


	if (is_permission_fault(esr) && (addr < USER_DS)) {
	if (is_permission_fault(esr) && (addr < USER_DS)) {
		if (get_fs() == KERNEL_DS)
		/* regs->orig_addr_limit may be 0 if we entered from EL0 */
			panic("Accessing user space memory with fs=KERNEL_DS");
		if (regs->orig_addr_limit == KERNEL_DS)
			die("Accessing user space memory with fs=KERNEL_DS", regs, esr);


		if (!search_exception_tables(regs->pc))
		if (!search_exception_tables(regs->pc))
			panic("Accessing user space memory outside uaccess.h routines");
			panic("Accessing user space memory outside uaccess.h routines");