aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Morse <james.morse@arm.com>2016-06-20 13:28:01 -0400
committerWill Deacon <will.deacon@arm.com>2016-07-07 10:55:37 -0400
commite19a6ee2460bdd0d0055a6029383422773f9999a (patch)
treef8e7898101568c82617d7afd66e712b9f0538a0e
parent4c2e07c6a29e0129e975727b9f57eede813eea85 (diff)
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: Will Deacon <will.deacon@arm.com> Reviewed-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/include/asm/ptrace.h2
-rw-r--r--arch/arm64/kernel/asm-offsets.c1
-rw-r--r--arch/arm64/kernel/entry.S19
-rw-r--r--arch/arm64/mm/fault.c3
4 files changed, 22 insertions, 3 deletions
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index a307eb6e7fa8..7f94755089e2 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -117,6 +117,8 @@ struct pt_regs {
117 }; 117 };
118 u64 orig_x0; 118 u64 orig_x0;
119 u64 syscallno; 119 u64 syscallno;
120 u64 orig_addr_limit;
121 u64 unused; // maintain 16 byte alignment
120}; 122};
121 123
122#define arch_has_single_step() (1) 124#define arch_has_single_step() (1)
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index f8e5d47f0880..2f4ba774488a 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -60,6 +60,7 @@ int main(void)
60 DEFINE(S_PC, offsetof(struct pt_regs, pc)); 60 DEFINE(S_PC, offsetof(struct pt_regs, pc));
61 DEFINE(S_ORIG_X0, offsetof(struct pt_regs, orig_x0)); 61 DEFINE(S_ORIG_X0, offsetof(struct pt_regs, orig_x0));
62 DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno)); 62 DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno));
63 DEFINE(S_ORIG_ADDR_LIMIT, offsetof(struct pt_regs, orig_addr_limit));
63 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); 64 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
64 BLANK(); 65 BLANK();
65 DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter)); 66 DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter));
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 12e8d2bcb3f9..6c3b7345a6c4 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -28,6 +28,7 @@
28#include <asm/errno.h> 28#include <asm/errno.h>
29#include <asm/esr.h> 29#include <asm/esr.h>
30#include <asm/irq.h> 30#include <asm/irq.h>
31#include <asm/memory.h>
31#include <asm/thread_info.h> 32#include <asm/thread_info.h>
32#include <asm/unistd.h> 33#include <asm/unistd.h>
33 34
@@ -97,7 +98,14 @@
97 mov x29, xzr // fp pointed to user-space 98 mov x29, xzr // fp pointed to user-space
98 .else 99 .else
99 add x21, sp, #S_FRAME_SIZE 100 add x21, sp, #S_FRAME_SIZE
100 .endif 101 get_thread_info tsk
102 /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
103 ldr x20, [tsk, #TI_ADDR_LIMIT]
104 str x20, [sp, #S_ORIG_ADDR_LIMIT]
105 mov x20, #TASK_SIZE_64
106 str x20, [tsk, #TI_ADDR_LIMIT]
107 ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO)
108 .endif /* \el == 0 */
101 mrs x22, elr_el1 109 mrs x22, elr_el1
102 mrs x23, spsr_el1 110 mrs x23, spsr_el1
103 stp lr, x21, [sp, #S_LR] 111 stp lr, x21, [sp, #S_LR]
@@ -128,6 +136,14 @@
128 .endm 136 .endm
129 137
130 .macro kernel_exit, el 138 .macro kernel_exit, el
139 .if \el != 0
140 /* Restore the task's original addr_limit. */
141 ldr x20, [sp, #S_ORIG_ADDR_LIMIT]
142 str x20, [tsk, #TI_ADDR_LIMIT]
143
144 /* No need to restore UAO, it will be restored from SPSR_EL1 */
145 .endif
146
131 ldp x21, x22, [sp, #S_PC] // load ELR, SPSR 147 ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
132 .if \el == 0 148 .if \el == 0
133 ct_user_enter 149 ct_user_enter
@@ -406,7 +422,6 @@ el1_irq:
406 bl trace_hardirqs_off 422 bl trace_hardirqs_off
407#endif 423#endif
408 424
409 get_thread_info tsk
410 irq_handler 425 irq_handler
411 426
412#ifdef CONFIG_PREEMPT 427#ifdef CONFIG_PREEMPT
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 013e2cbe7924..b1166d1e5955 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -280,7 +280,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
280 } 280 }
281 281
282 if (permission_fault(esr) && (addr < USER_DS)) { 282 if (permission_fault(esr) && (addr < USER_DS)) {
283 if (get_fs() == KERNEL_DS) 283 /* regs->orig_addr_limit may be 0 if we entered from EL0 */
284 if (regs->orig_addr_limit == KERNEL_DS)
284 die("Accessing user space memory with fs=KERNEL_DS", regs, esr); 285 die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
285 286
286 if (!search_exception_tables(regs->pc)) 287 if (!search_exception_tables(regs->pc))