aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/process.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2015-08-19 15:40:41 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-08-26 15:34:24 -0400
commita5e090acbf545c0a3b04080f8a488b17ec41fe02 (patch)
treeae603e2e67bcac0564b2eba0a7771f8c5cebf352 /arch/arm/kernel/process.c
parent2190fed67ba6f3e8129513929f2395843645e928 (diff)
ARM: software-based priviledged-no-access support
Provide a software-based implementation of the priviledged no access support found in ARMv8.1. Userspace pages are mapped using a different domain number from the kernel and IO mappings. If we switch the user domain to "no access" when we enter the kernel, we can prevent the kernel from touching userspace. However, the kernel needs to be able to access userspace via the various user accessor functions. With the wrapping in the previous patch, we can temporarily enable access when the kernel needs user access, and re-disable it afterwards. This allows us to trap non-intended accesses to userspace, eg, caused by an inadvertent dereference of the LIST_POISON* values, which, with appropriate user mappings setup, can be made to succeed. This in turn can allow use-after-free bugs to be further exploited than would otherwise be possible. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r--arch/arm/kernel/process.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index e722f9b3c9b1..3f18098dfd08 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -129,12 +129,36 @@ void __show_regs(struct pt_regs *regs)
129 buf[4] = '\0'; 129 buf[4] = '\0';
130 130
131#ifndef CONFIG_CPU_V7M 131#ifndef CONFIG_CPU_V7M
132 printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", 132 {
133 buf, interrupts_enabled(regs) ? "n" : "ff", 133 unsigned int domain = get_domain();
134 fast_interrupts_enabled(regs) ? "n" : "ff", 134 const char *segment;
135 processor_modes[processor_mode(regs)], 135
136 isa_modes[isa_mode(regs)], 136#ifdef CONFIG_CPU_SW_DOMAIN_PAN
137 get_fs() == get_ds() ? "kernel" : "user"); 137 /*
138 * Get the domain register for the parent context. In user
139 * mode, we don't save the DACR, so lets use what it should
140 * be. For other modes, we place it after the pt_regs struct.
141 */
142 if (user_mode(regs))
143 domain = DACR_UACCESS_ENABLE;
144 else
145 domain = *(unsigned int *)(regs + 1);
146#endif
147
148 if ((domain & domain_mask(DOMAIN_USER)) ==
149 domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
150 segment = "none";
151 else if (get_fs() == get_ds())
152 segment = "kernel";
153 else
154 segment = "user";
155
156 printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n",
157 buf, interrupts_enabled(regs) ? "n" : "ff",
158 fast_interrupts_enabled(regs) ? "n" : "ff",
159 processor_modes[processor_mode(regs)],
160 isa_modes[isa_mode(regs)], segment);
161 }
138#else 162#else
139 printk("xPSR: %08lx\n", regs->ARM_cpsr); 163 printk("xPSR: %08lx\n", regs->ARM_cpsr);
140#endif 164#endif