diff --git a/Kernel/Process.h b/Kernel/Process.h index bb3bb75ed9..caa1de3ccb 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -814,6 +814,11 @@ inline static String copy_string_from_user(const Kernel::Syscall::StringArgument return copy_string_from_user(string.characters, string.length); } +inline static KResultOr> try_copy_kstring_from_user(const Kernel::Syscall::StringArgument& string) +{ + return try_copy_kstring_from_user(string.characters, string.length); +} + template<> struct AK::Formatter : AK::Formatter { void format(FormatBuilder& builder, const Kernel::Process& value) diff --git a/Kernel/StdLib.cpp b/Kernel/StdLib.cpp index 6fbe4dfd04..183480dcc1 100644 --- a/Kernel/StdLib.cpp +++ b/Kernel/StdLib.cpp @@ -43,6 +43,40 @@ String copy_string_from_user(Userspace user_str, size_t user_str_si return copy_string_from_user(user_str.unsafe_userspace_ptr(), user_str_size); } +Kernel::KResultOr> try_copy_kstring_from_user(const char* user_str, size_t user_str_size) +{ + bool is_user = Kernel::is_user_range(VirtualAddress(user_str), user_str_size); + if (!is_user) + return EFAULT; + Kernel::SmapDisabler disabler; + void* fault_at; + ssize_t length = Kernel::safe_strnlen(user_str, user_str_size, fault_at); + if (length < 0) { + dbgln("copy_kstring_from_user({:p}, {}) failed at {} (strnlen)", static_cast(user_str), user_str_size, VirtualAddress { fault_at }); + return EFAULT; + } + char* buffer; + auto new_string = Kernel::KString::try_create_uninitialized(length, buffer); + if (!new_string) + return ENOMEM; + + buffer[length] = '\0'; + + if (length == 0) + return new_string.release_nonnull(); + + if (!Kernel::safe_memcpy(buffer, user_str, (size_t)length, fault_at)) { + dbgln("copy_kstring_from_user({:p}, {}) failed at {} (memcpy)", static_cast(user_str), user_str_size, VirtualAddress { fault_at }); + return EFAULT; + } + return new_string.release_nonnull(); +} + +Kernel::KResultOr> try_copy_kstring_from_user(Userspace user_str, size_t user_str_size) +{ + return try_copy_kstring_from_user(user_str.unsafe_userspace_ptr(), user_str_size); +} + [[nodiscard]] Optional