mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
x86-64: enable smep and smap
This commit is contained in:
@@ -12,6 +12,11 @@
|
|||||||
#include <arch/prof.h>
|
#include <arch/prof.h>
|
||||||
|
|
||||||
#define EFER_SYSCALLENABLE 1
|
#define EFER_SYSCALLENABLE 1
|
||||||
|
#define CR4_SMEP (1 << 20)
|
||||||
|
#define CR4_SMAP (1 << 21)
|
||||||
|
|
||||||
|
static bool has_smap;
|
||||||
|
static bool has_smap_detected;
|
||||||
|
|
||||||
void arch_syscall_entry();
|
void arch_syscall_entry();
|
||||||
static void illisr(isr_t *self, context_t *ctx) {
|
static void illisr(isr_t *self, context_t *ctx) {
|
||||||
@@ -61,6 +66,55 @@ static void reload_ldt(isr_t *self, context_t *ctx) {
|
|||||||
arch_ldt_invalidate();
|
arch_ldt_invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void enable_smep_if_available(void) {
|
||||||
|
if (cpuid_base_max_leaf() < 7)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpuid_results_t results;
|
||||||
|
cpuid_with_ecx(7, 0, &results);
|
||||||
|
if ((results.ebx & CPUID_LEAF_7_EBX_SMEP) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t cr4;
|
||||||
|
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
||||||
|
cr4 |= CR4_SMEP;
|
||||||
|
asm volatile("mov %0, %%cr4" : : "r"(cr4) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool detect_smap(void) {
|
||||||
|
if (cpuid_base_max_leaf() < 7)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cpuid_results_t results;
|
||||||
|
cpuid_with_ecx(7, 0, &results);
|
||||||
|
return results.ebx & CPUID_LEAF_7_EBX_SMAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enable_smap_if_available(void) {
|
||||||
|
if (!has_smap_detected) {
|
||||||
|
has_smap = detect_smap();
|
||||||
|
has_smap_detected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_smap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t cr4;
|
||||||
|
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
||||||
|
cr4 |= CR4_SMAP;
|
||||||
|
asm volatile("mov %0, %%cr4" : : "r"(cr4) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void arch_cpu_user_access_begin(void) {
|
||||||
|
if (has_smap)
|
||||||
|
asm volatile("stac" : : : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void arch_cpu_user_access_end(void) {
|
||||||
|
if (has_smap)
|
||||||
|
asm volatile("clac" : : : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
void arch_nmi_isr(context_t *ctx) {
|
void arch_nmi_isr(context_t *ctx) {
|
||||||
// we are in an NMI context, running on IST0
|
// we are in an NMI context, running on IST0
|
||||||
// first load the proper gsbase to get access to cpu-local variables.
|
// first load the proper gsbase to get access to cpu-local variables.
|
||||||
@@ -227,6 +281,8 @@ void arch_cpu_init() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
x86_64_mmu_enable_global_pages();
|
x86_64_mmu_enable_global_pages();
|
||||||
|
enable_smep_if_available();
|
||||||
|
enable_smap_if_available();
|
||||||
|
|
||||||
// register some exception handlers that give out signals
|
// register some exception handlers that give out signals
|
||||||
interrupt_register(0, sigfpeisr, NULL, IPL_IGNORE);
|
interrupt_register(0, sigfpeisr, NULL, IPL_IGNORE);
|
||||||
|
|||||||
@@ -324,7 +324,14 @@ static volatile struct limine_executable_address_request kaddrreq = {
|
|||||||
#define ERROR_FETCH 16
|
#define ERROR_FETCH 16
|
||||||
|
|
||||||
static void pfisr(isr_t *self, context_t *ctx) {
|
static void pfisr(isr_t *self, context_t *ctx) {
|
||||||
|
if ((ctx->rflags & ARCH_CONTEXT_RFLAGS_AC) == 0 && IS_USER_ADDRESS((void *)ctx->cr2) && !IS_USER_ADDRESS((void *)ctx->rip)) {
|
||||||
|
_panic("SMAP/SMEP violation", ctx);
|
||||||
|
}
|
||||||
|
|
||||||
thread_t *thread = current_thread();
|
thread_t *thread = current_thread();
|
||||||
|
if (thread && thread->usercopyctx)
|
||||||
|
arch_cpu_user_access_end();
|
||||||
|
|
||||||
interrupt_set(true);
|
interrupt_set(true);
|
||||||
int vmmerror = 0;
|
int vmmerror = 0;
|
||||||
|
|
||||||
@@ -338,6 +345,7 @@ static void pfisr(isr_t *self, context_t *ctx) {
|
|||||||
if (vmm_pagefault((void *)ctx->cr2, ctx->cs != 8, vmmerror) == false) {
|
if (vmm_pagefault((void *)ctx->cr2, ctx->cs != 8, vmmerror) == false) {
|
||||||
if (thread && thread->usercopyctx) {
|
if (thread && thread->usercopyctx) {
|
||||||
memcpy(ctx, thread->usercopyctx, sizeof(context_t));
|
memcpy(ctx, thread->usercopyctx, sizeof(context_t));
|
||||||
|
ctx->rflags &= ~ARCH_CONTEXT_RFLAGS_AC;
|
||||||
thread->usercopyctx = NULL;
|
thread->usercopyctx = NULL;
|
||||||
CTX_RET(ctx) = EFAULT;
|
CTX_RET(ctx) = EFAULT;
|
||||||
} else if (ARCH_CONTEXT_ISUSER(ctx)) {
|
} else if (ARCH_CONTEXT_ISUSER(ctx)) {
|
||||||
@@ -361,7 +369,9 @@ static void gpfisr(isr_t *self, context_t *ctx) {
|
|||||||
|
|
||||||
thread_t *thread = current_thread();
|
thread_t *thread = current_thread();
|
||||||
if (thread && thread->usercopyctx) {
|
if (thread && thread->usercopyctx) {
|
||||||
|
arch_cpu_user_access_end();
|
||||||
memcpy(ctx, thread->usercopyctx, sizeof(context_t));
|
memcpy(ctx, thread->usercopyctx, sizeof(context_t));
|
||||||
|
ctx->rflags &= ~ARCH_CONTEXT_RFLAGS_AC;
|
||||||
thread->usercopyctx = NULL;
|
thread->usercopyctx = NULL;
|
||||||
CTX_RET(ctx) = EFAULT;
|
CTX_RET(ctx) = EFAULT;
|
||||||
} else if (ARCH_CONTEXT_ISUSER(ctx)) {
|
} else if (ARCH_CONTEXT_ISUSER(ctx)) {
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ extern size_t arch_xsave_size;
|
|||||||
#define CTX_ARG1(x) (x)->rsi
|
#define CTX_ARG1(x) (x)->rsi
|
||||||
#define CTX_ARG2(x) (x)->rdx
|
#define CTX_ARG2(x) (x)->rdx
|
||||||
|
|
||||||
|
#define ARCH_CONTEXT_RFLAGS_AC (1 << 18)
|
||||||
|
|
||||||
#define PRINT_CTX(x) { \
|
#define PRINT_CTX(x) { \
|
||||||
printf("cr2: %016lx gs: %04x\nrax: %016lx fs: %04x\nrbx: %016lx es: %04x\nrcx: %016lx ds: %04x\nrdx: %016lx cs: %04x\n r8: %016lx ss: %04x\n r9: %016lx r10: %016lx\nr11: %016lx r12: %016lx\nr13: %016lx r14: %016lx\nr15: %016lx rdi: %016lx\nrsi: %016lx rbp: %016lx\nrip: %016lx rsp: %016lx\nerr: %016lx rfl: %016lx\n", \
|
printf("cr2: %016lx gs: %04x\nrax: %016lx fs: %04x\nrbx: %016lx es: %04x\nrcx: %016lx ds: %04x\nrdx: %016lx cs: %04x\n r8: %016lx ss: %04x\n r9: %016lx r10: %016lx\nr11: %016lx r12: %016lx\nr13: %016lx r14: %016lx\nr15: %016lx rdi: %016lx\nrsi: %016lx rbp: %016lx\nrip: %016lx rsp: %016lx\nerr: %016lx rfl: %016lx\n", \
|
||||||
x->cr2, x->gs, x->rax, x->fs, x->rbx, x->es, x->rcx, x->ds, x->rdx, x->cs, x->r8, x->ss, x->r9, x->r10, x->r11, x->r12, x->r13, x->r14, x->r15, x->rdi, x->rsi, x->rbp, x->rip, x->rsp, x->error, x->rflags); \
|
x->cr2, x->gs, x->rax, x->fs, x->rbx, x->es, x->rcx, x->ds, x->rdx, x->cs, x->r8, x->ss, x->r9, x->r10, x->r11, x->r12, x->r13, x->r14, x->r15, x->rdi, x->rsi, x->rbp, x->rip, x->rsp, x->error, x->rflags); \
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ static inline uint16_t be_to_cpu_w(uint16_t w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cpu_t *get_bsp(void);
|
cpu_t *get_bsp(void);
|
||||||
|
void arch_cpu_user_access_begin(void);
|
||||||
|
void arch_cpu_user_access_end(void);
|
||||||
|
|
||||||
static inline thread_t *current_thread(void) {
|
static inline thread_t *current_thread(void) {
|
||||||
thread_t *thread;
|
thread_t *thread;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ typedef struct {
|
|||||||
#define CPUID_LEAF_0x80000001_EDX_SYSCALL (1 << 11)
|
#define CPUID_LEAF_0x80000001_EDX_SYSCALL (1 << 11)
|
||||||
#define CPUID_LEAF_1_EDX_TSC (1 << 4)
|
#define CPUID_LEAF_1_EDX_TSC (1 << 4)
|
||||||
#define CPUID_LEAF_1_EDX_HTT (1 << 28)
|
#define CPUID_LEAF_1_EDX_HTT (1 << 28)
|
||||||
|
#define CPUID_LEAF_7_EBX_SMEP (1 << 7)
|
||||||
|
#define CPUID_LEAF_7_EBX_SMAP (1 << 20)
|
||||||
|
|
||||||
static inline void cpuid_with_ecx(uint32_t leaf, uint32_t ecx, cpuid_results_t *cpuid_results) {
|
static inline void cpuid_with_ecx(uint32_t leaf, uint32_t ecx, cpuid_results_t *cpuid_results) {
|
||||||
asm volatile ("cpuid"
|
asm volatile ("cpuid"
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buff
|
|||||||
size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset;
|
size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset;
|
||||||
size_t copy_current = min(remaining_current, remaining_total);
|
size_t copy_current = min(remaining_current, remaining_total);
|
||||||
|
|
||||||
error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), (void *)((uintptr_t)buffer + total_done), copy_current);
|
error = USERCOPY_POSSIBLY_TO_USER((void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), (void *)((uintptr_t)buffer + total_done), copy_current);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ static void memcpyinternal(context_t *ctx, void *arg) {
|
|||||||
// this context with CTX_RET set to EFAULT
|
// this context with CTX_RET set to EFAULT
|
||||||
current_thread()->usercopyctx = ctx;
|
current_thread()->usercopyctx = ctx;
|
||||||
|
|
||||||
|
arch_cpu_user_access_begin();
|
||||||
memcpy(desc->dst, desc->src, desc->size);
|
memcpy(desc->dst, desc->src, desc->size);
|
||||||
|
arch_cpu_user_access_end();
|
||||||
|
|
||||||
// no errors!
|
// no errors!
|
||||||
CTX_RET(ctx) = 0;
|
CTX_RET(ctx) = 0;
|
||||||
@@ -45,7 +47,9 @@ static void strleninternal(context_t *ctx, void *arg) {
|
|||||||
// this context with CTX_RET set to EFAULT
|
// this context with CTX_RET set to EFAULT
|
||||||
current_thread()->usercopyctx = ctx;
|
current_thread()->usercopyctx = ctx;
|
||||||
|
|
||||||
|
arch_cpu_user_access_begin();
|
||||||
*desc->size = strlen(desc->str);
|
*desc->size = strlen(desc->str);
|
||||||
|
arch_cpu_user_access_end();
|
||||||
|
|
||||||
// no errors!
|
// no errors!
|
||||||
CTX_RET(ctx) = 0;
|
CTX_RET(ctx) = 0;
|
||||||
@@ -59,7 +63,9 @@ static void atomic32internal(context_t *ctx, void *arg) {
|
|||||||
// this context with CTX_RET set to EFAULT
|
// this context with CTX_RET set to EFAULT
|
||||||
current_thread()->usercopyctx = ctx;
|
current_thread()->usercopyctx = ctx;
|
||||||
|
|
||||||
|
arch_cpu_user_access_begin();
|
||||||
__atomic_load(desc->address, desc->value, __ATOMIC_SEQ_CST);
|
__atomic_load(desc->address, desc->value, __ATOMIC_SEQ_CST);
|
||||||
|
arch_cpu_user_access_end();
|
||||||
|
|
||||||
// no errors!
|
// no errors!
|
||||||
CTX_RET(ctx) = 0;
|
CTX_RET(ctx) = 0;
|
||||||
@@ -73,7 +79,9 @@ static void memset_internal(context_t *ctx, void *arg) {
|
|||||||
// this context with CTX_RET set to EFAULT
|
// this context with CTX_RET set to EFAULT
|
||||||
current_thread()->usercopyctx = ctx;
|
current_thread()->usercopyctx = ctx;
|
||||||
|
|
||||||
|
arch_cpu_user_access_begin();
|
||||||
memset(desc->dst, desc->byte, desc->size);
|
memset(desc->dst, desc->byte, desc->size);
|
||||||
|
arch_cpu_user_access_end();
|
||||||
|
|
||||||
// no errors!
|
// no errors!
|
||||||
CTX_RET(ctx) = 0;
|
CTX_RET(ctx) = 0;
|
||||||
|
|||||||
+16
-3
@@ -4,6 +4,8 @@
|
|||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#include <kernel/vmm.h>
|
#include <kernel/vmm.h>
|
||||||
|
#include <kernel/usercopy.h>
|
||||||
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
#define ARCH_ELF_BITS 2
|
#define ARCH_ELF_BITS 2
|
||||||
@@ -72,7 +74,10 @@ static int load(vnode_t *vnode, elfph64_t *ph) {
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
memset(page, 0, firstpageoffset);
|
error = usercopy_memset(page, 0, firstpageoffset);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
mempos += firstpagecount;
|
mempos += firstpagecount;
|
||||||
msize -= firstpagecount;
|
msize -= firstpagecount;
|
||||||
fsize -= firstpagecount;
|
fsize -= firstpagecount;
|
||||||
@@ -85,7 +90,10 @@ static int load(vnode_t *vnode, elfph64_t *ph) {
|
|||||||
if (remainingmsize > ROUND_UP(mempos, PAGE_SIZE) - mempos)
|
if (remainingmsize > ROUND_UP(mempos, PAGE_SIZE) - mempos)
|
||||||
remainingmsize = pagediff;
|
remainingmsize = pagediff;
|
||||||
|
|
||||||
memset((void *)mempos, 0, remainingmsize);
|
error = usercopy_memset((void *)mempos, 0, remainingmsize);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
msize -= remainingmsize;
|
msize -= remainingmsize;
|
||||||
mempos += remainingmsize;
|
mempos += remainingmsize;
|
||||||
}
|
}
|
||||||
@@ -121,7 +129,10 @@ static int load(vnode_t *vnode, elfph64_t *ph) {
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
memset((void *)(mempos + lastpagecount), 0, PAGE_SIZE - lastpagecount);
|
error = usercopy_memset((void *)(mempos + lastpagecount), 0, PAGE_SIZE - lastpagecount);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
msize -= msize > PAGE_SIZE ? PAGE_SIZE : msize;
|
msize -= msize > PAGE_SIZE ? PAGE_SIZE : msize;
|
||||||
|
|
||||||
error = vmm_changemmuflags((void *)mempos, PAGE_SIZE, mmuflags, 0);
|
error = vmm_changemmuflags((void *)mempos, PAGE_SIZE, mmuflags, 0);
|
||||||
@@ -266,6 +277,7 @@ void *elf_preparestack(void *top, auxv64list_t *auxv64, char **argv, char **envp
|
|||||||
char **argstart = (char **)envstart - argc - 1;
|
char **argstart = (char **)envstart - argc - 1;
|
||||||
size_t *argcptr = (size_t *)argstart - 1;
|
size_t *argcptr = (size_t *)argstart - 1;
|
||||||
|
|
||||||
|
arch_cpu_user_access_begin();
|
||||||
auxv64->execfn.type = AT_EXECFN;
|
auxv64->execfn.type = AT_EXECFN;
|
||||||
auxv64->execfn.val = (uint64_t)pathdatastart;
|
auxv64->execfn.val = (uint64_t)pathdatastart;
|
||||||
|
|
||||||
@@ -289,5 +301,6 @@ void *elf_preparestack(void *top, auxv64list_t *auxv64, char **argv, char **envp
|
|||||||
*envstart = NULL;
|
*envstart = NULL;
|
||||||
*argcptr = argc;
|
*argcptr = argc;
|
||||||
|
|
||||||
|
arch_cpu_user_access_end();
|
||||||
return argcptr;
|
return argcptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ __attribute__((noreturn)) void syscall_sigreturn(context_t *context) {
|
|||||||
|
|
||||||
__assert(ARCH_CONTEXT_ISUSER(&sigframe->context));
|
__assert(ARCH_CONTEXT_ISUSER(&sigframe->context));
|
||||||
|
|
||||||
|
// XXX TODO FIXME there is a bug here that needs this temporarily.
|
||||||
|
arch_cpu_user_access_begin();
|
||||||
arch_extracontext_copy(¤t_thread()->extracontext, &sigframe->extracontext);
|
arch_extracontext_copy(¤t_thread()->extracontext, &sigframe->extracontext);
|
||||||
|
arch_cpu_user_access_end();
|
||||||
ARCH_CONTEXT_THREADLOAD(current_thread(), context);
|
ARCH_CONTEXT_THREADLOAD(current_thread(), context);
|
||||||
arch_context_switch(&sigframe->context);
|
arch_context_switch(&sigframe->context);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user