diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2016-05-13 06:40:20 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2016-07-07 11:01:01 -0400 |
commit | e6978e4bf181fb3b5f8cb6f71b4fe30fbf1b655c (patch) | |
tree | dddb20dbc9a5e594e406e71ed598039b33e0a4be | |
parent | dd665be0e243873343a28e18f9f345927b658daf (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.h | 2 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 7 | ||||
-rw-r--r-- | arch/arm/kernel/entry-header.S | 4 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 12 |
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 { | |||
22 | struct svc_pt_regs { | 22 | struct 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"; |