diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index fb7f57ee..300b5847 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include extern const u8 start_of_kernel_rodata[1]; extern const u8 end_of_kernel_rodata[1]; @@ -420,6 +421,28 @@ namespace MemoryManager return true; } + // FIXME: Make this more efficient. + Result strdup_from_user(u64 address) + { + if (!validate_user_readable_page(address)) return err(EFAULT); + + Vector result; + + while (*(char*)address != 0) + { + TRY(result.try_append(*(char*)address)); + address++; + if (address % ARCH_PAGE_SIZE) + { + if (!validate_user_readable_page(address)) return err(EFAULT); + } + } + + TRY(result.try_append(0)); // null terminator + + return OwnedStringView::from_string_literal(result.data()); + } + bool validate_user_write(void* user, usize size) { uintptr_t user_ptr = (uintptr_t)user; diff --git a/kernel/src/memory/MemoryManager.h b/kernel/src/memory/MemoryManager.h index 3ceecffb..bc2a11c8 100644 --- a/kernel/src/memory/MemoryManager.h +++ b/kernel/src/memory/MemoryManager.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include @@ -24,6 +25,7 @@ namespace MemoryManager bool validate_user_writable_page(u64 address); bool validate_userspace_string(u64 address); + Result strdup_from_user(u64 address); bool validate_user_write(void* user, usize size); bool validate_user_read(const void* user, usize size); diff --git a/kernel/src/sys/mkdir.cpp b/kernel/src/sys/mkdir.cpp index 7af9da44..5474d146 100644 --- a/kernel/src/sys/mkdir.cpp +++ b/kernel/src/sys/mkdir.cpp @@ -5,14 +5,11 @@ Result sys_mkdir(Registers*, SyscallArgs args) { - u64 path_address = args[0]; - if (!MemoryManager::validate_userspace_string(path_address)) return err(EFAULT); + auto path = TRY(MemoryManager::strdup_from_user(args[0])); - const char* path = (const char*)path_address; + kinfoln("mkdir: attempting to create %s", path.chars()); - kinfoln("mkdir: attempting to create %s", path); - - TRY(VFS::create_directory(path)); + TRY(VFS::create_directory(path.chars())); return 0; } diff --git a/kernel/src/sys/open.cpp b/kernel/src/sys/open.cpp index 0fb0d481..b619d264 100644 --- a/kernel/src/sys/open.cpp +++ b/kernel/src/sys/open.cpp @@ -10,25 +10,22 @@ constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND; Result sys_open(Registers*, SyscallArgs args) { - u64 path_address = args[0]; - if (!MemoryManager::validate_userspace_string(path_address)) return err(EFAULT); - - const char* path = (const char*)path_address; + auto path = TRY(MemoryManager::strdup_from_user(args[0])); int flags = (int)args[1]; Thread* current = Scheduler::current(); - kinfoln("open: trying to open file %s, flags %d", path, flags); + kinfoln("open: trying to open file %s, flags %d", path.chars(), flags); SharedPtr inode; // Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR if ((flags & O_RDWR) == 0) { return err(EINVAL); } - auto maybe_inode = VFS::resolve_path(path); + auto maybe_inode = VFS::resolve_path(path.chars()); if (maybe_inode.has_error()) { - if (maybe_inode.error() == ENOENT && (flags & O_CREAT)) inode = TRY(VFS::create_file(path)); + if (maybe_inode.error() == ENOENT && (flags & O_CREAT)) inode = TRY(VFS::create_file(path.chars())); else return maybe_inode.release_error(); }