Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+20 -6
+1 -1
arch/arm/include/asm/ptrace.h
··· 22 22 struct svc_pt_regs { 23 23 struct pt_regs regs; 24 24 u32 dacr; 25 - u32 unused; 25 + u32 addr_limit; 26 26 }; 27 27 28 28 #define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
+1
arch/arm/kernel/asm-offsets.c
··· 109 109 DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); 110 110 DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); 111 111 DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr)); 112 + DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit)); 112 113 DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs)); 113 114 BLANK(); 114 115 #ifdef CONFIG_CACHE_L2X0
+6 -1
arch/arm/kernel/entry-armv.S
··· 185 185 @ 186 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 194 uaccess_save r0 189 195 .if \uaccess 190 196 uaccess_disable r0 ··· 219 213 irq_handler 220 214 221 215 #ifdef CONFIG_PREEMPT 222 - get_thread_info tsk 223 216 ldr r8, [tsk, #TI_PREEMPT] @ get preempt count 224 217 ldr r0, [tsk, #TI_FLAGS] @ get flags 225 218 teq r8, #0 @ if preempt count != 0
+4
arch/arm/kernel/entry-header.S
··· 215 215 blne trace_hardirqs_off 216 216 #endif 217 217 .endif 218 + ldr r1, [sp, #SVC_ADDR_LIMIT] 218 219 uaccess_restore 220 + str r1, [tsk, #TI_ADDR_LIMIT] 219 221 220 222 #ifndef CONFIG_THUMB2_KERNEL 221 223 @ ARM mode SVC restore ··· 261 259 @ on the stack remains correct). 262 260 @ 263 261 .macro svc_exit_via_fiq 262 + ldr r1, [sp, #SVC_ADDR_LIMIT] 264 263 uaccess_restore 264 + str r1, [tsk, #TI_ADDR_LIMIT] 265 265 #ifndef CONFIG_THUMB2_KERNEL 266 266 @ ARM mode restore 267 267 mov r0, sp
+8 -4
arch/arm/kernel/process.c
··· 96 96 unsigned long flags; 97 97 char buf[64]; 98 98 #ifndef CONFIG_CPU_V7M 99 - unsigned int domain; 99 + unsigned int domain, fs; 100 100 #ifdef CONFIG_CPU_SW_DOMAIN_PAN 101 101 /* 102 102 * Get the domain register for the parent context. In user 103 103 * mode, we don't save the DACR, so lets use what it should 104 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 107 domain = DACR_UACCESS_ENABLE; 108 - else 108 + fs = get_fs(); 109 + } else { 109 110 domain = to_svc_pt_regs(regs)->dacr; 111 + fs = to_svc_pt_regs(regs)->addr_limit; 112 + } 110 113 #else 111 114 domain = get_domain(); 115 + fs = get_fs(); 112 116 #endif 113 117 #endif 114 118 ··· 148 144 if ((domain & domain_mask(DOMAIN_USER)) == 149 145 domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) 150 146 segment = "none"; 151 - else if (get_fs() == get_ds()) 147 + else if (fs == get_ds()) 152 148 segment = "kernel"; 153 149 else 154 150 segment = "user";