Skip to content

Commit 71f8af1

Browse files
author
Russell King
committed
ARM: uaccess: fix DACR mismatch with nested exceptions
Tomas Paukrt reports that his SAM9X60 based system (ARM926, ARMv5TJ) fails to fix up alignment faults, eventually resulting in a kernel oops. The problem occurs when using CONFIG_CPU_USE_DOMAINS with commit e6978e4 ("ARM: save and reset the address limit when entering an exception"). This is because the address limit is set back to TASK_SIZE on exception entry, and, although it is restored on exception exit, the domain register is not. Hence, this sequence can occur: interrupt pt_regs->addr_limit = addr_limit // USER_DS addr_limit = USER_DS alignment exception __probe_kernel_read() old_fs = get_fs() // USER_DS set_fs(KERNEL_DS) addr_limit = KERNEL_DS dacr.kernel = DOMAIN_MANAGER interrupt pt_regs->addr_limit = addr_limit // KERNEL_DS addr_limit = USER_DS alignment exception __probe_kernel_read() old_fs = get_fs() // USER_DS set_fs(KERNEL_DS) addr_limit = KERNEL_DS dacr.kernel = DOMAIN_MANAGER ... set_fs(old_fs) addr_limit = USER_DS dacr.kernel = DOMAIN_CLIENT ... addr_limit = pt_regs->addr_limit // KERNEL_DS interrupt returns At this point, addr_limit is correctly restored to KERNEL_DS for __probe_kernel_read() to continue execution, but dacr.kernel is not, it has been reset by the set_fs(old_fs) to DOMAIN_CLIENT. This would not have happened prior to the mentioned commit, because addr_limit would remain KERNEL_DS, so get_fs() would have returned KERNEL_DS, and so would correctly nest. This commit fixes the problem by also saving the DACR on exception entry if either CONFIG_CPU_SW_DOMAIN_PAN or CONFIG_CPU_USE_DOMAINS are enabled, and resetting the DACR appropriately on exception entry to match addr_limit and PAN settings. Fixes: e6978e4 ("ARM: save and reset the address limit when entering an exception") Reported-by: Tomas Paukrt <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 8ede890 commit 71f8af1

File tree

1 file changed

+20
-5
lines changed

1 file changed

+20
-5
lines changed

arch/arm/include/asm/uaccess-asm.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,21 @@
6767
#endif
6868
.endm
6969

70-
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
70+
#if defined(CONFIG_CPU_SW_DOMAIN_PAN) || defined(CONFIG_CPU_USE_DOMAINS)
7171
#define DACR(x...) x
7272
#else
7373
#define DACR(x...)
7474
#endif
7575

7676
/*
77-
* Save the address limit on entry to a privileged exception and
78-
* if using PAN, save and disable usermode access.
77+
* Save the address limit on entry to a privileged exception.
78+
*
79+
* If we are using the DACR for kernel access by the user accessors
80+
* (CONFIG_CPU_USE_DOMAINS=y), always reset the DACR kernel domain
81+
* back to client mode, whether or not \disable is set.
82+
*
83+
* If we are using SW PAN, set the DACR user domain to no access
84+
* if \disable is set.
7985
*/
8086
.macro uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
8187
ldr \tmp1, [\tsk, #TI_ADDR_LIMIT]
@@ -84,8 +90,17 @@
8490
DACR( mrc p15, 0, \tmp0, c3, c0, 0)
8591
DACR( str \tmp0, [sp, #SVC_DACR])
8692
str \tmp1, [sp, #SVC_ADDR_LIMIT]
87-
.if \disable
88-
uaccess_disable \tmp0
93+
.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
94+
/* kernel=client, user=no access */
95+
mov \tmp2, #DACR_UACCESS_DISABLE
96+
mcr p15, 0, \tmp2, c3, c0, 0
97+
instr_sync
98+
.elseif IS_ENABLED(CONFIG_CPU_USE_DOMAINS)
99+
/* kernel=client */
100+
bic \tmp2, \tmp0, #domain_mask(DOMAIN_KERNEL)
101+
orr \tmp2, \tmp2, #domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT)
102+
mcr p15, 0, \tmp2, c3, c0, 0
103+
instr_sync
89104
.endif
90105
.endm
91106

0 commit comments

Comments
 (0)