From 145056ca16ba2e9fd9c38a2916ce620bc8bac86b Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Tue, 1 Oct 2019 15:42:37 +0900 Subject: [PATCH] Switch to the kernel page directory when entering the kernel (i.e. separate the kernel and user address spaces to avoid side-channel attacks on speculative execution in certain CPUs) --- kernel/arch/entry.S | 43 +++++++++++++++++++++++++++++++++++++++++++ kernel/core/process.c | 1 + 2 files changed, 44 insertions(+) diff --git a/kernel/arch/entry.S b/kernel/arch/entry.S index 77705f1..38ee530 100644 --- a/kernel/arch/entry.S +++ b/kernel/arch/entry.S @@ -16,6 +16,8 @@ * along with Corax. If not, see . */ +#define __ASSEMBLY_SOURCE + #include #include "defs.h" @@ -78,6 +80,9 @@ .global _int_entry_common .global _int_restore +.extern _cpu +.extern _kernel_cr3 + .extern _exc_handle .extern _int_handle .extern _sys_handle @@ -329,6 +334,44 @@ _int_entry_common: movw %ax, %fs movw %ax, %gs + /* switch to the kernel page directory, if we're not already using it */ + movl (_kernel_cr3), %eax + movl %cr3, %ebx + cmpl %eax, %ebx + je _already_in_kernel + + movl %eax, %cr3 + + /* + * When the privilege level changes during an interrupt, the kernel + * automatically performs a stack switch, however it does not switch page + * directories, meaning we have no choice but to map the per-task kernel + * stack into the task's page directory and save the context there. We + * then manually switch to the kernel page directory. However, the task's + * kernel stack is at a different location in the kernel's page directory + * (i.e. its linear address), so we have to adjust the stack pointer before + * we can use the stack. + */ + + cpuidx %ecx + movl $_cpu, %eax +0: subl $1, %ecx + js 1f + addl $CPU_SIZE, %eax + jmp 0b + + /* reduce esp to the offset into the stack, then add the linear stack base */ +1: movl OFFSET_CPU_CTASK(%eax), %eax + subl $CONFIG_KERNEL_STACK_BASE, %esp + addl OFFSET_TASK_KSTACK(%eax), %esp + + /* do the same with ebp */ + subl $CONFIG_KERNEL_STACK_BASE, %ebp + addl OFFSET_TASK_KSTACK(%eax), %ebp + + /* we can now use the stack */ + +_already_in_kernel: cmp $EXC_MAX, 36(%esp) jl 0f diff --git a/kernel/core/process.c b/kernel/core/process.c index 8562f51..387907c 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -53,6 +53,7 @@ int process_create(process_t **dst, u32_t ppl, void *entry) proc->p_tasks->t_sp = (u32_t)(CONFIG_KERNEL_STACK_BASE + ((u32_t)proc->p_tasks->t_sp - (u32_t)kstack)); + proc->p_tasks->t_kstack = kstack; proc->p_tasks->t_tslice = 50; proc->p_tasks->t_rslice = 50; -- 2.47.3