diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 78f663a83a..fe95b82efc 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2340,21 +2340,22 @@ int Process::sys$mkdir(const char* user_path, size_t path_length, mode_t mode) return VFS::the().mkdir(path.value(), mode & ~umask(), current_directory()); } -int Process::sys$realpath(const char* pathname, char* buffer, size_t size) +int Process::sys$realpath(const Syscall::SC_realpath_params* user_params) { - SmapDisabler disabler; - if (!validate_read_str(pathname)) + if (!validate_read_typed(user_params)) return -EFAULT; - size_t pathname_length = strlen(pathname); - if (pathname_length == 0) - return -EINVAL; - if (pathname_length >= size) - return -ENAMETOOLONG; - if (!validate_write(buffer, size)) + Syscall::SC_realpath_params params; + copy_from_user(¶ms, user_params, sizeof(params)); + + if (!validate_write(params.buffer, params.buffer_size)) return -EFAULT; - auto custody_or_error = VFS::the().resolve_path(pathname, current_directory()); + auto path = get_syscall_path_argument(params.path, params.path_length); + if (path.is_error()) + return path.error(); + + auto custody_or_error = VFS::the().resolve_path(path.value(), current_directory()); if (custody_or_error.is_error()) return custody_or_error.error(); auto& custody = custody_or_error.value(); @@ -2366,7 +2367,10 @@ int Process::sys$realpath(const char* pathname, char* buffer, size_t size) ASSERT_NOT_REACHED(); } - strncpy(buffer, canonical_path.string().characters(), size); + if (canonical_path.string().length() + 1 > params.buffer_size) + return -ENAMETOOLONG; + + copy_to_user(params.buffer, canonical_path.string().characters(), canonical_path.string().length() + 1); return 0; }; diff --git a/Kernel/Process.h b/Kernel/Process.h index 720fb80646..61263fd064 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -221,7 +221,7 @@ public: int sys$halt(); int sys$reboot(); int sys$set_process_icon(int icon_id); - int sys$realpath(const char* pathname, char*, size_t); + int sys$realpath(const Syscall::SC_realpath_params*); ssize_t sys$getrandom(void*, size_t, unsigned int); int sys$setkeymap(const Syscall::SC_setkeymap_params*); int sys$module_load(const char* path, size_t path_length); diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 3b9d6de21b..36b937ba05 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -291,6 +291,13 @@ struct SC_create_thread_params { void* m_stack_location = nullptr; // nullptr means any, o.w. process virtual address }; +struct SC_realpath_params { + const char* path; + size_t path_length; + char* buffer; + size_t buffer_size; +}; + void initialize(); int sync(); diff --git a/Libraries/LibC/stdlib.cpp b/Libraries/LibC/stdlib.cpp index f8e3477ec4..bfac7194dd 100644 --- a/Libraries/LibC/stdlib.cpp +++ b/Libraries/LibC/stdlib.cpp @@ -704,10 +704,15 @@ uint32_t arc4random_uniform(uint32_t max_bounds) char* realpath(const char* pathname, char* buffer) { + if (!pathname) { + errno = EFAULT; + return nullptr; + } size_t size = PATH_MAX; if (buffer == nullptr) buffer = (char*)malloc(size); - int rc = syscall(SC_realpath, pathname, buffer, size); + Syscall::SC_realpath_params params { pathname, strlen(pathname), buffer, size }; + int rc = syscall(SC_realpath, ¶ms); if (rc < 0) { errno = -rc; return nullptr;