Skip to content

Commit e19a6ee

Browse files
James Morsewildea01
authored andcommitted
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>
1 parent 4c2e07c commit e19a6ee

File tree

4 files changed

+22
-3
lines changed

4 files changed

+22
-3
lines changed

arch/arm64/include/asm/ptrace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ struct pt_regs {
117117
};
118118
u64 orig_x0;
119119
u64 syscallno;
120+
u64 orig_addr_limit;
121+
u64 unused; // maintain 16 byte alignment
120122
};
121123

122124
#define arch_has_single_step() (1)

arch/arm64/kernel/asm-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ int main(void)
6060
DEFINE(S_PC, offsetof(struct pt_regs, pc));
6161
DEFINE(S_ORIG_X0, offsetof(struct pt_regs, orig_x0));
6262
DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno));
63+
DEFINE(S_ORIG_ADDR_LIMIT, offsetof(struct pt_regs, orig_addr_limit));
6364
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
6465
BLANK();
6566
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter));

arch/arm64/kernel/entry.S

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <asm/errno.h>
2929
#include <asm/esr.h>
3030
#include <asm/irq.h>
31+
#include <asm/memory.h>
3132
#include <asm/thread_info.h>
3233
#include <asm/unistd.h>
3334

@@ -97,7 +98,14 @@
9798
mov x29, xzr // fp pointed to user-space
9899
.else
99100
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 */
101109
mrs x22, elr_el1
102110
mrs x23, spsr_el1
103111
stp lr, x21, [sp, #S_LR]
@@ -128,6 +136,14 @@
128136
.endm
129137

130138
.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+
131147
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
132148
.if \el == 0
133149
ct_user_enter
@@ -406,7 +422,6 @@ el1_irq:
406422
bl trace_hardirqs_off
407423
#endif
408424

409-
get_thread_info tsk
410425
irq_handler
411426

412427
#ifdef CONFIG_PREEMPT

arch/arm64/mm/fault.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
280280
}
281281

282282
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)
284285
die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
285286

286287
if (!search_exception_tables(regs->pc))

0 commit comments

Comments
 (0)