summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.cpp22
-rw-r--r--Kernel/Process.h4
-rw-r--r--Kernel/StdLib.h4
-rw-r--r--Kernel/Syscall.h5
-rw-r--r--Libraries/LibC/unistd.cpp7
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(&params, 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, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}