summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2016-05-13 12:40:20 +0200
committerRussell King <rmk+kernel@armlinux.org.uk>2016-07-07 17:01:01 +0200
commite6978e4bf181fb3b5f8cb6f71b4fe30fbf1b655c (patch)
treedddb20dbc9a5e594e406e71ed598039b33e0a4be /arch/arm/kernel
parentARM: 8584/1: floppy: avoid gcc-6 warning (diff)
downloadlinux-e6978e4bf181fb3b5f8cb6f71b4fe30fbf1b655c.tar.xz
linux-e6978e4bf181fb3b5f8cb6f71b4fe30fbf1b655c.zip
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>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/asm-offsets.c1
-rw-r--r--arch/arm/kernel/entry-armv.S7
-rw-r--r--arch/arm/kernel/entry-header.S4
-rw-r--r--arch/arm/kernel/process.c12
4 files changed, 19 insertions, 5 deletions
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 9a8ce342cd82..608008229c7d 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -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
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0d6f5413be18..bc5f50799d75 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -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
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5e1d029147cb..6391728c8f03 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -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
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f1c720c0d568..612eb530f33f 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -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";