aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2016-05-13 06:40:20 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2016-07-07 11:01:01 -0400
commite6978e4bf181fb3b5f8cb6f71b4fe30fbf1b655c (patch)
treedddb20dbc9a5e594e406e71ed598039b33e0a4be
parentdd665be0e243873343a28e18f9f345927b658daf (diff)
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>
-rw-r--r--arch/arm/include/asm/ptrace.h2
-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
5 files changed, 20 insertions, 6 deletions
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 0ef0093800f2..e9c9a117bd25 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -22,7 +22,7 @@ struct pt_regs {
22struct svc_pt_regs { 22struct svc_pt_regs {
23 struct pt_regs regs; 23 struct pt_regs regs;
24 u32 dacr; 24 u32 dacr;
25 u32 unused; 25 u32 addr_limit;
26}; 26};
27 27
28#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs) 28#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
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)
109 DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); 109 DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
110 DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); 110 DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
111 DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr)); 111 DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr));
112 DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
112 DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs)); 113 DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
113 BLANK(); 114 BLANK();
114#ifdef CONFIG_CACHE_L2X0 115#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)
185 @ 185 @
186 stmia r7, {r2 - r6} 186 stmia r7, {r2 - r6}
187 187
188 get_thread_info tsk
189 ldr r0, [tsk, #TI_ADDR_LIMIT]
190 mov r1, #TASK_SIZE
191 str r1, [tsk, #TI_ADDR_LIMIT]
192 str r0, [sp, #SVC_ADDR_LIMIT]
193
188 uaccess_save r0 194 uaccess_save r0
189 .if \uaccess 195 .if \uaccess
190 uaccess_disable r0 196 uaccess_disable r0
@@ -213,7 +219,6 @@ __irq_svc:
213 irq_handler 219 irq_handler
214 220
215#ifdef CONFIG_PREEMPT 221#ifdef CONFIG_PREEMPT
216 get_thread_info tsk
217 ldr r8, [tsk, #TI_PREEMPT] @ get preempt count 222 ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
218 ldr r0, [tsk, #TI_FLAGS] @ get flags 223 ldr r0, [tsk, #TI_FLAGS] @ get flags
219 teq r8, #0 @ if preempt count != 0 224 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 @@
215 blne trace_hardirqs_off 215 blne trace_hardirqs_off
216#endif 216#endif
217 .endif 217 .endif
218 ldr r1, [sp, #SVC_ADDR_LIMIT]
218 uaccess_restore 219 uaccess_restore
220 str r1, [tsk, #TI_ADDR_LIMIT]
219 221
220#ifndef CONFIG_THUMB2_KERNEL 222#ifndef CONFIG_THUMB2_KERNEL
221 @ ARM mode SVC restore 223 @ ARM mode SVC restore
@@ -259,7 +261,9 @@
259 @ on the stack remains correct). 261 @ on the stack remains correct).
260 @ 262 @
261 .macro svc_exit_via_fiq 263 .macro svc_exit_via_fiq
264 ldr r1, [sp, #SVC_ADDR_LIMIT]
262 uaccess_restore 265 uaccess_restore
266 str r1, [tsk, #TI_ADDR_LIMIT]
263#ifndef CONFIG_THUMB2_KERNEL 267#ifndef CONFIG_THUMB2_KERNEL
264 @ ARM mode restore 268 @ ARM mode restore
265 mov r0, sp 269 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)
96 unsigned long flags; 96 unsigned long flags;
97 char buf[64]; 97 char buf[64];
98#ifndef CONFIG_CPU_V7M 98#ifndef CONFIG_CPU_V7M
99 unsigned int domain; 99 unsigned int domain, fs;
100#ifdef CONFIG_CPU_SW_DOMAIN_PAN 100#ifdef CONFIG_CPU_SW_DOMAIN_PAN
101 /* 101 /*
102 * Get the domain register for the parent context. In user 102 * Get the domain register for the parent context. In user
103 * mode, we don't save the DACR, so lets use what it should 103 * mode, we don't save the DACR, so lets use what it should
104 * be. For other modes, we place it after the pt_regs struct. 104 * be. For other modes, we place it after the pt_regs struct.
105 */ 105 */
106 if (user_mode(regs)) 106 if (user_mode(regs)) {
107 domain = DACR_UACCESS_ENABLE; 107 domain = DACR_UACCESS_ENABLE;
108 else 108 fs = get_fs();
109 } else {
109 domain = to_svc_pt_regs(regs)->dacr; 110 domain = to_svc_pt_regs(regs)->dacr;
111 fs = to_svc_pt_regs(regs)->addr_limit;
112 }
110#else 113#else
111 domain = get_domain(); 114 domain = get_domain();
115 fs = get_fs();
112#endif 116#endif
113#endif 117#endif
114 118
@@ -144,7 +148,7 @@ void __show_regs(struct pt_regs *regs)
144 if ((domain & domain_mask(DOMAIN_USER)) == 148 if ((domain & domain_mask(DOMAIN_USER)) ==
145 domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) 149 domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
146 segment = "none"; 150 segment = "none";
147 else if (get_fs() == get_ds()) 151 else if (fs == get_ds())
148 segment = "kernel"; 152 segment = "kernel";
149 else 153 else
150 segment = "user"; 154 segment = "user";