From: Tulio A M Mendes Date: Fri, 6 Feb 2026 14:08:03 +0000 (-0300) Subject: kernel: centralize user pointer access (uaccess) X-Git-Url: https://projects.tadryanom.me/sitemap.xml?a=commitdiff_plain;h=ebc5feee8decb33fd7ab56d89ae142525775d3c0;p=AdrOS.git kernel: centralize user pointer access (uaccess) --- diff --git a/Makefile b/Makefile index 2a2f7a7..878c26d 100644 --- a/Makefile +++ b/Makefile @@ -104,7 +104,7 @@ run: iso @rm -f serial.log qemu.log @qemu-system-i386 -boot d -cdrom adros-$(ARCH).iso -m 128M -display none \ -serial file:serial.log -monitor none -no-reboot -no-shutdown \ - -d int,cpu_reset,guest_errors -D qemu.log + $(if $(QEMU_DEBUG),-d guest_errors -D qemu.log,) $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c @mkdir -p $(dir $@) diff --git a/include/uaccess.h b/include/uaccess.h new file mode 100644 index 0000000..99016dd --- /dev/null +++ b/include/uaccess.h @@ -0,0 +1,10 @@ +#ifndef UACCESS_H +#define UACCESS_H + +#include + +int user_range_ok(const void* user_ptr, size_t len); +int copy_from_user(void* dst, const void* src_user, size_t len); +int copy_to_user(void* dst_user, const void* src, size_t len); + +#endif diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 61ba78b..4d094fe 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -1,52 +1,10 @@ #include "syscall.h" #include "idt.h" #include "uart_console.h" +#include "uaccess.h" #include -#if defined(__i386__) -#define X86_KERNEL_VIRT_BASE 0xC0000000U - -static int x86_user_range_basic_ok(uintptr_t uaddr, size_t len) { - if (len == 0) return 1; - if (uaddr == 0) return 0; - if (uaddr >= X86_KERNEL_VIRT_BASE) return 0; - uintptr_t end = uaddr + len - 1; - if (end < uaddr) return 0; - if (end >= X86_KERNEL_VIRT_BASE) return 0; - return 1; -} - -static int x86_user_page_present_and_user(uintptr_t vaddr) { - volatile uint32_t* pd = (volatile uint32_t*)0xFFFFF000U; - volatile uint32_t* pt_base = (volatile uint32_t*)0xFFC00000U; - - uint32_t pde = pd[vaddr >> 22]; - if (!(pde & 0x1)) return 0; - if (!(pde & 0x4)) return 0; - - volatile uint32_t* pt = pt_base + ((vaddr >> 22) << 10); - uint32_t pte = pt[(vaddr >> 12) & 0x3FF]; - if (!(pte & 0x1)) return 0; - if (!(pte & 0x4)) return 0; - - return 1; -} - -static int x86_user_range_mapped_and_user(uintptr_t uaddr, size_t len) { - if (!x86_user_range_basic_ok(uaddr, len)) return 0; - if (len == 0) return 1; - - uintptr_t start = uaddr & ~(uintptr_t)0xFFF; - uintptr_t end = (uaddr + len - 1) & ~(uintptr_t)0xFFF; - for (uintptr_t va = start;; va += 0x1000) { - if (!x86_user_page_present_and_user(va)) return 0; - if (va == end) break; - } - return 1; -} -#endif - static void syscall_handler(struct registers* regs) { uint32_t syscall_no = regs->eax; @@ -65,12 +23,10 @@ static void syscall_handler(struct registers* regs) { return; } -#if defined(__i386__) - if (!x86_user_range_mapped_and_user((uintptr_t)buf, (size_t)len)) { + if (user_range_ok(buf, (size_t)len) == 0) { regs->eax = (uint32_t)-1; return; } -#endif char kbuf[256]; uint32_t remaining = len; @@ -80,16 +36,10 @@ static void syscall_handler(struct registers* regs) { uint32_t chunk = remaining; if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf); -#if defined(__i386__) - if (!x86_user_range_mapped_and_user(up, (size_t)chunk)) { + if (copy_from_user(kbuf, (const void*)up, (size_t)chunk) < 0) { regs->eax = (uint32_t)-1; return; } -#endif - - for (uint32_t i = 0; i < chunk; i++) { - kbuf[i] = ((const volatile char*)up)[i]; - } for (uint32_t i = 0; i < chunk; i++) { uart_put_char(kbuf[i]); diff --git a/src/kernel/uaccess.c b/src/kernel/uaccess.c new file mode 100644 index 0000000..ef6642f --- /dev/null +++ b/src/kernel/uaccess.c @@ -0,0 +1,82 @@ +#include "uaccess.h" + +#include + +#if defined(__i386__) +#define X86_KERNEL_VIRT_BASE 0xC0000000U + +static int x86_user_range_basic_ok(uintptr_t uaddr, size_t len) { + if (len == 0) return 1; + if (uaddr == 0) return 0; + if (uaddr >= X86_KERNEL_VIRT_BASE) return 0; + uintptr_t end = uaddr + len - 1; + if (end < uaddr) return 0; + if (end >= X86_KERNEL_VIRT_BASE) return 0; + return 1; +} + +static int x86_user_page_present_and_user(uintptr_t vaddr) { + volatile uint32_t* pd = (volatile uint32_t*)0xFFFFF000U; + volatile uint32_t* pt_base = (volatile uint32_t*)0xFFC00000U; + + uint32_t pde = pd[vaddr >> 22]; + if (!(pde & 0x1)) return 0; + if (!(pde & 0x4)) return 0; + + volatile uint32_t* pt = pt_base + ((vaddr >> 22) << 10); + uint32_t pte = pt[(vaddr >> 12) & 0x3FF]; + if (!(pte & 0x1)) return 0; + if (!(pte & 0x4)) return 0; + + return 1; +} + +static int x86_user_range_mapped_and_user(uintptr_t uaddr, size_t len) { + if (!x86_user_range_basic_ok(uaddr, len)) return 0; + if (len == 0) return 1; + + uintptr_t start = uaddr & ~(uintptr_t)0xFFF; + uintptr_t end = (uaddr + len - 1) & ~(uintptr_t)0xFFF; + for (uintptr_t va = start;; va += 0x1000) { + if (!x86_user_page_present_and_user(va)) return 0; + if (va == end) break; + } + return 1; +} +#endif + +int user_range_ok(const void* user_ptr, size_t len) { + uintptr_t uaddr = (uintptr_t)user_ptr; + +#if defined(__i386__) + return x86_user_range_mapped_and_user(uaddr, len); +#else + if (len == 0) return 1; + if (uaddr == 0) return 0; + uintptr_t end = uaddr + len - 1; + if (end < uaddr) return 0; + return 1; +#endif +} + +int copy_from_user(void* dst, const void* src_user, size_t len) { + if (len == 0) return 0; + if (!user_range_ok(src_user, len)) return -1; + + uintptr_t up = (uintptr_t)src_user; + for (size_t i = 0; i < len; i++) { + ((uint8_t*)dst)[i] = ((const volatile uint8_t*)up)[i]; + } + return 0; +} + +int copy_to_user(void* dst_user, const void* src, size_t len) { + if (len == 0) return 0; + if (!user_range_ok(dst_user, len)) return -1; + + uintptr_t up = (uintptr_t)dst_user; + for (size_t i = 0; i < len; i++) { + ((volatile uint8_t*)up)[i] = ((const uint8_t*)src)[i]; + } + return 0; +}