ARM: save and reset the address limit when entering an exception
When we enter an exception, the current address limit should not apply to the exception context: if the exception context wishes to access kernel space via the user accessors (eg, perf code), it must explicitly request such access. Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
parent
dd665be0e2
commit
e6978e4bf1
5 changed files with 20 additions and 6 deletions
|
@ -22,7 +22,7 @@ struct pt_regs {
|
|||
struct svc_pt_regs {
|
||||
struct pt_regs regs;
|
||||
u32 dacr;
|
||||
u32 unused;
|
||||
u32 addr_limit;
|
||||
};
|
||||
|
||||
#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
|
||||
|
|
|
@ -109,6 +109,7 @@ int main(void)
|
|||
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
|
||||
DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
|
||||
DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr));
|
||||
DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
|
||||
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
|
||||
BLANK();
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
|
|
|
@ -185,6 +185,12 @@ ENDPROC(__und_invalid)
|
|||
@
|
||||
stmia r7, {r2 - r6}
|
||||
|
||||
get_thread_info tsk
|
||||
ldr r0, [tsk, #TI_ADDR_LIMIT]
|
||||
mov r1, #TASK_SIZE
|
||||
str r1, [tsk, #TI_ADDR_LIMIT]
|
||||
str r0, [sp, #SVC_ADDR_LIMIT]
|
||||
|
||||
uaccess_save r0
|
||||
.if \uaccess
|
||||
uaccess_disable r0
|
||||
|
@ -213,7 +219,6 @@ __irq_svc:
|
|||
irq_handler
|
||||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
get_thread_info tsk
|
||||
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
|
||||
ldr r0, [tsk, #TI_FLAGS] @ get flags
|
||||
teq r8, #0 @ if preempt count != 0
|
||||
|
|
|
@ -215,7 +215,9 @@
|
|||
blne trace_hardirqs_off
|
||||
#endif
|
||||
.endif
|
||||
ldr r1, [sp, #SVC_ADDR_LIMIT]
|
||||
uaccess_restore
|
||||
str r1, [tsk, #TI_ADDR_LIMIT]
|
||||
|
||||
#ifndef CONFIG_THUMB2_KERNEL
|
||||
@ ARM mode SVC restore
|
||||
|
@ -259,7 +261,9 @@
|
|||
@ on the stack remains correct).
|
||||
@
|
||||
.macro svc_exit_via_fiq
|
||||
ldr r1, [sp, #SVC_ADDR_LIMIT]
|
||||
uaccess_restore
|
||||
str r1, [tsk, #TI_ADDR_LIMIT]
|
||||
#ifndef CONFIG_THUMB2_KERNEL
|
||||
@ ARM mode restore
|
||||
mov r0, sp
|
||||
|
|
|
@ -96,19 +96,23 @@ void __show_regs(struct pt_regs *regs)
|
|||
unsigned long flags;
|
||||
char buf[64];
|
||||
#ifndef CONFIG_CPU_V7M
|
||||
unsigned int domain;
|
||||
unsigned int domain, fs;
|
||||
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
||||
/*
|
||||
* Get the domain register for the parent context. In user
|
||||
* mode, we don't save the DACR, so lets use what it should
|
||||
* be. For other modes, we place it after the pt_regs struct.
|
||||
*/
|
||||
if (user_mode(regs))
|
||||
if (user_mode(regs)) {
|
||||
domain = DACR_UACCESS_ENABLE;
|
||||
else
|
||||
fs = get_fs();
|
||||
} else {
|
||||
domain = to_svc_pt_regs(regs)->dacr;
|
||||
fs = to_svc_pt_regs(regs)->addr_limit;
|
||||
}
|
||||
#else
|
||||
domain = get_domain();
|
||||
fs = get_fs();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -144,7 +148,7 @@ void __show_regs(struct pt_regs *regs)
|
|||
if ((domain & domain_mask(DOMAIN_USER)) ==
|
||||
domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
|
||||
segment = "none";
|
||||
else if (get_fs() == get_ds())
|
||||
else if (fs == get_ds())
|
||||
segment = "kernel";
|
||||
else
|
||||
segment = "user";
|
||||
|
|
Loading…
Reference in a new issue