diff options
-rw-r--r-- | Kernel/Process.cpp | 22 | ||||
-rw-r--r-- | Kernel/Process.h | 4 | ||||
-rw-r--r-- | Kernel/StdLib.h | 4 | ||||
-rw-r--r-- | Kernel/Syscall.h | 5 | ||||
-rw-r--r-- | Libraries/LibC/unistd.cpp | 7 |
5 files changed, 35 insertions, 7 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index bdfb384b3c..971ad69b04 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1564,6 +1564,15 @@ bool Process::validate(const Syscall::MutableBufferArgument<DataType, SizeType>& return validate_write(buffer.data, buffer.size); } +String Process::validate_and_copy_string_from_user(const Syscall::StringArgument& string) const +{ + if (!validate_read(string.characters, string.length)) + return {}; + SmapDisabler disabler; + size_t length = strnlen(string.characters, string.length); + return String(string.characters, length); +} + int Process::sys$readlink(const Syscall::SC_readlink_params* user_params) { if (!validate_read_typed(user_params)) @@ -2548,14 +2557,17 @@ Custody& Process::current_directory() return *m_cwd; } -int Process::sys$link(const char* old_path, const char* new_path) +int Process::sys$link(const Syscall::SC_link_params* user_params) { - SmapDisabler disabler; - if (!validate_read_str(old_path)) + if (!validate_read_typed(user_params)) return -EFAULT; - if (!validate_read_str(new_path)) + Syscall::SC_link_params params; + copy_from_user(¶ms, user_params, sizeof(params)); + auto old_path = validate_and_copy_string_from_user(params.old_path); + auto new_path = validate_and_copy_string_from_user(params.new_path); + if (old_path.is_null() || new_path.is_null()) return -EFAULT; - return VFS::the().link(StringView(old_path), StringView(new_path), current_directory()); + return VFS::the().link(old_path, new_path, current_directory()); } int Process::sys$unlink(const char* user_path, size_t path_length) diff --git a/Kernel/Process.h b/Kernel/Process.h index d3aac8d661..f1995de0aa 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -175,7 +175,7 @@ public: int sys$mkdir(const char* pathname, size_t path_length, mode_t mode); clock_t sys$times(tms*); int sys$utime(const char* pathname, size_t path_length, const struct utimbuf*); - int sys$link(const char* old_path, const char* new_path); + int sys$link(const Syscall::SC_link_params*); int sys$unlink(const char* pathname, size_t path_length); int sys$symlink(const char* target, const char* linkpath); int sys$rmdir(const char* pathname, size_t path_length); @@ -263,6 +263,8 @@ public: template<typename DataType, typename SizeType> bool validate(const Syscall::MutableBufferArgument<DataType, SizeType>&); + String validate_and_copy_string_from_user(const Syscall::StringArgument&) const; + Custody& current_directory(); Custody* executable() { return m_executable.ptr(); } diff --git a/Kernel/StdLib.h b/Kernel/StdLib.h index f721c008fe..937ddc1f0f 100644 --- a/Kernel/StdLib.h +++ b/Kernel/StdLib.h @@ -6,6 +6,10 @@ namespace AK { class String; } +namespace Syscall { +struct StringArgument; +} + AK::String copy_string_from_user(const char*, size_t); extern "C" { diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 9193b917f7..d267b568d2 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -327,6 +327,11 @@ struct SC_readlink_params { MutableBufferArgument<char, size_t> buffer; }; +struct SC_link_params { + StringArgument old_path; + StringArgument new_path; +}; + void initialize(); int sync(); diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index 8d63256b4a..da27a3b0e9 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -339,7 +339,12 @@ off_t lseek(int fd, off_t offset, int whence) int link(const char* old_path, const char* new_path) { - int rc = syscall(SC_link, old_path, new_path); + if (!old_path || !new_path) { + errno = EFAULT; + return -1; + } + Syscall::SC_link_params params { { old_path, strlen(old_path) }, { new_path, strlen(new_path) } }; + int rc = syscall(SC_link, ¶ms); __RETURN_WITH_ERRNO(rc, rc, -1); } |