diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-05-13 16:28:06 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-05-13 16:28:06 +0800 |
| commit | 8cbf571e56fd5ef631b51f4e5e3f181df1a529ff (patch) | |
| tree | bab065dec38cafc7ba161b5cd42515df4d8be2a9 /na/kernel | |
| parent | 84be4cc9baf7b0a75af18e77995184e0494b4e87 (diff) | |
| download | lume-8cbf571e56fd5ef631b51f4e5e3f181df1a529ff.tar.gz lume-8cbf571e56fd5ef631b51f4e5e3f181df1a529ff.tar.xz | |
feat: implement user-kernel memory copy functions with validation
Diffstat (limited to 'na/kernel')
| -rw-r--r-- | na/kernel/uaccess.cc | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/na/kernel/uaccess.cc b/na/kernel/uaccess.cc new file mode 100644 index 0000000..4a5b963 --- /dev/null +++ b/na/kernel/uaccess.cc @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +/* + * User-Kernel Memory Copy — Phase 3 (Exception Tables) + * + * Validates user pointers by checking they fall within user address space + * (below KERNEL_VA_BASE). Uses assembly-level safe copy functions that + * integrate with the kernel's Exception Table mechanism. + * + * Reference: docs/specs/syscall.md §8 + */ + +#include <lume/uaccess.h> +#include <lume/task.h> +#include <lume/errno.h> +#include <lume/config.h> + +/* Kernel VA base — addresses at or above this are kernel space */ +inline constexpr uint64 kKernelVABase = 0xFFFFFFC000000000ULL; + +extern "C" int __uaccess_memcpy(void* dst, const void* src, uint64 len); +extern "C" int64 __uaccess_strncpy(char* dst, const char* src, uint64 max_len); + +/* Validate that [addr, addr+len) is entirely in user space */ +static bool is_user_range(uint64 addr, uint64 len) +{ + if (addr >= kKernelVABase) + return false; + if (addr + len < addr) /* overflow */ + return false; + if (addr + len > kKernelVABase) + return false; + return true; +} + +int copy_from_user(void* kernel_dst, uint64 user_src, uint64 len) +{ + if (len == 0) return 0; + if (!is_user_range(user_src, len)) return -EFAULT; + + return __uaccess_memcpy(kernel_dst, reinterpret_cast<const void*>(user_src), len); +} + +int copy_to_user(uint64 user_dst, const void* kernel_src, uint64 len) +{ + if (len == 0) return 0; + if (!is_user_range(user_dst, len)) return -EFAULT; + + return __uaccess_memcpy(reinterpret_cast<void*>(user_dst), kernel_src, len); +} + +int64 strncpy_from_user(char* kernel_dst, uint64 user_src, uint64 max_len) +{ + if (!is_user_range(user_src, 1)) return -EFAULT; + + /* We must also check that the string does not cross into kernel space. + This is safely handled by the assembly routine which will fault if it hits + an unmapped page. However, to strictly respect kKernelVABase, we should + restrict max_len to the distance to kKernelVABase. */ + uint64 max_allowed = kKernelVABase - user_src; + if (max_len > max_allowed) { + max_len = max_allowed; + } + + return __uaccess_strncpy(kernel_dst, reinterpret_cast<const char*>(user_src), max_len); +} |
