From 0695ff8282eca40ab08300c5a9be8716d453aee6 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 10 Jan 2020 20:13:23 +0100 Subject: [PATCH] Kernel: Pass characters+length to readlink() Note that I'm developing some helper types in the Syscall namespace as I go here. Once I settle on some nice types, I will convert all the other syscalls to use them as well. --- Kernel/Process.cpp | 31 +++++++++++++++++++++---------- Kernel/Process.h | 4 +++- Kernel/Syscall.h | 11 +++++++++++ Libraries/LibC/unistd.cpp | 3 ++- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 5bd8de15e6..0430aba5d7 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1558,17 +1558,27 @@ int Process::sys$stat(const char* user_path, size_t path_length, stat* user_stat return 0; } -int Process::sys$readlink(const char* path, char* buffer, ssize_t size) +template +bool Process::validate(const Syscall::MutableBufferArgument& buffer) { - if (size < 0) - return -EINVAL; - SmapDisabler disabler; - if (!validate_read_str(path)) + return validate_write(buffer.data, buffer.size); +} + +int Process::sys$readlink(const Syscall::SC_readlink_params* user_params) +{ + if (!validate_read_typed(user_params)) return -EFAULT; - if (!validate_write(buffer, size)) + Syscall::SC_readlink_params params; + copy_from_user(¶ms, user_params, sizeof(params)); + + if (!validate(params.buffer)) return -EFAULT; - auto result = VFS::the().open(path, O_RDONLY | O_NOFOLLOW_NOERROR, 0, current_directory()); + auto path = get_syscall_path_argument(params.path.characters, params.path.length); + if (path.is_error()) + return path.error(); + + auto result = VFS::the().open(path.value(), O_RDONLY | O_NOFOLLOW_NOERROR, 0, current_directory()); if (result.is_error()) return result.error(); auto description = result.value(); @@ -1580,9 +1590,10 @@ int Process::sys$readlink(const char* path, char* buffer, ssize_t size) if (!contents) return -EIO; // FIXME: Get a more detailed error from VFS. - copy_to_user(buffer, contents.data(), min(size, (ssize_t)contents.size())); - if (contents.size() + 1 < size) - buffer[contents.size()] = '\0'; + auto link_target = String::copy(contents); + if (link_target.length() + 1 > params.buffer.size) + return -ENAMETOOLONG; + copy_to_user(params.buffer.data, link_target.characters(), link_target.length() + 1); return 0; } diff --git a/Kernel/Process.h b/Kernel/Process.h index 5c9980b557..d3aac8d661 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -151,7 +151,7 @@ public: int sys$clock_nanosleep(const Syscall::SC_clock_nanosleep_params*); int sys$gethostname(char*, ssize_t); int sys$uname(utsname*); - int sys$readlink(const char*, char*, ssize_t); + int sys$readlink(const Syscall::SC_readlink_params*); int sys$ttyname_r(int fd, char*, ssize_t); int sys$ptsname_r(int fd, char*, ssize_t); pid_t sys$fork(RegisterDump&); @@ -260,6 +260,8 @@ public: bool validate_read_typed(T* value, size_t count = 1) { return validate_read(value, sizeof(T) * count); } template bool validate_write_typed(T* value, size_t count = 1) { return validate_write(value, sizeof(T) * count); } + template + bool validate(const Syscall::MutableBufferArgument&); Custody& current_directory(); Custody* executable() { return m_executable.ptr(); } diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 8c973d3660..9396a97d5e 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -305,6 +305,12 @@ struct SyscallString { size_t length { 0 }; }; +template +struct MutableBufferArgument { + DataType* data { nullptr }; + SizeType size { 0 }; +}; + struct SyscallStringList { SyscallString* strings { nullptr }; size_t length { 0 }; @@ -316,6 +322,11 @@ struct SC_execve_params { SyscallStringList environment; }; +struct SC_readlink_params { + SyscallString path; + MutableBufferArgument buffer; +}; + void initialize(); int sync(); diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index 2f4debf7b3..658291b478 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -326,7 +326,8 @@ int gethostname(char* buffer, size_t size) ssize_t readlink(const char* path, char* buffer, size_t size) { - int rc = syscall(SC_readlink, path, buffer, size); + Syscall::SC_readlink_params params { { path, strlen(path) }, { buffer, size } }; + int rc = syscall(SC_readlink, ¶ms); __RETURN_WITH_ERRNO(rc, rc, -1); }