From 045431b2de05f81582cf85c7ed40585e08fd74da Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Thu, 18 Nov 2021 19:47:28 +0900 Subject: [PATCH] kernel: prevent modules from being loaded multiple times --- base/usr/include/kernel/arch/x86_64/mmu.h | 1 + kernel/arch/x86_64/mmu.c | 24 +++++++++++++++ kernel/generic.c | 2 ++ kernel/misc/elf64.c | 36 ++++++++++++++++++----- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/base/usr/include/kernel/arch/x86_64/mmu.h b/base/usr/include/kernel/arch/x86_64/mmu.h index e815601d..298c3492 100644 --- a/base/usr/include/kernel/arch/x86_64/mmu.h +++ b/base/usr/include/kernel/arch/x86_64/mmu.h @@ -36,6 +36,7 @@ union PML * mmu_get_kernel_directory(void); void * mmu_map_from_physical(uintptr_t frameaddress); void * mmu_map_mmio_region(uintptr_t physical_address, size_t size); void * mmu_map_module(size_t size); +void mmu_unmap_module(uintptr_t base_address, size_t size); size_t mmu_count_user(union PML * from); size_t mmu_count_shm(union PML * from); diff --git a/kernel/arch/x86_64/mmu.c b/kernel/arch/x86_64/mmu.c index f6d54eb8..ee49e5e3 100644 --- a/kernel/arch/x86_64/mmu.c +++ b/kernel/arch/x86_64/mmu.c @@ -905,6 +905,30 @@ void * mmu_map_module(size_t size) { return out; } +void mmu_unmap_module(uintptr_t start_address, size_t size) { + if ((size & PAGE_LOW_MASK) || (start_address & PAGE_LOW_MASK)) { + arch_fatal_prepare(); + printf("mmu_unmap_module start and size must be multiple of page size %#zx:%#zx.\n", start_address, size); + arch_dump_traceback(); + arch_fatal(); + } + + spin_lock(module_space_lock); + uintptr_t end_address = start_address + size; + + /* Unmap all pages we just allocated */ + for (uintptr_t i = start_address; i < end_address; i += 0x1000) { + union PML * p = mmu_get_page(i, 0); + mmu_frame_clear(p->bits.page << 12); + } + + /* Reset module base address if it was at the end, to avoid wasting address space */ + if (end_address == module_base_address) { + module_base_address = start_address; + } + spin_unlock(module_space_lock); +} + int mmu_validate_user_pointer(void * addr, size_t size, int flags) { if (addr == NULL && !(flags & MMU_PTR_NULL)) return 0; diff --git a/kernel/generic.c b/kernel/generic.c index 9b60fd1f..10a4d0b3 100644 --- a/kernel/generic.c +++ b/kernel/generic.c @@ -28,6 +28,7 @@ extern int system(const char * path, int argc, const char ** argv, const char ** extern void snd_install(void); extern void net_install(void); extern void console_initialize(void); +extern void modules_install(void); void generic_startup(void) { args_parse(arch_get_cmdline()); @@ -45,6 +46,7 @@ void generic_startup(void) { snd_install(); net_install(); tasking_start(); + modules_install(); } int generic_main(void) { diff --git a/kernel/misc/elf64.c b/kernel/misc/elf64.c index 7c793ec8..e594fcf7 100644 --- a/kernel/misc/elf64.c +++ b/kernel/misc/elf64.c @@ -20,14 +20,22 @@ #include #include #include +#include -static hashmap_t * _modules_table = NULL; +hashmap_t * _modules_table = NULL; +sched_mutex_t * _modules_mutex = NULL; + +void modules_install(void) { + _modules_table = hashmap_create(10); + _modules_mutex = mutex_init("module loader"); +} hashmap_t * modules_get_list(void) { return _modules_table; } int elf_module(char ** args) { + int error = 0; Elf64_Header header; fs_node_t * file = kopen(args[0],0); @@ -49,14 +57,18 @@ int elf_module(char ** args) { if (header.e_ident[EI_CLASS] != ELFCLASS64) { printf("(Wrong Elf class)\n"); + close_fs(file); return -EINVAL; } if (header.e_type != ET_REL) { printf("(Not a relocatable object)\n"); + close_fs(file); return -EINVAL; } + mutex_acquire(_modules_mutex); + /* Just slap the whole thing into memory, why not... */ char * module_load_address = mmu_map_module(file->length); read_fs(file, 0, file->length, (void*)module_load_address); @@ -119,8 +131,8 @@ int elf_module(char ** args) { } if (!moduleData) { - printf("No module data, bailing.\n"); - return -EINVAL; + error = EINVAL; + goto _unmap_module; } for (unsigned int i = 0; i < header.e_shnum; ++i) { @@ -149,14 +161,15 @@ int elf_module(char ** args) { *(uint32_t*)target = symbolTable[ELF64_R_SYM(table[rela].r_info)].st_value + table[rela].r_addend - target; break; default: - printf("Unsupported relocation: %ld\n", ELF64_R_TYPE(table[rela].r_info)); - return -EINVAL; + error = EINVAL; + goto _unmap_module; } } } - if (!_modules_table) { - _modules_table = hashmap_create(10); + if (hashmap_has(_modules_table, moduleData->name)) { + error = EEXIST; + goto _unmap_module; } struct LoadedModule * loadedData = malloc(sizeof(struct LoadedModule)); @@ -168,12 +181,21 @@ int elf_module(char ** args) { close_fs(file); hashmap_set(_modules_table, moduleData->name, loadedData); + mutex_release(_modules_mutex); /* Count arguments */ int argc = 0; for (char ** aa = args; *aa; ++aa) ++argc; return moduleData->init(argc, args); + +_unmap_module: + close_fs(file); + + mmu_unmap_module((uintptr_t)module_load_address, (uintptr_t)mmu_map_module(0) - (uintptr_t)module_load_address); + + mutex_release(_modules_mutex); + return -error; } int elf_exec(const char * path, fs_node_t * file, int argc, const char *const argv[], const char *const env[], int interp) {