summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DevTools/UserspaceEmulator/Emulator.cpp4
-rw-r--r--Kernel/API/Syscall.h56
-rw-r--r--Kernel/Arch/i386/CPU.cpp8
-rw-r--r--Kernel/CMakeLists.txt1
-rw-r--r--Kernel/Console.cpp16
-rw-r--r--Kernel/Console.h4
-rw-r--r--Kernel/Devices/BXVGADevice.cpp25
-rw-r--r--Kernel/Devices/BXVGADevice.h8
-rw-r--r--Kernel/Devices/BlockDevice.cpp8
-rw-r--r--Kernel/Devices/BlockDevice.h12
-rw-r--r--Kernel/Devices/DiskPartition.cpp8
-rw-r--r--Kernel/Devices/DiskPartition.h8
-rw-r--r--Kernel/Devices/EBRPartitionTable.cpp13
-rw-r--r--Kernel/Devices/FullDevice.cpp7
-rw-r--r--Kernel/Devices/FullDevice.h4
-rw-r--r--Kernel/Devices/GPTPartitionTable.cpp6
-rw-r--r--Kernel/Devices/KeyboardDevice.cpp12
-rw-r--r--Kernel/Devices/KeyboardDevice.h4
-rw-r--r--Kernel/Devices/MBRPartitionTable.cpp3
-rw-r--r--Kernel/Devices/MBVGADevice.cpp20
-rw-r--r--Kernel/Devices/MBVGADevice.h8
-rw-r--r--Kernel/Devices/NullDevice.cpp4
-rw-r--r--Kernel/Devices/NullDevice.h4
-rw-r--r--Kernel/Devices/PATAChannel.cpp49
-rw-r--r--Kernel/Devices/PATAChannel.h8
-rw-r--r--Kernel/Devices/PATADiskDevice.cpp36
-rw-r--r--Kernel/Devices/PATADiskDevice.h16
-rw-r--r--Kernel/Devices/PS2MouseDevice.cpp7
-rw-r--r--Kernel/Devices/PS2MouseDevice.h4
-rw-r--r--Kernel/Devices/RandomDevice.cpp11
-rw-r--r--Kernel/Devices/RandomDevice.h4
-rw-r--r--Kernel/Devices/SB16.cpp7
-rw-r--r--Kernel/Devices/SB16.h4
-rw-r--r--Kernel/Devices/SerialDevice.cpp25
-rw-r--r--Kernel/Devices/SerialDevice.h4
-rw-r--r--Kernel/Devices/ZeroDevice.cpp7
-rw-r--r--Kernel/Devices/ZeroDevice.h4
-rw-r--r--Kernel/DoubleBuffer.cpp14
-rw-r--r--Kernel/DoubleBuffer.h14
-rw-r--r--Kernel/FileSystem/BlockBasedFileSystem.cpp76
-rw-r--r--Kernel/FileSystem/BlockBasedFileSystem.h16
-rw-r--r--Kernel/FileSystem/DevPtsFS.cpp4
-rw-r--r--Kernel/FileSystem/DevPtsFS.h4
-rw-r--r--Kernel/FileSystem/Ext2FileSystem.cpp92
-rw-r--r--Kernel/FileSystem/Ext2FileSystem.h4
-rw-r--r--Kernel/FileSystem/FIFO.cpp4
-rw-r--r--Kernel/FileSystem/FIFO.h4
-rw-r--r--Kernel/FileSystem/File.h5
-rw-r--r--Kernel/FileSystem/FileDescription.cpp9
-rw-r--r--Kernel/FileSystem/FileDescription.h6
-rw-r--r--Kernel/FileSystem/FileSystem.h1
-rw-r--r--Kernel/FileSystem/Inode.cpp7
-rw-r--r--Kernel/FileSystem/Inode.h6
-rw-r--r--Kernel/FileSystem/InodeFile.cpp4
-rw-r--r--Kernel/FileSystem/InodeFile.h4
-rw-r--r--Kernel/FileSystem/InodeWatcher.cpp12
-rw-r--r--Kernel/FileSystem/InodeWatcher.h4
-rw-r--r--Kernel/FileSystem/Plan9FileSystem.cpp19
-rw-r--r--Kernel/FileSystem/Plan9FileSystem.h4
-rw-r--r--Kernel/FileSystem/ProcFS.cpp52
-rw-r--r--Kernel/FileSystem/ProcFS.h12
-rw-r--r--Kernel/FileSystem/TmpFS.cpp16
-rw-r--r--Kernel/FileSystem/TmpFS.h4
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp3
-rw-r--r--Kernel/Forward.h1
-rw-r--r--Kernel/KSyms.cpp20
-rw-r--r--Kernel/Net/IPv4Socket.cpp122
-rw-r--r--Kernel/Net/IPv4Socket.h14
-rw-r--r--Kernel/Net/LocalSocket.cpp42
-rw-r--r--Kernel/Net/LocalSocket.h6
-rw-r--r--Kernel/Net/NetworkAdapter.cpp29
-rw-r--r--Kernel/Net/NetworkAdapter.h5
-rw-r--r--Kernel/Net/NetworkTask.cpp39
-rw-r--r--Kernel/Net/Socket.cpp41
-rw-r--r--Kernel/Net/Socket.h10
-rw-r--r--Kernel/Net/TCPSocket.cpp50
-rw-r--r--Kernel/Net/TCPSocket.h6
-rw-r--r--Kernel/Net/UDPSocket.cpp13
-rw-r--r--Kernel/Net/UDPSocket.h4
-rw-r--r--Kernel/Process.cpp47
-rw-r--r--Kernel/Process.h112
-rw-r--r--Kernel/Ptrace.cpp16
-rw-r--r--Kernel/Scheduler.cpp2
-rw-r--r--Kernel/StdLib.cpp71
-rw-r--r--Kernel/StdLib.h72
-rw-r--r--Kernel/Syscalls/chdir.cpp5
-rw-r--r--Kernel/Syscalls/chown.cpp2
-rw-r--r--Kernel/Syscalls/clock.cpp31
-rw-r--r--Kernel/Syscalls/debug.cpp18
-rw-r--r--Kernel/Syscalls/execve.cpp17
-rw-r--r--Kernel/Syscalls/futex.cpp16
-rw-r--r--Kernel/Syscalls/get_dir_entries.cpp7
-rw-r--r--Kernel/Syscalls/get_stack_bounds.cpp11
-rw-r--r--Kernel/Syscalls/getrandom.cpp15
-rw-r--r--Kernel/Syscalls/getuid.cpp15
-rw-r--r--Kernel/Syscalls/hostname.cpp10
-rw-r--r--Kernel/Syscalls/link.cpp12
-rw-r--r--Kernel/Syscalls/mknod.cpp2
-rw-r--r--Kernel/Syscalls/mmap.cpp10
-rw-r--r--Kernel/Syscalls/module.cpp2
-rw-r--r--Kernel/Syscalls/mount.cpp12
-rw-r--r--Kernel/Syscalls/open.cpp2
-rw-r--r--Kernel/Syscalls/pipe.cpp8
-rw-r--r--Kernel/Syscalls/pledge.cpp6
-rw-r--r--Kernel/Syscalls/process.cpp8
-rw-r--r--Kernel/Syscalls/ptrace.cpp35
-rw-r--r--Kernel/Syscalls/read.cpp7
-rw-r--r--Kernel/Syscalls/readlink.cpp8
-rw-r--r--Kernel/Syscalls/realpath.cpp8
-rw-r--r--Kernel/Syscalls/rename.cpp2
-rw-r--r--Kernel/Syscalls/sched.cpp12
-rw-r--r--Kernel/Syscalls/select.cpp172
-rw-r--r--Kernel/Syscalls/setkeymap.cpp15
-rw-r--r--Kernel/Syscalls/setuid.cpp5
-rw-r--r--Kernel/Syscalls/shbuf.cpp10
-rw-r--r--Kernel/Syscalls/sigaction.cpp31
-rw-r--r--Kernel/Syscalls/socket.cpp102
-rw-r--r--Kernel/Syscalls/stat.cpp12
-rw-r--r--Kernel/Syscalls/thread.cpp28
-rw-r--r--Kernel/Syscalls/times.cpp6
-rw-r--r--Kernel/Syscalls/ttyname.cpp10
-rw-r--r--Kernel/Syscalls/uname.cpp18
-rw-r--r--Kernel/Syscalls/unlink.cpp2
-rw-r--r--Kernel/Syscalls/unveil.cpp4
-rw-r--r--Kernel/Syscalls/utime.cpp5
-rw-r--r--Kernel/Syscalls/waitid.cpp16
-rw-r--r--Kernel/Syscalls/write.cpp32
-rw-r--r--Kernel/TTY/MasterPTY.cpp9
-rw-r--r--Kernel/TTY/MasterPTY.h6
-rw-r--r--Kernel/TTY/PTYMultiplexer.h4
-rw-r--r--Kernel/TTY/SlavePTY.cpp17
-rw-r--r--Kernel/TTY/SlavePTY.h6
-rw-r--r--Kernel/TTY/TTY.cpp71
-rw-r--r--Kernel/TTY/TTY.h6
-rw-r--r--Kernel/TTY/VirtualConsole.cpp14
-rw-r--r--Kernel/TTY/VirtualConsole.h2
-rw-r--r--Kernel/Thread.cpp41
-rw-r--r--Kernel/Thread.h3
-rw-r--r--Kernel/UserOrKernelBuffer.cpp88
-rw-r--r--Kernel/UserOrKernelBuffer.h172
-rw-r--r--Kernel/VM/InodeVMObject.cpp2
-rw-r--r--Kernel/VM/InodeVMObject.h2
-rw-r--r--Kernel/VM/MemoryManager.cpp33
-rw-r--r--Kernel/VM/MemoryManager.h6
-rw-r--r--Kernel/VM/Region.cpp30
-rw-r--r--Kernel/VM/Region.h1
-rw-r--r--Libraries/LibC/unistd.cpp4
-rw-r--r--Libraries/LibELF/Loader.cpp10
-rw-r--r--Libraries/LibPthread/pthread.cpp2
149 files changed, 1585 insertions, 1244 deletions
diff --git a/DevTools/UserspaceEmulator/Emulator.cpp b/DevTools/UserspaceEmulator/Emulator.cpp
index 77d92aca67..72b37b1fd3 100644
--- a/DevTools/UserspaceEmulator/Emulator.cpp
+++ b/DevTools/UserspaceEmulator/Emulator.cpp
@@ -930,7 +930,7 @@ int Emulator::virt$execve(FlatPtr params_addr)
auto copy_string_list = [this](auto& output_vector, auto& string_list) {
for (size_t i = 0; i < string_list.length; ++i) {
Syscall::StringArgument string;
- mmu().copy_from_vm(&string, (FlatPtr)&string_list.strings.ptr()[i], sizeof(string));
+ mmu().copy_from_vm(&string, (FlatPtr)&string_list.strings[i], sizeof(string));
output_vector.append(String::copy(mmu().copy_buffer_from_vm((FlatPtr)string.characters, string.length)));
}
};
@@ -1307,7 +1307,7 @@ int Emulator::virt$waitid(FlatPtr params_addr)
}
if (params.infop)
- mmu().copy_to_vm(params.infop, &info, sizeof(info));
+ mmu().copy_to_vm((FlatPtr)params.infop, &info, sizeof(info));
return rc;
}
diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h
index b4822cdcdf..5a95809701 100644
--- a/Kernel/API/Syscall.h
+++ b/Kernel/API/Syscall.h
@@ -222,7 +222,7 @@ inline constexpr const char* to_string(Function function)
#ifdef __serenity__
struct StringArgument {
- Userspace<const char*> characters;
+ const char* characters;
size_t length { 0 };
};
@@ -239,7 +239,7 @@ struct ImmutableBufferArgument {
};
struct StringListArgument {
- Userspace<StringArgument*> strings {};
+ StringArgument* strings {};
size_t length { 0 };
};
@@ -273,22 +273,22 @@ struct SC_select_params {
struct SC_poll_params {
struct pollfd* fds;
unsigned nfds;
- Userspace<const struct timespec*> timeout;
- Userspace<const u32*> sigmask;
+ const struct timespec* timeout;
+ const u32* sigmask;
};
struct SC_clock_nanosleep_params {
int clock_id;
int flags;
- Userspace<const struct timespec*> requested_sleep;
- Userspace<struct timespec*> remaining_sleep;
+ const struct timespec* requested_sleep;
+ struct timespec* remaining_sleep;
};
struct SC_sendto_params {
int sockfd;
ImmutableBufferArgument<void, size_t> data;
int flags;
- Userspace<const sockaddr*> addr;
+ const sockaddr* addr;
socklen_t addr_length;
};
@@ -296,50 +296,50 @@ struct SC_recvfrom_params {
int sockfd;
MutableBufferArgument<void, size_t> buffer;
int flags;
- Userspace<sockaddr*> addr;
- Userspace<socklen_t*> addr_length;
+ sockaddr* addr;
+ socklen_t* addr_length;
};
struct SC_getsockopt_params {
int sockfd;
int level;
int option;
- Userspace<void*> value;
- Userspace<socklen_t*> value_size;
+ void* value;
+ socklen_t* value_size;
};
struct SC_setsockopt_params {
int sockfd;
int level;
int option;
- Userspace<const void*> value;
+ const void* value;
socklen_t value_size;
};
struct SC_getsockname_params {
int sockfd;
- Userspace<sockaddr*> addr;
- Userspace<socklen_t*> addrlen;
+ sockaddr* addr;
+ socklen_t* addrlen;
};
struct SC_getpeername_params {
int sockfd;
- Userspace<sockaddr*> addr;
- Userspace<socklen_t*> addrlen;
+ sockaddr* addr;
+ socklen_t* addrlen;
};
struct SC_futex_params {
- Userspace<const i32*> userspace_address;
+ const i32* userspace_address;
int futex_op;
i32 val;
- Userspace<const timespec*> timeout;
+ const timespec* timeout;
};
struct SC_setkeymap_params {
- Userspace<const u32*> map;
- Userspace<const u32*> shift_map;
- Userspace<const u32*> alt_map;
- Userspace<const u32*> altgr_map;
+ const u32* map;
+ const u32* shift_map;
+ const u32* alt_map;
+ const u32* altgr_map;
StringArgument map_name;
};
@@ -354,7 +354,7 @@ struct SC_create_thread_params {
unsigned int m_guard_page_size = 0; // Rounded up to PAGE_SIZE
unsigned int m_reported_guard_page_size = 0; // The lie we tell callers
unsigned int m_stack_size = 4 * MiB; // Default PTHREAD_STACK_MIN
- Userspace<void*> m_stack_location; // nullptr means any, o.w. process virtual address
+ void* m_stack_location; // nullptr means any, o.w. process virtual address
};
struct SC_realpath_params {
@@ -426,26 +426,26 @@ struct SC_unveil_params {
struct SC_waitid_params {
int idtype;
int id;
- Userspace<struct siginfo*> infop;
+ struct siginfo* infop;
int options;
};
struct SC_stat_params {
StringArgument path;
- Userspace<struct stat*> statbuf;
+ struct stat* statbuf;
bool follow_symlinks;
};
struct SC_ptrace_params {
int request;
pid_t tid;
- Userspace<u8*> addr;
+ u8* addr;
int data;
};
struct SC_ptrace_peek_params {
- Userspace<const u32*> address;
- Userspace<u32*> out_data;
+ const u32* address;
+ u32* out_data;
};
void initialize();
diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp
index 7fbe6faa35..d1a9ccb136 100644
--- a/Kernel/Arch/i386/CPU.cpp
+++ b/Kernel/Arch/i386/CPU.cpp
@@ -226,6 +226,7 @@ extern "C" u8* safe_memset_2_faulted;
bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
{
+ fault_at = nullptr;
size_t dest = (size_t)dest_ptr;
size_t src = (size_t)src_ptr;
size_t remainder;
@@ -233,7 +234,6 @@ bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
if (!(dest & 0x3) && !(src & 0x3) && n >= 12) {
size_t size_ts = n / sizeof(size_t);
asm volatile(
- "xor %[fault_at], %[fault_at] \n"
".global safe_memcpy_ins_1 \n"
"safe_memcpy_ins_1: \n"
"rep movsl \n"
@@ -256,7 +256,6 @@ bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
}
}
asm volatile(
- "xor %[fault_at], %[fault_at] \n"
".global safe_memcpy_ins_2 \n"
"safe_memcpy_ins_2: \n"
"rep movsb \n"
@@ -277,8 +276,8 @@ bool safe_memcpy(void* dest_ptr, const void* src_ptr, size_t n, void*& fault_at)
ssize_t safe_strnlen(const char* str, size_t max_n, void*& fault_at)
{
ssize_t count = 0;
+ fault_at = nullptr;
asm volatile(
- "xor %[fault_at], %[fault_at] \n"
"1: \n"
"test %[max_n], %[max_n] \n"
"je 2f \n"
@@ -307,6 +306,7 @@ ssize_t safe_strnlen(const char* str, size_t max_n, void*& fault_at)
bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
{
+ fault_at = nullptr;
size_t dest = (size_t)dest_ptr;
size_t remainder;
// FIXME: Support starting at an unaligned address.
@@ -316,7 +316,6 @@ bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
expanded_c |= expanded_c << 8;
expanded_c |= expanded_c << 16;
asm volatile(
- "xor %[fault_at], %[fault_at] \n"
".global safe_memset_ins_1 \n"
"safe_memset_ins_1: \n"
"rep stosl \n"
@@ -338,7 +337,6 @@ bool safe_memset(void* dest_ptr, int c, size_t n, void*& fault_at)
}
}
asm volatile(
- "xor %[fault_at], %[fault_at] \n"
".global safe_memset_ins_2 \n"
"safe_memset_ins_2: \n"
"rep stosb \n"
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index 1b7d04e10e..646cf406d1 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -176,6 +176,7 @@ set(KERNEL_SOURCES
Time/RTC.cpp
Time/TimeManagement.cpp
TimerQueue.cpp
+ UserOrKernelBuffer.cpp
VM/AnonymousVMObject.cpp
VM/ContiguousVMObject.cpp
VM/InodeVMObject.cpp
diff --git a/Kernel/Console.cpp b/Kernel/Console.cpp
index e511a2d876..b919f4fe08 100644
--- a/Kernel/Console.cpp
+++ b/Kernel/Console.cpp
@@ -65,20 +65,26 @@ bool Console::can_read(const Kernel::FileDescription&, size_t) const
return false;
}
-Kernel::KResultOr<size_t> Console::read(Kernel::FileDescription&, size_t, u8*, size_t)
+Kernel::KResultOr<size_t> Console::read(Kernel::FileDescription&, size_t, Kernel::UserOrKernelBuffer&, size_t)
{
// FIXME: Implement reading from the console.
// Maybe we could use a ring buffer for this device?
return 0;
}
-Kernel::KResultOr<size_t> Console::write(Kernel::FileDescription&, size_t, const u8* data, size_t size)
+Kernel::KResultOr<size_t> Console::write(Kernel::FileDescription&, size_t, const Kernel::UserOrKernelBuffer& data, size_t size)
{
if (!size)
return 0;
- for (size_t i = 0; i < size; ++i)
- put_char(data[i]);
- return size;
+
+ ssize_t nread = data.read_buffered<256>(size, [&](const u8* bytes, size_t bytes_count) {
+ for (size_t i = 0; i < bytes_count; i++)
+ put_char((char)bytes[i]);
+ return (ssize_t)bytes_count;
+ });
+ if (nread < 0)
+ return Kernel::KResult(nread);
+ return (size_t)nread;
}
void Console::put_char(char ch)
diff --git a/Kernel/Console.h b/Kernel/Console.h
index f06ebf2a6a..c37731e4f7 100644
--- a/Kernel/Console.h
+++ b/Kernel/Console.h
@@ -43,8 +43,8 @@ public:
// ^CharacterDevice
virtual bool can_read(const Kernel::FileDescription&, size_t) const override;
virtual bool can_write(const Kernel::FileDescription&, size_t) const override { return true; }
- virtual Kernel::KResultOr<size_t> read(Kernel::FileDescription&, size_t, u8*, size_t) override;
- virtual Kernel::KResultOr<size_t> write(Kernel::FileDescription&, size_t, const u8*, size_t) override;
+ virtual Kernel::KResultOr<size_t> read(Kernel::FileDescription&, size_t, Kernel::UserOrKernelBuffer&, size_t) override;
+ virtual Kernel::KResultOr<size_t> write(Kernel::FileDescription&, size_t, const Kernel::UserOrKernelBuffer&, size_t) override;
virtual const char* class_name() const override { return "Console"; }
void put_char(char);
diff --git a/Kernel/Devices/BXVGADevice.cpp b/Kernel/Devices/BXVGADevice.cpp
index c9f1732260..85040ed747 100644
--- a/Kernel/Devices/BXVGADevice.cpp
+++ b/Kernel/Devices/BXVGADevice.cpp
@@ -203,18 +203,16 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
switch (request) {
case FB_IOCTL_GET_SIZE_IN_BYTES: {
auto* out = (size_t*)arg;
- if (!Process::current()->validate_write_typed(out))
- return -EFAULT;
size_t value = framebuffer_size_in_bytes();
- copy_to_user(out, &value);
+ if (!copy_to_user(out, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_GET_BUFFER: {
auto* index = (int*)arg;
- if (!Process::current()->validate_write_typed(index))
- return -EFAULT;
int value = m_y_offset == 0 ? 0 : 1;
- copy_to_user(index, &value);
+ if (!copy_to_user(index, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_SET_BUFFER: {
@@ -225,21 +223,18 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
}
case FB_IOCTL_GET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_SET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
- if (!Process::current()->validate_read_and_copy_typed(&resolution, user_resolution))
+ if (!copy_from_user(&resolution, user_resolution))
return -EFAULT;
if (resolution.width > MAX_RESOLUTION_WIDTH || resolution.height > MAX_RESOLUTION_HEIGHT)
return -EINVAL;
@@ -250,7 +245,8 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return -EINVAL;
}
#ifdef BXVGA_DEBUG
@@ -259,7 +255,8 @@ int BXVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
default:
diff --git a/Kernel/Devices/BXVGADevice.h b/Kernel/Devices/BXVGADevice.h
index 213fc1617c..6b98db525b 100644
--- a/Kernel/Devices/BXVGADevice.h
+++ b/Kernel/Devices/BXVGADevice.h
@@ -48,10 +48,10 @@ private:
virtual const char* class_name() const override { return "BXVGA"; }
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override { return -EINVAL; }
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override { return -EINVAL; }
- virtual bool read_blocks(unsigned, u16, u8*) override { return false; }
- virtual bool write_blocks(unsigned, u16, const u8*) override { return false; }
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual bool read_blocks(unsigned, u16, UserOrKernelBuffer&) override { return false; }
+ virtual bool write_blocks(unsigned, u16, const UserOrKernelBuffer&) override { return false; }
void set_safe_resolution();
diff --git a/Kernel/Devices/BlockDevice.cpp b/Kernel/Devices/BlockDevice.cpp
index 2120db0edc..d78388b610 100644
--- a/Kernel/Devices/BlockDevice.cpp
+++ b/Kernel/Devices/BlockDevice.cpp
@@ -32,17 +32,17 @@ BlockDevice::~BlockDevice()
{
}
-bool BlockDevice::read_block(unsigned index, u8* buffer) const
+bool BlockDevice::read_block(unsigned index, UserOrKernelBuffer& buffer) const
{
return const_cast<BlockDevice*>(this)->read_blocks(index, 1, buffer);
}
-bool BlockDevice::write_block(unsigned index, const u8* data)
+bool BlockDevice::write_block(unsigned index, const UserOrKernelBuffer& data)
{
return write_blocks(index, 1, data);
}
-bool BlockDevice::read_raw(u32 offset, unsigned length, u8* out) const
+bool BlockDevice::read_raw(u32 offset, unsigned length, UserOrKernelBuffer& out) const
{
ASSERT((offset % block_size()) == 0);
ASSERT((length % block_size()) == 0);
@@ -51,7 +51,7 @@ bool BlockDevice::read_raw(u32 offset, unsigned length, u8* out) const
return const_cast<BlockDevice*>(this)->read_blocks(first_block, end_block - first_block, out);
}
-bool BlockDevice::write_raw(u32 offset, unsigned length, const u8* in)
+bool BlockDevice::write_raw(u32 offset, unsigned length, const UserOrKernelBuffer& in)
{
ASSERT((offset % block_size()) == 0);
ASSERT((length % block_size()) == 0);
diff --git a/Kernel/Devices/BlockDevice.h b/Kernel/Devices/BlockDevice.h
index 042a2cfce1..69786df3f8 100644
--- a/Kernel/Devices/BlockDevice.h
+++ b/Kernel/Devices/BlockDevice.h
@@ -37,13 +37,13 @@ public:
size_t block_size() const { return m_block_size; }
virtual bool is_seekable() const override { return true; }
- bool read_block(unsigned index, u8*) const;
- bool write_block(unsigned index, const u8*);
- bool read_raw(u32 offset, unsigned length, u8*) const;
- bool write_raw(u32 offset, unsigned length, const u8*);
+ bool read_block(unsigned index, UserOrKernelBuffer&) const;
+ bool write_block(unsigned index, const UserOrKernelBuffer&);
+ bool read_raw(u32 offset, unsigned length, UserOrKernelBuffer&) const;
+ bool write_raw(u32 offset, unsigned length, const UserOrKernelBuffer&);
- virtual bool read_blocks(unsigned index, u16 count, u8*) = 0;
- virtual bool write_blocks(unsigned index, u16 count, const u8*) = 0;
+ virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) = 0;
+ virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) = 0;
protected:
BlockDevice(unsigned major, unsigned minor, size_t block_size = PAGE_SIZE)
diff --git a/Kernel/Devices/DiskPartition.cpp b/Kernel/Devices/DiskPartition.cpp
index 75f83d3976..d1ccb90d1b 100644
--- a/Kernel/Devices/DiskPartition.cpp
+++ b/Kernel/Devices/DiskPartition.cpp
@@ -48,7 +48,7 @@ DiskPartition::~DiskPartition()
{
}
-KResultOr<size_t> DiskPartition::read(FileDescription& fd, size_t offset, u8* outbuf, size_t len)
+KResultOr<size_t> DiskPartition::read(FileDescription& fd, size_t offset, UserOrKernelBuffer& outbuf, size_t len)
{
unsigned adjust = m_block_offset * block_size();
@@ -70,7 +70,7 @@ bool DiskPartition::can_read(const FileDescription& fd, size_t offset) const
return m_device->can_read(fd, offset + adjust);
}
-KResultOr<size_t> DiskPartition::write(FileDescription& fd, size_t offset, const u8* inbuf, size_t len)
+KResultOr<size_t> DiskPartition::write(FileDescription& fd, size_t offset, const UserOrKernelBuffer& inbuf, size_t len)
{
unsigned adjust = m_block_offset * block_size();
@@ -92,7 +92,7 @@ bool DiskPartition::can_write(const FileDescription& fd, size_t offset) const
return m_device->can_write(fd, offset + adjust);
}
-bool DiskPartition::read_blocks(unsigned index, u16 count, u8* out)
+bool DiskPartition::read_blocks(unsigned index, u16 count, UserOrKernelBuffer& out)
{
#ifdef OFFD_DEBUG
klog() << "DiskPartition::read_blocks " << index << " (really: " << (m_block_offset + index) << ") count=" << count;
@@ -101,7 +101,7 @@ bool DiskPartition::read_blocks(unsigned index, u16 count, u8* out)
return m_device->read_blocks(m_block_offset + index, count, out);
}
-bool DiskPartition::write_blocks(unsigned index, u16 count, const u8* data)
+bool DiskPartition::write_blocks(unsigned index, u16 count, const UserOrKernelBuffer& data)
{
#ifdef OFFD_DEBUG
klog() << "DiskPartition::write_blocks " << index << " (really: " << (m_block_offset + index) << ") count=" << count;
diff --git a/Kernel/Devices/DiskPartition.h b/Kernel/Devices/DiskPartition.h
index 51d3342869..e9551b8097 100644
--- a/Kernel/Devices/DiskPartition.h
+++ b/Kernel/Devices/DiskPartition.h
@@ -36,13 +36,13 @@ public:
static NonnullRefPtr<DiskPartition> create(BlockDevice&, unsigned block_offset, unsigned block_limit);
virtual ~DiskPartition();
- virtual bool read_blocks(unsigned index, u16 count, u8*) override;
- virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
+ virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) override;
+ virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) override;
// ^BlockDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
private:
diff --git a/Kernel/Devices/EBRPartitionTable.cpp b/Kernel/Devices/EBRPartitionTable.cpp
index 095fc78ecd..48826636de 100644
--- a/Kernel/Devices/EBRPartitionTable.cpp
+++ b/Kernel/Devices/EBRPartitionTable.cpp
@@ -63,7 +63,8 @@ int EBRPartitionTable::index_of_ebr_container() const
bool EBRPartitionTable::initialize()
{
- if (!m_device->read_block(0, m_cached_mbr_header)) {
+ auto mbr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_mbr_header);
+ if (!m_device->read_block(0, mbr_header_buffer)) {
return false;
}
auto& header = this->header();
@@ -80,7 +81,8 @@ bool EBRPartitionTable::initialize()
}
auto& ebr_entry = header.entry[m_ebr_container_id - 1];
- if (!m_device->read_block(ebr_entry.offset, m_cached_ebr_header)) {
+ auto ebr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_ebr_header);
+ if (!m_device->read_block(ebr_entry.offset, ebr_header_buffer)) {
return false;
}
size_t index = 1;
@@ -89,7 +91,7 @@ bool EBRPartitionTable::initialize()
break;
}
index++;
- if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, m_cached_ebr_header)) {
+ if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, ebr_header_buffer)) {
return false;
}
}
@@ -140,7 +142,8 @@ RefPtr<DiskPartition> EBRPartitionTable::get_extended_partition(unsigned index)
klog() << "EBRPartitionTable::partition: Extended partition, offset 0x" << String::format("%x", ebr_entry.offset) << ", type " << String::format("%x", ebr_entry.type);
#endif
- if (!m_device->read_block(ebr_entry.offset, m_cached_ebr_header)) {
+ auto ebr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_ebr_header);
+ if (!m_device->read_block(ebr_entry.offset, ebr_header_buffer)) {
return nullptr;
}
size_t i = 0;
@@ -154,7 +157,7 @@ RefPtr<DiskPartition> EBRPartitionTable::get_extended_partition(unsigned index)
}
i++;
- if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, m_cached_ebr_header)) {
+ if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, ebr_header_buffer)) {
return nullptr;
}
}
diff --git a/Kernel/Devices/FullDevice.cpp b/Kernel/Devices/FullDevice.cpp
index bfd2c15a82..0d43d7a950 100644
--- a/Kernel/Devices/FullDevice.cpp
+++ b/Kernel/Devices/FullDevice.cpp
@@ -46,14 +46,15 @@ bool FullDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> FullDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> FullDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
ssize_t count = min(static_cast<size_t>(PAGE_SIZE), size);
- memset(buffer, 0, count);
+ if (!buffer.memset(0, count))
+ return KResult(-EFAULT);
return count;
}
-KResultOr<size_t> FullDevice::write(FileDescription&, size_t, const u8*, size_t size)
+KResultOr<size_t> FullDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t size)
{
if (size == 0)
return 0;
diff --git a/Kernel/Devices/FullDevice.h b/Kernel/Devices/FullDevice.h
index 3404ce22aa..43070686c1 100644
--- a/Kernel/Devices/FullDevice.h
+++ b/Kernel/Devices/FullDevice.h
@@ -38,8 +38,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* class_name() const override { return "FullDevice"; }
diff --git a/Kernel/Devices/GPTPartitionTable.cpp b/Kernel/Devices/GPTPartitionTable.cpp
index e5413a0336..f442952cd6 100644
--- a/Kernel/Devices/GPTPartitionTable.cpp
+++ b/Kernel/Devices/GPTPartitionTable.cpp
@@ -49,7 +49,8 @@ const GPTPartitionHeader& GPTPartitionTable::header() const
bool GPTPartitionTable::initialize()
{
- if (!m_device->read_block(1, m_cached_header)) {
+ auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header);
+ if (!m_device->read_block(1, header_buffer)) {
return false;
}
@@ -82,7 +83,8 @@ RefPtr<DiskPartition> GPTPartitionTable::partition(unsigned index)
u8 entries_per_sector = BytesPerSector / header.partition_entry_size;
GPTPartitionEntry entries[entries_per_sector];
- this->m_device->read_blocks(lba, 1, (u8*)&entries);
+ auto entries_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&entries);
+ this->m_device->read_blocks(lba, 1, entries_buffer);
GPTPartitionEntry& entry = entries[((index - 1) % entries_per_sector)];
#ifdef GPT_DEBUG
diff --git a/Kernel/Devices/KeyboardDevice.cpp b/Kernel/Devices/KeyboardDevice.cpp
index 531c488a9f..9f60268986 100644
--- a/Kernel/Devices/KeyboardDevice.cpp
+++ b/Kernel/Devices/KeyboardDevice.cpp
@@ -369,7 +369,7 @@ bool KeyboardDevice::can_read(const FileDescription&, size_t) const
return !m_queue.is_empty();
}
-KResultOr<size_t> KeyboardDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> KeyboardDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
size_t nread = 0;
while (nread < size) {
@@ -379,13 +379,19 @@ KResultOr<size_t> KeyboardDevice::read(FileDescription&, size_t, u8* buffer, siz
if ((size - nread) < (ssize_t)sizeof(Event))
break;
auto event = m_queue.dequeue();
- memcpy(buffer, &event, sizeof(Event));
+ ssize_t n = buffer.write_buffered<sizeof(Event)>(sizeof(Event), [&](u8* data, size_t data_bytes) {
+ memcpy(data, &event, sizeof(Event));
+ return (ssize_t)data_bytes;
+ });
+ if (n < 0)
+ return KResult(n);
+ ASSERT((size_t)n == sizeof(Event));
nread += sizeof(Event);
}
return nread;
}
-KResultOr<size_t> KeyboardDevice::write(FileDescription&, size_t, const u8*, size_t)
+KResultOr<size_t> KeyboardDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t)
{
return 0;
}
diff --git a/Kernel/Devices/KeyboardDevice.h b/Kernel/Devices/KeyboardDevice.h
index 74a53a0da6..1d7f60ab7d 100644
--- a/Kernel/Devices/KeyboardDevice.h
+++ b/Kernel/Devices/KeyboardDevice.h
@@ -57,9 +57,9 @@ public:
const String keymap_name() { return m_character_map.character_map_name(); }
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* purpose() const override { return class_name(); }
diff --git a/Kernel/Devices/MBRPartitionTable.cpp b/Kernel/Devices/MBRPartitionTable.cpp
index b836a9b479..a57a5db310 100644
--- a/Kernel/Devices/MBRPartitionTable.cpp
+++ b/Kernel/Devices/MBRPartitionTable.cpp
@@ -49,7 +49,8 @@ const MBRPartitionHeader& MBRPartitionTable::header() const
bool MBRPartitionTable::initialize()
{
- if (!m_device->read_block(0, m_cached_header)) {
+ auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header);
+ if (!m_device->read_block(0, header_buffer)) {
return false;
}
diff --git a/Kernel/Devices/MBVGADevice.cpp b/Kernel/Devices/MBVGADevice.cpp
index f19de93e41..84998f14c8 100644
--- a/Kernel/Devices/MBVGADevice.cpp
+++ b/Kernel/Devices/MBVGADevice.cpp
@@ -79,40 +79,36 @@ int MBVGADevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
switch (request) {
case FB_IOCTL_GET_SIZE_IN_BYTES: {
auto* out = (size_t*)arg;
- if (!Process::current()->validate_write_typed(out))
- return -EFAULT;
size_t value = framebuffer_size_in_bytes();
- copy_to_user(out, &value);
+ if (!copy_to_user(out, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_GET_BUFFER: {
auto* index = (int*)arg;
- if (!Process::current()->validate_write_typed(index))
- return -EFAULT;
int value = 0;
- copy_to_user(index, &value);
+ if (!copy_to_user(index, &value))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_GET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
case FB_IOCTL_SET_RESOLUTION: {
auto* user_resolution = (FBResolution*)arg;
- if (!Process::current()->validate_read_typed(user_resolution) || !Process::current()->validate_write_typed(user_resolution))
- return -EFAULT;
FBResolution resolution;
resolution.pitch = m_framebuffer_pitch;
resolution.width = m_framebuffer_width;
resolution.height = m_framebuffer_height;
- copy_to_user(user_resolution, &resolution);
+ if (!copy_to_user(user_resolution, &resolution))
+ return -EFAULT;
return 0;
}
default:
diff --git a/Kernel/Devices/MBVGADevice.h b/Kernel/Devices/MBVGADevice.h
index 8a7d60e54c..09dda1f853 100644
--- a/Kernel/Devices/MBVGADevice.h
+++ b/Kernel/Devices/MBVGADevice.h
@@ -47,10 +47,10 @@ private:
virtual const char* class_name() const override { return "MBVGA"; }
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override { return -EINVAL; }
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override { return -EINVAL; }
- virtual bool read_blocks(unsigned, u16, u8*) override { return false; }
- virtual bool write_blocks(unsigned, u16, const u8*) override { return false; }
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override { return -EINVAL; }
+ virtual bool read_blocks(unsigned, u16, UserOrKernelBuffer&) override { return false; }
+ virtual bool write_blocks(unsigned, u16, const UserOrKernelBuffer&) override { return false; }
size_t framebuffer_size_in_bytes() const { return m_framebuffer_pitch * m_framebuffer_height; }
diff --git a/Kernel/Devices/NullDevice.cpp b/Kernel/Devices/NullDevice.cpp
index 5c6a5c59c5..260e8d9aa8 100644
--- a/Kernel/Devices/NullDevice.cpp
+++ b/Kernel/Devices/NullDevice.cpp
@@ -56,12 +56,12 @@ bool NullDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> NullDevice::read(FileDescription&, size_t, u8*, size_t)
+KResultOr<size_t> NullDevice::read(FileDescription&, size_t, UserOrKernelBuffer&, size_t)
{
return 0;
}
-KResultOr<size_t> NullDevice::write(FileDescription&, size_t, const u8*, size_t buffer_size)
+KResultOr<size_t> NullDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t buffer_size)
{
return min(static_cast<size_t>(PAGE_SIZE), buffer_size);
}
diff --git a/Kernel/Devices/NullDevice.h b/Kernel/Devices/NullDevice.h
index c7968258f7..4fcc9c0258 100644
--- a/Kernel/Devices/NullDevice.h
+++ b/Kernel/Devices/NullDevice.h
@@ -41,8 +41,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual bool can_read(const FileDescription&, size_t) const override;
virtual const char* class_name() const override { return "NullDevice"; }
diff --git a/Kernel/Devices/PATAChannel.cpp b/Kernel/Devices/PATAChannel.cpp
index 172816ea1b..cc47ff532c 100644
--- a/Kernel/Devices/PATAChannel.cpp
+++ b/Kernel/Devices/PATAChannel.cpp
@@ -274,11 +274,11 @@ void PATAChannel::detect_disks()
}
}
-bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool slave_request)
+bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer& outbuf, bool slave_request)
{
LOCKER(s_lock());
#ifdef PATA_DEBUG
- dbg() << "PATAChannel::ata_read_sectors_with_dma (" << lba << " x" << count << ") -> " << outbuf;
+ dbg() << "PATAChannel::ata_read_sectors_with_dma (" << lba << " x" << count << ") -> " << outbuf.user_or_kernel_ptr();
#endif
prdt().offset = m_dma_buffer_page->paddr();
@@ -335,24 +335,26 @@ bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool
if (m_device_error)
return false;
- memcpy(outbuf, m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * count);
+ if (!outbuf.write(m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * count))
+ return false; // TODO: -EFAULT
// I read somewhere that this may trigger a cache flush so let's do it.
m_bus_master_base.offset(2).out<u8>(m_bus_master_base.offset(2).in<u8>() | 0x6);
return true;
}
-bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf, bool slave_request)
+bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer& inbuf, bool slave_request)
{
LOCKER(s_lock());
#ifdef PATA_DEBUG
- dbg() << "PATAChannel::ata_write_sectors_with_dma (" << lba << " x" << count << ") <- " << inbuf;
+ dbg() << "PATAChannel::ata_write_sectors_with_dma (" << lba << " x" << count << ") <- " << inbuf.user_or_kernel_ptr();
#endif
prdt().offset = m_dma_buffer_page->paddr();
prdt().size = 512 * count;
- memcpy(m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), inbuf, 512 * count);
+ if (!inbuf.read(m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * count))
+ return false; // TODO: -EFAULT
ASSERT(prdt().size <= PAGE_SIZE);
@@ -406,12 +408,12 @@ bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf
return true;
}
-bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_request)
+bool PATAChannel::ata_read_sectors(u32 lba, u16 count, UserOrKernelBuffer& outbuf, bool slave_request)
{
ASSERT(count <= 256);
LOCKER(s_lock());
#ifdef PATA_DEBUG
- dbg() << "PATAChannel::ata_read_sectors request (" << count << " sector(s) @ " << lba << " into " << outbuf << ")";
+ dbg() << "PATAChannel::ata_read_sectors request (" << count << " sector(s) @ " << lba << " into " << outbuf.user_or_kernel_ptr() << ")";
#endif
while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY)
@@ -460,14 +462,21 @@ bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_re
u8 status = m_control_base.offset(ATA_CTL_ALTSTATUS).in<u8>();
ASSERT(!(status & ATA_SR_BSY));
- auto* buffer = (u16*)(outbuf + i * 512);
+ auto out = outbuf.offset(i * 512);
#ifdef PATA_DEBUG
- dbg() << "PATAChannel: Retrieving 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), outbuf=(" << buffer << ")...";
+ dbg() << "PATAChannel: Retrieving 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), outbuf=(" << out.user_or_kernel_ptr() << ")...";
#endif
prepare_for_irq();
- for (int i = 0; i < 256; i++) {
- buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get());
+ ssize_t nwritten = out.write_buffered<512>(512, [&](u8* buffer, size_t buffer_bytes) {
+ for (size_t i = 0; i < buffer_bytes; i += sizeof(u16))
+ *(u16*)&buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get());
+ return (ssize_t)buffer_bytes;
+ });
+ if (nwritten < 0) {
+ sti();
+ disable_irq();
+ return false; // TODO: -EFAULT
}
}
@@ -476,7 +485,7 @@ bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_re
return true;
}
-bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf, bool slave_request)
+bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const UserOrKernelBuffer& inbuf, bool slave_request)
{
ASSERT(count <= 256);
LOCKER(s_lock());
@@ -515,17 +524,21 @@ bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf
u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
ASSERT(status & ATA_SR_DRQ);
+ auto in = inbuf.offset(i * 512);
#ifdef PATA_DEBUG
- dbg() << "PATAChannel: Writing 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), inbuf=(" << (inbuf + (512 * i)) << ")...";
+ dbg() << "PATAChannel: Writing 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), inbuf=(" << in.user_or_kernel_ptr() << ")...";
#endif
prepare_for_irq();
- auto* buffer = (u16*)(const_cast<u8*>(inbuf) + i * 512);
- for (int i = 0; i < 256; i++) {
- IO::out16(m_io_base.offset(ATA_REG_DATA).get(), buffer[i]);
- }
+ ssize_t nread = in.read_buffered<512>(512, [&](const u8* buffer, size_t buffer_bytes) {
+ for (size_t i = 0; i < buffer_bytes; i += sizeof(u16))
+ IO::out16(m_io_base.offset(ATA_REG_DATA).get(), *(const u16*)&buffer[i]);
+ return (ssize_t)buffer_bytes;
+ });
wait_for_irq();
status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
ASSERT(!(status & ATA_SR_BSY));
+ if (nread < 0)
+ return false; // TODO: -EFAULT
}
prepare_for_irq();
m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_CACHE_FLUSH);
diff --git a/Kernel/Devices/PATAChannel.h b/Kernel/Devices/PATAChannel.h
index 60ed95d6c1..40e331a4e8 100644
--- a/Kernel/Devices/PATAChannel.h
+++ b/Kernel/Devices/PATAChannel.h
@@ -84,10 +84,10 @@ private:
void detect_disks();
void wait_for_irq();
- bool ata_read_sectors_with_dma(u32, u16, u8*, bool);
- bool ata_write_sectors_with_dma(u32, u16, const u8*, bool);
- bool ata_read_sectors(u32, u16, u8*, bool);
- bool ata_write_sectors(u32, u16, const u8*, bool);
+ bool ata_read_sectors_with_dma(u32, u16, UserOrKernelBuffer&, bool);
+ bool ata_write_sectors_with_dma(u32, u16, const UserOrKernelBuffer&, bool);
+ bool ata_read_sectors(u32, u16, UserOrKernelBuffer&, bool);
+ bool ata_write_sectors(u32, u16, const UserOrKernelBuffer&, bool);
inline void prepare_for_irq();
diff --git a/Kernel/Devices/PATADiskDevice.cpp b/Kernel/Devices/PATADiskDevice.cpp
index 384c0c7bba..a81f7bb557 100644
--- a/Kernel/Devices/PATADiskDevice.cpp
+++ b/Kernel/Devices/PATADiskDevice.cpp
@@ -55,19 +55,19 @@ const char* PATADiskDevice::class_name() const
return "PATADiskDevice";
}
-bool PATADiskDevice::read_blocks(unsigned index, u16 count, u8* out)
+bool PATADiskDevice::read_blocks(unsigned index, u16 count, UserOrKernelBuffer& out)
{
if (!m_channel.m_bus_master_base.is_null() && m_channel.m_dma_enabled.resource())
return read_sectors_with_dma(index, count, out);
return read_sectors(index, count, out);
}
-bool PATADiskDevice::write_blocks(unsigned index, u16 count, const u8* data)
+bool PATADiskDevice::write_blocks(unsigned index, u16 count, const UserOrKernelBuffer& data)
{
if (!m_channel.m_bus_master_base.is_null() && m_channel.m_dma_enabled.resource())
return write_sectors_with_dma(index, count, data);
for (unsigned i = 0; i < count; ++i) {
- if (!write_sectors(index + i, 1, data + i * 512))
+ if (!write_sectors(index + i, 1, data.offset(i * 512)))
return false;
}
return true;
@@ -80,7 +80,7 @@ void PATADiskDevice::set_drive_geometry(u16 cyls, u16 heads, u16 spt)
m_sectors_per_track = spt;
}
-KResultOr<size_t> PATADiskDevice::read(FileDescription&, size_t offset, u8* outbuf, size_t len)
+KResultOr<size_t> PATADiskDevice::read(FileDescription&, size_t offset, UserOrKernelBuffer& outbuf, size_t len)
{
unsigned index = offset / block_size();
u16 whole_blocks = len / block_size();
@@ -107,10 +107,12 @@ KResultOr<size_t> PATADiskDevice::read(FileDescription&, size_t offset, u8* outb
off_t pos = whole_blocks * block_size();
if (remaining > 0) {
- auto buf = ByteBuffer::create_uninitialized(block_size());
- if (!read_blocks(index + whole_blocks, 1, buf.data()))
+ auto data = ByteBuffer::create_uninitialized(block_size());
+ auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
+ if (!read_blocks(index + whole_blocks, 1, data_buffer))
return pos;
- memcpy(&outbuf[pos], buf.data(), remaining);
+ if (!outbuf.write(data.data(), pos, remaining))
+ return KResult(-EFAULT);
}
return pos + remaining;
@@ -121,7 +123,7 @@ bool PATADiskDevice::can_read(const FileDescription&, size_t offset) const
return offset < (m_cylinders * m_heads * m_sectors_per_track * block_size());
}
-KResultOr<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const u8* inbuf, size_t len)
+KResultOr<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const UserOrKernelBuffer& inbuf, size_t len)
{
unsigned index = offset / block_size();
u16 whole_blocks = len / block_size();
@@ -151,11 +153,13 @@ KResultOr<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const u
// partial write, we have to read the block's content first, modify it,
// then write the whole block back to the disk.
if (remaining > 0) {
- auto buf = ByteBuffer::create_zeroed(block_size());
- if (!read_blocks(index + whole_blocks, 1, buf.data()))
+ auto data = ByteBuffer::create_zeroed(block_size());
+ auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data.data());
+ if (!read_blocks(index + whole_blocks, 1, data_buffer))
return pos;
- memcpy(buf.data(), &inbuf[pos], remaining);
- if (!write_blocks(index + whole_blocks, 1, buf.data()))
+ if (!inbuf.read(data.data(), pos, remaining))
+ return KResult(-EFAULT);
+ if (!write_blocks(index + whole_blocks, 1, data_buffer))
return pos;
}
@@ -167,22 +171,22 @@ bool PATADiskDevice::can_write(const FileDescription&, size_t offset) const
return offset < (m_cylinders * m_heads * m_sectors_per_track * block_size());
}
-bool PATADiskDevice::read_sectors_with_dma(u32 lba, u16 count, u8* outbuf)
+bool PATADiskDevice::read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer& outbuf)
{
return m_channel.ata_read_sectors_with_dma(lba, count, outbuf, is_slave());
}
-bool PATADiskDevice::read_sectors(u32 start_sector, u16 count, u8* outbuf)
+bool PATADiskDevice::read_sectors(u32 start_sector, u16 count, UserOrKernelBuffer& outbuf)
{
return m_channel.ata_read_sectors(start_sector, count, outbuf, is_slave());
}
-bool PATADiskDevice::write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf)
+bool PATADiskDevice::write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer& inbuf)
{
return m_channel.ata_write_sectors_with_dma(lba, count, inbuf, is_slave());
}
-bool PATADiskDevice::write_sectors(u32 start_sector, u16 count, const u8* inbuf)
+bool PATADiskDevice::write_sectors(u32 start_sector, u16 count, const UserOrKernelBuffer& inbuf)
{
return m_channel.ata_write_sectors(start_sector, count, inbuf, is_slave());
}
diff --git a/Kernel/Devices/PATADiskDevice.h b/Kernel/Devices/PATADiskDevice.h
index d9b7fa9432..eb9377e1bf 100644
--- a/Kernel/Devices/PATADiskDevice.h
+++ b/Kernel/Devices/PATADiskDevice.h
@@ -55,15 +55,15 @@ public:
virtual ~PATADiskDevice() override;
// ^DiskDevice
- virtual bool read_blocks(unsigned index, u16 count, u8*) override;
- virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
+ virtual bool read_blocks(unsigned index, u16 count, UserOrKernelBuffer&) override;
+ virtual bool write_blocks(unsigned index, u16 count, const UserOrKernelBuffer&) override;
void set_drive_geometry(u16, u16, u16);
// ^BlockDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
protected:
@@ -74,10 +74,10 @@ private:
virtual const char* class_name() const override;
bool wait_for_irq();
- bool read_sectors_with_dma(u32 lba, u16 count, u8*);
- bool write_sectors_with_dma(u32 lba, u16 count, const u8*);
- bool read_sectors(u32 lba, u16 count, u8* buffer);
- bool write_sectors(u32 lba, u16 count, const u8* data);
+ bool read_sectors_with_dma(u32 lba, u16 count, UserOrKernelBuffer&);
+ bool write_sectors_with_dma(u32 lba, u16 count, const UserOrKernelBuffer&);
+ bool read_sectors(u32 lba, u16 count, UserOrKernelBuffer& buffer);
+ bool write_sectors(u32 lba, u16 count, const UserOrKernelBuffer& data);
bool is_slave() const;
Lock m_lock { "IDEDiskDevice" };
diff --git a/Kernel/Devices/PS2MouseDevice.cpp b/Kernel/Devices/PS2MouseDevice.cpp
index 65fcc33264..75ae40524e 100644
--- a/Kernel/Devices/PS2MouseDevice.cpp
+++ b/Kernel/Devices/PS2MouseDevice.cpp
@@ -336,7 +336,7 @@ bool PS2MouseDevice::can_read(const FileDescription&, size_t) const
return !m_queue.is_empty();
}
-KResultOr<size_t> PS2MouseDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> PS2MouseDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
ASSERT(size > 0);
size_t nread = 0;
@@ -349,14 +349,15 @@ KResultOr<size_t> PS2MouseDevice::read(FileDescription&, size_t, u8* buffer, siz
dbg() << "PS2 Mouse Read: Filter packets";
#endif
size_t bytes_read_from_packet = min(remaining_space_in_buffer, sizeof(MousePacket));
- memcpy(buffer + nread, &packet, bytes_read_from_packet);
+ if (!buffer.write(&packet, nread, bytes_read_from_packet))
+ return KResult(-EFAULT);
nread += bytes_read_from_packet;
remaining_space_in_buffer -= bytes_read_from_packet;
}
return nread;
}
-KResultOr<size_t> PS2MouseDevice::write(FileDescription&, size_t, const u8*, size_t)
+KResultOr<size_t> PS2MouseDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t)
{
return 0;
}
diff --git a/Kernel/Devices/PS2MouseDevice.h b/Kernel/Devices/PS2MouseDevice.h
index 10f382f43d..07cfcc7a61 100644
--- a/Kernel/Devices/PS2MouseDevice.h
+++ b/Kernel/Devices/PS2MouseDevice.h
@@ -45,8 +45,8 @@ public:
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* purpose() const override { return class_name(); }
diff --git a/Kernel/Devices/RandomDevice.cpp b/Kernel/Devices/RandomDevice.cpp
index 5c6b7eb22b..fa625d0ecf 100644
--- a/Kernel/Devices/RandomDevice.cpp
+++ b/Kernel/Devices/RandomDevice.cpp
@@ -43,13 +43,18 @@ bool RandomDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> RandomDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> RandomDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
- get_good_random_bytes(buffer, size);
+ bool success = buffer.write_buffered<256>(size, [&](u8* data, size_t data_size) {
+ get_good_random_bytes(data, data_size);
+ return (ssize_t)data_size;
+ });
+ if (!success)
+ return KResult(-EFAULT);
return size;
}
-KResultOr<size_t> RandomDevice::write(FileDescription&, size_t, const u8*, size_t size)
+KResultOr<size_t> RandomDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t size)
{
// FIXME: Use input for entropy? I guess that could be a neat feature?
return min(static_cast<size_t>(PAGE_SIZE), size);
diff --git a/Kernel/Devices/RandomDevice.h b/Kernel/Devices/RandomDevice.h
index d8951297ab..c419934107 100644
--- a/Kernel/Devices/RandomDevice.h
+++ b/Kernel/Devices/RandomDevice.h
@@ -38,8 +38,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* class_name() const override { return "RandomDevice"; }
diff --git a/Kernel/Devices/SB16.cpp b/Kernel/Devices/SB16.cpp
index 8d7406f39b..eb6d15b993 100644
--- a/Kernel/Devices/SB16.cpp
+++ b/Kernel/Devices/SB16.cpp
@@ -177,7 +177,7 @@ bool SB16::can_read(const FileDescription&, size_t) const
return false;
}
-KResultOr<size_t> SB16::read(FileDescription&, size_t, u8*, size_t)
+KResultOr<size_t> SB16::read(FileDescription&, size_t, UserOrKernelBuffer&, size_t)
{
return 0;
}
@@ -231,7 +231,7 @@ void SB16::wait_for_irq()
disable_irq();
}
-KResultOr<size_t> SB16::write(FileDescription&, size_t, const u8* data, size_t length)
+KResultOr<size_t> SB16::write(FileDescription&, size_t, const UserOrKernelBuffer& data, size_t length)
{
if (!m_dma_region) {
auto page = MM.allocate_supervisor_physical_page();
@@ -252,7 +252,8 @@ KResultOr<size_t> SB16::write(FileDescription&, size_t, const u8* data, size_t l
const int sample_rate = 44100;
set_sample_rate(sample_rate);
- memcpy(m_dma_region->vaddr().as_ptr(), data, length);
+ if (!data.read(m_dma_region->vaddr().as_ptr(), length))
+ return KResult(-EFAULT);
dma_start(length);
// 16-bit single-cycle output.
diff --git a/Kernel/Devices/SB16.h b/Kernel/Devices/SB16.h
index e0d5ba7ca3..cc18fde5ef 100644
--- a/Kernel/Devices/SB16.h
+++ b/Kernel/Devices/SB16.h
@@ -47,8 +47,8 @@ public:
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* purpose() const override { return class_name(); }
diff --git a/Kernel/Devices/SerialDevice.cpp b/Kernel/Devices/SerialDevice.cpp
index e286afb7d4..a54a8bed3e 100644
--- a/Kernel/Devices/SerialDevice.cpp
+++ b/Kernel/Devices/SerialDevice.cpp
@@ -45,7 +45,7 @@ bool SerialDevice::can_read(const FileDescription&, size_t) const
return (get_line_status() & DataReady) != 0;
}
-KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
if (!size)
return 0;
@@ -53,9 +53,15 @@ KResultOr<size_t> SerialDevice::read(FileDescription&, size_t, u8* buffer, size_
if (!(get_line_status() & DataReady))
return 0;
- buffer[0] = IO::in8(m_base_addr);
+ ssize_t nwritten = buffer.write_buffered<128>(size, [&](u8* data, size_t data_size) {
+ for (size_t i = 0; i < data_size; i++)
+ data[i] = IO::in8(m_base_addr);
+ return (ssize_t)data_size;
+ });
+ if (nwritten < 0)
+ return KResult(nwritten);
- return 1;
+ return size;
}
bool SerialDevice::can_write(const FileDescription&, size_t) const
@@ -63,7 +69,7 @@ bool SerialDevice::can_write(const FileDescription&, size_t) const
return (get_line_status() & EmptyTransmitterHoldingRegister) != 0;
}
-KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const u8* buffer, size_t size)
+KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size)
{
if (!size)
return 0;
@@ -71,9 +77,14 @@ KResultOr<size_t> SerialDevice::write(FileDescription&, size_t, const u8* buffer
if (!(get_line_status() & EmptyTransmitterHoldingRegister))
return 0;
- IO::out8(m_base_addr, buffer[0]);
-
- return 1;
+ ssize_t nread = buffer.read_buffered<128>(size, [&](const u8* data, size_t data_size) {
+ for (size_t i = 0; i < data_size; i++)
+ IO::out8(m_base_addr, data[i]);
+ return (ssize_t)data_size;
+ });
+ if (nread < 0)
+ return KResult(nread);
+ return (size_t)nread;
}
void SerialDevice::initialize()
diff --git a/Kernel/Devices/SerialDevice.h b/Kernel/Devices/SerialDevice.h
index bac77ce9b1..5c76f5abdf 100644
--- a/Kernel/Devices/SerialDevice.h
+++ b/Kernel/Devices/SerialDevice.h
@@ -43,9 +43,9 @@ public:
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
enum InterruptEnable {
LowPowerMode = 0x01 << 5,
diff --git a/Kernel/Devices/ZeroDevice.cpp b/Kernel/Devices/ZeroDevice.cpp
index e568d9a215..ac326434d0 100644
--- a/Kernel/Devices/ZeroDevice.cpp
+++ b/Kernel/Devices/ZeroDevice.cpp
@@ -44,14 +44,15 @@ bool ZeroDevice::can_read(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> ZeroDevice::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> ZeroDevice::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
ssize_t count = min(static_cast<size_t>(PAGE_SIZE), size);
- memset(buffer, 0, count);
+ if (!buffer.memset(0, count))
+ return KResult(-EFAULT);
return count;
}
-KResultOr<size_t> ZeroDevice::write(FileDescription&, size_t, const u8*, size_t size)
+KResultOr<size_t> ZeroDevice::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t size)
{
return min(static_cast<size_t>(PAGE_SIZE), size);
}
diff --git a/Kernel/Devices/ZeroDevice.h b/Kernel/Devices/ZeroDevice.h
index 0f3e76e5d6..f307c6f645 100644
--- a/Kernel/Devices/ZeroDevice.h
+++ b/Kernel/Devices/ZeroDevice.h
@@ -38,8 +38,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
virtual const char* class_name() const override { return "ZeroDevice"; }
diff --git a/Kernel/DoubleBuffer.cpp b/Kernel/DoubleBuffer.cpp
index 6cc74f5ed7..4b9285e327 100644
--- a/Kernel/DoubleBuffer.cpp
+++ b/Kernel/DoubleBuffer.cpp
@@ -58,7 +58,7 @@ void DoubleBuffer::flip()
compute_lockfree_metadata();
}
-size_t DoubleBuffer::write(const u8* data, size_t size)
+ssize_t DoubleBuffer::write(const UserOrKernelBuffer& data, size_t size)
{
if (!size)
return 0;
@@ -68,11 +68,12 @@ size_t DoubleBuffer::write(const u8* data, size_t size)
u8* write_ptr = m_write_buffer->data + m_write_buffer->size;
m_write_buffer->size += bytes_to_write;
compute_lockfree_metadata();
- memcpy(write_ptr, data, bytes_to_write);
- return bytes_to_write;
+ if (!data.read(write_ptr, bytes_to_write))
+ return -EFAULT;
+ return (ssize_t)bytes_to_write;
}
-size_t DoubleBuffer::read(u8* data, size_t size)
+ssize_t DoubleBuffer::read(UserOrKernelBuffer& data, size_t size)
{
if (!size)
return 0;
@@ -83,10 +84,11 @@ size_t DoubleBuffer::read(u8* data, size_t size)
if (m_read_buffer_index >= m_read_buffer->size)
return 0;
size_t nread = min(m_read_buffer->size - m_read_buffer_index, size);
- memcpy(data, m_read_buffer->data + m_read_buffer_index, nread);
+ if (!data.write(m_read_buffer->data + m_read_buffer_index, nread))
+ return -EFAULT;
m_read_buffer_index += nread;
compute_lockfree_metadata();
- return nread;
+ return (ssize_t)nread;
}
}
diff --git a/Kernel/DoubleBuffer.h b/Kernel/DoubleBuffer.h
index 02a8a2bf12..b855fb8853 100644
--- a/Kernel/DoubleBuffer.h
+++ b/Kernel/DoubleBuffer.h
@@ -29,6 +29,7 @@
#include <AK/Types.h>
#include <Kernel/KBuffer.h>
#include <Kernel/Lock.h>
+#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
@@ -36,8 +37,17 @@ class DoubleBuffer {
public:
explicit DoubleBuffer(size_t capacity = 65536);
- size_t write(const u8*, size_t);
- size_t read(u8*, size_t);
+ [[nodiscard]] ssize_t write(const UserOrKernelBuffer&, size_t);
+ [[nodiscard]] ssize_t write(const u8* data, size_t size)
+ {
+ return write(UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>(data)), size);
+ }
+ [[nodiscard]] ssize_t read(UserOrKernelBuffer&, size_t);
+ [[nodiscard]] ssize_t read(u8* data, size_t size)
+ {
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(data);
+ return read(buffer, size);
+ }
bool is_empty() const { return m_empty; }
diff --git a/Kernel/FileSystem/BlockBasedFileSystem.cpp b/Kernel/FileSystem/BlockBasedFileSystem.cpp
index e5880e0897..2df34a58bb 100644
--- a/Kernel/FileSystem/BlockBasedFileSystem.cpp
+++ b/Kernel/FileSystem/BlockBasedFileSystem.cpp
@@ -119,7 +119,7 @@ BlockBasedFS::~BlockBasedFS()
{
}
-bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, size_t offset, bool allow_cache)
+int BlockBasedFS::write_block(unsigned index, const UserOrKernelBuffer& data, size_t count, size_t offset, bool allow_cache)
{
ASSERT(m_logical_block_size);
ASSERT(offset + count <= block_size());
@@ -133,9 +133,9 @@ bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, siz
file_description().seek(base_offset, SEEK_SET);
auto nwritten = file_description().write(data, count);
if (nwritten.is_error())
- return false;
+ return -EIO; // TODO: Return error code as-is, could be -EFAULT!
ASSERT(nwritten.value() == count);
- return true;
+ return 0;
}
auto& entry = cache().get(index);
@@ -143,15 +143,16 @@ bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, siz
// Fill the cache first.
read_block(index, nullptr, block_size());
}
- memcpy(entry.data + offset, data, count);
+ if (!data.read(entry.data + offset, count))
+ return -EFAULT;
entry.is_dirty = true;
entry.has_data = true;
cache().set_dirty(true);
- return true;
+ return 0;
}
-bool BlockBasedFS::raw_read(unsigned index, u8* buffer)
+bool BlockBasedFS::raw_read(unsigned index, UserOrKernelBuffer& buffer)
{
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size);
file_description().seek(base_offset, SEEK_SET);
@@ -160,7 +161,7 @@ bool BlockBasedFS::raw_read(unsigned index, u8* buffer)
ASSERT(nread.value() == m_logical_block_size);
return true;
}
-bool BlockBasedFS::raw_write(unsigned index, const u8* buffer)
+bool BlockBasedFS::raw_write(unsigned index, const UserOrKernelBuffer& buffer)
{
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size);
file_description().seek(base_offset, SEEK_SET);
@@ -170,37 +171,39 @@ bool BlockBasedFS::raw_write(unsigned index, const u8* buffer)
return true;
}
-bool BlockBasedFS::raw_read_blocks(unsigned index, size_t count, u8* buffer)
+bool BlockBasedFS::raw_read_blocks(unsigned index, size_t count, UserOrKernelBuffer& buffer)
{
+ auto current = buffer;
for (unsigned block = index; block < (index + count); block++) {
- if (!raw_read(block, buffer))
+ if (!raw_read(block, current))
return false;
- buffer += logical_block_size();
+ current = current.offset(logical_block_size());
}
return true;
}
-bool BlockBasedFS::raw_write_blocks(unsigned index, size_t count, const u8* buffer)
+bool BlockBasedFS::raw_write_blocks(unsigned index, size_t count, const UserOrKernelBuffer& buffer)
{
+ auto current = buffer;
for (unsigned block = index; block < (index + count); block++) {
- if (!raw_write(block, buffer))
+ if (!raw_write(block, current))
return false;
- buffer += logical_block_size();
+ current = current.offset(logical_block_size());
}
return true;
}
-bool BlockBasedFS::write_blocks(unsigned index, unsigned count, const u8* data, bool allow_cache)
+int BlockBasedFS::write_blocks(unsigned index, unsigned count, const UserOrKernelBuffer& data, bool allow_cache)
{
ASSERT(m_logical_block_size);
#ifdef BBFS_DEBUG
klog() << "BlockBasedFileSystem::write_blocks " << index << " x" << count;
#endif
for (unsigned i = 0; i < count; ++i)
- write_block(index + i, data + i * block_size(), block_size(), 0, allow_cache);
- return true;
+ write_block(index + i, data.offset(i * block_size()), block_size(), 0, allow_cache);
+ return 0;
}
-bool BlockBasedFS::read_block(unsigned index, u8* buffer, size_t count, size_t offset, bool allow_cache) const
+int BlockBasedFS::read_block(unsigned index, UserOrKernelBuffer* buffer, size_t count, size_t offset, bool allow_cache) const
{
ASSERT(m_logical_block_size);
ASSERT(offset + count <= block_size());
@@ -212,44 +215,45 @@ bool BlockBasedFS::read_block(unsigned index, u8* buffer, size_t count, size_t o
const_cast<BlockBasedFS*>(this)->flush_specific_block_if_needed(index);
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size()) + static_cast<u32>(offset);
file_description().seek(base_offset, SEEK_SET);
- auto nread = file_description().read(buffer, count);
+ auto nread = file_description().read(*buffer, count);
if (nread.is_error())
- return false;
+ return -EIO;
ASSERT(nread.value() == count);
- return true;
+ return 0;
}
auto& entry = cache().get(index);
if (!entry.has_data) {
u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size());
file_description().seek(base_offset, SEEK_SET);
- auto nread = file_description().read(entry.data, block_size());
+ auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data);
+ auto nread = file_description().read(entry_data_buffer, block_size());
if (nread.is_error())
- return false;
+ return -EIO;
ASSERT(nread.value() == block_size());
entry.has_data = true;
}
- if (buffer)
- memcpy(buffer, entry.data + offset, count);
- return true;
+ if (buffer && !buffer->write(entry.data + offset, count))
+ return -EFAULT;
+ return 0;
}
-bool BlockBasedFS::read_blocks(unsigned index, unsigned count, u8* buffer, bool allow_cache) const
+int BlockBasedFS::read_blocks(unsigned index, unsigned count, UserOrKernelBuffer& buffer, bool allow_cache) const
{
ASSERT(m_logical_block_size);
if (!count)
return false;
if (count == 1)
- return read_block(index, buffer, block_size(), 0, allow_cache);
- u8* out = buffer;
-
+ return read_block(index, &buffer, block_size(), 0, allow_cache);
+ auto out = buffer;
for (unsigned i = 0; i < count; ++i) {
- if (!read_block(index + i, out, block_size(), 0, allow_cache))
- return false;
- out += block_size();
+ auto err = read_block(index + i, &out, block_size(), 0, allow_cache);
+ if (err < 0)
+ return err;
+ out = out.offset(block_size());
}
- return true;
+ return 0;
}
void BlockBasedFS::flush_specific_block_if_needed(unsigned index)
@@ -262,7 +266,8 @@ void BlockBasedFS::flush_specific_block_if_needed(unsigned index)
u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size());
file_description().seek(base_offset, SEEK_SET);
// FIXME: Should this error path be surfaced somehow?
- (void)file_description().write(entry.data, block_size());
+ auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data);
+ (void)file_description().write(entry_data_buffer, block_size());
entry.is_dirty = false;
}
});
@@ -280,7 +285,8 @@ void BlockBasedFS::flush_writes_impl()
u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size());
file_description().seek(base_offset, SEEK_SET);
// FIXME: Should this error path be surfaced somehow?
- (void)file_description().write(entry.data, block_size());
+ auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data);
+ (void)file_description().write(entry_data_buffer, block_size());
++count;
entry.is_dirty = false;
});
diff --git a/Kernel/FileSystem/BlockBasedFileSystem.h b/Kernel/FileSystem/BlockBasedFileSystem.h
index b9f7bdf601..fcf096aec3 100644
--- a/Kernel/FileSystem/BlockBasedFileSystem.h
+++ b/Kernel/FileSystem/BlockBasedFileSystem.h
@@ -42,17 +42,17 @@ public:
protected:
explicit BlockBasedFS(FileDescription&);
- bool read_block(unsigned index, u8* buffer, size_t count, size_t offset = 0, bool allow_cache = true) const;
- bool read_blocks(unsigned index, unsigned count, u8* buffer, bool allow_cache = true) const;
+ int read_block(unsigned index, UserOrKernelBuffer* buffer, size_t count, size_t offset = 0, bool allow_cache = true) const;
+ int read_blocks(unsigned index, unsigned count, UserOrKernelBuffer& buffer, bool allow_cache = true) const;
- bool raw_read(unsigned index, u8* buffer);
- bool raw_write(unsigned index, const u8* buffer);
+ bool raw_read(unsigned index, UserOrKernelBuffer& buffer);
+ bool raw_write(unsigned index, const UserOrKernelBuffer& buffer);
- bool raw_read_blocks(unsigned index, size_t count, u8* buffer);
- bool raw_write_blocks(unsigned index, size_t count, const u8* buffer);
+ bool raw_read_blocks(unsigned index, size_t count, UserOrKernelBuffer& buffer);
+ bool raw_write_blocks(unsigned index, size_t count, const UserOrKernelBuffer& buffer);
- bool write_block(unsigned index, const u8* buffer, size_t count, size_t offset = 0, bool allow_cache = true);
- bool write_blocks(unsigned index, unsigned count, const u8*, bool allow_cache = true);
+ int write_block(unsigned index, const UserOrKernelBuffer& buffer, size_t count, size_t offset = 0, bool allow_cache = true);
+ int write_blocks(unsigned index, unsigned count, const UserOrKernelBuffer&, bool allow_cache = true);
size_t m_logical_block_size { 512 };
diff --git a/Kernel/FileSystem/DevPtsFS.cpp b/Kernel/FileSystem/DevPtsFS.cpp
index 01b78c44c0..d05437591a 100644
--- a/Kernel/FileSystem/DevPtsFS.cpp
+++ b/Kernel/FileSystem/DevPtsFS.cpp
@@ -120,12 +120,12 @@ DevPtsFSInode::~DevPtsFSInode()
{
}
-ssize_t DevPtsFSInode::read_bytes(off_t, ssize_t, u8*, FileDescription*) const
+ssize_t DevPtsFSInode::read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const
{
ASSERT_NOT_REACHED();
}
-ssize_t DevPtsFSInode::write_bytes(off_t, ssize_t, const u8*, FileDescription*)
+ssize_t DevPtsFSInode::write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*)
{
ASSERT_NOT_REACHED();
}
diff --git a/Kernel/FileSystem/DevPtsFS.h b/Kernel/FileSystem/DevPtsFS.h
index 3c302180fe..8ac7571136 100644
--- a/Kernel/FileSystem/DevPtsFS.h
+++ b/Kernel/FileSystem/DevPtsFS.h
@@ -67,12 +67,12 @@ private:
DevPtsFSInode(DevPtsFS&, unsigned index, SlavePTY*);
// ^Inode
- virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override;
- virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
virtual KResult remove_child(const StringView& name) override;
diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp
index cbc9a93968..52b3037c68 100644
--- a/Kernel/FileSystem/Ext2FileSystem.cpp
+++ b/Kernel/FileSystem/Ext2FileSystem.cpp
@@ -88,7 +88,8 @@ bool Ext2FS::flush_super_block()
{
LOCKER(m_lock);
ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0);
- bool success = raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), (const u8*)&m_super_block);
+ auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block);
+ bool success = raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer);
ASSERT(success);
return true;
}
@@ -104,7 +105,8 @@ bool Ext2FS::initialize()
{
LOCKER(m_lock);
ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0);
- bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), (u8*)&m_super_block);
+ auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block);
+ bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer);
ASSERT(success);
auto& super_block = this->super_block();
@@ -139,7 +141,8 @@ bool Ext2FS::initialize()
unsigned blocks_to_read = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size());
BlockIndex first_block_of_bgdt = block_size() == 1024 ? 2 : 1;
m_cached_group_descriptor_table = KBuffer::create_with_size(block_size() * blocks_to_read, Region::Access::Read | Region::Access::Write, "Ext2FS: Block group descriptors");
- read_blocks(first_block_of_bgdt, blocks_to_read, m_cached_group_descriptor_table.value().data());
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_group_descriptor_table.value().data());
+ read_blocks(first_block_of_bgdt, blocks_to_read, buffer);
#ifdef EXT2_DEBUG
for (unsigned i = 1; i <= m_block_group_count; ++i) {
@@ -291,8 +294,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
--remaining_blocks;
}
stream.fill_to_end(0);
- bool success = write_block(e2inode.i_block[EXT2_IND_BLOCK], block_contents.data(), block_size());
- ASSERT(success);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(block_contents.data());
+ int err = write_block(e2inode.i_block[EXT2_IND_BLOCK], buffer, block_size());
+ ASSERT(err >= 0);
}
if (!remaining_blocks)
@@ -329,7 +333,8 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
memset(dind_block_contents.data(), 0, dind_block_contents.size());
dind_block_dirty = true;
} else {
- read_block(e2inode.i_block[EXT2_DIND_BLOCK], dind_block_contents.data(), block_size());
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(dind_block_contents.data());
+ read_block(e2inode.i_block[EXT2_DIND_BLOCK], &buffer, block_size());
}
auto* dind_block_as_pointers = (unsigned*)dind_block_contents.data();
@@ -351,7 +356,8 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
memset(ind_block_contents.data(), 0, dind_block_contents.size());
ind_block_dirty = true;
} else {
- read_block(indirect_block_index, ind_block_contents.data(), block_size());
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(ind_block_contents.data());
+ read_block(indirect_block_index, &buffer, block_size());
}
auto* ind_block_as_pointers = (unsigned*)ind_block_contents.data();
@@ -376,8 +382,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
}
if (ind_block_dirty) {
- bool success = write_block(indirect_block_index, ind_block_contents.data(), block_size());
- ASSERT(success);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(ind_block_contents.data());
+ int err = write_block(indirect_block_index, buffer, block_size());
+ ASSERT(err >= 0);
}
}
for (unsigned i = indirect_block_count; i < entries_per_block; ++i) {
@@ -388,8 +395,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
}
if (dind_block_dirty) {
- bool success = write_block(e2inode.i_block[EXT2_DIND_BLOCK], dind_block_contents.data(), block_size());
- ASSERT(success);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(dind_block_contents.data());
+ int err = write_block(e2inode.i_block[EXT2_DIND_BLOCK], buffer, block_size());
+ ASSERT(err >= 0);
}
}
@@ -462,7 +470,8 @@ Vector<Ext2FS::BlockIndex> Ext2FS::block_list_for_inode_impl(const ext2_inode& e
unsigned count = min(blocks_remaining, entries_per_block);
size_t read_size = count * sizeof(__u32);
auto array_block = ByteBuffer::create_uninitialized(read_size);
- read_block(array_block_index, array_block.data(), read_size, 0);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(array_block.data());
+ read_block(array_block_index, &buffer, read_size, 0);
ASSERT(array_block);
auto* array = reinterpret_cast<const __u32*>(array_block.data());
for (BlockIndex i = 0; i < count; ++i)
@@ -532,7 +541,8 @@ void Ext2FS::flush_block_group_descriptor_table()
LOCKER(m_lock);
unsigned blocks_to_write = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size());
unsigned first_block_of_bgdt = block_size() == 1024 ? 2 : 1;
- write_blocks(first_block_of_bgdt, blocks_to_write, (const u8*)block_group_descriptors());
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)block_group_descriptors());
+ write_blocks(first_block_of_bgdt, blocks_to_write, buffer);
}
void Ext2FS::flush_writes()
@@ -548,7 +558,8 @@ void Ext2FS::flush_writes()
}
for (auto& cached_bitmap : m_cached_bitmaps) {
if (cached_bitmap->dirty) {
- write_block(cached_bitmap->bitmap_block_index, cached_bitmap->buffer.data(), block_size());
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(cached_bitmap->buffer.data());
+ write_block(cached_bitmap->bitmap_block_index, buffer, block_size());
cached_bitmap->dirty = false;
#ifdef EXT2_DEBUG
dbg() << "Flushed bitmap block " << cached_bitmap->bitmap_block_index;
@@ -653,12 +664,13 @@ RefPtr<Inode> Ext2FS::get_inode(InodeIdentifier inode) const
return {};
auto new_inode = adopt(*new Ext2FSInode(const_cast<Ext2FS&>(*this), inode.index()));
- read_block(block_index, reinterpret_cast<u8*>(&new_inode->m_raw_inode), sizeof(ext2_inode), offset);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(reinterpret_cast<u8*>(&new_inode->m_raw_inode));
+ read_block(block_index, &buffer, sizeof(ext2_inode), offset);
m_inode_cache.set(inode.index(), new_inode);
return new_inode;
}
-ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const
+ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
{
Locker inode_locker(m_lock);
ASSERT(offset >= 0);
@@ -670,7 +682,8 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
if (is_symlink() && size() < max_inline_symlink_length) {
ASSERT(offset == 0);
ssize_t nread = min((off_t)size() - offset, static_cast<off_t>(count));
- memcpy(buffer, ((const u8*)m_raw_inode.i_block) + offset, (size_t)nread);
+ if (!buffer.write(((const u8*)m_raw_inode.i_block) + offset, (size_t)nread))
+ return -EFAULT;
return nread;
}
@@ -697,10 +710,9 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
ssize_t nread = 0;
size_t remaining_count = min((off_t)count, (off_t)size() - offset);
- u8* out = buffer;
#ifdef EXT2_DEBUG
- dbg() << "Ext2FS: Reading up to " << count << " bytes " << offset << " bytes into inode " << identifier() << " to " << (const void*)buffer;
+ dbg() << "Ext2FS: Reading up to " << count << " bytes " << offset << " bytes into inode " << identifier() << " to " << buffer.user_or_kernel_ptr();
#endif
for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) {
@@ -708,14 +720,14 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
ASSERT(block_index);
size_t offset_into_block = (bi == first_block_logical_index) ? offset_into_first_block : 0;
size_t num_bytes_to_copy = min(block_size - offset_into_block, remaining_count);
- bool success = fs().read_block(block_index, out, num_bytes_to_copy, offset_into_block, allow_cache);
- if (!success) {
+ auto buffer_offset = buffer.offset(nread);
+ int err = fs().read_block(block_index, &buffer_offset, num_bytes_to_copy, offset_into_block, allow_cache);
+ if (err < 0) {
klog() << "ext2fs: read_bytes: read_block(" << block_index << ") failed (lbi: " << bi << ")";
- return -EIO;
+ return err;
}
remaining_count -= num_bytes_to_copy;
nread += num_bytes_to_copy;
- out += num_bytes_to_copy;
}
return nread;
@@ -760,9 +772,9 @@ KResult Ext2FSInode::resize(u64 new_size)
}
}
- bool success = fs().write_block_list_for_inode(index(), m_raw_inode, block_list);
- if (!success)
- return KResult(-EIO);
+ int err = fs().write_block_list_for_inode(index(), m_raw_inode, block_list);
+ if (err < 0)
+ return KResult(err);
m_raw_inode.i_size = new_size;
set_metadata_dirty(true);
@@ -771,7 +783,7 @@ KResult Ext2FSInode::resize(u64 new_size)
return KSuccess;
}
-ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, FileDescription* description)
+ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const UserOrKernelBuffer& data, FileDescription* description)
{
ASSERT(offset >= 0);
ASSERT(count >= 0);
@@ -787,9 +799,10 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
ASSERT(offset == 0);
if (max((size_t)(offset + count), (size_t)m_raw_inode.i_size) < max_inline_symlink_length) {
#ifdef EXT2_DEBUG
- dbg() << "Ext2FS: write_bytes poking into i_block array for inline symlink '" << StringView(data, count) << " ' (" << count << " bytes)";
+ dbg() << "Ext2FS: write_bytes poking into i_block array for inline symlink '" << data.copy_into_string(count) << " ' (" << count << " bytes)";
#endif
- memcpy(((u8*)m_raw_inode.i_block) + offset, data, (size_t)count);
+ if (!data.read(((u8*)m_raw_inode.i_block) + offset, (size_t)count))
+ return -EFAULT;
if ((size_t)(offset + count) > (size_t)m_raw_inode.i_size)
m_raw_inode.i_size = offset + count;
set_metadata_dirty(true);
@@ -824,10 +837,9 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
ssize_t nwritten = 0;
size_t remaining_count = min((off_t)count, (off_t)new_size - offset);
- const u8* in = data;
#ifdef EXT2_DEBUG
- dbg() << "Ext2FS: Writing " << count << " bytes " << offset << " bytes into inode " << identifier() << " from " << (const void*)data;
+ dbg() << "Ext2FS: Writing " << count << " bytes " << offset << " bytes into inode " << identifier() << " from " << data.user_or_kernel_ptr();
#endif
for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) {
@@ -836,15 +848,14 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
#ifdef EXT2_DEBUG
dbg() << "Ext2FS: Writing block " << m_block_list[bi] << " (offset_into_block: " << offset_into_block << ")";
#endif
- bool success = fs().write_block(m_block_list[bi], in, num_bytes_to_copy, offset_into_block, allow_cache);
- if (!success) {
+ int err = fs().write_block(m_block_list[bi], data.offset(nwritten), num_bytes_to_copy, offset_into_block, allow_cache);
+ if (err < 0) {
dbg() << "Ext2FS: write_block(" << m_block_list[bi] << ") failed (bi: " << bi << ")";
ASSERT_NOT_REACHED();
- return -EIO;
+ return err;
}
remaining_count -= num_bytes_to_copy;
nwritten += num_bytes_to_copy;
- in += num_bytes_to_copy;
}
#ifdef EXT2_DEBUG
@@ -958,7 +969,8 @@ bool Ext2FSInode::write_directory(const Vector<Ext2FSDirectoryEntry>& entries)
stream.fill_to_end(0);
- ssize_t nwritten = write_bytes(0, directory_data.size(), directory_data.data(), nullptr);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(directory_data.data());
+ ssize_t nwritten = write_bytes(0, directory_data.size(), buffer, nullptr);
if (nwritten < 0)
return false;
set_metadata_dirty(true);
@@ -1087,7 +1099,8 @@ bool Ext2FS::write_ext2_inode(unsigned inode, const ext2_inode& e2inode)
unsigned offset;
if (!find_block_containing_inode(inode, block_index, offset))
return false;
- return write_block(block_index, reinterpret_cast<const u8*>(&e2inode), inode_size(), offset);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)&e2inode));
+ return write_block(block_index, buffer, inode_size(), offset) >= 0;
}
Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(GroupIndex preferred_group_index, size_t count)
@@ -1314,8 +1327,9 @@ Ext2FS::CachedBitmap& Ext2FS::get_bitmap_block(BlockIndex bitmap_block_index)
}
auto block = KBuffer::create_with_size(block_size(), Region::Access::Read | Region::Access::Write, "Ext2FS: Cached bitmap block");
- bool success = read_block(bitmap_block_index, block.data(), block_size());
- ASSERT(success);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(block.data());
+ int err = read_block(bitmap_block_index, &buffer, block_size());
+ ASSERT(err >= 0);
m_cached_bitmaps.append(make<CachedBitmap>(bitmap_block_index, move(block)));
return *m_cached_bitmaps.last();
}
diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h
index bdaa3255ca..7d28b84ff2 100644
--- a/Kernel/FileSystem/Ext2FileSystem.h
+++ b/Kernel/FileSystem/Ext2FileSystem.h
@@ -58,12 +58,12 @@ public:
private:
// ^Inode
- virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override;
- virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override;
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) override;
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
virtual KResult add_child(Inode& child, const StringView& name, mode_t) override;
virtual KResult remove_child(const StringView& name) override;
diff --git a/Kernel/FileSystem/FIFO.cpp b/Kernel/FileSystem/FIFO.cpp
index 3f9c1e33a1..2aa6c55cd9 100644
--- a/Kernel/FileSystem/FIFO.cpp
+++ b/Kernel/FileSystem/FIFO.cpp
@@ -145,14 +145,14 @@ bool FIFO::can_write(const FileDescription&, size_t) const
return m_buffer.space_for_writing() || !m_readers;
}
-KResultOr<size_t> FIFO::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> FIFO::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
if (!m_writers && m_buffer.is_empty())
return 0;
return m_buffer.read(buffer, size);
}
-KResultOr<size_t> FIFO::write(FileDescription&, size_t, const u8* buffer, size_t size)
+KResultOr<size_t> FIFO::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size)
{
if (!m_readers) {
Thread::current()->send_signal(SIGPIPE, Process::current());
diff --git a/Kernel/FileSystem/FIFO.h b/Kernel/FileSystem/FIFO.h
index 81b04597f2..8e3a146012 100644
--- a/Kernel/FileSystem/FIFO.h
+++ b/Kernel/FileSystem/FIFO.h
@@ -57,8 +57,8 @@ public:
private:
// ^File
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual KResult stat(::stat&) const override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override;
diff --git a/Kernel/FileSystem/File.h b/Kernel/FileSystem/File.h
index 150f04f518..b2400b803b 100644
--- a/Kernel/FileSystem/File.h
+++ b/Kernel/FileSystem/File.h
@@ -34,6 +34,7 @@
#include <Kernel/Forward.h>
#include <Kernel/KResult.h>
#include <Kernel/UnixTypes.h>
+#include <Kernel/UserOrKernelBuffer.h>
#include <Kernel/VirtualAddress.h>
namespace Kernel {
@@ -77,8 +78,8 @@ public:
virtual bool can_read(const FileDescription&, size_t) const = 0;
virtual bool can_write(const FileDescription&, size_t) const = 0;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) = 0;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) = 0;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) = 0;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) = 0;
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg);
virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared);
virtual KResult stat(::stat&) const { return KResult(-EBADF); }
diff --git a/Kernel/FileSystem/FileDescription.cpp b/Kernel/FileSystem/FileDescription.cpp
index 80153e6225..8c88dfc816 100644
--- a/Kernel/FileSystem/FileDescription.cpp
+++ b/Kernel/FileSystem/FileDescription.cpp
@@ -116,7 +116,7 @@ off_t FileDescription::seek(off_t offset, int whence)
return m_current_offset;
}
-KResultOr<size_t> FileDescription::read(u8* buffer, size_t count)
+KResultOr<size_t> FileDescription::read(UserOrKernelBuffer& buffer, size_t count)
{
LOCKER(m_lock);
Checked<size_t> new_offset = m_current_offset;
@@ -130,7 +130,7 @@ KResultOr<size_t> FileDescription::read(u8* buffer, size_t count)
return nread_or_error;
}
-KResultOr<size_t> FileDescription::write(const u8* data, size_t size)
+KResultOr<size_t> FileDescription::write(const UserOrKernelBuffer& data, size_t size)
{
LOCKER(m_lock);
Checked<size_t> new_offset = m_current_offset;
@@ -162,7 +162,7 @@ KResultOr<KBuffer> FileDescription::read_entire_file()
return m_inode->read_entire(this);
}
-ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size)
+ssize_t FileDescription::get_dir_entries(UserOrKernelBuffer& buffer, ssize_t size)
{
LOCKER(m_lock, Lock::Mode::Shared);
if (!is_directory())
@@ -195,7 +195,8 @@ ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size)
if (static_cast<size_t>(size) < temp_buffer.size())
return -EINVAL;
- copy_to_user(buffer, temp_buffer.data(), temp_buffer.size());
+ if (!buffer.write(temp_buffer.data(), temp_buffer.size()))
+ return -EFAULT;
return stream.offset();
}
diff --git a/Kernel/FileSystem/FileDescription.h b/Kernel/FileSystem/FileDescription.h
index 3427ad1e18..60d85db945 100644
--- a/Kernel/FileSystem/FileDescription.h
+++ b/Kernel/FileSystem/FileDescription.h
@@ -60,8 +60,8 @@ public:
KResult close();
off_t seek(off_t, int whence);
- KResultOr<size_t> read(u8*, size_t);
- KResultOr<size_t> write(const u8* data, size_t);
+ KResultOr<size_t> read(UserOrKernelBuffer&, size_t);
+ KResultOr<size_t> write(const UserOrKernelBuffer& data, size_t);
KResult stat(::stat&);
KResult chmod(mode_t);
@@ -69,7 +69,7 @@ public:
bool can_read() const;
bool can_write() const;
- ssize_t get_dir_entries(u8* buffer, ssize_t);
+ ssize_t get_dir_entries(UserOrKernelBuffer& buffer, ssize_t);
KResultOr<KBuffer> read_entire_file();
diff --git a/Kernel/FileSystem/FileSystem.h b/Kernel/FileSystem/FileSystem.h
index 19fea4bafd..99a8131ca4 100644
--- a/Kernel/FileSystem/FileSystem.h
+++ b/Kernel/FileSystem/FileSystem.h
@@ -34,6 +34,7 @@
#include <Kernel/KResult.h>
#include <Kernel/Lock.h>
#include <Kernel/UnixTypes.h>
+#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
diff --git a/Kernel/FileSystem/Inode.cpp b/Kernel/FileSystem/Inode.cpp
index e78f87bf59..b0e91bafc5 100644
--- a/Kernel/FileSystem/Inode.cpp
+++ b/Kernel/FileSystem/Inode.cpp
@@ -73,7 +73,10 @@ KResultOr<KBuffer> Inode::read_entire(FileDescription* descriptor) const
u8 buffer[4096];
off_t offset = 0;
for (;;) {
- nread = read_bytes(offset, sizeof(buffer), buffer, descriptor);
+ auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer);
+ nread = read_bytes(offset, sizeof(buffer), buf, descriptor);
+ if (nread < 0)
+ return KResult(nread);
ASSERT(nread <= (ssize_t)sizeof(buffer));
if (nread <= 0)
break;
@@ -124,7 +127,7 @@ void Inode::will_be_destroyed()
flush_metadata();
}
-void Inode::inode_contents_changed(off_t offset, ssize_t size, const u8* data)
+void Inode::inode_contents_changed(off_t offset, ssize_t size, const UserOrKernelBuffer& data)
{
if (m_shared_vmobject)
m_shared_vmobject->inode_contents_changed({}, offset, size, data);
diff --git a/Kernel/FileSystem/Inode.h b/Kernel/FileSystem/Inode.h
index f9ed0db158..d506ab0d18 100644
--- a/Kernel/FileSystem/Inode.h
+++ b/Kernel/FileSystem/Inode.h
@@ -69,10 +69,10 @@ public:
KResultOr<KBuffer> read_entire(FileDescription* = nullptr) const;
- virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const = 0;
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const = 0;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0;
virtual RefPtr<Inode> lookup(StringView name) = 0;
- virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) = 0;
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) = 0;
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) = 0;
virtual KResult add_child(Inode&, const StringView& name, mode_t) = 0;
virtual KResult remove_child(const StringView& name) = 0;
@@ -122,7 +122,7 @@ public:
protected:
Inode(FS& fs, unsigned index);
void set_metadata_dirty(bool);
- void inode_contents_changed(off_t, ssize_t, const u8*);
+ void inode_contents_changed(off_t, ssize_t, const UserOrKernelBuffer&);
void inode_size_changed(size_t old_size, size_t new_size);
KResult prepare_to_write_data();
diff --git a/Kernel/FileSystem/InodeFile.cpp b/Kernel/FileSystem/InodeFile.cpp
index c2657fe969..bc4d243957 100644
--- a/Kernel/FileSystem/InodeFile.cpp
+++ b/Kernel/FileSystem/InodeFile.cpp
@@ -44,7 +44,7 @@ InodeFile::~InodeFile()
{
}
-KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, u8* buffer, size_t count)
+KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, UserOrKernelBuffer& buffer, size_t count)
{
ssize_t nread = m_inode->read_bytes(offset, count, buffer, &description);
if (nread > 0)
@@ -54,7 +54,7 @@ KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, u
return nread;
}
-KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset, const u8* data, size_t count)
+KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset, const UserOrKernelBuffer& data, size_t count)
{
ssize_t nwritten = m_inode->write_bytes(offset, count, data, &description);
if (nwritten > 0) {
diff --git a/Kernel/FileSystem/InodeFile.h b/Kernel/FileSystem/InodeFile.h
index ab64201b3b..e051476b2b 100644
--- a/Kernel/FileSystem/InodeFile.h
+++ b/Kernel/FileSystem/InodeFile.h
@@ -47,8 +47,8 @@ public:
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) override;
virtual String absolute_path(const FileDescription&) const override;
diff --git a/Kernel/FileSystem/InodeWatcher.cpp b/Kernel/FileSystem/InodeWatcher.cpp
index a4612a588d..6e76cc69b6 100644
--- a/Kernel/FileSystem/InodeWatcher.cpp
+++ b/Kernel/FileSystem/InodeWatcher.cpp
@@ -57,7 +57,7 @@ bool InodeWatcher::can_write(const FileDescription&, size_t) const
return true;
}
-KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, u8* buffer, size_t buffer_size)
+KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t buffer_size)
{
LOCKER(m_lock);
ASSERT(!m_queue.is_empty() || !m_inode);
@@ -68,11 +68,17 @@ KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, u8* buffer, size_
// FIXME: What should we do if the output buffer is too small?
ASSERT(buffer_size >= (int)sizeof(Event));
auto event = m_queue.dequeue();
- memcpy(buffer, &event, sizeof(event));
+ ssize_t nwritten = buffer.write_buffered<sizeof(event)>(sizeof(event), [&](u8* data, size_t data_bytes) {
+ memcpy(data, &event, sizeof(event));
+ return (ssize_t)data_bytes;
+ });
+ if (nwritten < 0)
+ return KResult(nwritten);
+ ASSERT((size_t)nwritten == sizeof(event));
return sizeof(event);
}
-KResultOr<size_t> InodeWatcher::write(FileDescription&, size_t, const u8*, size_t)
+KResultOr<size_t> InodeWatcher::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t)
{
return KResult(-EIO);
}
diff --git a/Kernel/FileSystem/InodeWatcher.h b/Kernel/FileSystem/InodeWatcher.h
index 31a094b88f..cd371e2f1a 100644
--- a/Kernel/FileSystem/InodeWatcher.h
+++ b/Kernel/FileSystem/InodeWatcher.h
@@ -55,8 +55,8 @@ public:
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual String absolute_path(const FileDescription&) const override;
virtual const char* class_name() const override { return "InodeWatcher"; };
diff --git a/Kernel/FileSystem/Plan9FileSystem.cpp b/Kernel/FileSystem/Plan9FileSystem.cpp
index 952a176066..975883df67 100644
--- a/Kernel/FileSystem/Plan9FileSystem.cpp
+++ b/Kernel/FileSystem/Plan9FileSystem.cpp
@@ -426,7 +426,8 @@ KResult Plan9FS::post_message(Message& message)
if (Thread::current()->block<Thread::WriteBlocker>(nullptr, description).was_interrupted())
return KResult(-EINTR);
}
- auto nwritten_or_error = description.write(data, size);
+ auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>(data));
+ auto nwritten_or_error = description.write(data_buffer, size);
if (nwritten_or_error.is_error())
return nwritten_or_error.error();
auto nwritten = nwritten_or_error.value();
@@ -445,7 +446,8 @@ KResult Plan9FS::do_read(u8* data, size_t size)
if (Thread::current()->block<Thread::ReadBlocker>(nullptr, description).was_interrupted())
return KResult(-EINTR);
}
- auto nread_or_error = description.read(data, size);
+ auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data);
+ auto nread_or_error = description.read(data_buffer, size);
if (nread_or_error.is_error())
return nread_or_error.error();
auto nread = nread_or_error.value();
@@ -677,7 +679,7 @@ KResult Plan9FSInode::ensure_open_for_mode(int mode)
}
}
-ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescription*) const
+ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, UserOrKernelBuffer& buffer, FileDescription*) const
{
auto result = const_cast<Plan9FSInode&>(*this).ensure_open_for_mode(O_RDONLY);
if (result.is_error())
@@ -710,12 +712,13 @@ ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDes
// Guard against the server returning more data than requested.
size_t nread = min(data.length(), (size_t)size);
- memcpy(buffer, data.characters_without_null_termination(), nread);
+ if (!buffer.write(data.characters_without_null_termination(), nread))
+ return -EFAULT;
return nread;
}
-ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const u8* data, FileDescription*)
+ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& data, FileDescription*)
{
auto result = ensure_open_for_mode(O_WRONLY);
if (result.is_error())
@@ -723,9 +726,13 @@ ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const u8* data, Fi
size = fs().adjust_buffer_size(size);
+ auto data_copy = data.copy_into_string(size); // FIXME: this seems ugly
+ if (data_copy.is_null())
+ return -EFAULT;
+
Plan9FS::Message message { fs(), Plan9FS::Message::Type::Twrite };
message << fid() << (u64)offset;
- message.append_data({ data, (size_t)size });
+ message.append_data(data_copy);
result = fs().post_message_and_wait_for_a_reply(message);
if (result.is_error())
return result.error();
diff --git a/Kernel/FileSystem/Plan9FileSystem.h b/Kernel/FileSystem/Plan9FileSystem.h
index 77af39e47a..5851cbe8dd 100644
--- a/Kernel/FileSystem/Plan9FileSystem.h
+++ b/Kernel/FileSystem/Plan9FileSystem.h
@@ -124,8 +124,8 @@ public:
// ^Inode
virtual InodeMetadata metadata() const override;
virtual void flush_metadata() override;
- virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
- virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override;
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp
index 0fe482cf36..eef030b29f 100644
--- a/Kernel/FileSystem/ProcFS.cpp
+++ b/Kernel/FileSystem/ProcFS.cpp
@@ -976,21 +976,33 @@ static ByteBuffer read_sys_bool(InodeIdentifier inode_id)
return buffer;
}
-static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data)
+static ssize_t write_sys_bool(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size)
{
auto& variable = SysVariable::for_inode(inode_id);
ASSERT(variable.type == SysVariable::Type::Boolean);
- if (data.is_empty() || !(data[0] == '0' || data[0] == '1'))
- return data.size();
+ char value = 0;
+ bool did_read = false;
+ ssize_t nread = buffer.read_buffered<1>(1, [&](const u8* data, size_t) {
+ if (did_read)
+ return 0;
+ value = (char)data[0];
+ did_read = true;
+ return 1;
+ });
+ if (nread < 0)
+ return nread;
+ ASSERT(nread == 0 || (nread == 1 && did_read));
+ if (nread == 0 || !(value == '0' || value == '1'))
+ return (ssize_t)size;
auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address);
{
LOCKER(lockable_bool->lock());
- lockable_bool->resource() = data[0] == '1';
+ lockable_bool->resource() = value == '1';
}
variable.notify();
- return data.size();
+ return (ssize_t)size;
}
static ByteBuffer read_sys_string(InodeIdentifier inode_id)
@@ -1003,18 +1015,22 @@ static ByteBuffer read_sys_string(InodeIdentifier inode_id)
return lockable_string->resource().to_byte_buffer();
}
-static ssize_t write_sys_string(InodeIdentifier inode_id, const ByteBuffer& data)
+static ssize_t write_sys_string(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size)
{
auto& variable = SysVariable::for_inode(inode_id);
ASSERT(variable.type == SysVariable::Type::String);
+ auto string_copy = buffer.copy_into_string(size);
+ if (string_copy.is_null())
+ return -EFAULT;
+
{
auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address);
LOCKER(lockable_string->lock());
- lockable_string->resource() = String((const char*)data.data(), data.size());
+ lockable_string->resource() = move(string_copy);
}
variable.notify();
- return data.size();
+ return (ssize_t)size;
}
void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&& notify_callback)
@@ -1180,13 +1196,13 @@ InodeMetadata ProcFSInode::metadata() const
return metadata;
}
-ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const
+ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const
{
#ifdef PROCFS_DEBUG
dbg() << "ProcFS: read_bytes " << index();
#endif
ASSERT(offset >= 0);
- ASSERT(buffer);
+ ASSERT(buffer.user_or_kernel_ptr());
auto* directory_entry = fs().get_directory_entry(identifier());
@@ -1240,7 +1256,8 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
return 0;
ssize_t nread = min(static_cast<off_t>(data.value().size() - offset), static_cast<off_t>(count));
- memcpy(buffer, data.value().data() + offset, nread);
+ if (!buffer.write(data.value().data() + offset, nread))
+ return -EFAULT;
if (nread == 0 && description && description->generator_cache().has_value())
description->generator_cache().clear();
@@ -1461,7 +1478,7 @@ void ProcFSInode::flush_metadata()
{
}
-ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*)
+ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& buffer, FileDescription*)
{
auto result = prepare_to_write_data();
if (result.is_error())
@@ -1469,8 +1486,8 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F
auto* directory_entry = fs().get_directory_entry(identifier());
- Function<ssize_t(InodeIdentifier, const ByteBuffer&)> callback_tmp;
- Function<ssize_t(InodeIdentifier, const ByteBuffer&)>* write_callback { nullptr };
+ Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)> callback_tmp;
+ Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)>* write_callback { nullptr };
if (directory_entry == nullptr) {
if (to_proc_parent_directory(identifier()) == PDI_Root_sys) {
@@ -1496,9 +1513,10 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F
ASSERT(is_persistent_inode(identifier()));
// FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support..
ASSERT(offset == 0);
- bool success = (*write_callback)(identifier(), ByteBuffer::wrap(const_cast<u8*>(buffer), size));
- ASSERT(success);
- return 0;
+ ssize_t nwritten = (*write_callback)(identifier(), buffer, (size_t)size);
+ if (nwritten < 0)
+ klog() << "ProcFS: Writing " << size << " bytes failed: " << nwritten;
+ return nwritten;
}
KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const
diff --git a/Kernel/FileSystem/ProcFS.h b/Kernel/FileSystem/ProcFS.h
index a68df543f0..5d2d3fb124 100644
--- a/Kernel/FileSystem/ProcFS.h
+++ b/Kernel/FileSystem/ProcFS.h
@@ -59,7 +59,7 @@ private:
struct ProcFSDirectoryEntry {
ProcFSDirectoryEntry() { }
- ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
+ ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
: name(a_name)
, proc_file_type(a_proc_file_type)
, supervisor_only(a_supervisor_only)
@@ -73,7 +73,7 @@ private:
unsigned proc_file_type { 0 };
bool supervisor_only { false };
Function<Optional<KBuffer>(InodeIdentifier)> read_callback;
- Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback;
+ Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)> write_callback;
RefPtr<ProcFSInode> inode;
InodeIdentifier identifier(unsigned fsid) const;
};
@@ -96,12 +96,12 @@ public:
private:
// ^Inode
- virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override;
- virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
virtual KResult remove_child(const StringView& name) override;
@@ -123,12 +123,12 @@ public:
private:
// ^Inode
- virtual ssize_t read_bytes(off_t, ssize_t, u8*, FileDescription*) const override { ASSERT_NOT_REACHED(); }
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const override { ASSERT_NOT_REACHED(); }
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); }
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override {};
- virtual ssize_t write_bytes(off_t, ssize_t, const u8*, FileDescription*) override { ASSERT_NOT_REACHED(); }
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*) override { ASSERT_NOT_REACHED(); }
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
virtual KResult remove_child(const StringView& name) override;
diff --git a/Kernel/FileSystem/TmpFS.cpp b/Kernel/FileSystem/TmpFS.cpp
index 04ac98d33d..31222d6e87 100644
--- a/Kernel/FileSystem/TmpFS.cpp
+++ b/Kernel/FileSystem/TmpFS.cpp
@@ -141,7 +141,7 @@ KResult TmpFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry
return KSuccess;
}
-ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescription*) const
+ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, UserOrKernelBuffer& buffer, FileDescription*) const
{
LOCKER(m_lock, Lock::Mode::Shared);
ASSERT(!is_directory());
@@ -157,11 +157,12 @@ ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescr
if (static_cast<off_t>(size) > m_metadata.size - offset)
size = m_metadata.size - offset;
- memcpy(buffer, m_content.value().data() + offset, size);
+ if (!buffer.write(m_content.value().data() + offset, size))
+ return -EFAULT;
return size;
}
-ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*)
+ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& buffer, FileDescription*)
{
LOCKER(m_lock);
ASSERT(!is_directory());
@@ -199,7 +200,8 @@ ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, Fi
inode_size_changed(old_size, new_size);
}
- memcpy(m_content.value().data() + offset, buffer, size);
+ if (!buffer.read(m_content.value().data() + offset, size)) // TODO: partial reads?
+ return -EFAULT;
inode_contents_changed(offset, size, buffer);
return size;
@@ -343,8 +345,10 @@ KResult TmpFSInode::truncate(u64 size)
if (old_size != (size_t)size) {
inode_size_changed(old_size, size);
- if (m_content.has_value())
- inode_contents_changed(0, size, m_content.value().data());
+ if (m_content.has_value()) {
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_content.value().data());
+ inode_contents_changed(0, size, buffer);
+ }
}
return KSuccess;
diff --git a/Kernel/FileSystem/TmpFS.h b/Kernel/FileSystem/TmpFS.h
index bb77e6b946..02eed3f17f 100644
--- a/Kernel/FileSystem/TmpFS.h
+++ b/Kernel/FileSystem/TmpFS.h
@@ -74,12 +74,12 @@ public:
const TmpFS& fs() const { return static_cast<const TmpFS&>(Inode::fs()); }
// ^Inode
- virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
+ virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override;
virtual InodeMetadata metadata() const override;
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
virtual RefPtr<Inode> lookup(StringView name) override;
virtual void flush_metadata() override;
- virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
+ virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override;
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
virtual KResult remove_child(const StringView& name) override;
diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp
index ea06d462c3..c0c93dfecb 100644
--- a/Kernel/FileSystem/VirtualFileSystem.cpp
+++ b/Kernel/FileSystem/VirtualFileSystem.cpp
@@ -707,7 +707,8 @@ KResult VFS::symlink(StringView target, StringView linkpath, Custody& base)
if (inode_or_error.is_error())
return inode_or_error.error();
auto& inode = inode_or_error.value();
- ssize_t nwritten = inode->write_bytes(0, target.length(), (const u8*)target.characters_without_null_termination(), nullptr);
+ auto target_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)target.characters_without_null_termination()));
+ ssize_t nwritten = inode->write_bytes(0, target.length(), target_buffer, nullptr);
if (nwritten < 0)
return KResult(nwritten);
return KSuccess;
diff --git a/Kernel/Forward.h b/Kernel/Forward.h
index 8a40cdce04..66afa30896 100644
--- a/Kernel/Forward.h
+++ b/Kernel/Forward.h
@@ -68,6 +68,7 @@ class TCPSocket;
class TTY;
class Thread;
class UDPSocket;
+class UserOrKernelBuffer;
class VFS;
class VMObject;
class WaitQueue;
diff --git a/Kernel/KSyms.cpp b/Kernel/KSyms.cpp
index 5a7d26caac..69c01318e0 100644
--- a/Kernel/KSyms.cpp
+++ b/Kernel/KSyms.cpp
@@ -142,16 +142,22 @@ NEVER_INLINE static void dump_backtrace_impl(FlatPtr base_pointer, bool use_ksym
RecognizedSymbol recognized_symbols[max_recognized_symbol_count];
size_t recognized_symbol_count = 0;
if (use_ksyms) {
- for (FlatPtr* stack_ptr = (FlatPtr*)base_pointer;
- (current_process ? current_process->validate_read_from_kernel(VirtualAddress(stack_ptr), sizeof(void*) * 2) : 1) && recognized_symbol_count < max_recognized_symbol_count; stack_ptr = (FlatPtr*)*stack_ptr) {
- FlatPtr retaddr = stack_ptr[1];
+ FlatPtr copied_stack_ptr[2];
+ for (FlatPtr* stack_ptr = (FlatPtr*)base_pointer; stack_ptr && recognized_symbol_count < max_recognized_symbol_count; stack_ptr = (FlatPtr*)copied_stack_ptr[0]) {
+ void* fault_at;
+ if (!safe_memcpy(copied_stack_ptr, stack_ptr, sizeof(copied_stack_ptr), fault_at))
+ break;
+ FlatPtr retaddr = copied_stack_ptr[1];
recognized_symbols[recognized_symbol_count++] = { retaddr, symbolicate_kernel_address(retaddr) };
}
} else {
- for (FlatPtr* stack_ptr = (FlatPtr*)base_pointer;
- (current_process ? current_process->validate_read_from_kernel(VirtualAddress(stack_ptr), sizeof(void*) * 2) : 1); stack_ptr = (FlatPtr*)*stack_ptr) {
- FlatPtr retaddr = stack_ptr[1];
- dbg() << String::format("%x", retaddr) << " (next: " << String::format("%x", (stack_ptr ? (u32*)*stack_ptr : 0)) << ")";
+ void* fault_at;
+ FlatPtr copied_stack_ptr[2];
+ FlatPtr* stack_ptr = (FlatPtr*)base_pointer;
+ while (stack_ptr && safe_memcpy(copied_stack_ptr, stack_ptr, sizeof(copied_stack_ptr), fault_at)) {
+ FlatPtr retaddr = copied_stack_ptr[1];
+ dbg() << String::format("%x", retaddr) << " (next: " << String::format("%x", (stack_ptr ? (u32*)copied_stack_ptr[0] : 0)) << ")";
+ stack_ptr = (FlatPtr*)copied_stack_ptr[0];
}
return;
}
diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp
index 7ddead3e15..c64c036c4d 100644
--- a/Kernel/Net/IPv4Socket.cpp
+++ b/Kernel/Net/IPv4Socket.cpp
@@ -105,7 +105,8 @@ KResult IPv4Socket::bind(Userspace<const sockaddr*> user_address, socklen_t addr
return KResult(-EINVAL);
sockaddr_in address;
- copy_from_user(&address, user_address, sizeof(sockaddr_in));
+ if (!copy_from_user(&address, user_address, sizeof(sockaddr_in)))
+ return KResult(-EFAULT);
if (address.sin_family != AF_INET)
return KResult(-EINVAL);
@@ -144,18 +145,25 @@ KResult IPv4Socket::listen(size_t backlog)
return protocol_listen();
}
-KResult IPv4Socket::connect(FileDescription& description, const sockaddr* address, socklen_t address_size, ShouldBlock should_block)
+KResult IPv4Socket::connect(FileDescription& description, Userspace<const sockaddr*> address, socklen_t address_size, ShouldBlock should_block)
{
if (address_size != sizeof(sockaddr_in))
return KResult(-EINVAL);
- if (address->sa_family != AF_INET)
+ u16 sa_family_copy;
+ auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
+ if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
+ return KResult(-EFAULT);
+ if (sa_family_copy != AF_INET)
return KResult(-EINVAL);
if (m_role == Role::Connected)
return KResult(-EISCONN);
- auto& ia = *(const sockaddr_in*)address;
- m_peer_address = IPv4Address((const u8*)&ia.sin_addr.s_addr);
- m_peer_port = ntohs(ia.sin_port);
+ sockaddr_in safe_address;
+ if (!copy_from_user(&safe_address, (const sockaddr_in*)user_address, sizeof(sockaddr_in)))
+ return KResult(-EFAULT);
+
+ m_peer_address = IPv4Address((const u8*)&safe_address.sin_addr.s_addr);
+ m_peer_port = ntohs(safe_address.sin_port);
return protocol_connect(description, should_block);
}
@@ -193,7 +201,7 @@ int IPv4Socket::allocate_local_port_if_needed()
return port;
}
-KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t data_length, int flags, Userspace<const sockaddr*> addr, socklen_t addr_length)
+KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const UserOrKernelBuffer& data, size_t data_length, int flags, Userspace<const sockaddr*> addr, socklen_t addr_length)
{
(void)flags;
if (addr && addr_length != sizeof(sockaddr_in))
@@ -201,7 +209,7 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t
if (addr) {
sockaddr_in ia;
- if (!Process::current()->validate_read_and_copy_typed(&ia, Userspace<const sockaddr_in*>(addr.ptr())))
+ if (!copy_from_user(&ia, Userspace<const sockaddr_in*>(addr.ptr())))
return KResult(-EFAULT);
if (ia.sin_family != AF_INET) {
@@ -229,7 +237,9 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t
#endif
if (type() == SOCK_RAW) {
- routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), { (const u8*)data, data_length }, m_ttl);
+ int err = routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), data, data_length, m_ttl);
+ if (err < 0)
+ return KResult(err);
return data_length;
}
@@ -239,7 +249,7 @@ KResultOr<size_t> IPv4Socket::sendto(FileDescription&, const void* data, size_t
return nsent_or_error;
}
-KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description, void* buffer, size_t buffer_length, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
+KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_length, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
{
Locker locker(lock());
if (m_receive_buffer.is_empty()) {
@@ -262,7 +272,7 @@ KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description
}
ASSERT(!m_receive_buffer.is_empty());
- int nreceived = m_receive_buffer.read((u8*)buffer, buffer_length);
+ int nreceived = m_receive_buffer.read(buffer, buffer_length);
if (nreceived > 0)
Thread::current()->did_ipv4_socket_read((size_t)nreceived);
@@ -270,7 +280,7 @@ KResultOr<size_t> IPv4Socket::receive_byte_buffered(FileDescription& description
return nreceived;
}
-KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& description, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*> addr, Userspace<socklen_t*> addr_length)
+KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*> addr, Userspace<socklen_t*> addr_length)
{
Locker locker(lock());
ReceivedPacket packet;
@@ -330,27 +340,30 @@ KResultOr<size_t> IPv4Socket::receive_packet_buffered(FileDescription& descripti
out_addr.sin_port = htons(packet.peer_port);
out_addr.sin_family = AF_INET;
Userspace<sockaddr_in*> dest_addr = addr.ptr();
- copy_to_user(dest_addr, &out_addr);
+ if (!copy_to_user(dest_addr, &out_addr))
+ return KResult(-EFAULT);
socklen_t out_length = sizeof(sockaddr_in);
ASSERT(addr_length);
- copy_to_user(addr_length, &out_length);
+ if (!copy_to_user(addr_length, &out_length))
+ return KResult(-EFAULT);
}
if (type() == SOCK_RAW) {
size_t bytes_written = min((size_t) ipv4_packet.payload_size(), buffer_length);
- memcpy(buffer, ipv4_packet.payload(), bytes_written);
+ if (!buffer.write(ipv4_packet.payload(), bytes_written))
+ return KResult(-EFAULT);
return bytes_written;
}
return protocol_receive(packet.data.value(), buffer, buffer_length, flags);
}
-KResultOr<size_t> IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*> user_addr, Userspace<socklen_t*> user_addr_length)
+KResultOr<size_t> IPv4Socket::recvfrom(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*> user_addr, Userspace<socklen_t*> user_addr_length)
{
if (user_addr_length) {
socklen_t addr_length;
- if (!Process::current()->validate_read_and_copy_typed(&addr_length, user_addr_length))
+ if (!copy_from_user(&addr_length, user_addr_length.unsafe_userspace_ptr()))
return KResult(-EFAULT);
if (addr_length < sizeof(sockaddr_in))
return KResult(-EINVAL);
@@ -387,10 +400,13 @@ bool IPv4Socket::did_receive(const IPv4Address& source_address, u16 source_port,
ASSERT(m_can_read);
return false;
}
- auto nreceived_or_error = protocol_receive(packet, m_scratch_buffer.value().data(), m_scratch_buffer.value().size(), 0);
+ auto scratch_buffer = UserOrKernelBuffer::for_kernel_buffer(m_scratch_buffer.value().data());
+ auto nreceived_or_error = protocol_receive(packet, scratch_buffer, m_scratch_buffer.value().size(), 0);
if (nreceived_or_error.is_error())
return false;
- m_receive_buffer.write(m_scratch_buffer.value().data(), nreceived_or_error.value());
+ ssize_t nwritten = m_receive_buffer.write(scratch_buffer, nreceived_or_error.value());
+ if (nwritten < 0)
+ return false;
m_can_read = !m_receive_buffer.is_empty();
} else {
if (m_receive_queue.size() > 2000) {
@@ -452,7 +468,7 @@ KResult IPv4Socket::setsockopt(int level, int option, Userspace<const void*> use
if (user_value_size < sizeof(int))
return KResult(-EINVAL);
int value;
- if (!Process::current()->validate_read_and_copy_typed(&value, static_ptr_cast<const int*>(user_value)))
+ if (!copy_from_user(&value, static_ptr_cast<const int*>(user_value)))
return KResult(-EFAULT);
if (value < 0 || value > 255)
return KResult(-EINVAL);
@@ -470,16 +486,18 @@ KResult IPv4Socket::getsockopt(FileDescription& description, int level, int opti
return Socket::getsockopt(description, level, option, value, value_size);
socklen_t size;
- if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
+ if (!copy_from_user(&size, value_size.unsafe_userspace_ptr()))
return KResult(-EFAULT);
switch (option) {
case IP_TTL:
if (size < sizeof(int))
return KResult(-EINVAL);
- copy_to_user(static_ptr_cast<int*>(value), (int*)&m_ttl);
+ if (!copy_to_user(static_ptr_cast<int*>(value), (int*)&m_ttl))
+ return KResult(-EFAULT);
size = sizeof(int);
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
default:
return KResult(-ENOPROTOOPT);
@@ -493,15 +511,15 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
SmapDisabler disabler;
auto ioctl_route = [request, arg]() {
- auto* route = (rtentry*)arg;
- if (!Process::current()->validate_read_typed(route))
+ rtentry route;
+ if (!copy_from_user(&route, (rtentry*)arg))
return -EFAULT;
- char namebuf[IFNAMSIZ + 1];
- memcpy(namebuf, route->rt_dev, IFNAMSIZ);
- namebuf[sizeof(namebuf) - 1] = '\0';
+ auto copied_ifname = copy_string_from_user(route.rt_dev, IFNAMSIZ);
+ if (copied_ifname.is_null())
+ return -EFAULT;
- auto adapter = NetworkAdapter::lookup_by_name(namebuf);
+ auto adapter = NetworkAdapter::lookup_by_name(copied_ifname);
if (!adapter)
return -ENODEV;
@@ -509,11 +527,11 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
case SIOCADDRT:
if (!Process::current()->is_superuser())
return -EPERM;
- if (route->rt_gateway.sa_family != AF_INET)
+ if (route.rt_gateway.sa_family != AF_INET)
return -EAFNOSUPPORT;
- if ((route->rt_flags & (RTF_UP | RTF_GATEWAY)) != (RTF_UP | RTF_GATEWAY))
+ if ((route.rt_flags & (RTF_UP | RTF_GATEWAY)) != (RTF_UP | RTF_GATEWAY))
return -EINVAL; // FIXME: Find the correct value to return
- adapter->set_ipv4_gateway(IPv4Address(((sockaddr_in&)route->rt_gateway).sin_addr.s_addr));
+ adapter->set_ipv4_gateway(IPv4Address(((sockaddr_in&)route.rt_gateway).sin_addr.s_addr));
return 0;
case SIOCDELRT:
@@ -525,12 +543,13 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
};
auto ioctl_interface = [request, arg]() {
- auto* ifr = (ifreq*)arg;
- if (!Process::current()->validate_read_typed(ifr))
+ ifreq* user_ifr = (ifreq*)arg;
+ ifreq ifr;
+ if (!copy_from_user(&ifr, user_ifr))
return -EFAULT;
char namebuf[IFNAMSIZ + 1];
- memcpy(namebuf, ifr->ifr_name, IFNAMSIZ);
+ memcpy(namebuf, ifr.ifr_name, IFNAMSIZ);
namebuf[sizeof(namebuf) - 1] = '\0';
auto adapter = NetworkAdapter::lookup_by_name(namebuf);
@@ -541,36 +560,39 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
case SIOCSIFADDR:
if (!Process::current()->is_superuser())
return -EPERM;
- if (ifr->ifr_addr.sa_family != AF_INET)
+ if (ifr.ifr_addr.sa_family != AF_INET)
return -EAFNOSUPPORT;
- adapter->set_ipv4_address(IPv4Address(((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr));
+ adapter->set_ipv4_address(IPv4Address(((sockaddr_in&)ifr.ifr_addr).sin_addr.s_addr));
return 0;
case SIOCSIFNETMASK:
if (!Process::current()->is_superuser())
return -EPERM;
- if (ifr->ifr_addr.sa_family != AF_INET)
+ if (ifr.ifr_addr.sa_family != AF_INET)
return -EAFNOSUPPORT;
- adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr->ifr_netmask).sin_addr.s_addr));
+ adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr.ifr_netmask).sin_addr.s_addr));
return 0;
- case SIOCGIFADDR:
- if (!Process::current()->validate_write_typed(ifr))
+ case SIOCGIFADDR: {
+ u16 sa_family = AF_INET;
+ if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
+ return -EFAULT;
+ auto ip4_addr = adapter->ipv4_address().to_u32();
+ if (!copy_to_user(&((sockaddr_in&)user_ifr->ifr_addr).sin_addr.s_addr, &ip4_addr, sizeof(ip4_addr)))
return -EFAULT;
- ifr->ifr_addr.sa_family = AF_INET;
- ((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr = adapter->ipv4_address().to_u32();
return 0;
+ }
- case SIOCGIFHWADDR:
- if (!Process::current()->validate_write_typed(ifr))
+ case SIOCGIFHWADDR: {
+ u16 sa_family = AF_INET;
+ if (!copy_to_user(&user_ifr->ifr_hwaddr.sa_family, &sa_family))
+ return -EFAULT;
+ auto mac_address = adapter->mac_address();
+ if (!copy_to_user(ifr.ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress)))
return -EFAULT;
- ifr->ifr_hwaddr.sa_family = AF_INET;
- {
- auto mac_address = adapter->mac_address();
- memcpy(ifr->ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress));
- }
return 0;
}
+ }
return -EINVAL;
};
diff --git a/Kernel/Net/IPv4Socket.h b/Kernel/Net/IPv4Socket.h
index cb513247ac..675cfbfcd1 100644
--- a/Kernel/Net/IPv4Socket.h
+++ b/Kernel/Net/IPv4Socket.h
@@ -50,7 +50,7 @@ public:
virtual KResult close() override;
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) override;
- virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
+ virtual KResult connect(FileDescription&, Userspace<const sockaddr*>, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
virtual KResult listen(size_t) override;
virtual void get_local_address(sockaddr*, socklen_t*) override;
virtual void get_peer_address(sockaddr*, socklen_t*) override;
@@ -58,8 +58,8 @@ public:
virtual void detach(FileDescription&) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
- virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
+ virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
+ virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t) override;
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
@@ -96,8 +96,8 @@ protected:
virtual KResult protocol_bind() { return KSuccess; }
virtual KResult protocol_listen() { return KSuccess; }
- virtual KResultOr<size_t> protocol_receive(const KBuffer&, void*, size_t, int) { return -ENOTIMPL; }
- virtual KResultOr<size_t> protocol_send(const void*, size_t) { return -ENOTIMPL; }
+ virtual KResultOr<size_t> protocol_receive(const KBuffer&, UserOrKernelBuffer&, size_t, int) { return -ENOTIMPL; }
+ virtual KResultOr<size_t> protocol_send(const UserOrKernelBuffer&, size_t) { return -ENOTIMPL; }
virtual KResult protocol_connect(FileDescription&, ShouldBlock) { return KSuccess; }
virtual int protocol_allocate_local_port() { return 0; }
virtual bool protocol_is_disconnected() const { return false; }
@@ -110,8 +110,8 @@ protected:
private:
virtual bool is_ipv4() const override { return true; }
- KResultOr<size_t> receive_byte_buffered(FileDescription&, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
- KResultOr<size_t> receive_packet_buffered(FileDescription&, void* buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
+ KResultOr<size_t> receive_byte_buffered(FileDescription&, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
+ KResultOr<size_t> receive_packet_buffered(FileDescription&, UserOrKernelBuffer& buffer, size_t buffer_length, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>);
IPv4Address m_local_address;
IPv4Address m_peer_address;
diff --git a/Kernel/Net/LocalSocket.cpp b/Kernel/Net/LocalSocket.cpp
index a401af1e9f..ee08ca0c26 100644
--- a/Kernel/Net/LocalSocket.cpp
+++ b/Kernel/Net/LocalSocket.cpp
@@ -98,7 +98,8 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
return KResult(-EINVAL);
sockaddr_un address;
- copy_from_user(&address, user_address, sizeof(sockaddr_un));
+ if (!copy_from_user(&address, user_address, sizeof(sockaddr_un)))
+ return KResult(-EFAULT);
if (address.sun_family != AF_LOCAL)
return KResult(-EINVAL);
@@ -131,19 +132,25 @@ KResult LocalSocket::bind(Userspace<const sockaddr*> user_address, socklen_t add
return KSuccess;
}
-KResult LocalSocket::connect(FileDescription& description, const sockaddr* address, socklen_t address_size, ShouldBlock)
+KResult LocalSocket::connect(FileDescription& description, Userspace<const sockaddr*> address, socklen_t address_size, ShouldBlock)
{
ASSERT(!m_bound);
if (address_size != sizeof(sockaddr_un))
return KResult(-EINVAL);
- if (address->sa_family != AF_LOCAL)
+ u16 sa_family_copy;
+ auto* user_address = reinterpret_cast<const sockaddr*>(address.unsafe_userspace_ptr());
+ if (!copy_from_user(&sa_family_copy, &user_address->sa_family, sizeof(u16)))
+ return KResult(-EFAULT);
+ if (sa_family_copy != AF_LOCAL)
return KResult(-EINVAL);
if (is_connected())
return KResult(-EISCONN);
- const sockaddr_un& local_address = *reinterpret_cast<const sockaddr_un*>(address);
+ const auto& local_address = *reinterpret_cast<const sockaddr_un*>(user_address);
char safe_address[sizeof(local_address.sun_path) + 1] = { 0 };
- memcpy(safe_address, local_address.sun_path, sizeof(local_address.sun_path));
+ if (!copy_from_user(&safe_address[0], &local_address.sun_path[0], sizeof(safe_address) - 1))
+ return KResult(-EFAULT);
+ safe_address[sizeof(safe_address) - 1] = '\0';
#ifdef DEBUG_LOCAL_SOCKET
dbg() << "LocalSocket{" << this << "} connect(" << safe_address << ")";
@@ -159,7 +166,8 @@ KResult LocalSocket::connect(FileDescription& description, const sockaddr* addre
if (!m_file->inode()->socket())
return KResult(-ECONNREFUSED);
- m_address = local_address;
+ m_address.sun_family = sa_family_copy;
+ memcpy(m_address.sun_path, safe_address, sizeof(m_address.sun_path));
ASSERT(m_connect_side_fd == &description);
m_connect_side_role = Role::Connecting;
@@ -260,11 +268,11 @@ bool LocalSocket::can_write(const FileDescription& description, size_t) const
return false;
}
-KResultOr<size_t> LocalSocket::sendto(FileDescription& description, const void* data, size_t data_size, int, Userspace<const sockaddr*>, socklen_t)
+KResultOr<size_t> LocalSocket::sendto(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size, int, Userspace<const sockaddr*>, socklen_t)
{
if (!has_attached_peer(description))
return KResult(-EPIPE);
- ssize_t nwritten = send_buffer_for(description).write((const u8*)data, data_size);
+ ssize_t nwritten = send_buffer_for(description).write(data, data_size);
if (nwritten > 0)
Thread::current()->did_unix_socket_write(nwritten);
return nwritten;
@@ -290,7 +298,7 @@ DoubleBuffer& LocalSocket::send_buffer_for(FileDescription& description)
ASSERT_NOT_REACHED();
}
-KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, void* buffer, size_t buffer_size, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
+KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, UserOrKernelBuffer& buffer, size_t buffer_size, int, Userspace<sockaddr*>, Userspace<socklen_t*>)
{
auto& buffer_for_me = receive_buffer_for(description);
if (!description.is_blocking()) {
@@ -306,7 +314,7 @@ KResultOr<size_t> LocalSocket::recvfrom(FileDescription& description, void* buff
if (!has_attached_peer(description) && buffer_for_me.is_empty())
return 0;
ASSERT(!buffer_for_me.is_empty());
- int nread = buffer_for_me.read((u8*)buffer, buffer_size);
+ int nread = buffer_for_me.read(buffer, buffer_size);
if (nread > 0)
Thread::current()->did_unix_socket_read(nread);
return nread;
@@ -350,7 +358,7 @@ KResult LocalSocket::getsockopt(FileDescription& description, int level, int opt
return Socket::getsockopt(description, level, option, value, value_size);
socklen_t size;
- if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
+ if (!copy_from_user(&size, value_size.unsafe_userspace_ptr()))
return KResult(-EFAULT);
switch (option) {
@@ -359,14 +367,18 @@ KResult LocalSocket::getsockopt(FileDescription& description, int level, int opt
return KResult(-EINVAL);
switch (role(description)) {
case Role::Accepted:
- copy_to_user(static_ptr_cast<ucred*>(value), &m_origin);
+ if (!copy_to_user(static_ptr_cast<ucred*>(value), &m_origin))
+ return KResult(-EFAULT);
size = sizeof(ucred);
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
case Role::Connected:
- copy_to_user(static_ptr_cast<ucred*>(value), &m_acceptor);
+ if (!copy_to_user(static_ptr_cast<ucred*>(value), &m_acceptor))
+ return KResult(-EFAULT);
size = sizeof(ucred);
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
case Role::Connecting:
return KResult(-ENOTCONN);
diff --git a/Kernel/Net/LocalSocket.h b/Kernel/Net/LocalSocket.h
index cafdf599a4..d39e78d20b 100644
--- a/Kernel/Net/LocalSocket.h
+++ b/Kernel/Net/LocalSocket.h
@@ -52,7 +52,7 @@ public:
// ^Socket
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) override;
- virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
+ virtual KResult connect(FileDescription&, Userspace<const sockaddr*>, socklen_t, ShouldBlock = ShouldBlock::Yes) override;
virtual KResult listen(size_t) override;
virtual void get_local_address(sockaddr*, socklen_t*) override;
virtual void get_peer_address(sockaddr*, socklen_t*) override;
@@ -60,8 +60,8 @@ public:
virtual void detach(FileDescription&) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
- virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
+ virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int, Userspace<const sockaddr*>, socklen_t) override;
+ virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) override;
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
virtual KResult chown(FileDescription&, uid_t, gid_t) override;
virtual KResult chmod(FileDescription&, mode_t) override;
diff --git a/Kernel/Net/NetworkAdapter.cpp b/Kernel/Net/NetworkAdapter.cpp
index 4cfdd1cd43..4a81fa77af 100644
--- a/Kernel/Net/NetworkAdapter.cpp
+++ b/Kernel/Net/NetworkAdapter.cpp
@@ -100,15 +100,13 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
send_raw({ (const u8*)eth, size_in_bytes });
}
-void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, ReadonlyBytes payload, u8 ttl)
+int NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl)
{
- size_t ipv4_packet_size = sizeof(IPv4Packet) + payload.size();
- if (ipv4_packet_size > mtu()) {
- send_ipv4_fragmented(destination_mac, destination_ipv4, protocol, payload, ttl);
- return;
- }
+ size_t ipv4_packet_size = sizeof(IPv4Packet) + payload_size;
+ if (ipv4_packet_size > mtu())
+ return send_ipv4_fragmented(destination_mac, destination_ipv4, protocol, payload, payload_size, ttl);
- size_t ethernet_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload.size();
+ size_t ethernet_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload_size;
auto buffer = ByteBuffer::create_zeroed(ethernet_frame_size);
auto& eth = *(EthernetFrameHeader*)buffer.data();
eth.set_source(mac_address());
@@ -120,22 +118,25 @@ void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Addr
ipv4.set_source(ipv4_address());
ipv4.set_destination(destination_ipv4);
ipv4.set_protocol((u8)protocol);
- ipv4.set_length(sizeof(IPv4Packet) + payload.size());
+ ipv4.set_length(sizeof(IPv4Packet) + payload_size);
ipv4.set_ident(1);
ipv4.set_ttl(ttl);
ipv4.set_checksum(ipv4.compute_checksum());
m_packets_out++;
m_bytes_out += ethernet_frame_size;
- memcpy(ipv4.payload(), payload.data(), payload.size());
+
+ if (!payload.read(ipv4.payload(), payload_size))
+ return -EFAULT;
send_raw({ (const u8*)&eth, ethernet_frame_size });
+ return 0;
}
-void NetworkAdapter::send_ipv4_fragmented(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, ReadonlyBytes payload, u8 ttl)
+int NetworkAdapter::send_ipv4_fragmented(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl)
{
// packets must be split on the 64-bit boundary
auto packet_boundary_size = (mtu() - sizeof(IPv4Packet) - sizeof(EthernetFrameHeader)) & 0xfffffff8;
- auto fragment_block_count = (payload.size() + packet_boundary_size) / packet_boundary_size;
- auto last_block_size = payload.size() - packet_boundary_size * (fragment_block_count - 1);
+ auto fragment_block_count = (payload_size + packet_boundary_size) / packet_boundary_size;
+ auto last_block_size = payload_size - packet_boundary_size * (fragment_block_count - 1);
auto number_of_blocks_in_fragment = packet_boundary_size / 8;
auto identification = get_good_random<u16>();
@@ -163,9 +164,11 @@ void NetworkAdapter::send_ipv4_fragmented(const MACAddress& destination_mac, con
ipv4.set_checksum(ipv4.compute_checksum());
m_packets_out++;
m_bytes_out += ethernet_frame_size;
- memcpy(ipv4.payload(), payload.data() + packet_index * packet_boundary_size, packet_payload_size);
+ if (!payload.read(ipv4.payload(), packet_index * packet_boundary_size, packet_payload_size))
+ return -EFAULT;
send_raw({ (const u8*)&eth, ethernet_frame_size });
}
+ return 0;
}
void NetworkAdapter::did_receive(ReadonlyBytes payload)
diff --git a/Kernel/Net/NetworkAdapter.h b/Kernel/Net/NetworkAdapter.h
index 7fc178bf7d..619b25f281 100644
--- a/Kernel/Net/NetworkAdapter.h
+++ b/Kernel/Net/NetworkAdapter.h
@@ -37,6 +37,7 @@
#include <Kernel/Net/ARP.h>
#include <Kernel/Net/ICMP.h>
#include <Kernel/Net/IPv4.h>
+#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
@@ -63,8 +64,8 @@ public:
void set_ipv4_gateway(const IPv4Address&);
void send(const MACAddress&, const ARPPacket&);
- void send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, ReadonlyBytes payload, u8 ttl);
- void send_ipv4_fragmented(const MACAddress&, const IPv4Address&, IPv4Protocol, ReadonlyBytes payload, u8 ttl);
+ int send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl);
+ int send_ipv4_fragmented(const MACAddress&, const IPv4Address&, IPv4Protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl);
size_t dequeue_packet(u8* buffer, size_t buffer_size);
diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp
index f198bc0607..0098d686fd 100644
--- a/Kernel/Net/NetworkTask.cpp
+++ b/Kernel/Net/NetworkTask.cpp
@@ -285,7 +285,8 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
memcpy(response.payload(), request.payload(), icmp_payload_size);
response.header.set_checksum(internet_checksum(&response, icmp_packet_size));
// FIXME: What is the right TTL value here? Is 64 ok? Should we use the same TTL as the echo request?
- adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, buffer, 64);
+ auto response_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&response);
+ adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, response_buffer, buffer.size(), 64);
}
}
@@ -379,7 +380,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
case TCPSocket::State::TimeWait:
klog() << "handle_tcp: unexpected flags in TimeWait state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
case TCPSocket::State::Listen:
@@ -400,46 +401,46 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
#endif
client->set_sequence_number(1000);
client->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
- client->send_tcp_packet(TCPFlags::SYN | TCPFlags::ACK);
+ (void)client->send_tcp_packet(TCPFlags::SYN | TCPFlags::ACK);
client->set_state(TCPSocket::State::SynReceived);
return;
}
default:
klog() << "handle_tcp: unexpected flags in Listen state";
- // socket->send_tcp_packet(TCPFlags::RST);
+ // (void)socket->send_tcp_packet(TCPFlags::RST);
return;
}
case TCPSocket::State::SynSent:
switch (tcp_packet.flags()) {
case TCPFlags::SYN:
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
- socket->send_tcp_packet(TCPFlags::ACK);
+ (void)socket->send_tcp_packet(TCPFlags::ACK);
socket->set_state(TCPSocket::State::SynReceived);
return;
case TCPFlags::ACK | TCPFlags::SYN:
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
- socket->send_tcp_packet(TCPFlags::ACK);
+ (void)socket->send_tcp_packet(TCPFlags::ACK);
socket->set_state(TCPSocket::State::Established);
socket->set_setup_state(Socket::SetupState::Completed);
socket->set_connected(true);
return;
case TCPFlags::ACK | TCPFlags::FIN:
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
- socket->send_tcp_packet(TCPFlags::ACK);
+ (void)socket->send_tcp_packet(TCPFlags::ACK);
socket->set_state(TCPSocket::State::Closed);
socket->set_error(TCPSocket::Error::FINDuringConnect);
socket->set_setup_state(Socket::SetupState::Completed);
return;
case TCPFlags::ACK | TCPFlags::RST:
socket->set_ack_number(tcp_packet.sequence_number() + payload_size);
- socket->send_tcp_packet(TCPFlags::ACK);
+ (void)socket->send_tcp_packet(TCPFlags::ACK);
socket->set_state(TCPSocket::State::Closed);
socket->set_error(TCPSocket::Error::RSTDuringConnect);
socket->set_setup_state(Socket::SetupState::Completed);
return;
default:
klog() << "handle_tcp: unexpected flags in SynSent state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
socket->set_error(TCPSocket::Error::UnexpectedFlagsDuringConnect);
socket->set_setup_state(Socket::SetupState::Completed);
@@ -454,7 +455,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
case TCPSocket::Direction::Incoming:
if (!socket->has_originator()) {
klog() << "handle_tcp: connection doesn't have an originating socket; maybe it went away?";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -470,7 +471,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
default:
klog() << "handle_tcp: got ACK in SynReceived state but direction is invalid (" << TCPSocket::to_string(socket->direction()) << ")";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -478,7 +479,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
default:
klog() << "handle_tcp: unexpected flags in SynReceived state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -486,7 +487,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
switch (tcp_packet.flags()) {
default:
klog() << "handle_tcp: unexpected flags in CloseWait state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -498,7 +499,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
default:
klog() << "handle_tcp: unexpected flags in LastAck state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -514,7 +515,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
default:
klog() << "handle_tcp: unexpected flags in FinWait1 state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -529,7 +530,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
default:
klog() << "handle_tcp: unexpected flags in FinWait2 state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -541,7 +542,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
return;
default:
klog() << "handle_tcp: unexpected flags in Closing state";
- socket->send_tcp_packet(TCPFlags::RST);
+ (void)socket->send_tcp_packet(TCPFlags::RST);
socket->set_state(TCPSocket::State::Closed);
return;
}
@@ -551,7 +552,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
- socket->send_tcp_packet(TCPFlags::ACK);
+ (void)socket->send_tcp_packet(TCPFlags::ACK);
socket->set_state(TCPSocket::State::CloseWait);
socket->set_connected(false);
return;
@@ -565,7 +566,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
if (payload_size) {
if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())))
- socket->send_tcp_packet(TCPFlags::ACK);
+ (void)socket->send_tcp_packet(TCPFlags::ACK);
}
}
}
diff --git a/Kernel/Net/Socket.cpp b/Kernel/Net/Socket.cpp
index 061068e3ec..1caa3c5328 100644
--- a/Kernel/Net/Socket.cpp
+++ b/Kernel/Net/Socket.cpp
@@ -108,18 +108,20 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
case SO_SNDTIMEO:
if (user_value_size != sizeof(timeval))
return KResult(-EINVAL);
- copy_from_user(&m_send_timeout, static_ptr_cast<const timeval*>(user_value));
+ if (!copy_from_user(&m_send_timeout, static_ptr_cast<const timeval*>(user_value)))
+ return KResult(-EFAULT);
return KSuccess;
case SO_RCVTIMEO:
if (user_value_size != sizeof(timeval))
return KResult(-EINVAL);
- copy_from_user(&m_receive_timeout, static_ptr_cast<const timeval*>(user_value));
+ if (!copy_from_user(&m_receive_timeout, static_ptr_cast<const timeval*>(user_value)))
+ return KResult(-EFAULT);
return KSuccess;
case SO_BINDTODEVICE: {
if (user_value_size != IFNAMSIZ)
return KResult(-EINVAL);
auto user_string = static_ptr_cast<const char*>(user_value);
- auto ifname = Process::current()->validate_and_copy_string_from_user(user_string, user_value_size);
+ auto ifname = copy_string_from_user(user_string, user_value_size);
if (ifname.is_null())
return KResult(-EFAULT);
auto device = NetworkAdapter::lookup_by_name(ifname);
@@ -140,7 +142,7 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
{
socklen_t size;
- if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
+ if (!copy_from_user(&size, value_size.unsafe_userspace_ptr()))
return KResult(-EFAULT);
ASSERT(level == SOL_SOCKET);
@@ -148,25 +150,31 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
case SO_SNDTIMEO:
if (size < sizeof(timeval))
return KResult(-EINVAL);
- copy_to_user(static_ptr_cast<timeval*>(value), &m_send_timeout);
+ if (!copy_to_user(static_ptr_cast<timeval*>(value), &m_send_timeout))
+ return KResult(-EFAULT);
size = sizeof(timeval);
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
case SO_RCVTIMEO:
if (size < sizeof(timeval))
return KResult(-EINVAL);
- copy_to_user(static_ptr_cast<timeval*>(value), &m_receive_timeout);
+ if (!copy_to_user(static_ptr_cast<timeval*>(value), &m_receive_timeout))
+ return KResult(-EFAULT);
size = sizeof(timeval);
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
case SO_ERROR: {
if (size < sizeof(int))
return KResult(-EINVAL);
dbg() << "getsockopt(SO_ERROR): FIXME!";
int errno = 0;
- copy_to_user(static_ptr_cast<int*>(value), &errno);
+ if (!copy_to_user(static_ptr_cast<int*>(value), &errno))
+ return KResult(-EFAULT);
size = sizeof(int);
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
}
case SO_BINDTODEVICE:
@@ -175,13 +183,16 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
if (m_bound_interface) {
const auto& name = m_bound_interface->name();
auto length = name.length() + 1;
- copy_to_user(static_ptr_cast<char*>(value), name.characters(), length);
+ if (!copy_to_user(static_ptr_cast<char*>(value), name.characters(), length))
+ return KResult(-EFAULT);
size = length;
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KSuccess;
} else {
size = 0;
- copy_to_user(value_size, &size);
+ if (!copy_to_user(value_size, &size))
+ return KResult(-EFAULT);
return KResult(-EFAULT);
}
@@ -191,14 +202,14 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
}
}
-KResultOr<size_t> Socket::read(FileDescription& description, size_t, u8* buffer, size_t size)
+KResultOr<size_t> Socket::read(FileDescription& description, size_t, UserOrKernelBuffer& buffer, size_t size)
{
if (is_shut_down_for_reading())
return 0;
return recvfrom(description, buffer, size, 0, {}, 0);
}
-KResultOr<size_t> Socket::write(FileDescription& description, size_t, const u8* data, size_t size)
+KResultOr<size_t> Socket::write(FileDescription& description, size_t, const UserOrKernelBuffer& data, size_t size)
{
if (is_shut_down_for_writing())
return -EPIPE;
diff --git a/Kernel/Net/Socket.h b/Kernel/Net/Socket.h
index b72fa5f837..c768793292 100644
--- a/Kernel/Net/Socket.h
+++ b/Kernel/Net/Socket.h
@@ -99,7 +99,7 @@ public:
KResult shutdown(int how);
virtual KResult bind(Userspace<const sockaddr*>, socklen_t) = 0;
- virtual KResult connect(FileDescription&, const sockaddr*, socklen_t, ShouldBlock) = 0;
+ virtual KResult connect(FileDescription&, Userspace<const sockaddr*>, socklen_t, ShouldBlock) = 0;
virtual KResult listen(size_t) = 0;
virtual void get_local_address(sockaddr*, socklen_t*) = 0;
virtual void get_peer_address(sockaddr*, socklen_t*) = 0;
@@ -107,8 +107,8 @@ public:
virtual bool is_ipv4() const { return false; }
virtual void attach(FileDescription&) = 0;
virtual void detach(FileDescription&) = 0;
- virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int flags, Userspace<const sockaddr*>, socklen_t) = 0;
- virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) = 0;
+ virtual KResultOr<size_t> sendto(FileDescription&, const UserOrKernelBuffer&, size_t, int flags, Userspace<const sockaddr*>, socklen_t) = 0;
+ virtual KResultOr<size_t> recvfrom(FileDescription&, UserOrKernelBuffer&, size_t, int flags, Userspace<sockaddr*>, Userspace<socklen_t*>) = 0;
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t);
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>);
@@ -124,8 +124,8 @@ public:
Lock& lock() { return m_lock; }
// ^File
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override final;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override final;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override final;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override final;
virtual KResult stat(::stat&) const override;
virtual String absolute_path(const FileDescription&) const override = 0;
diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp
index b7b615c951..e14ecf2770 100644
--- a/Kernel/Net/TCPSocket.cpp
+++ b/Kernel/Net/TCPSocket.cpp
@@ -161,7 +161,7 @@ NonnullRefPtr<TCPSocket> TCPSocket::create(int protocol)
return adopt(*new TCPSocket(protocol));
}
-KResultOr<size_t> TCPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
+KResultOr<size_t> TCPSocket::protocol_receive(const KBuffer& packet_buffer, UserOrKernelBuffer& buffer, size_t buffer_size, int flags)
{
(void)flags;
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
@@ -171,17 +171,20 @@ KResultOr<size_t> TCPSocket::protocol_receive(const KBuffer& packet_buffer, void
klog() << "payload_size " << payload_size << ", will it fit in " << buffer_size << "?";
#endif
ASSERT(buffer_size >= payload_size);
- memcpy(buffer, tcp_packet.payload(), payload_size);
+ if (!buffer.write(tcp_packet.payload(), payload_size))
+ return KResult(-EFAULT);
return payload_size;
}
-KResultOr<size_t> TCPSocket::protocol_send(const void* data, size_t data_length)
+KResultOr<size_t> TCPSocket::protocol_send(const UserOrKernelBuffer& data, size_t data_length)
{
- send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, data, data_length);
+ int err = send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, &data, data_length);
+ if (err < 0)
+ return KResult(err);
return data_length;
}
-void TCPSocket::send_tcp_packet(u16 flags, const void* payload, size_t payload_size)
+int TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, size_t payload_size)
{
auto buffer = ByteBuffer::create_zeroed(sizeof(TCPPacket) + payload_size);
auto& tcp_packet = *(TCPPacket*)(buffer.data());
@@ -196,31 +199,37 @@ void TCPSocket::send_tcp_packet(u16 flags, const void* payload, size_t payload_s
if (flags & TCPFlags::ACK)
tcp_packet.set_ack_number(m_ack_number);
+ if (payload && !payload->read(tcp_packet.payload(), payload_size))
+ return -EFAULT;
+
if (flags & TCPFlags::SYN) {
++m_sequence_number;
} else {
m_sequence_number += payload_size;
}
- memcpy(tcp_packet.payload(), payload, payload_size);
tcp_packet.set_checksum(compute_tcp_checksum(local_address(), peer_address(), tcp_packet, payload_size));
if (tcp_packet.has_syn() || payload_size > 0) {
LOCKER(m_not_acked_lock);
m_not_acked.append({ m_sequence_number, move(buffer) });
send_outgoing_packets();
- return;
+ return 0;
}
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
ASSERT(!routing_decision.is_zero());
- routing_decision.adapter->send_ipv4(
+ auto packet_buffer = UserOrKernelBuffer::for_kernel_buffer(buffer.data());
+ int err = routing_decision.adapter->send_ipv4(
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
- buffer, ttl());
+ packet_buffer, buffer.size(), ttl());
+ if (err < 0)
+ return err;
m_packets_out++;
m_bytes_out += buffer.size();
+ return 0;
}
void TCPSocket::send_outgoing_packets()
@@ -243,12 +252,17 @@ void TCPSocket::send_outgoing_packets()
auto& tcp_packet = *(TCPPacket*)(packet.buffer.data());
klog() << "sending tcp packet from " << local_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << " with (" << (tcp_packet.has_syn() ? "SYN " : "") << (tcp_packet.has_ack() ? "ACK " : "") << (tcp_packet.has_fin() ? "FIN " : "") << (tcp_packet.has_rst() ? "RST " : "") << ") seq_no=" << tcp_packet.sequence_number() << ", ack_no=" << tcp_packet.ack_number() << ", tx_counter=" << packet.tx_counter;
#endif
- routing_decision.adapter->send_ipv4(
+ auto packet_buffer = UserOrKernelBuffer::for_kernel_buffer(packet.buffer.data());
+ int err = routing_decision.adapter->send_ipv4(
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
- packet.buffer, ttl());
-
- m_packets_out++;
- m_bytes_out += packet.buffer.size();
+ packet_buffer, packet.buffer.size(), ttl());
+ if (err < 0) {
+ auto& tcp_packet = *(TCPPacket*)(packet.buffer.data());
+ klog() << "Error (" << err << ") sending tcp packet from " << local_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << " with (" << (tcp_packet.has_syn() ? "SYN " : "") << (tcp_packet.has_ack() ? "ACK " : "") << (tcp_packet.has_fin() ? "FIN " : "") << (tcp_packet.has_rst() ? "RST " : "") << ") seq_no=" << tcp_packet.sequence_number() << ", ack_no=" << tcp_packet.ack_number() << ", tx_counter=" << packet.tx_counter;
+ } else {
+ m_packets_out++;
+ m_bytes_out += packet.buffer.size();
+ }
}
}
@@ -366,7 +380,9 @@ KResult TCPSocket::protocol_connect(FileDescription& description, ShouldBlock sh
m_ack_number = 0;
set_setup_state(SetupState::InProgress);
- send_tcp_packet(TCPFlags::SYN);
+ int err = send_tcp_packet(TCPFlags::SYN);
+ if (err < 0)
+ return KResult(err);
m_state = State::SynSent;
m_role = Role::Connecting;
m_direction = Direction::Outgoing;
@@ -433,7 +449,7 @@ void TCPSocket::shut_down_for_writing()
#ifdef TCP_SOCKET_DEBUG
dbg() << " Sending FIN/ACK from Established and moving into FinWait1";
#endif
- send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
+ (void)send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
set_state(State::FinWait1);
} else {
dbg() << " Shutting down TCPSocket for writing but not moving to FinWait1 since state is " << to_string(state());
@@ -447,7 +463,7 @@ KResult TCPSocket::close()
#ifdef TCP_SOCKET_DEBUG
dbg() << " Sending FIN from CloseWait and moving into LastAck";
#endif
- send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
+ (void)send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
set_state(State::LastAck);
}
diff --git a/Kernel/Net/TCPSocket.h b/Kernel/Net/TCPSocket.h
index bff5ac14c2..0a8e25119d 100644
--- a/Kernel/Net/TCPSocket.h
+++ b/Kernel/Net/TCPSocket.h
@@ -148,7 +148,7 @@ public:
u32 packets_out() const { return m_packets_out; }
u32 bytes_out() const { return m_bytes_out; }
- void send_tcp_packet(u16 flags, const void* = nullptr, size_t = 0);
+ [[nodiscard]] int send_tcp_packet(u16 flags, const UserOrKernelBuffer* = nullptr, size_t = 0);
void send_outgoing_packets();
void receive_tcp_packet(const TCPPacket&, u16 size);
@@ -177,8 +177,8 @@ private:
virtual void shut_down_for_writing() override;
- virtual KResultOr<size_t> protocol_receive(const KBuffer&, void* buffer, size_t buffer_size, int flags) override;
- virtual KResultOr<size_t> protocol_send(const void*, size_t) override;
+ virtual KResultOr<size_t> protocol_receive(const KBuffer&, UserOrKernelBuffer& buffer, size_t buffer_size, int flags) override;
+ virtual KResultOr<size_t> protocol_send(const UserOrKernelBuffer&, size_t) override;
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
virtual int protocol_allocate_local_port() override;
virtual bool protocol_is_disconnected() const override;
diff --git a/Kernel/Net/UDPSocket.cpp b/Kernel/Net/UDPSocket.cpp
index c770a4e184..22db799af7 100644
--- a/Kernel/Net/UDPSocket.cpp
+++ b/Kernel/Net/UDPSocket.cpp
@@ -79,18 +79,19 @@ NonnullRefPtr<UDPSocket> UDPSocket::create(int protocol)
return adopt(*new UDPSocket(protocol));
}
-KResultOr<size_t> UDPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
+KResultOr<size_t> UDPSocket::protocol_receive(const KBuffer& packet_buffer, UserOrKernelBuffer& buffer, size_t buffer_size, int flags)
{
(void)flags;
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket)));
- memcpy(buffer, udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket));
+ if (!buffer.write(udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket)))
+ return KResult(-EFAULT);
return udp_packet.length() - sizeof(UDPPacket);
}
-KResultOr<size_t> UDPSocket::protocol_send(const void* data, size_t data_length)
+KResultOr<size_t> UDPSocket::protocol_send(const UserOrKernelBuffer& data, size_t data_length)
{
auto routing_decision = route_to(peer_address(), local_address(), bound_interface());
if (routing_decision.is_zero())
@@ -100,9 +101,11 @@ KResultOr<size_t> UDPSocket::protocol_send(const void* data, size_t data_length)
udp_packet.set_source_port(local_port());
udp_packet.set_destination_port(peer_port());
udp_packet.set_length(sizeof(UDPPacket) + data_length);
- memcpy(udp_packet.payload(), data, data_length);
+ if (!data.read(udp_packet.payload(), data_length))
+ return KResult(-EFAULT);
klog() << "sending as udp packet from " << routing_decision.adapter->ipv4_address().to_string().characters() << ":" << local_port() << " to " << peer_address().to_string().characters() << ":" << peer_port() << "!";
- routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, buffer, ttl());
+ auto udp_packet_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&udp_packet);
+ routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, udp_packet_buffer, buffer.size(), ttl());
return data_length;
}
diff --git a/Kernel/Net/UDPSocket.h b/Kernel/Net/UDPSocket.h
index ab711a9dc8..d640be316e 100644
--- a/Kernel/Net/UDPSocket.h
+++ b/Kernel/Net/UDPSocket.h
@@ -43,8 +43,8 @@ private:
virtual const char* class_name() const override { return "UDPSocket"; }
static Lockable<HashMap<u16, UDPSocket*>>& sockets_by_port();
- virtual KResultOr<size_t> protocol_receive(const KBuffer&, void* buffer, size_t buffer_size, int flags) override;
- virtual KResultOr<size_t> protocol_send(const void*, size_t) override;
+ virtual KResultOr<size_t> protocol_receive(const KBuffer&, UserOrKernelBuffer& buffer, size_t buffer_size, int flags) override;
+ virtual KResultOr<size_t> protocol_send(const UserOrKernelBuffer&, size_t) override;
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
virtual int protocol_allocate_local_port() override;
virtual KResult protocol_bind() override;
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 2fc9c11e6b..5e1348b07a 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -520,24 +520,6 @@ int Process::fd_flags(int fd) const
return -1;
}
-String Process::validate_and_copy_string_from_user(const char* user_characters, size_t user_length) const
-{
- if (user_length == 0)
- return String::empty();
- if (!user_characters)
- return {};
- if (!validate_read(user_characters, user_length))
- return {};
- SmapDisabler disabler;
- size_t measured_length = strnlen(user_characters, user_length);
- return String(user_characters, measured_length);
-}
-
-String Process::validate_and_copy_string_from_user(const Syscall::StringArgument& string) const
-{
- return validate_and_copy_string_from_user(string.characters, string.length);
-}
-
int Process::number_of_open_file_descriptors() const
{
int count = 0;
@@ -602,27 +584,6 @@ siginfo_t Process::reap(Process& process)
return siginfo;
}
-bool Process::validate_read_from_kernel(VirtualAddress vaddr, size_t size) const
-{
- if (vaddr.is_null())
- return false;
- return MM.validate_kernel_read(*this, vaddr, size);
-}
-
-bool Process::validate_read(const void* address, size_t size) const
-{
- if (!size)
- return false;
- return MM.validate_user_read(*this, VirtualAddress(address), size);
-}
-
-bool Process::validate_write(void* address, size_t size) const
-{
- if (!size)
- return false;
- return MM.validate_user_write(*this, VirtualAddress(address), size);
-}
-
Custody& Process::current_directory()
{
if (!m_cwd)
@@ -636,9 +597,10 @@ KResultOr<String> Process::get_syscall_path_argument(const char* user_path, size
return KResult(-EINVAL);
if (path_length > PATH_MAX)
return KResult(-ENAMETOOLONG);
- if (!validate_read(user_path, path_length))
+ auto copied_string = copy_string_from_user(user_path, path_length);
+ if (copied_string.is_null())
return KResult(-EFAULT);
- return copy_string_from_user(user_path, path_length);
+ return copied_string;
}
KResultOr<String> Process::get_syscall_path_argument(const Syscall::StringArgument& path) const
@@ -659,7 +621,8 @@ void Process::finalize()
auto& description = description_or_error.value();
auto json = m_perf_event_buffer->to_json(m_pid, m_executable ? m_executable->absolute_path() : "");
// FIXME: Should this error path be surfaced somehow?
- (void)description->write(json.data(), json.size());
+ auto json_buffer = UserOrKernelBuffer::for_kernel_buffer(json.data());
+ (void)description->write(json_buffer, json.size());
}
}
diff --git a/Kernel/Process.h b/Kernel/Process.h
index 6f19527c0a..76bc8c51d7 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -362,111 +362,6 @@ public:
u32 m_ticks_in_user_for_dead_children { 0 };
u32 m_ticks_in_kernel_for_dead_children { 0 };
- [[nodiscard]] bool validate_read_from_kernel(VirtualAddress, size_t) const;
-
- [[nodiscard]] bool validate_read(const void*, size_t) const;
- [[nodiscard]] bool validate_write(void*, size_t) const;
-
- template<typename T>
- [[nodiscard]] bool validate_read(Userspace<T*> ptr, size_t size) const
- {
- return validate_read(ptr.unsafe_userspace_ptr(), size);
- }
-
- template<typename T>
- [[nodiscard]] bool validate_write(Userspace<T*> ptr, size_t size) const
- {
- return validate_write(ptr.unsafe_userspace_ptr(), size);
- }
-
- template<typename T>
- [[nodiscard]] bool validate_read_typed(T* value, size_t count = 1)
- {
- Checked size = sizeof(T);
- size *= count;
- if (size.has_overflow())
- return false;
- return validate_read(value, size.value());
- }
-
- template<typename T>
- [[nodiscard]] bool validate_read_typed(Userspace<T*> value, size_t count = 1)
- {
- Checked size = sizeof(T);
- size *= count;
- if (size.has_overflow())
- return false;
- return validate_read(value, size.value());
- }
-
- template<typename T>
- [[nodiscard]] bool validate_read_and_copy_typed(T* dest, const T* src)
- {
- bool validated = validate_read_typed(src);
- if (validated) {
- copy_from_user(dest, src);
- }
- return validated;
- }
-
- template<typename T>
- [[nodiscard]] bool validate_read_and_copy_typed(T* dest, Userspace<const T*> src)
- {
- bool validated = validate_read_typed(src);
- if (validated) {
- copy_from_user(dest, src);
- }
- return validated;
- }
-
- template<typename T>
- [[nodiscard]] bool validate_read_and_copy_typed(T* dest, Userspace<T*> src)
- {
- Userspace<const T*> const_src { src.ptr() };
- return validate_read_and_copy_typed(dest, const_src);
- }
-
- template<typename T>
- [[nodiscard]] bool validate_write_typed(T* value, size_t count = 1)
- {
- Checked size = sizeof(T);
- size *= count;
- if (size.has_overflow())
- return false;
- return validate_write(value, size.value());
- }
-
- template<typename T>
- [[nodiscard]] bool validate_write_typed(Userspace<T*> value, size_t count = 1)
- {
- Checked size = sizeof(T);
- size *= count;
- if (size.has_overflow())
- return false;
- return validate_write(value, size.value());
- }
-
- template<typename DataType, typename SizeType>
- [[nodiscard]] bool validate(const Syscall::MutableBufferArgument<DataType, SizeType>& buffer)
- {
- return validate_write(buffer.data, buffer.size);
- }
-
- template<typename DataType, typename SizeType>
- [[nodiscard]] bool validate(const Syscall::ImmutableBufferArgument<DataType, SizeType>& buffer)
- {
- return validate_read(buffer.data, buffer.size);
- }
-
- [[nodiscard]] String validate_and_copy_string_from_user(const char*, size_t) const;
-
- [[nodiscard]] String validate_and_copy_string_from_user(Userspace<const char*> user_characters, size_t size) const
- {
- return validate_and_copy_string_from_user(user_characters.unsafe_userspace_ptr(), size);
- }
-
- [[nodiscard]] String validate_and_copy_string_from_user(const Syscall::StringArgument&) const;
-
Custody& current_directory();
Custody* executable()
{
@@ -582,7 +477,7 @@ private:
void kill_all_threads();
int do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags);
- ssize_t do_write(FileDescription&, const u8*, int data_size);
+ ssize_t do_write(FileDescription&, const UserOrKernelBuffer&, size_t);
KResultOr<NonnullRefPtr<FileDescription>> find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size);
Vector<AuxiliaryValue> generate_auxiliary_vector() const;
@@ -834,3 +729,8 @@ inline u32 Thread::effective_priority() const
} while (0)
}
+
+inline static String copy_string_from_user(const Kernel::Syscall::StringArgument& string)
+{
+ return copy_string_from_user(string.characters, string.length);
+}
diff --git a/Kernel/Ptrace.cpp b/Kernel/Ptrace.cpp
index ab085c3054..8e8bc6c7bf 100644
--- a/Kernel/Ptrace.cpp
+++ b/Kernel/Ptrace.cpp
@@ -105,10 +105,9 @@ KResultOr<u32> handle_syscall(const Kernel::Syscall::SC_ptrace_params& params, P
if (!tracer->has_regs())
return KResult(-EINVAL);
- auto* regs = reinterpret_cast<PtraceRegisters*>(params.addr.unsafe_userspace_ptr());
- if (!caller.validate_write_typed(regs))
+ auto* regs = reinterpret_cast<PtraceRegisters*>(params.addr);
+ if (!copy_to_user(regs, &tracer->regs()))
return KResult(-EFAULT);
- copy_to_user(regs, &tracer->regs());
break;
}
@@ -117,7 +116,7 @@ KResultOr<u32> handle_syscall(const Kernel::Syscall::SC_ptrace_params& params, P
return KResult(-EINVAL);
PtraceRegisters regs;
- if (!caller.validate_read_and_copy_typed(&regs, (const PtraceRegisters*)params.addr.unsafe_userspace_ptr()))
+ if (!copy_from_user(&regs, (const PtraceRegisters*)params.addr))
return KResult(-EFAULT);
auto& peer_saved_registers = peer->get_register_dump_from_stack();
@@ -132,21 +131,20 @@ KResultOr<u32> handle_syscall(const Kernel::Syscall::SC_ptrace_params& params, P
case PT_PEEK: {
Kernel::Syscall::SC_ptrace_peek_params peek_params;
- if (!caller.validate_read_and_copy_typed(&peek_params, reinterpret_cast<Kernel::Syscall::SC_ptrace_peek_params*>(params.addr.unsafe_userspace_ptr())))
+ if (!copy_from_user(&peek_params, reinterpret_cast<Kernel::Syscall::SC_ptrace_peek_params*>(params.addr)))
return -EFAULT;
// read validation is done inside 'peek_user_data'
- auto result = peer->process().peek_user_data(peek_params.address);
+ auto result = peer->process().peek_user_data((FlatPtr)peek_params.address);
if (result.is_error())
return -EFAULT;
- if (!caller.validate_write(peek_params.out_data, sizeof(u32)))
+ if (!copy_to_user(peek_params.out_data, &result.value()))
return -EFAULT;
- copy_to_user(peek_params.out_data, &result.value());
break;
}
case PT_POKE: {
- Userspace<u32*> addr = reinterpret_cast<FlatPtr>(params.addr.ptr());
+ Userspace<u32*> addr = reinterpret_cast<FlatPtr>(params.addr);
// write validation is done inside 'poke_user_data'
return peer->process().poke_user_data(addr, params.data);
}
diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp
index 620558caf7..2a1e6e82a7 100644
--- a/Kernel/Scheduler.cpp
+++ b/Kernel/Scheduler.cpp
@@ -651,7 +651,7 @@ void Scheduler::initialize()
ASSERT(s_colonel_process);
ASSERT(idle_thread);
idle_thread->set_priority(THREAD_PRIORITY_MIN);
- idle_thread->set_name("idle thread #0");
+ idle_thread->set_name(StringView("idle thread #0"));
set_idle_thread(idle_thread);
}
diff --git a/Kernel/StdLib.cpp b/Kernel/StdLib.cpp
index 27dee8d3c4..1bdb4c912b 100644
--- a/Kernel/StdLib.cpp
+++ b/Kernel/StdLib.cpp
@@ -35,27 +35,68 @@
String copy_string_from_user(const char* user_str, size_t user_str_size)
{
+ bool is_user = Kernel::is_user_range(VirtualAddress(user_str), user_str_size);
+ ASSERT(is_user); // For now assert to catch bugs, but technically not an error
+ if (!is_user)
+ return {};
Kernel::SmapDisabler disabler;
- size_t length = strnlen(user_str, user_str_size);
- return String(user_str, length);
+ void* fault_at;
+ ssize_t length = Kernel::safe_strnlen(user_str, user_str_size, fault_at);
+ if (length < 0) {
+ klog() << "copy_string_from_user(" << user_str << ", " << user_str_size << ") failed at " << VirtualAddress(fault_at) << " (strnlen)";
+ return {};
+ }
+ if (length == 0)
+ return String::empty();
+
+ char* buffer;
+ auto copied_string = StringImpl::create_uninitialized((size_t)length, buffer);
+ if (!Kernel::safe_memcpy(buffer, user_str, (size_t)length, fault_at)) {
+ klog() << "copy_string_from_user(" << user_str << ", " << user_str_size << ") failed at " << VirtualAddress(fault_at) << " (memcpy)";
+ return {};
+ }
+ return copied_string;
+}
+
+String copy_string_from_user(Userspace<const char*> user_str, size_t user_str_size)
+{
+ return copy_string_from_user(user_str.unsafe_userspace_ptr(), user_str_size);
}
extern "C" {
-void copy_to_user(void* dest_ptr, const void* src_ptr, size_t n)
+bool copy_to_user(void* dest_ptr, const void* src_ptr, size_t n)
{
- ASSERT(Kernel::is_user_range(VirtualAddress(dest_ptr), n));
+ bool is_user = Kernel::is_user_range(VirtualAddress(dest_ptr), n);
+ ASSERT(is_user); // For now assert to catch bugs, but technically not an error
+ if (!is_user)
+ return false;
ASSERT(!Kernel::is_user_range(VirtualAddress(src_ptr), n));
Kernel::SmapDisabler disabler;
- memcpy(dest_ptr, src_ptr, n);
+ void* fault_at;
+ if (!Kernel::safe_memcpy(dest_ptr, src_ptr, n, fault_at)) {
+ ASSERT(VirtualAddress(fault_at) >= VirtualAddress(dest_ptr) && VirtualAddress(fault_at) <= VirtualAddress((FlatPtr)dest_ptr + n));
+ klog() << "copy_to_user(" << dest_ptr << ", " << src_ptr << ", " << n << ") failed at " << VirtualAddress(fault_at);
+ return false;
+ }
+ return true;
}
-void copy_from_user(void* dest_ptr, const void* src_ptr, size_t n)
+bool copy_from_user(void* dest_ptr, const void* src_ptr, size_t n)
{
- ASSERT(Kernel::is_user_range(VirtualAddress(src_ptr), n));
+ bool is_user = Kernel::is_user_range(VirtualAddress(src_ptr), n);
+ ASSERT(is_user); // For now assert to catch bugs, but technically not an error
+ if (!is_user)
+ return false;
ASSERT(!Kernel::is_user_range(VirtualAddress(dest_ptr), n));
Kernel::SmapDisabler disabler;
- memcpy(dest_ptr, src_ptr, n);
+ void* fault_at;
+ if (!Kernel::safe_memcpy(dest_ptr, src_ptr, n, fault_at)) {
+ ASSERT(VirtualAddress(fault_at) >= VirtualAddress(src_ptr) && VirtualAddress(fault_at) <= VirtualAddress((FlatPtr)src_ptr + n));
+ klog() << "copy_from_user(" << dest_ptr << ", " << src_ptr << ", " << n << ") failed at " << VirtualAddress(fault_at);
+ return false;
+ }
+ return true;
}
void* memcpy(void* dest_ptr, const void* src_ptr, size_t n)
@@ -97,11 +138,19 @@ const void* memmem(const void* haystack, size_t haystack_length, const void* nee
return AK::memmem(haystack, haystack_length, needle, needle_length);
}
-void memset_user(void* dest_ptr, int c, size_t n)
+[[nodiscard]] bool memset_user(void* dest_ptr, int c, size_t n)
{
- ASSERT(Kernel::is_user_range(VirtualAddress(dest_ptr), n));
+ bool is_user = Kernel::is_user_range(VirtualAddress(dest_ptr), n);
+ ASSERT(is_user); // For now assert to catch bugs, but technically not an error
+ if (!is_user)
+ return false;
Kernel::SmapDisabler disabler;
- memset(dest_ptr, c, n);
+ void* fault_at;
+ if (!Kernel::safe_memset(dest_ptr, c, n, fault_at)) {
+ klog() << "memset(" << dest_ptr << ", " << n << ") failed at " << VirtualAddress(fault_at);
+ return false;
+ }
+ return true;
}
void* memset(void* dest_ptr, int c, size_t n)
diff --git a/Kernel/StdLib.h b/Kernel/StdLib.h
index 1a9398700f..00b8912987 100644
--- a/Kernel/StdLib.h
+++ b/Kernel/StdLib.h
@@ -26,6 +26,7 @@
#pragma once
+#include <AK/Checked.h>
#include <AK/Forward.h>
#include <AK/Userspace.h>
@@ -34,12 +35,13 @@ struct StringArgument;
}
String copy_string_from_user(const char*, size_t);
+String copy_string_from_user(Userspace<const char*>, size_t);
extern "C" {
-void copy_to_user(void*, const void*, size_t);
-void copy_from_user(void*, const void*, size_t);
-void memset_user(void*, int, size_t);
+[[nodiscard]] bool copy_to_user(void*, const void*, size_t);
+[[nodiscard]] bool copy_from_user(void*, const void*, size_t);
+[[nodiscard]] bool memset_user(void*, int, size_t);
void* memcpy(void*, const void*, size_t);
int strncmp(const char* s1, const char* s2, size_t n);
@@ -57,37 +59,77 @@ inline u16 htons(u16 w) { return (w & 0xff) << 8 | ((w >> 8) & 0xff); }
}
template<typename T>
-inline void copy_from_user(T* dest, const T* src)
+[[nodiscard]] inline bool copy_from_user(T* dest, const T* src)
{
- copy_from_user(dest, src, sizeof(T));
+ return copy_from_user(dest, src, sizeof(T));
}
template<typename T>
-inline void copy_to_user(T* dest, const T* src)
+[[nodiscard]] inline bool copy_to_user(T* dest, const T* src)
{
- copy_to_user(dest, src, sizeof(T));
+ return copy_to_user(dest, src, sizeof(T));
}
template<typename T>
-inline void copy_from_user(T* dest, Userspace<const T*> src)
+[[nodiscard]] inline bool copy_from_user(T* dest, Userspace<const T*> src)
{
- copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T));
+ return copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T));
}
template<typename T>
-inline void copy_to_user(Userspace<T*> dest, const T* src)
+[[nodiscard]] inline bool copy_to_user(Userspace<T*> dest, const T* src)
{
- copy_to_user(dest.unsafe_userspace_ptr(), src, sizeof(T));
+ return copy_to_user(dest.unsafe_userspace_ptr(), src, sizeof(T));
}
template<typename T>
-inline void copy_to_user(Userspace<T*> dest, const void* src, size_t size)
+[[nodiscard]] inline bool copy_to_user(Userspace<T*> dest, const void* src, size_t size)
{
- copy_to_user(dest.unsafe_userspace_ptr(), src, size);
+ return copy_to_user(dest.unsafe_userspace_ptr(), src, size);
}
template<typename T>
-inline void copy_from_user(void* dest, Userspace<const T*> src, size_t size)
+[[nodiscard]] inline bool copy_from_user(void* dest, Userspace<const T*> src, size_t size)
{
- copy_from_user(dest, src.unsafe_userspace_ptr(), size);
+ return copy_from_user(dest, src.unsafe_userspace_ptr(), size);
+}
+
+template<typename T>
+[[nodiscard]] inline bool copy_n_from_user(T* dest, const T* src, size_t count)
+{
+ Checked size = sizeof(T);
+ size *= count;
+ if (size.has_overflow())
+ return false;
+ return copy_from_user(dest, src, sizeof(T) * count);
+}
+
+template<typename T>
+[[nodiscard]] inline bool copy_n_to_user(T* dest, const T* src, size_t count)
+{
+ Checked size = sizeof(T);
+ size *= count;
+ if (size.has_overflow())
+ return false;
+ return copy_to_user(dest, src, sizeof(T) * count);
+}
+
+template<typename T>
+[[nodiscard]] inline bool copy_n_from_user(T* dest, Userspace<const T*> src, size_t count)
+{
+ Checked size = sizeof(T);
+ size *= count;
+ if (size.has_overflow())
+ return false;
+ return copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T) * count);
+}
+
+template<typename T>
+[[nodiscard]] inline bool copy_n_to_user(Userspace<T*> dest, const T* src, size_t count)
+{
+ Checked size = sizeof(T);
+ size *= count;
+ if (size.has_overflow())
+ return false;
+ return copy_to_user(dest.unsafe_userspace_ptr(), src, sizeof(T) * count);
}
diff --git a/Kernel/Syscalls/chdir.cpp b/Kernel/Syscalls/chdir.cpp
index 68437ab0a9..46cf3a2459 100644
--- a/Kernel/Syscalls/chdir.cpp
+++ b/Kernel/Syscalls/chdir.cpp
@@ -66,12 +66,11 @@ int Process::sys$getcwd(Userspace<char*> buffer, ssize_t size)
REQUIRE_PROMISE(rpath);
if (size < 0)
return -EINVAL;
- if (!validate_write(buffer, size))
- return -EFAULT;
auto path = current_directory().absolute_path();
if ((size_t)size < path.length() + 1)
return -ERANGE;
- copy_to_user(buffer, path.characters(), path.length() + 1);
+ if (!copy_to_user(buffer, path.characters(), path.length() + 1))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/chown.cpp b/Kernel/Syscalls/chown.cpp
index 8de435c468..e07ab19f8a 100644
--- a/Kernel/Syscalls/chown.cpp
+++ b/Kernel/Syscalls/chown.cpp
@@ -42,7 +42,7 @@ int Process::sys$chown(Userspace<const Syscall::SC_chown_params*> user_params)
{
REQUIRE_PROMISE(chown);
Syscall::SC_chown_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto path = get_syscall_path_argument(params.path);
if (path.is_error())
diff --git a/Kernel/Syscalls/clock.cpp b/Kernel/Syscalls/clock.cpp
index de83b63035..3ee0c85339 100644
--- a/Kernel/Syscalls/clock.cpp
+++ b/Kernel/Syscalls/clock.cpp
@@ -32,8 +32,6 @@ namespace Kernel {
int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(user_ts))
- return -EFAULT;
timespec ts = {};
@@ -49,7 +47,8 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
return -EINVAL;
}
- copy_to_user(user_ts, &ts);
+ if (!copy_to_user(user_ts, &ts))
+ return -EFAULT;
return 0;
}
@@ -61,7 +60,7 @@ int Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> us
return -EPERM;
timespec ts;
- if (!validate_read_and_copy_typed(&ts, user_ts))
+ if (!copy_from_user(&ts, user_ts))
return -EFAULT;
switch (clock_id) {
@@ -79,16 +78,11 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
REQUIRE_PROMISE(stdio);
Syscall::SC_clock_nanosleep_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
-
- if (params.requested_sleep && !validate_read_typed(params.requested_sleep))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
timespec requested_sleep;
- copy_from_user(&requested_sleep, params.requested_sleep);
-
- if (params.remaining_sleep && !validate_write_typed(params.remaining_sleep))
+ if (!copy_from_user(&requested_sleep, params.requested_sleep))
return -EFAULT;
bool is_absolute = params.flags & TIMER_ABSTIME;
@@ -109,18 +103,12 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
if (wakeup_time > g_uptime) {
u64 ticks_left = wakeup_time - g_uptime;
if (!is_absolute && params.remaining_sleep) {
- if (!validate_write_typed(params.remaining_sleep)) {
- // This can happen because the lock is dropped while
- // sleeping, thus giving other threads the opportunity
- // to make the region unwritable.
- return -EFAULT;
- }
-
timespec remaining_sleep = {};
remaining_sleep.tv_sec = ticks_left / TimeManagement::the().ticks_per_second();
ticks_left -= remaining_sleep.tv_sec * TimeManagement::the().ticks_per_second();
remaining_sleep.tv_nsec = ticks_left * 1000000000 / TimeManagement::the().ticks_per_second();
- copy_to_user(params.remaining_sleep, &remaining_sleep);
+ if (!copy_to_user(params.remaining_sleep, &remaining_sleep))
+ return -EFAULT;
}
return -EINTR;
}
@@ -134,10 +122,9 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
int Process::sys$gettimeofday(Userspace<timeval*> user_tv)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(user_tv))
- return -EFAULT;
auto tv = kgettimeofday();
- copy_to_user(user_tv, &tv);
+ if (!copy_to_user(user_tv, &tv))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/debug.cpp b/Kernel/Syscalls/debug.cpp
index bd22e8b4c2..8bafe6399d 100644
--- a/Kernel/Syscalls/debug.cpp
+++ b/Kernel/Syscalls/debug.cpp
@@ -27,6 +27,7 @@
#include <Kernel/IO.h>
#include <Kernel/KSyms.h>
#include <Kernel/Process.h>
+#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
@@ -44,13 +45,20 @@ int Process::sys$dbgputch(u8 ch)
int Process::sys$dbgputstr(Userspace<const u8*> characters, int length)
{
- if (!length)
+ if (length <= 0)
return 0;
- if (!validate_read(characters, length))
- return -EFAULT;
+
SmapDisabler disabler;
- for (int i = 0; i < length; ++i)
- IO::out8(0xe9, characters.unsafe_userspace_ptr()[i]);
+ auto buffer = UserOrKernelBuffer::for_user_buffer(characters, length);
+ if (!buffer.has_value())
+ return -EFAULT;
+ ssize_t nread = buffer.value().read_buffered<1024>(length, [&](const u8* buffer, size_t buffer_size) {
+ for (size_t i = 0; i < buffer_size; ++i)
+ IO::out8(0xe9, buffer[i]);
+ return (ssize_t)buffer_size;
+ });
+ if (nread < 0)
+ return (int)nread;
return 0;
}
diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp
index bb0012a8e1..0e95a4c29e 100644
--- a/Kernel/Syscalls/execve.cpp
+++ b/Kernel/Syscalls/execve.cpp
@@ -423,7 +423,8 @@ KResultOr<NonnullRefPtr<FileDescription>> Process::find_elf_interpreter_for_exec
return KResult(-ENOEXEC);
memset(first_page, 0, sizeof(first_page));
- auto nread_or_error = interpreter_description->read((u8*)&first_page, sizeof(first_page));
+ auto first_page_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&first_page);
+ auto nread_or_error = interpreter_description->read(first_page_buffer, sizeof(first_page));
if (nread_or_error.is_error())
return KResult(-ENOEXEC);
nread = nread_or_error.value();
@@ -490,7 +491,8 @@ int Process::exec(String path, Vector<String> arguments, Vector<String> environm
// Read the first page of the program into memory so we can validate the binfmt of it
char first_page[PAGE_SIZE];
- auto nread_or_error = description->read((u8*)&first_page, sizeof(first_page));
+ auto first_page_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&first_page);
+ auto nread_or_error = description->read(first_page_buffer, sizeof(first_page));
if (nread_or_error.is_error())
return -ENOEXEC;
@@ -554,7 +556,7 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
// NOTE: Be extremely careful with allocating any kernel memory in exec().
// On success, the kernel stack will be lost.
Syscall::SC_execve_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
@@ -574,13 +576,16 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
auto copy_user_strings = [this](const auto& list, auto& output) {
if (!list.length)
return true;
- if (!validate_read_typed(list.strings, list.length))
+ Checked size = sizeof(list.length);
+ size *= list.length;
+ if (size.has_overflow())
return false;
Vector<Syscall::StringArgument, 32> strings;
strings.resize(list.length);
- copy_from_user(strings.data(), list.strings.unsafe_userspace_ptr(), list.length * sizeof(Syscall::StringArgument));
+ if (!copy_from_user(strings.data(), list.strings, list.length * sizeof(Syscall::StringArgument)))
+ return false;
for (size_t i = 0; i < list.length; ++i) {
- auto string = validate_and_copy_string_from_user(strings[i]);
+ auto string = copy_string_from_user(strings[i]);
if (string.is_null())
return false;
output.append(move(string));
diff --git a/Kernel/Syscalls/futex.cpp b/Kernel/Syscalls/futex.cpp
index 830579934c..cd0f8fd21f 100644
--- a/Kernel/Syscalls/futex.cpp
+++ b/Kernel/Syscalls/futex.cpp
@@ -55,21 +55,19 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
REQUIRE_PROMISE(thread);
Syscall::SC_futex_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
-
- if (!validate_read_typed(params.userspace_address))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
switch (params.futex_op) {
case FUTEX_WAIT: {
i32 user_value;
- copy_from_user(&user_value, params.userspace_address);
+ if (!copy_from_user(&user_value, params.userspace_address))
+ return -EFAULT;
if (user_value != params.val)
return -EAGAIN;
timespec ts_abstimeout { 0, 0 };
- if (params.timeout && !validate_read_and_copy_typed(&ts_abstimeout, params.timeout))
+ if (params.timeout && !copy_from_user(&ts_abstimeout, params.timeout))
return -EFAULT;
timeval* optional_timeout = nullptr;
@@ -80,7 +78,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
}
// FIXME: This is supposed to be interruptible by a signal, but right now WaitQueue cannot be interrupted.
- WaitQueue& wait_queue = futex_queue(params.userspace_address);
+ WaitQueue& wait_queue = futex_queue((FlatPtr)params.userspace_address);
Thread::BlockResult result = Thread::current()->wait_on(wait_queue, "Futex", optional_timeout);
if (result == Thread::BlockResult::InterruptedByTimeout) {
return -ETIMEDOUT;
@@ -92,9 +90,9 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
if (params.val == 0)
return 0;
if (params.val == 1) {
- futex_queue(params.userspace_address).wake_one();
+ futex_queue((FlatPtr)params.userspace_address).wake_one();
} else {
- futex_queue(params.userspace_address).wake_n(params.val);
+ futex_queue((FlatPtr)params.userspace_address).wake_n(params.val);
}
break;
}
diff --git a/Kernel/Syscalls/get_dir_entries.cpp b/Kernel/Syscalls/get_dir_entries.cpp
index 56d98cd9f0..a94bf584d3 100644
--- a/Kernel/Syscalls/get_dir_entries.cpp
+++ b/Kernel/Syscalls/get_dir_entries.cpp
@@ -34,12 +34,13 @@ ssize_t Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size)
REQUIRE_PROMISE(stdio);
if (size < 0)
return -EINVAL;
- if (!validate_write(buffer, size))
- return -EFAULT;
auto description = file_description(fd);
if (!description)
return -EBADF;
- return description->get_dir_entries((u8*)buffer, size);
+ auto user_buffer = UserOrKernelBuffer::for_user_buffer((u8*)buffer, size);
+ if (!user_buffer.has_value())
+ return -EFAULT;
+ return description->get_dir_entries(user_buffer.value(), size);
}
}
diff --git a/Kernel/Syscalls/get_stack_bounds.cpp b/Kernel/Syscalls/get_stack_bounds.cpp
index e41bcb5ddb..a91a401946 100644
--- a/Kernel/Syscalls/get_stack_bounds.cpp
+++ b/Kernel/Syscalls/get_stack_bounds.cpp
@@ -31,11 +31,6 @@ namespace Kernel {
int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_size)
{
- if (!validate_write_typed(user_stack_base))
- return -EFAULT;
- if (!validate_write_typed(user_stack_size))
- return -EFAULT;
-
FlatPtr stack_pointer = Thread::current()->get_register_dump_from_stack().userspace_esp;
auto* stack_region = MM.find_region_from_vaddr(*this, VirtualAddress(stack_pointer));
if (!stack_region) {
@@ -45,8 +40,10 @@ int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_s
FlatPtr stack_base = stack_region->range().base().get();
size_t stack_size = stack_region->size();
- copy_to_user(user_stack_base, &stack_base);
- copy_to_user(user_stack_size, &stack_size);
+ if (!copy_to_user(user_stack_base, &stack_base))
+ return -EFAULT;
+ if (!copy_to_user(user_stack_size, &stack_size))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/getrandom.cpp b/Kernel/Syscalls/getrandom.cpp
index 53361d9263..c000c9cf87 100644
--- a/Kernel/Syscalls/getrandom.cpp
+++ b/Kernel/Syscalls/getrandom.cpp
@@ -26,6 +26,7 @@
#include <Kernel/Process.h>
#include <Kernel/Random.h>
+#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {
@@ -38,13 +39,15 @@ ssize_t Process::sys$getrandom(Userspace<void*> buffer, size_t buffer_size, [[ma
if (buffer_size <= 0)
return -EINVAL;
- if (!validate_write(buffer, buffer_size))
- return -EFAULT;
-
SmapDisabler disabler;
- // FIXME: We should really push Userspace<T> down through the interface.
- get_good_random_bytes((u8*)buffer.ptr(), buffer_size);
- return 0;
+ auto data_buffer = UserOrKernelBuffer::for_user_buffer(buffer, buffer_size);
+ if (!data_buffer.has_value())
+ return -EFAULT;
+ ssize_t nwritten = data_buffer.value().write_buffered<1024>(buffer_size, [&](u8* buffer, size_t buffer_bytes) {
+ get_good_random_bytes(buffer, buffer_bytes);
+ return (ssize_t)buffer_bytes;
+ });
+ return nwritten;
}
}
diff --git a/Kernel/Syscalls/getuid.cpp b/Kernel/Syscalls/getuid.cpp
index 699ad9b6ca..73889c8ca6 100644
--- a/Kernel/Syscalls/getuid.cpp
+++ b/Kernel/Syscalls/getuid.cpp
@@ -55,22 +55,16 @@ gid_t Process::sys$getegid()
int Process::sys$getresuid(Userspace<uid_t*> ruid, Userspace<uid_t*> euid, Userspace<uid_t*> suid)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(ruid) || !validate_write_typed(euid) || !validate_write_typed(suid))
+ if (!copy_to_user(ruid, &m_uid) || !copy_to_user(euid, &m_euid) || !copy_to_user(suid, &m_suid))
return -EFAULT;
- copy_to_user(ruid, &m_uid);
- copy_to_user(euid, &m_euid);
- copy_to_user(suid, &m_suid);
return 0;
}
int Process::sys$getresgid(Userspace<gid_t*> rgid, Userspace<gid_t*> egid, Userspace<gid_t*> sgid)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(rgid) || !validate_write_typed(egid) || !validate_write_typed(sgid))
+ if (!copy_to_user(rgid, &m_gid) || !copy_to_user(egid, &m_egid) || !copy_to_user(sgid, &m_sgid))
return -EFAULT;
- copy_to_user(rgid, &m_gid);
- copy_to_user(egid, &m_egid);
- copy_to_user(sgid, &m_sgid);
return 0;
}
@@ -83,10 +77,9 @@ int Process::sys$getgroups(ssize_t count, Userspace<gid_t*> user_gids)
return m_extra_gids.size();
if (count != (int)m_extra_gids.size())
return -EINVAL;
- if (!validate_write_typed(user_gids, m_extra_gids.size()))
- return -EFAULT;
- copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count);
+ if (!copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/hostname.cpp b/Kernel/Syscalls/hostname.cpp
index 490c6a169d..fa5c992b52 100644
--- a/Kernel/Syscalls/hostname.cpp
+++ b/Kernel/Syscalls/hostname.cpp
@@ -36,12 +36,11 @@ int Process::sys$gethostname(Userspace<char*> buffer, ssize_t size)
REQUIRE_PROMISE(stdio);
if (size < 0)
return -EINVAL;
- if (!validate_write(buffer, size))
- return -EFAULT;
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
if ((size_t)size < (g_hostname->length() + 1))
return -ENAMETOOLONG;
- copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1);
+ if (!copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1))
+ return -EFAULT;
return 0;
}
@@ -55,7 +54,10 @@ int Process::sys$sethostname(Userspace<const char*> hostname, ssize_t length)
LOCKER(*g_hostname_lock, Lock::Mode::Exclusive);
if (length > 64)
return -ENAMETOOLONG;
- *g_hostname = validate_and_copy_string_from_user(hostname, length);
+ auto copied_hostname = copy_string_from_user(hostname, length);
+ if (copied_hostname.is_null())
+ return -EFAULT;
+ *g_hostname = move(copied_hostname);
return 0;
}
diff --git a/Kernel/Syscalls/link.cpp b/Kernel/Syscalls/link.cpp
index cbb3185e03..f3bf17ff3e 100644
--- a/Kernel/Syscalls/link.cpp
+++ b/Kernel/Syscalls/link.cpp
@@ -34,11 +34,13 @@ int Process::sys$link(Userspace<const Syscall::SC_link_params*> user_params)
{
REQUIRE_PROMISE(cpath);
Syscall::SC_link_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
- 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())
+ auto old_path = copy_string_from_user(params.old_path);
+ if (old_path.is_null())
+ return -EFAULT;
+ auto new_path = copy_string_from_user(params.new_path);
+ if (new_path.is_null())
return -EFAULT;
return VFS::the().link(old_path, new_path, current_directory());
}
@@ -47,7 +49,7 @@ int Process::sys$symlink(Userspace<const Syscall::SC_symlink_params*> user_param
{
REQUIRE_PROMISE(cpath);
Syscall::SC_symlink_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto target = get_syscall_path_argument(params.target);
if (target.is_error())
diff --git a/Kernel/Syscalls/mknod.cpp b/Kernel/Syscalls/mknod.cpp
index 1a599b138d..1b6a4d9444 100644
--- a/Kernel/Syscalls/mknod.cpp
+++ b/Kernel/Syscalls/mknod.cpp
@@ -34,7 +34,7 @@ int Process::sys$mknod(Userspace<const Syscall::SC_mknod_params*> user_params)
{
REQUIRE_PROMISE(dpath);
Syscall::SC_mknod_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode))
return -EPERM;
diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp
index e99be2775a..74dbe31edf 100644
--- a/Kernel/Syscalls/mmap.cpp
+++ b/Kernel/Syscalls/mmap.cpp
@@ -81,7 +81,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
REQUIRE_PROMISE(stdio);
Syscall::SC_mmap_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return (void*)-EFAULT;
void* addr = (void*)params.addr;
@@ -102,7 +102,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
if (params.name.characters) {
if (params.name.length > PATH_MAX)
return (void*)-ENAMETOOLONG;
- name = validate_and_copy_string_from_user(params.name);
+ name = copy_string_from_user(params.name);
if (name.is_null())
return (void*)-EFAULT;
}
@@ -336,13 +336,13 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
REQUIRE_PROMISE(stdio);
Syscall::SC_set_mmap_name_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
if (params.name.length > PATH_MAX)
return -ENAMETOOLONG;
- auto name = validate_and_copy_string_from_user(params.name);
+ auto name = copy_string_from_user(params.name);
if (name.is_null())
return -EFAULT;
@@ -351,7 +351,7 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
return -EINVAL;
if (!region->is_mmap())
return -EPERM;
- region->set_name(name);
+ region->set_name(move(name));
return 0;
}
diff --git a/Kernel/Syscalls/module.cpp b/Kernel/Syscalls/module.cpp
index 6da8ff8144..f8d9e0ac9f 100644
--- a/Kernel/Syscalls/module.cpp
+++ b/Kernel/Syscalls/module.cpp
@@ -169,7 +169,7 @@ int Process::sys$module_unload(Userspace<const char*> user_name, size_t name_len
REQUIRE_NO_PROMISES;
- auto module_name = validate_and_copy_string_from_user(user_name, name_length);
+ auto module_name = copy_string_from_user(user_name, name_length);
if (module_name.is_null())
return -EFAULT;
diff --git a/Kernel/Syscalls/mount.cpp b/Kernel/Syscalls/mount.cpp
index 68f9a3ba89..ca95f84636 100644
--- a/Kernel/Syscalls/mount.cpp
+++ b/Kernel/Syscalls/mount.cpp
@@ -43,15 +43,16 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
REQUIRE_NO_PROMISES;
Syscall::SC_mount_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto source_fd = params.source_fd;
- auto target = validate_and_copy_string_from_user(params.target);
- auto fs_type = validate_and_copy_string_from_user(params.fs_type);
-
+ auto target = copy_string_from_user(params.target);
if (target.is_null())
return -EFAULT;
+ auto fs_type = copy_string_from_user(params.fs_type);
+ if (fs_type.is_null())
+ return -EFAULT;
auto description = file_description(source_fd);
if (!description.is_null())
@@ -129,9 +130,6 @@ int Process::sys$umount(Userspace<const char*> user_mountpoint, size_t mountpoin
REQUIRE_NO_PROMISES;
- if (!validate_read(user_mountpoint, mountpoint_length))
- return -EFAULT;
-
auto mountpoint = get_syscall_path_argument(user_mountpoint, mountpoint_length);
if (mountpoint.is_error())
return mountpoint.error();
diff --git a/Kernel/Syscalls/open.cpp b/Kernel/Syscalls/open.cpp
index 0d8a3d5e48..abcc413f01 100644
--- a/Kernel/Syscalls/open.cpp
+++ b/Kernel/Syscalls/open.cpp
@@ -34,7 +34,7 @@ namespace Kernel {
int Process::sys$open(Userspace<const Syscall::SC_open_params*> user_params)
{
Syscall::SC_open_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
int dirfd = params.dirfd;
diff --git a/Kernel/Syscalls/pipe.cpp b/Kernel/Syscalls/pipe.cpp
index 182c289857..3d82917c8f 100644
--- a/Kernel/Syscalls/pipe.cpp
+++ b/Kernel/Syscalls/pipe.cpp
@@ -33,8 +33,6 @@ namespace Kernel {
int Process::sys$pipe(int pipefd[2], int flags)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(pipefd))
- return -EFAULT;
if (number_of_open_file_descriptors() + 2 > max_open_file_descriptors())
return -EMFILE;
// Reject flags other than O_CLOEXEC.
@@ -47,12 +45,14 @@ int Process::sys$pipe(int pipefd[2], int flags)
int reader_fd = alloc_fd();
m_fds[reader_fd].set(fifo->open_direction(FIFO::Direction::Reader), fd_flags);
m_fds[reader_fd].description()->set_readable(true);
- copy_to_user(&pipefd[0], &reader_fd);
+ if (!copy_to_user(&pipefd[0], &reader_fd))
+ return -EFAULT;
int writer_fd = alloc_fd();
m_fds[writer_fd].set(fifo->open_direction(FIFO::Direction::Writer), fd_flags);
m_fds[writer_fd].description()->set_writable(true);
- copy_to_user(&pipefd[1], &writer_fd);
+ if (!copy_to_user(&pipefd[1], &writer_fd))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/pledge.cpp b/Kernel/Syscalls/pledge.cpp
index 4cd9345235..e90e7eefea 100644
--- a/Kernel/Syscalls/pledge.cpp
+++ b/Kernel/Syscalls/pledge.cpp
@@ -32,7 +32,7 @@ namespace Kernel {
int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
{
Syscall::SC_pledge_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
if (params.promises.length > 1024 || params.execpromises.length > 1024)
@@ -40,14 +40,14 @@ int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
String promises;
if (params.promises.characters) {
- promises = validate_and_copy_string_from_user(params.promises);
+ auto promises = copy_string_from_user(params.promises);
if (promises.is_null())
return -EFAULT;
}
String execpromises;
if (params.execpromises.characters) {
- execpromises = validate_and_copy_string_from_user(params.execpromises);
+ execpromises = copy_string_from_user(params.execpromises);
if (execpromises.is_null())
return -EFAULT;
}
diff --git a/Kernel/Syscalls/process.cpp b/Kernel/Syscalls/process.cpp
index 6a58ee3388..2e166c1967 100644
--- a/Kernel/Syscalls/process.cpp
+++ b/Kernel/Syscalls/process.cpp
@@ -58,13 +58,11 @@ int Process::sys$set_process_icon(int icon_id)
int Process::sys$get_process_name(Userspace<char*> buffer, size_t buffer_size)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write(buffer, buffer_size))
- return -EFAULT;
-
if (m_name.length() + 1 > buffer_size)
return -ENAMETOOLONG;
- copy_to_user(buffer, m_name.characters(), m_name.length() + 1);
+ if (!copy_to_user(buffer, m_name.characters(), m_name.length() + 1))
+ return -EFAULT;
return 0;
}
@@ -73,7 +71,7 @@ int Process::sys$set_process_name(Userspace<const char*> user_name, size_t user_
REQUIRE_PROMISE(proc);
if (user_name_length > 256)
return -ENAMETOOLONG;
- auto name = validate_and_copy_string_from_user(user_name, user_name_length);
+ auto name = copy_string_from_user(user_name, user_name_length);
if (name.is_null())
return -EFAULT;
m_name = move(name);
diff --git a/Kernel/Syscalls/ptrace.cpp b/Kernel/Syscalls/ptrace.cpp
index 2f19df3056..8ca71c9860 100644
--- a/Kernel/Syscalls/ptrace.cpp
+++ b/Kernel/Syscalls/ptrace.cpp
@@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <AK/ScopeGuard.h>
#include <Kernel/Process.h>
#include <Kernel/Ptrace.h>
#include <Kernel/VM/MemoryManager.h>
@@ -38,7 +39,7 @@ int Process::sys$ptrace(Userspace<const Syscall::SC_ptrace_params*> user_params)
{
REQUIRE_PROMISE(proc);
Syscall::SC_ptrace_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto result = Ptrace::handle_syscall(params, *this);
return result.is_error() ? result.error() : result.value();
@@ -63,28 +64,21 @@ bool Process::has_tracee_thread(ProcessID tracer_pid) const
KResultOr<u32> Process::peek_user_data(Userspace<const u32*> address)
{
- if (!MM.validate_user_read(*this, VirtualAddress(address), sizeof(u32))) {
- dbg() << "Invalid address for peek_user_data: " << address.ptr();
- return KResult(-EFAULT);
- }
uint32_t result;
// This function can be called from the context of another
// process that called PT_PEEK
ProcessPagingScope scope(*this);
- copy_from_user(&result, address);
+ if (!copy_from_user(&result, address)) {
+ dbg() << "Invalid address for peek_user_data: " << address.ptr();
+ return KResult(-EFAULT);
+ }
return result;
}
KResult Process::poke_user_data(Userspace<u32*> address, u32 data)
{
- // We validate for read (rather than write) because PT_POKE can write to readonly pages.
- // So we effectively only care that the poke operation is trying to write to user pages.
- if (!MM.validate_user_read(*this, VirtualAddress(address), sizeof(u32))) {
- dbg() << "Invalid address for poke_user_data: " << address.ptr();
- return KResult(-EFAULT);
- }
ProcessPagingScope scope(*this);
Range range = { VirtualAddress(address), sizeof(u32) };
auto* region = find_region_containing(range);
@@ -97,18 +91,23 @@ KResult Process::poke_user_data(Userspace<u32*> address, u32 data)
region->set_shared(false);
}
const bool was_writable = region->is_writable();
- if (!was_writable) //TODO refactor into scopeguard
+ if (!was_writable)
{
region->set_writable(true);
region->remap();
}
+ ScopeGuard rollback([&]() {
+ if (!was_writable) {
+ region->set_writable(false);
+ region->remap();
+ }
+ });
- copy_to_user(address, &data);
-
- if (!was_writable) {
- region->set_writable(false);
- region->remap();
+ if (!copy_to_user(address, &data)) {
+ dbg() << "Invalid address for poke_user_data: " << address.ptr();
+ return KResult(-EFAULT);
}
+
return KResult(KSuccess);
}
diff --git a/Kernel/Syscalls/read.cpp b/Kernel/Syscalls/read.cpp
index 82a774b75b..df2873a8fe 100644
--- a/Kernel/Syscalls/read.cpp
+++ b/Kernel/Syscalls/read.cpp
@@ -38,8 +38,6 @@ ssize_t Process::sys$read(int fd, Userspace<u8*> buffer, ssize_t size)
return -EINVAL;
if (size == 0)
return 0;
- if (!validate_write(buffer, size))
- return -EFAULT;
#ifdef DEBUG_IO
dbg() << "sys$read(" << fd << ", " << (const void*)buffer.ptr() << ", " << size << ")";
#endif
@@ -58,7 +56,10 @@ ssize_t Process::sys$read(int fd, Userspace<u8*> buffer, ssize_t size)
return -EAGAIN;
}
}
- auto result = description->read(buffer.unsafe_userspace_ptr(), size);
+ auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size);
+ if (!user_buffer.has_value())
+ return -EFAULT;
+ auto result = description->read(user_buffer.value(), size);
if (result.is_error())
return result.error();
return result.value();
diff --git a/Kernel/Syscalls/readlink.cpp b/Kernel/Syscalls/readlink.cpp
index d2b35733a9..b9da03db87 100644
--- a/Kernel/Syscalls/readlink.cpp
+++ b/Kernel/Syscalls/readlink.cpp
@@ -36,10 +36,7 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
REQUIRE_PROMISE(rpath);
Syscall::SC_readlink_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
-
- if (!validate(params.buffer))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto path = get_syscall_path_argument(params.path);
@@ -60,7 +57,8 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
auto& link_target = contents.value();
auto size_to_copy = min(link_target.size(), params.buffer.size);
- copy_to_user(params.buffer.data, link_target.data(), size_to_copy);
+ if (!copy_to_user(params.buffer.data, link_target.data(), size_to_copy))
+ return -EFAULT;
// Note: we return the whole size here, not the copied size.
return link_target.size();
}
diff --git a/Kernel/Syscalls/realpath.cpp b/Kernel/Syscalls/realpath.cpp
index 4728115a72..83f6cba839 100644
--- a/Kernel/Syscalls/realpath.cpp
+++ b/Kernel/Syscalls/realpath.cpp
@@ -36,10 +36,7 @@ int Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_par
REQUIRE_PROMISE(rpath);
Syscall::SC_realpath_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
-
- if (!validate_write(params.buffer.data, params.buffer.size))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto path = get_syscall_path_argument(params.path);
@@ -55,7 +52,8 @@ int Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_par
if (absolute_path.length() + 1 > params.buffer.size)
return -ENAMETOOLONG;
- copy_to_user(params.buffer.data, absolute_path.characters(), absolute_path.length() + 1);
+ if (!copy_to_user(params.buffer.data, absolute_path.characters(), absolute_path.length() + 1))
+ return -EFAULT;
return 0;
};
diff --git a/Kernel/Syscalls/rename.cpp b/Kernel/Syscalls/rename.cpp
index 0a06eaceb8..ef9463c860 100644
--- a/Kernel/Syscalls/rename.cpp
+++ b/Kernel/Syscalls/rename.cpp
@@ -34,7 +34,7 @@ int Process::sys$rename(Userspace<const Syscall::SC_rename_params*> user_params)
{
REQUIRE_PROMISE(cpath);
Syscall::SC_rename_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto old_path = get_syscall_path_argument(params.old_path);
if (old_path.is_error())
diff --git a/Kernel/Syscalls/sched.cpp b/Kernel/Syscalls/sched.cpp
index 7729a817b0..91ca08884e 100644
--- a/Kernel/Syscalls/sched.cpp
+++ b/Kernel/Syscalls/sched.cpp
@@ -51,11 +51,9 @@ int Process::sys$donate(pid_t tid)
int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> user_param)
{
REQUIRE_PROMISE(proc);
- if (!validate_read_typed(user_param))
- return -EFAULT;
-
struct sched_param desired_param;
- copy_from_user(&desired_param, user_param);
+ if (!copy_from_user(&desired_param, user_param))
+ return -EFAULT;
InterruptDisabler disabler;
auto* peer = Thread::current();
@@ -78,9 +76,6 @@ int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> us
int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_param)
{
REQUIRE_PROMISE(proc);
- if (!validate_write_typed(user_param))
- return -EFAULT;
-
InterruptDisabler disabler;
auto* peer = Thread::current();
if (pid != 0) {
@@ -98,7 +93,8 @@ int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_p
struct sched_param param {
(int)peer->priority()
};
- copy_to_user(user_param, &param);
+ if (!copy_to_user(user_param, &param))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/select.cpp b/Kernel/Syscalls/select.cpp
index ccf2110a3a..c518ae7acb 100644
--- a/Kernel/Syscalls/select.cpp
+++ b/Kernel/Syscalls/select.cpp
@@ -34,51 +34,43 @@
namespace Kernel {
-int Process::sys$select(const Syscall::SC_select_params* params)
+int Process::sys$select(const Syscall::SC_select_params* user_params)
{
REQUIRE_PROMISE(stdio);
- // FIXME: Return -EINVAL if timeout is invalid.
- if (!validate_read_typed(params))
- return -EFAULT;
+ Syscall::SC_select_params params;
SmapDisabler disabler;
-
- int nfds = params->nfds;
- fd_set* readfds = params->readfds;
- fd_set* writefds = params->writefds;
- fd_set* exceptfds = params->exceptfds;
- const timespec* timeout = params->timeout;
- const sigset_t* sigmask = params->sigmask;
-
- if (writefds && !validate_write_typed(writefds))
- return -EFAULT;
- if (readfds && !validate_write_typed(readfds))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
- if (exceptfds && !validate_write_typed(exceptfds))
- return -EFAULT;
- if (timeout && !validate_read_typed(timeout))
- return -EFAULT;
- if (sigmask && !validate_read_typed(sigmask))
- return -EFAULT;
- if (nfds < 0)
+
+ if (params.nfds < 0)
return -EINVAL;
timespec computed_timeout;
bool select_has_timeout = false;
- if (timeout && (timeout->tv_sec || timeout->tv_nsec)) {
- timespec ts_since_boot;
- timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
- timespec_add(ts_since_boot, *timeout, computed_timeout);
- select_has_timeout = true;
+ if (params.timeout) {
+ timespec timeout_copy;
+ if (!copy_from_user(&timeout_copy, params.timeout))
+ return -EFAULT;
+ if (timeout_copy.tv_sec || timeout_copy.tv_nsec) {
+ timespec ts_since_boot;
+ timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
+ timespec_add(ts_since_boot, timeout_copy, computed_timeout);
+ select_has_timeout = true;
+ }
}
auto current_thread = Thread::current();
u32 previous_signal_mask = 0;
- if (sigmask)
- previous_signal_mask = current_thread->update_signal_mask(*sigmask);
+ if (params.sigmask) {
+ sigset_t sigmask_copy;
+ if (!copy_from_user(&sigmask_copy, params.sigmask))
+ return -EFAULT;
+ previous_signal_mask = current_thread->update_signal_mask(sigmask_copy);
+ }
ScopeGuard rollback_signal_mask([&]() {
- if (sigmask)
+ if (params.sigmask)
current_thread->update_signal_mask(previous_signal_mask);
});
@@ -86,12 +78,15 @@ int Process::sys$select(const Syscall::SC_select_params* params)
Thread::SelectBlocker::FDVector wfds;
Thread::SelectBlocker::FDVector efds;
- auto transfer_fds = [&](auto* fds, auto& vector) -> int {
+ auto transfer_fds = [&](auto* fds_unsafe, auto& vector) -> int {
vector.clear_with_capacity();
- if (!fds)
+ if (!fds_unsafe)
return 0;
- for (int fd = 0; fd < nfds; ++fd) {
- if (FD_ISSET(fd, fds)) {
+ fd_set fds;
+ if (!copy_from_user(&fds, fds_unsafe))
+ return -EFAULT;
+ for (int fd = 0; fd < params.nfds; ++fd) {
+ if (FD_ISSET(fd, &fds)) {
if (!file_description(fd)) {
dbg() << "sys$select: Bad fd number " << fd;
return -EBADF;
@@ -101,47 +96,42 @@ int Process::sys$select(const Syscall::SC_select_params* params)
}
return 0;
};
- if (int error = transfer_fds(writefds, wfds))
+ if (int error = transfer_fds(params.writefds, wfds))
return error;
- if (int error = transfer_fds(readfds, rfds))
+ if (int error = transfer_fds(params.readfds, rfds))
return error;
- if (int error = transfer_fds(exceptfds, efds))
+ if (int error = transfer_fds(params.exceptfds, efds))
return error;
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
- dbg() << "selecting on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout;
+ dbg() << "selecting on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << params.timeout;
#endif
- if (!timeout || select_has_timeout) {
+ if (!params.timeout || select_has_timeout) {
if (current_thread->block<Thread::SelectBlocker>(select_has_timeout ? &computed_timeout : nullptr, rfds, wfds, efds).was_interrupted())
return -EINTR;
- // While we blocked, the process lock was dropped. This gave other threads
- // the opportunity to mess with the memory. For example, it could free the
- // region, and map it to a region to which it has no write permissions.
- // Therefore, we need to re-validate all pointers.
- if (writefds && !validate_write_typed(writefds))
- return -EFAULT;
- if (readfds && !validate_write_typed(readfds))
- return -EFAULT;
- // See the fixme below.
- if (exceptfds && !validate_write_typed(exceptfds))
- return -EFAULT;
}
int marked_fd_count = 0;
- auto mark_fds = [&](auto* fds, auto& vector, auto should_mark) {
- if (!fds)
- return;
- FD_ZERO(fds);
+ auto mark_fds = [&](auto* fds_unsafe, auto& vector, auto should_mark) {
+ if (!fds_unsafe)
+ return 0;
+ fd_set fds;
+ FD_ZERO(&fds);
for (int fd : vector) {
if (auto description = file_description(fd); description && should_mark(*description)) {
- FD_SET(fd, fds);
+ FD_SET(fd, &fds);
++marked_fd_count;
}
}
+ if (!copy_to_user(fds_unsafe, &fds))
+ return -EFAULT;
+ return 0;
};
- mark_fds(readfds, rfds, [](auto& description) { return description.can_read(); });
- mark_fds(writefds, wfds, [](auto& description) { return description.can_write(); });
+ if (int error = mark_fds(params.readfds, rfds, [](auto& description) { return description.can_read(); }))
+ return error;
+ if (int error = mark_fds(params.writefds, wfds, [](auto& description) { return description.can_write(); }))
+ return error;
// FIXME: We should also mark exceptfds as appropriate.
return marked_fd_count;
@@ -153,33 +143,39 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
// FIXME: Return -EINVAL if timeout is invalid.
Syscall::SC_poll_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
SmapDisabler disabler;
- pollfd* fds = params.fds;
- unsigned nfds = params.nfds;
-
- if (fds && !validate_read_typed(fds, nfds))
- return -EFAULT;
-
timespec timeout = {};
- if (params.timeout && !validate_read_and_copy_typed(&timeout, params.timeout))
+ if (params.timeout && !copy_from_user(&timeout, params.timeout))
return -EFAULT;
sigset_t sigmask = {};
- if (params.sigmask && !validate_read_and_copy_typed(&sigmask, params.sigmask))
+ if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
return -EFAULT;
+ Vector<pollfd> fds_copy;
+ if (params.nfds > 0) {
+ Checked nfds_checked = sizeof(pollfd);
+ nfds_checked *= params.nfds;
+ if (nfds_checked.has_overflow())
+ return -EFAULT;
+ fds_copy.resize(params.nfds);
+ if (!copy_from_user(&fds_copy[0], &params.fds[0], params.nfds * sizeof(pollfd)))
+ return -EFAULT;
+ }
+
Thread::SelectBlocker::FDVector rfds;
Thread::SelectBlocker::FDVector wfds;
- for (unsigned i = 0; i < nfds; ++i) {
- if (fds[i].events & POLLIN)
- rfds.append(fds[i].fd);
- if (fds[i].events & POLLOUT)
- wfds.append(fds[i].fd);
+ for (unsigned i = 0; i < params.nfds; ++i) {
+ auto& pfd = fds_copy[i];
+ if (pfd.events & POLLIN)
+ rfds.append(pfd.fd);
+ if (pfd.events & POLLOUT)
+ wfds.append(pfd.fd);
}
timespec actual_timeout;
@@ -195,7 +191,7 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
u32 previous_signal_mask = 0;
if (params.sigmask)
- previous_signal_mask = current_thread->update_signal_mask(params.sigmask);
+ previous_signal_mask = current_thread->update_signal_mask(sigmask);
ScopeGuard rollback_signal_mask([&]() {
if (params.sigmask)
current_thread->update_signal_mask(previous_signal_mask);
@@ -210,28 +206,28 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
return -EINTR;
}
- // Validate we can still write after waking up.
- if (fds && !validate_write_typed(fds, nfds))
- return -EFAULT;
-
int fds_with_revents = 0;
- for (unsigned i = 0; i < nfds; ++i) {
- auto description = file_description(fds[i].fd);
+ for (unsigned i = 0; i < params.nfds; ++i) {
+ auto& pfd = fds_copy[i];
+ auto description = file_description(pfd.fd);
if (!description) {
- fds[i].revents = POLLNVAL;
- continue;
+ pfd.revents = POLLNVAL;
+ } else {
+ pfd.revents = 0;
+ if (pfd.events & POLLIN && description->can_read())
+ pfd.revents |= POLLIN;
+ if (pfd.events & POLLOUT && description->can_write())
+ pfd.revents |= POLLOUT;
+
+ if (pfd.revents)
+ ++fds_with_revents;
}
- fds[i].revents = 0;
- if (fds[i].events & POLLIN && description->can_read())
- fds[i].revents |= POLLIN;
- if (fds[i].events & POLLOUT && description->can_write())
- fds[i].revents |= POLLOUT;
-
- if (fds[i].revents)
- ++fds_with_revents;
}
+ if (params.nfds > 0 && !copy_to_user(&params.fds[0], &fds_copy[0], params.nfds * sizeof(pollfd)))
+ return -EFAULT;
+
return fds_with_revents;
}
diff --git a/Kernel/Syscalls/setkeymap.cpp b/Kernel/Syscalls/setkeymap.cpp
index 9920435135..8f9b441dd2 100644
--- a/Kernel/Syscalls/setkeymap.cpp
+++ b/Kernel/Syscalls/setkeymap.cpp
@@ -37,25 +37,20 @@ int Process::sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*> user_p
return -EPERM;
Syscall::SC_setkeymap_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
Keyboard::CharacterMapData character_map_data;
- if (!validate_read(params.map, CHAR_MAP_SIZE))
+ if (!copy_from_user(character_map_data.map, params.map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT;
- if (!validate_read(params.shift_map, CHAR_MAP_SIZE))
+ if (!copy_from_user(character_map_data.shift_map, params.shift_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT;
- if (!validate_read(params.alt_map, CHAR_MAP_SIZE))
+ if (!copy_from_user(character_map_data.alt_map, params.alt_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT;
- if (!validate_read(params.altgr_map, CHAR_MAP_SIZE))
+ if (!copy_from_user(character_map_data.altgr_map, params.altgr_map, CHAR_MAP_SIZE * sizeof(u32)))
return -EFAULT;
- copy_from_user(character_map_data.map, params.map, CHAR_MAP_SIZE * sizeof(u32));
- copy_from_user(character_map_data.shift_map, params.shift_map, CHAR_MAP_SIZE * sizeof(u32));
- copy_from_user(character_map_data.alt_map, params.alt_map, CHAR_MAP_SIZE * sizeof(u32));
- copy_from_user(character_map_data.altgr_map, params.altgr_map, CHAR_MAP_SIZE * sizeof(u32));
-
auto map_name = get_syscall_path_argument(params.map_name);
if (map_name.is_error()) {
return map_name.error();
diff --git a/Kernel/Syscalls/setuid.cpp b/Kernel/Syscalls/setuid.cpp
index 3cedc049ec..8ea014039d 100644
--- a/Kernel/Syscalls/setuid.cpp
+++ b/Kernel/Syscalls/setuid.cpp
@@ -125,8 +125,6 @@ int Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids)
return -EINVAL;
if (!is_superuser())
return -EPERM;
- if (count && !validate_read(user_gids, count))
- return -EFAULT;
if (!count) {
m_extra_gids.clear();
@@ -135,7 +133,8 @@ int Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids)
Vector<gid_t> gids;
gids.resize(count);
- copy_from_user(gids.data(), user_gids, sizeof(gid_t) * count);
+ if (!copy_from_user(gids.data(), user_gids.unsafe_userspace_ptr(), sizeof(gid_t) * count))
+ return -EFAULT;
HashTable<gid_t> unique_extra_gids;
for (auto& gid : gids) {
diff --git a/Kernel/Syscalls/shbuf.cpp b/Kernel/Syscalls/shbuf.cpp
index 8f92562642..6d85c2d50a 100644
--- a/Kernel/Syscalls/shbuf.cpp
+++ b/Kernel/Syscalls/shbuf.cpp
@@ -47,8 +47,6 @@ int Process::sys$shbuf_create(int size, void** buffer)
if (!size || size < 0)
return -EINVAL;
size = PAGE_ROUND_UP(size);
- if (!validate_write_typed(buffer))
- return -EFAULT;
LOCKER(shared_buffers().lock());
static int s_next_shbuf_id;
@@ -57,7 +55,8 @@ int Process::sys$shbuf_create(int size, void** buffer)
shared_buffer->share_with(m_pid);
void* address = shared_buffer->ref_for_process_and_get_address(*this);
- copy_to_user(buffer, &address);
+ if (!copy_to_user(buffer, &address))
+ return -EFAULT;
ASSERT((int)shared_buffer->size() >= size);
#ifdef SHARED_BUFFER_DEBUG
klog() << "Created shared buffer " << shbuf_id << " @ " << buffer << " (" << size << " bytes, vmobject is " << shared_buffer->size() << ")";
@@ -123,8 +122,6 @@ int Process::sys$shbuf_release(int shbuf_id)
void* Process::sys$shbuf_get(int shbuf_id, Userspace<size_t*> user_size)
{
REQUIRE_PROMISE(shared_buffer);
- if (user_size && !validate_write_typed(user_size))
- return (void*)-EFAULT;
LOCKER(shared_buffers().lock());
auto it = shared_buffers().resource().find(shbuf_id);
if (it == shared_buffers().resource().end())
@@ -137,7 +134,8 @@ void* Process::sys$shbuf_get(int shbuf_id, Userspace<size_t*> user_size)
#endif
if (user_size) {
size_t size = shared_buffer.size();
- copy_to_user(user_size, &size);
+ if (!copy_to_user(user_size, &size))
+ return (void*)-EFAULT;
}
return shared_buffer.ref_for_process_and_get_address(*this);
}
diff --git a/Kernel/Syscalls/sigaction.cpp b/Kernel/Syscalls/sigaction.cpp
index c735b34eca..a3151c6d1e 100644
--- a/Kernel/Syscalls/sigaction.cpp
+++ b/Kernel/Syscalls/sigaction.cpp
@@ -34,10 +34,9 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
auto current_thread = Thread::current();
u32 previous_signal_mask;
if (set) {
- if (!validate_read_typed(set))
- return -EFAULT;
sigset_t set_value;
- copy_from_user(&set_value, set);
+ if (!copy_from_user(&set_value, set))
+ return -EFAULT;
switch (how) {
case SIG_BLOCK:
previous_signal_mask = current_thread->signal_mask_block(set_value, true);
@@ -54,21 +53,17 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
} else {
previous_signal_mask = current_thread->signal_mask();
}
- if (old_set) {
- if (!validate_write_typed(old_set))
- return -EFAULT;
- copy_to_user(old_set, &previous_signal_mask);
- }
+ if (old_set && !copy_to_user(old_set, &previous_signal_mask))
+ return -EFAULT;
return 0;
}
int Process::sys$sigpending(Userspace<sigset_t*> set)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(set))
- return -EFAULT;
auto pending_signals = Thread::current()->pending_signals();
- copy_to_user(set, &pending_signals);
+ if (!copy_to_user(set, &pending_signals))
+ return -EFAULT;
return 0;
}
@@ -77,18 +72,18 @@ int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act)
REQUIRE_PROMISE(sigaction);
if (signum < 1 || signum >= 32 || signum == SIGKILL || signum == SIGSTOP)
return -EINVAL;
- if (!validate_read_typed(act))
- return -EFAULT;
InterruptDisabler disabler; // FIXME: This should use a narrower lock. Maybe a way to ignore signals temporarily?
auto& action = Thread::current()->m_signal_action_data[signum];
if (old_act) {
- if (!validate_write_typed(old_act))
+ if (!copy_to_user(&old_act->sa_flags, &action.flags))
+ return -EFAULT;
+ if (!copy_to_user(&old_act->sa_sigaction, &action.handler_or_sigaction, sizeof(action.handler_or_sigaction)))
return -EFAULT;
- copy_to_user(&old_act->sa_flags, &action.flags);
- copy_to_user(&old_act->sa_sigaction, &action.handler_or_sigaction, sizeof(action.handler_or_sigaction));
}
- copy_from_user(&action.flags, &act->sa_flags);
- copy_from_user(&action.handler_or_sigaction, &act->sa_sigaction, sizeof(action.handler_or_sigaction));
+ if (!copy_from_user(&action.flags, &act->sa_flags))
+ return -EFAULT;
+ if (!copy_from_user(&action.handler_or_sigaction, &act->sa_sigaction, sizeof(action.handler_or_sigaction)))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/socket.cpp b/Kernel/Syscalls/socket.cpp
index a32d87e23d..70d30765dc 100644
--- a/Kernel/Syscalls/socket.cpp
+++ b/Kernel/Syscalls/socket.cpp
@@ -65,8 +65,6 @@ int Process::sys$socket(int domain, int type, int protocol)
int Process::sys$bind(int sockfd, Userspace<const sockaddr*> address, socklen_t address_length)
{
- if (!validate_read(address, address_length))
- return -EFAULT;
auto description = file_description(sockfd);
if (!description)
return -EBADF;
@@ -98,14 +96,8 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
REQUIRE_PROMISE(accept);
socklen_t address_size = 0;
- if (user_address) {
- if (!validate_write_typed(user_address_size))
- return -EFAULT;
- if (!validate_read_and_copy_typed(&address_size, user_address_size))
- return -EFAULT;
- if (!validate_write(user_address, address_size))
- return -EFAULT;
- }
+ if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size)))
+ return -EFAULT;
int accepted_socket_fd = alloc_fd();
if (accepted_socket_fd < 0)
@@ -132,8 +124,10 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
u8 address_buffer[sizeof(sockaddr_un)];
address_size = min(sizeof(sockaddr_un), static_cast<size_t>(address_size));
accepted_socket->get_peer_address((sockaddr*)address_buffer, &address_size);
- copy_to_user(user_address, address_buffer, address_size);
- copy_to_user(user_address_size, &address_size);
+ if (!copy_to_user(user_address, address_buffer, address_size))
+ return -EFAULT;
+ if (!copy_to_user(user_address_size, &address_size))
+ return -EFAULT;
}
auto accepted_socket_description = FileDescription::create(*accepted_socket);
@@ -151,8 +145,6 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
int Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, socklen_t user_address_size)
{
- if (!validate_read(user_address, user_address_size))
- return -EFAULT;
int fd = alloc_fd();
if (fd < 0)
return fd;
@@ -165,11 +157,7 @@ int Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, so
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
- u8 address[sizeof(sockaddr_un)];
- size_t address_size = min(sizeof(address), static_cast<size_t>(user_address_size));
- copy_from_user(address, user_address, address_size);
-
- return socket.connect(*description, (const sockaddr*)address, address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No);
+ return socket.connect(*description, user_address, user_address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No);
}
int Process::sys$shutdown(int sockfd, int how)
@@ -192,17 +180,13 @@ ssize_t Process::sys$sendto(Userspace<const Syscall::SC_sendto_params*> user_par
{
REQUIRE_PROMISE(stdio);
Syscall::SC_sendto_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
int flags = params.flags;
- Userspace<const sockaddr*> addr = params.addr;
+ Userspace<const sockaddr*> addr((FlatPtr)params.addr);
socklen_t addr_length = params.addr_length;
- if (!validate(params.data))
- return -EFAULT;
- if (addr && !validate_read(addr, addr_length))
- return -EFAULT;
auto description = file_description(params.sockfd);
if (!description)
return -EBADF;
@@ -212,7 +196,10 @@ ssize_t Process::sys$sendto(Userspace<const Syscall::SC_sendto_params*> user_par
if (socket.is_shut_down_for_writing())
return -EPIPE;
SmapDisabler disabler;
- auto result = socket.sendto(*description, params.data.data, params.data.size, flags, addr, addr_length);
+ auto data_buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>((const u8*)params.data.data), params.data.size);
+ if (!data_buffer.has_value())
+ return -EFAULT;
+ auto result = socket.sendto(*description, data_buffer.value(), params.data.size, flags, addr, addr_length);
if (result.is_error())
return result.error();
return result.value();
@@ -223,27 +210,17 @@ ssize_t Process::sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*> user
REQUIRE_PROMISE(stdio);
Syscall::SC_recvfrom_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
int flags = params.flags;
- Userspace<sockaddr*> user_addr = params.addr;
- Userspace<socklen_t*> user_addr_length = params.addr_length;
+ Userspace<sockaddr*> user_addr((FlatPtr)params.addr);
+ Userspace<socklen_t*> user_addr_length((FlatPtr)params.addr_length);
SmapDisabler disabler;
- if (!validate(params.buffer))
- return -EFAULT;
- if (user_addr_length) {
- socklen_t addr_length;
- if (!validate_read_and_copy_typed(&addr_length, user_addr_length))
- return -EFAULT;
- if (!validate_write_typed(user_addr_length))
- return -EFAULT;
- if (!validate_write(user_addr, addr_length))
- return -EFAULT;
- } else if (user_addr) {
+ if (!user_addr_length && user_addr)
return -EINVAL;
- }
+
auto description = file_description(params.sockfd);
if (!description)
return -EBADF;
@@ -258,7 +235,10 @@ ssize_t Process::sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*> user
if (flags & MSG_DONTWAIT)
description->set_blocking(false);
- auto result = socket.recvfrom(*description, params.buffer.data, params.buffer.size, flags, user_addr, user_addr_length);
+ auto data_buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>((const u8*)params.buffer.data), params.buffer.size);
+ if (!data_buffer.has_value())
+ return -EFAULT;
+ auto result = socket.recvfrom(*description, data_buffer.value(), params.buffer.size, flags, user_addr, user_addr_length);
if (flags & MSG_DONTWAIT)
description->set_blocking(original_blocking);
@@ -271,18 +251,12 @@ template<bool sockname, typename Params>
int Process::get_sock_or_peer_name(const Params& params)
{
socklen_t addrlen_value;
- if (!validate_read_and_copy_typed(&addrlen_value, params.addrlen))
+ if (!copy_from_user(&addrlen_value, params.addrlen, sizeof(socklen_t)))
return -EFAULT;
if (addrlen_value <= 0)
return -EINVAL;
- if (!validate_write(params.addr, addrlen_value))
- return -EFAULT;
-
- if (!validate_write_typed(params.addrlen))
- return -EFAULT;
-
auto description = file_description(params.sockfd);
if (!description)
return -EBADF;
@@ -299,15 +273,17 @@ int Process::get_sock_or_peer_name(const Params& params)
socket.get_local_address((sockaddr*)address_buffer, &addrlen_value);
else
socket.get_peer_address((sockaddr*)address_buffer, &addrlen_value);
- copy_to_user(params.addr, address_buffer, addrlen_value);
- copy_to_user(params.addrlen, &addrlen_value);
+ if (!copy_to_user(params.addr, address_buffer, addrlen_value))
+ return -EFAULT;
+ if (!copy_to_user(params.addrlen, &addrlen_value))
+ return -EFAULT;
return 0;
}
int Process::sys$getsockname(Userspace<const Syscall::SC_getsockname_params*> user_params)
{
Syscall::SC_getsockname_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
return get_sock_or_peer_name<true>(params);
}
@@ -315,7 +291,7 @@ int Process::sys$getsockname(Userspace<const Syscall::SC_getsockname_params*> us
int Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> user_params)
{
Syscall::SC_getpeername_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
return get_sock_or_peer_name<false>(params);
}
@@ -323,22 +299,19 @@ int Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> us
int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user_params)
{
Syscall::SC_getsockopt_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
int sockfd = params.sockfd;
int level = params.level;
int option = params.option;
- Userspace<void*> user_value = params.value;
- Userspace<socklen_t*> user_value_size = params.value_size;
+ Userspace<void*> user_value((FlatPtr)params.value);
+ Userspace<socklen_t*> user_value_size((FlatPtr)params.value_size);
- if (!validate_write_typed(user_value_size))
- return -EFAULT;
socklen_t value_size;
- if (!validate_read_and_copy_typed(&value_size, user_value_size))
- return -EFAULT;
- if (!validate_write(user_value, value_size))
+ if (!copy_from_user(&value_size, params.value_size, sizeof(socklen_t)))
return -EFAULT;
+
auto description = file_description(sockfd);
if (!description)
return -EBADF;
@@ -357,10 +330,9 @@ int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user
int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user_params)
{
Syscall::SC_setsockopt_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
- if (!validate_read(params.value, params.value_size))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
+ Userspace<const void*> user_value((FlatPtr)params.value);
auto description = file_description(params.sockfd);
if (!description)
return -EBADF;
@@ -368,7 +340,7 @@ int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user
return -ENOTSOCK;
auto& socket = *description->socket();
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
- return socket.setsockopt(params.level, params.option, params.value, params.value_size);
+ return socket.setsockopt(params.level, params.option, user_value, params.value_size);
}
}
diff --git a/Kernel/Syscalls/stat.cpp b/Kernel/Syscalls/stat.cpp
index a5ad5882c5..19cdb14f78 100644
--- a/Kernel/Syscalls/stat.cpp
+++ b/Kernel/Syscalls/stat.cpp
@@ -34,14 +34,13 @@ namespace Kernel {
int Process::sys$fstat(int fd, Userspace<stat*> user_statbuf)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(user_statbuf))
- return -EFAULT;
auto description = file_description(fd);
if (!description)
return -EBADF;
stat buffer = {};
int rc = description->stat(buffer);
- copy_to_user(user_statbuf, &buffer);
+ if (!copy_to_user(user_statbuf, &buffer))
+ return -EFAULT;
return rc;
}
@@ -49,9 +48,7 @@ int Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params)
{
REQUIRE_PROMISE(rpath);
Syscall::SC_stat_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
- if (!validate_write_typed(params.statbuf))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
auto path = get_syscall_path_argument(params.path);
if (path.is_error())
@@ -63,7 +60,8 @@ int Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params)
auto result = metadata_or_error.value().stat(statbuf);
if (result.is_error())
return result;
- copy_to_user(params.statbuf, &statbuf);
+ if (!copy_to_user(params.statbuf, &statbuf))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/thread.cpp b/Kernel/Syscalls/thread.cpp
index 39e59baff9..1f13f90ce3 100644
--- a/Kernel/Syscalls/thread.cpp
+++ b/Kernel/Syscalls/thread.cpp
@@ -36,22 +36,16 @@ namespace Kernel {
int Process::sys$create_thread(void* (*entry)(void*), Userspace<const Syscall::SC_create_thread_params*> user_params)
{
REQUIRE_PROMISE(thread);
- if (!validate_read((const void*)entry, sizeof(void*)))
- return -EFAULT;
Syscall::SC_create_thread_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
unsigned detach_state = params.m_detach_state;
int schedule_priority = params.m_schedule_priority;
- Userspace<void*> stack_location = params.m_stack_location;
unsigned stack_size = params.m_stack_size;
- if (!validate_write(stack_location, stack_size))
- return -EFAULT;
-
- u32 user_stack_address = reinterpret_cast<u32>(stack_location.ptr()) + stack_size;
+ auto user_stack_address = (u8*)params.m_stack_location + stack_size;
if (!MM.validate_user_stack(*this, VirtualAddress(user_stack_address - 4)))
return -EFAULT;
@@ -83,7 +77,7 @@ int Process::sys$create_thread(void* (*entry)(void*), Userspace<const Syscall::S
tss.eip = (FlatPtr)entry;
tss.eflags = 0x0202;
tss.cr3 = page_directory().cr3();
- tss.esp = user_stack_address;
+ tss.esp = (u32)user_stack_address;
thread->make_thread_specific_region({});
thread->set_state(Thread::State::Runnable);
@@ -120,8 +114,6 @@ int Process::sys$detach_thread(pid_t tid)
int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
{
REQUIRE_PROMISE(thread);
- if (exit_value && !validate_write_typed(exit_value))
- return -EFAULT;
InterruptDisabler disabler;
auto* thread = Thread::from_tid(tid);
@@ -164,15 +156,15 @@ int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
// NOTE: 'thread' is very possibly deleted at this point. Clear it just to be safe.
thread = nullptr;
- if (exit_value)
- copy_to_user(exit_value, &joinee_exit_value);
+ if (exit_value && !copy_to_user(exit_value, &joinee_exit_value))
+ return -EFAULT;
return 0;
}
int Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, size_t user_name_length)
{
REQUIRE_PROMISE(thread);
- auto name = validate_and_copy_string_from_user(user_name, user_name_length);
+ auto name = copy_string_from_user(user_name, user_name_length);
if (name.is_null())
return -EFAULT;
@@ -185,7 +177,7 @@ int Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, si
if (!thread || thread->pid() != pid())
return -ESRCH;
- thread->set_name(name);
+ thread->set_name(move(name));
return 0;
}
@@ -195,9 +187,6 @@ int Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buff
if (buffer_size == 0)
return -EINVAL;
- if (!validate_write(buffer, buffer_size))
- return -EFAULT;
-
InterruptDisabler disabler;
auto* thread = Thread::from_tid(tid);
if (!thread || thread->pid() != pid())
@@ -206,7 +195,8 @@ int Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buff
if (thread->name().length() + 1 > (size_t)buffer_size)
return -ENAMETOOLONG;
- copy_to_user(buffer, thread->name().characters(), thread->name().length() + 1);
+ if (!copy_to_user(buffer, thread->name().characters(), thread->name().length() + 1))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/times.cpp b/Kernel/Syscalls/times.cpp
index 61355595cf..f769fee590 100644
--- a/Kernel/Syscalls/times.cpp
+++ b/Kernel/Syscalls/times.cpp
@@ -31,16 +31,14 @@ namespace Kernel {
clock_t Process::sys$times(Userspace<tms*> user_times)
{
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(user_times))
- return -EFAULT;
-
tms times = {};
times.tms_utime = m_ticks_in_user;
times.tms_stime = m_ticks_in_kernel;
times.tms_cutime = m_ticks_in_user_for_dead_children;
times.tms_cstime = m_ticks_in_kernel_for_dead_children;
- copy_to_user(user_times, &times);
+ if (!copy_to_user(user_times, &times))
+ return -EFAULT;
return g_uptime & 0x7fffffff;
}
diff --git a/Kernel/Syscalls/ttyname.cpp b/Kernel/Syscalls/ttyname.cpp
index 544135cb5e..9f37a94768 100644
--- a/Kernel/Syscalls/ttyname.cpp
+++ b/Kernel/Syscalls/ttyname.cpp
@@ -34,8 +34,6 @@ namespace Kernel {
int Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t size)
{
REQUIRE_PROMISE(tty);
- if (!validate_write(buffer, size))
- return -EFAULT;
auto description = file_description(fd);
if (!description)
return -EBADF;
@@ -44,15 +42,14 @@ int Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t size)
auto tty_name = description->tty()->tty_name();
if (size < tty_name.length() + 1)
return -ERANGE;
- copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1);
+ if (!copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1))
+ return -EFAULT;
return 0;
}
int Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t size)
{
REQUIRE_PROMISE(tty);
- if (!validate_write(buffer, size))
- return -EFAULT;
auto description = file_description(fd);
if (!description)
return -EBADF;
@@ -62,7 +59,8 @@ int Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t size)
auto pts_name = master_pty->pts_name();
if (size < pts_name.length() + 1)
return -ERANGE;
- copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1);
+ if (!copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/uname.cpp b/Kernel/Syscalls/uname.cpp
index 33172798dd..6f56388396 100644
--- a/Kernel/Syscalls/uname.cpp
+++ b/Kernel/Syscalls/uname.cpp
@@ -34,9 +34,6 @@ int Process::sys$uname(Userspace<utsname*> buf)
extern Lock* g_hostname_lock;
REQUIRE_PROMISE(stdio);
- if (!validate_write_typed(buf))
- return -EFAULT;
-
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
if (g_hostname->length() + 1 > sizeof(utsname::nodename))
@@ -45,11 +42,16 @@ int Process::sys$uname(Userspace<utsname*> buf)
// We have already validated the entire utsname struct at this
// point, there is no need to re-validate every write to the struct.
utsname* user_buf = buf.unsafe_userspace_ptr();
- copy_to_user(user_buf->sysname, "SerenityOS", 11);
- copy_to_user(user_buf->release, "1.0-dev", 8);
- copy_to_user(user_buf->version, "FIXME", 6);
- copy_to_user(user_buf->machine, "i686", 5);
- copy_to_user(user_buf->nodename, g_hostname->characters(), g_hostname->length() + 1);
+ if (!copy_to_user(user_buf->sysname, "SerenityOS", 11))
+ return -EFAULT;
+ if (!copy_to_user(user_buf->release, "1.0-dev", 8))
+ return -EFAULT;
+ if (!copy_to_user(user_buf->version, "FIXME", 6))
+ return -EFAULT;
+ if (!copy_to_user(user_buf->machine, "i686", 5))
+ return -EFAULT;
+ if (!copy_to_user(user_buf->nodename, g_hostname->characters(), g_hostname->length() + 1))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/unlink.cpp b/Kernel/Syscalls/unlink.cpp
index 7c2ac59193..f7cf1faf22 100644
--- a/Kernel/Syscalls/unlink.cpp
+++ b/Kernel/Syscalls/unlink.cpp
@@ -33,8 +33,6 @@ namespace Kernel {
int Process::sys$unlink(Userspace<const char*> user_path, size_t path_length)
{
REQUIRE_PROMISE(cpath);
- if (!validate_read(user_path, path_length))
- return -EFAULT;
auto path = get_syscall_path_argument(user_path, path_length);
if (path.is_error())
return path.error();
diff --git a/Kernel/Syscalls/unveil.cpp b/Kernel/Syscalls/unveil.cpp
index 466d50ed79..dd13d13057 100644
--- a/Kernel/Syscalls/unveil.cpp
+++ b/Kernel/Syscalls/unveil.cpp
@@ -34,7 +34,7 @@ namespace Kernel {
int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
{
Syscall::SC_unveil_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
if (!params.path.characters && !params.permissions.characters) {
@@ -66,7 +66,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
auto& custody = custody_or_error.value();
auto new_unveiled_path = custody->absolute_path();
- auto permissions = validate_and_copy_string_from_user(params.permissions);
+ auto permissions = copy_string_from_user(params.permissions);
if (permissions.is_null())
return -EFAULT;
diff --git a/Kernel/Syscalls/utime.cpp b/Kernel/Syscalls/utime.cpp
index c7134eb330..ae848b906c 100644
--- a/Kernel/Syscalls/utime.cpp
+++ b/Kernel/Syscalls/utime.cpp
@@ -33,14 +33,13 @@ namespace Kernel {
int Process::sys$utime(Userspace<const char*> user_path, size_t path_length, Userspace<const struct utimbuf*> user_buf)
{
REQUIRE_PROMISE(fattr);
- if (user_buf && !validate_read_typed(user_buf))
- return -EFAULT;
auto path = get_syscall_path_argument(user_path, path_length);
if (path.is_error())
return path.error();
utimbuf buf;
if (user_buf) {
- copy_from_user(&buf, user_buf);
+ if (!copy_from_user(&buf, user_buf))
+ return -EFAULT;
} else {
auto now = kgettimeofday();
buf = { now.tv_sec, now.tv_sec };
diff --git a/Kernel/Syscalls/waitid.cpp b/Kernel/Syscalls/waitid.cpp
index 41a0d7c12a..1b12c2a744 100644
--- a/Kernel/Syscalls/waitid.cpp
+++ b/Kernel/Syscalls/waitid.cpp
@@ -104,27 +104,19 @@ pid_t Process::sys$waitid(Userspace<const Syscall::SC_waitid_params*> user_param
REQUIRE_PROMISE(proc);
Syscall::SC_waitid_params params;
- if (!validate_read_and_copy_typed(&params, user_params))
- return -EFAULT;
-
- if (!validate_write_typed(params.infop))
+ if (!copy_from_user(&params, user_params))
return -EFAULT;
#ifdef PROCESS_DEBUG
- dbg() << "sys$waitid(" << params.idtype << ", " << params.id << ", " << params.infop.ptr() << ", " << params.options << ")";
+ dbg() << "sys$waitid(" << params.idtype << ", " << params.id << ", " << params.infop << ", " << params.options << ")";
#endif
auto siginfo_or_error = do_waitid(static_cast<idtype_t>(params.idtype), params.id, params.options);
if (siginfo_or_error.is_error())
return siginfo_or_error.error();
- // While we waited, the process lock was dropped. This gave other threads
- // the opportunity to mess with the memory. For example, it could free the
- // region, and map it to a region to which it has no write permissions.
- // Therefore, we need to re-validate the pointer.
- if (!validate_write_typed(params.infop))
- return -EFAULT;
- copy_to_user(params.infop, &siginfo_or_error.value());
+ if (!copy_to_user(params.infop, &siginfo_or_error.value()))
+ return -EFAULT;
return 0;
}
diff --git a/Kernel/Syscalls/write.cpp b/Kernel/Syscalls/write.cpp
index 62a421b2d3..0385bcbb8e 100644
--- a/Kernel/Syscalls/write.cpp
+++ b/Kernel/Syscalls/write.cpp
@@ -36,16 +36,19 @@ ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
if (iov_count < 0)
return -EINVAL;
- if (!validate_read_typed(iov, iov_count))
- return -EFAULT;
+ {
+ Checked checked_iov_count = sizeof(iovec);
+ checked_iov_count *= iov_count;
+ if (checked_iov_count.has_overflow())
+ return -EFAULT;
+ }
u64 total_length = 0;
Vector<iovec, 32> vecs;
vecs.resize(iov_count);
- copy_from_user(vecs.data(), iov, iov_count * sizeof(iovec));
+ if (!copy_n_from_user(vecs.data(), iov, iov_count))
+ return -EFAULT;
for (auto& vec : vecs) {
- if (!validate_read(vec.iov_base, vec.iov_len))
- return -EFAULT;
total_length += vec.iov_len;
if (total_length > NumericLimits<i32>::max())
return -EINVAL;
@@ -60,7 +63,10 @@ ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
int nwritten = 0;
for (auto& vec : vecs) {
- int rc = do_write(*description, (const u8*)vec.iov_base, vec.iov_len);
+ auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len);
+ if (!buffer.has_value())
+ return -EFAULT;
+ int rc = do_write(*description, buffer.value(), vec.iov_len);
if (rc < 0) {
if (nwritten == 0)
return rc;
@@ -72,7 +78,7 @@ ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
return nwritten;
}
-ssize_t Process::do_write(FileDescription& description, const u8* data, int data_size)
+ssize_t Process::do_write(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size)
{
ssize_t total_nwritten = 0;
if (!description.is_blocking()) {
@@ -83,7 +89,7 @@ ssize_t Process::do_write(FileDescription& description, const u8* data, int data
if (description.should_append())
description.seek(0, SEEK_END);
- while (total_nwritten < data_size) {
+ while ((size_t)total_nwritten < data_size) {
if (!description.can_write()) {
if (!description.is_blocking()) {
// Short write: We can no longer write to this non-blocking description.
@@ -95,7 +101,7 @@ ssize_t Process::do_write(FileDescription& description, const u8* data, int data
return -EINTR;
}
}
- auto nwritten_or_error = description.write(data + total_nwritten, data_size - total_nwritten);
+ auto nwritten_or_error = description.write(data.offset(total_nwritten), data_size - total_nwritten);
if (nwritten_or_error.is_error()) {
if (total_nwritten)
return total_nwritten;
@@ -115,8 +121,7 @@ ssize_t Process::sys$write(int fd, const u8* data, ssize_t size)
return -EINVAL;
if (size == 0)
return 0;
- if (!validate_read(data, size))
- return -EFAULT;
+
#ifdef DEBUG_IO
dbg() << "sys$write(" << fd << ", " << (const void*)(data) << ", " << size << ")";
#endif
@@ -126,7 +131,10 @@ ssize_t Process::sys$write(int fd, const u8* data, ssize_t size)
if (!description->is_writable())
return -EBADF;
- return do_write(*description, data, size);
+ auto buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>(data), (size_t)size);
+ if (!buffer.has_value())
+ return -EFAULT;
+ return do_write(*description, buffer.value(), size);
}
}
diff --git a/Kernel/TTY/MasterPTY.cpp b/Kernel/TTY/MasterPTY.cpp
index 27c251158a..6bbcfb92b2 100644
--- a/Kernel/TTY/MasterPTY.cpp
+++ b/Kernel/TTY/MasterPTY.cpp
@@ -60,14 +60,14 @@ String MasterPTY::pts_name() const
return m_pts_name;
}
-KResultOr<size_t> MasterPTY::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> MasterPTY::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
if (!m_slave && m_buffer.is_empty())
return 0;
return m_buffer.read(buffer, size);
}
-KResultOr<size_t> MasterPTY::write(FileDescription&, size_t, const u8* buffer, size_t size)
+KResultOr<size_t> MasterPTY::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size)
{
if (!m_slave)
return KResult(-EIO);
@@ -98,12 +98,11 @@ void MasterPTY::notify_slave_closed(Badge<SlavePTY>)
m_slave = nullptr;
}
-ssize_t MasterPTY::on_slave_write(const u8* data, ssize_t size)
+ssize_t MasterPTY::on_slave_write(const UserOrKernelBuffer& data, ssize_t size)
{
if (m_closed)
return -EIO;
- m_buffer.write(data, size);
- return size;
+ return m_buffer.write(data, size);
}
bool MasterPTY::can_write_from_slave() const
diff --git a/Kernel/TTY/MasterPTY.h b/Kernel/TTY/MasterPTY.h
index 08e48907e6..69ba0a16dc 100644
--- a/Kernel/TTY/MasterPTY.h
+++ b/Kernel/TTY/MasterPTY.h
@@ -41,7 +41,7 @@ public:
unsigned index() const { return m_index; }
String pts_name() const;
- ssize_t on_slave_write(const u8*, ssize_t);
+ ssize_t on_slave_write(const UserOrKernelBuffer&, ssize_t);
bool can_write_from_slave() const;
void notify_slave_closed(Badge<SlavePTY>);
bool is_closed() const { return m_closed; }
@@ -50,8 +50,8 @@ public:
private:
// ^CharacterDevice
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override;
virtual KResult close() override;
diff --git a/Kernel/TTY/PTYMultiplexer.h b/Kernel/TTY/PTYMultiplexer.h
index 17698009c5..bb20469f38 100644
--- a/Kernel/TTY/PTYMultiplexer.h
+++ b/Kernel/TTY/PTYMultiplexer.h
@@ -48,8 +48,8 @@ public:
// ^CharacterDevice
virtual KResultOr<NonnullRefPtr<FileDescription>> open(int options) override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override { return 0; }
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override { return 0; }
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override { return 0; }
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override { return 0; }
virtual bool can_read(const FileDescription&, size_t) const override { return true; }
virtual bool can_write(const FileDescription&, size_t) const override { return true; }
diff --git a/Kernel/TTY/SlavePTY.cpp b/Kernel/TTY/SlavePTY.cpp
index 6a5106df38..e7daab0a39 100644
--- a/Kernel/TTY/SlavePTY.cpp
+++ b/Kernel/TTY/SlavePTY.cpp
@@ -62,17 +62,22 @@ String SlavePTY::tty_name() const
void SlavePTY::echo(u8 ch)
{
if (should_echo_input()) {
- m_master->on_slave_write(&ch, 1);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(&ch);
+ m_master->on_slave_write(buffer, 1);
}
}
-void SlavePTY::on_master_write(const u8* buffer, ssize_t size)
+void SlavePTY::on_master_write(const UserOrKernelBuffer& buffer, ssize_t size)
{
- for (ssize_t i = 0; i < size; ++i)
- emit(buffer[i]);
+ ssize_t nread = buffer.read_buffered<128>(size, [&](const u8* data, size_t data_size) {
+ for (size_t i = 0; i < data_size; ++i)
+ emit(data[i]);
+ return (ssize_t)data_size;
+ });
+ (void)nread;
}
-ssize_t SlavePTY::on_tty_write(const u8* data, ssize_t size)
+ssize_t SlavePTY::on_tty_write(const UserOrKernelBuffer& data, ssize_t size)
{
m_time_of_last_write = kgettimeofday().tv_sec;
return m_master->on_slave_write(data, size);
@@ -90,7 +95,7 @@ bool SlavePTY::can_read(const FileDescription& description, size_t offset) const
return TTY::can_read(description, offset);
}
-KResultOr<size_t> SlavePTY::read(FileDescription& description, size_t offset, u8* buffer, size_t size)
+KResultOr<size_t> SlavePTY::read(FileDescription& description, size_t offset, UserOrKernelBuffer& buffer, size_t size)
{
if (m_master->is_closed())
return 0;
diff --git a/Kernel/TTY/SlavePTY.h b/Kernel/TTY/SlavePTY.h
index ff86f0c04d..2f1d0d5e76 100644
--- a/Kernel/TTY/SlavePTY.h
+++ b/Kernel/TTY/SlavePTY.h
@@ -37,7 +37,7 @@ class SlavePTY final : public TTY {
public:
virtual ~SlavePTY() override;
- void on_master_write(const u8*, ssize_t);
+ void on_master_write(const UserOrKernelBuffer&, ssize_t);
unsigned index() const { return m_index; }
time_t time_of_last_write() const { return m_time_of_last_write; }
@@ -45,12 +45,12 @@ public:
private:
// ^TTY
virtual String tty_name() const override;
- virtual ssize_t on_tty_write(const u8*, ssize_t) override;
+ virtual ssize_t on_tty_write(const UserOrKernelBuffer&, ssize_t) override;
virtual void echo(u8) override;
// ^CharacterDevice
virtual bool can_read(const FileDescription&, size_t) const override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
virtual bool can_write(const FileDescription&, size_t) const override;
virtual const char* class_name() const override { return "SlavePTY"; }
virtual KResult close() override;
diff --git a/Kernel/TTY/TTY.cpp b/Kernel/TTY/TTY.cpp
index 672e1885d2..3130b3cceb 100644
--- a/Kernel/TTY/TTY.cpp
+++ b/Kernel/TTY/TTY.cpp
@@ -52,7 +52,7 @@ void TTY::set_default_termios()
memcpy(m_termios.c_cc, default_cc, sizeof(default_cc));
}
-KResultOr<size_t> TTY::read(FileDescription&, size_t, u8* buffer, size_t size)
+KResultOr<size_t> TTY::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size)
{
if (Process::current()->pgid() != pgid()) {
// FIXME: Should we propigate this error path somehow?
@@ -63,33 +63,40 @@ KResultOr<size_t> TTY::read(FileDescription&, size_t, u8* buffer, size_t size)
if (m_input_buffer.size() < static_cast<size_t>(size))
size = m_input_buffer.size();
+ ssize_t nwritten;
if (in_canonical_mode()) {
- size_t i = 0;
- for (; i < size; i++) {
- u8 ch = m_input_buffer.dequeue();
- if (ch == '\0') {
- //Here we handle a ^D line, so we don't add the
- //character to the output.
- m_available_lines--;
- break;
- } else if (ch == '\n' || is_eol(ch)) {
- buffer[i] = ch;
- i++;
- m_available_lines--;
- break;
+ nwritten = buffer.write_buffered<512>(size, [&](u8* data, size_t data_size) {
+ size_t i = 0;
+ for (; i < data_size; i++) {
+ u8 ch = m_input_buffer.dequeue();
+ if (ch == '\0') {
+ //Here we handle a ^D line, so we don't add the
+ //character to the output.
+ m_available_lines--;
+ break;
+ } else if (ch == '\n' || is_eol(ch)) {
+ data[i] = ch;
+ i++;
+ m_available_lines--;
+ break;
+ }
+ data[i] = ch;
}
- buffer[i] = ch;
- }
- return i;
+ return (ssize_t)i;
+ });
+ } else {
+ nwritten = buffer.write_buffered<512>(size, [&](u8* data, size_t data_size) {
+ for (size_t i = 0; i < data_size; i++)
+ data[i] = m_input_buffer.dequeue();
+ return (ssize_t)data_size;
+ });
}
-
- for (size_t i = 0; i < size; i++)
- buffer[i] = m_input_buffer.dequeue();
-
- return size;
+ if (nwritten < 0)
+ return KResult(nwritten);
+ return (size_t)nwritten;
}
-KResultOr<size_t> TTY::write(FileDescription&, size_t, const u8* buffer, size_t size)
+KResultOr<size_t> TTY::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size)
{
if (Process::current()->pgid() != pgid()) {
(void)Process::current()->send_signal(SIGTTOU, nullptr);
@@ -337,19 +344,17 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
}
case TCGETS: {
user_termios = reinterpret_cast<termios*>(arg);
- if (!current_process.validate_write(user_termios, sizeof(termios)))
+ if (!copy_to_user(user_termios, &m_termios))
return -EFAULT;
- copy_to_user(user_termios, &m_termios);
return 0;
}
case TCSETS:
case TCSETSF:
case TCSETSW: {
user_termios = reinterpret_cast<termios*>(arg);
- if (!current_process.validate_read(user_termios, sizeof(termios)))
- return -EFAULT;
termios termios;
- copy_from_user(&termios, user_termios);
+ if (!copy_from_user(&termios, user_termios))
+ return -EFAULT;
set_termios(termios);
if (request == TCSETSF)
flush_input();
@@ -365,21 +370,19 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
return 0;
case TIOCGWINSZ:
user_winsize = reinterpret_cast<winsize*>(arg);
- if (!current_process.validate_write(user_winsize, sizeof(winsize)))
- return -EFAULT;
winsize ws;
ws.ws_row = m_rows;
ws.ws_col = m_columns;
ws.ws_xpixel = 0;
ws.ws_ypixel = 0;
- copy_to_user(user_winsize, &ws);
+ if (!copy_to_user(user_winsize, &ws))
+ return -EFAULT;
return 0;
case TIOCSWINSZ: {
user_winsize = reinterpret_cast<winsize*>(arg);
- if (!current_process.validate_read(user_winsize, sizeof(winsize)))
- return -EFAULT;
winsize ws;
- copy_from_user(&ws, user_winsize);
+ if (!copy_from_user(&ws, user_winsize))
+ return -EFAULT;
if (ws.ws_col == m_columns && ws.ws_row == m_rows)
return 0;
m_rows = ws.ws_row;
diff --git a/Kernel/TTY/TTY.h b/Kernel/TTY/TTY.h
index d858aa68a6..6b9d571336 100644
--- a/Kernel/TTY/TTY.h
+++ b/Kernel/TTY/TTY.h
@@ -39,8 +39,8 @@ class TTY : public CharacterDevice {
public:
virtual ~TTY() override;
- virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override;
- virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override;
+ virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
+ virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
virtual bool can_read(const FileDescription&, size_t) const override;
virtual bool can_write(const FileDescription&, size_t) const override;
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg) override final;
@@ -63,7 +63,7 @@ public:
void hang_up();
protected:
- virtual ssize_t on_tty_write(const u8*, ssize_t) = 0;
+ virtual ssize_t on_tty_write(const UserOrKernelBuffer&, ssize_t) = 0;
void set_size(unsigned short columns, unsigned short rows);
TTY(unsigned major, unsigned minor);
diff --git a/Kernel/TTY/VirtualConsole.cpp b/Kernel/TTY/VirtualConsole.cpp
index 29742a8222..f73e07bd4f 100644
--- a/Kernel/TTY/VirtualConsole.cpp
+++ b/Kernel/TTY/VirtualConsole.cpp
@@ -241,14 +241,17 @@ void VirtualConsole::on_key_pressed(KeyboardDevice::Event event)
m_terminal.handle_key_press(event.key, event.code_point, event.flags);
}
-ssize_t VirtualConsole::on_tty_write(const u8* data, ssize_t size)
+ssize_t VirtualConsole::on_tty_write(const UserOrKernelBuffer& data, ssize_t size)
{
ScopedSpinLock lock(s_lock);
- for (ssize_t i = 0; i < size; ++i)
- m_terminal.on_input(data[i]);
+ ssize_t nread = data.read_buffered<512>((size_t)size, [&](const u8* buffer, size_t buffer_bytes) {
+ for (size_t i = 0; i < buffer_bytes; ++i)
+ m_terminal.on_input(buffer[i]);
+ return (ssize_t)buffer_bytes;
+ });
if (m_active)
flush_dirty_lines();
- return size;
+ return nread;
}
void VirtualConsole::set_vga_start_row(u16 row)
@@ -336,7 +339,8 @@ void VirtualConsole::emit(const u8* data, size_t size)
void VirtualConsole::echo(u8 ch)
{
if (should_echo_input()) {
- on_tty_write(&ch, 1);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(&ch);
+ on_tty_write(buffer, 1);
}
}
diff --git a/Kernel/TTY/VirtualConsole.h b/Kernel/TTY/VirtualConsole.h
index b6a04587fb..f9f4665be1 100644
--- a/Kernel/TTY/VirtualConsole.h
+++ b/Kernel/TTY/VirtualConsole.h
@@ -54,7 +54,7 @@ private:
virtual void on_key_pressed(KeyboardDevice::Event) override;
// ^TTY
- virtual ssize_t on_tty_write(const u8*, ssize_t) override;
+ virtual ssize_t on_tty_write(const UserOrKernelBuffer&, ssize_t) override;
virtual String tty_name() const override { return m_tty_name; }
virtual void echo(u8) override;
diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp
index 40b82bd2e6..07b7a8112f 100644
--- a/Kernel/Thread.cpp
+++ b/Kernel/Thread.cpp
@@ -479,10 +479,10 @@ bool Thread::has_signal_handler(u8 signal) const
return !action.handler_or_sigaction.is_null();
}
-static void push_value_on_user_stack(u32* stack, u32 data)
+static bool push_value_on_user_stack(u32* stack, u32 data)
{
*stack -= 4;
- copy_to_user((u32*)*stack, &data);
+ return copy_to_user((u32*)*stack, &data);
}
void Thread::resume_from_stopped()
@@ -659,11 +659,11 @@ void Thread::set_default_signal_dispositions()
m_signal_action_data[SIGWINCH].handler_or_sigaction = VirtualAddress(SIG_IGN);
}
-void Thread::push_value_on_stack(FlatPtr value)
+bool Thread::push_value_on_stack(FlatPtr value)
{
m_tss.esp -= 4;
FlatPtr* stack_ptr = (FlatPtr*)m_tss.esp;
- copy_to_user(stack_ptr, &value);
+ return copy_to_user(stack_ptr, &value);
}
RegisterState& Thread::get_register_dump_from_stack()
@@ -682,19 +682,19 @@ u32 Thread::make_userspace_stack_for_main_thread(Vector<String> arguments, Vecto
auto push_on_new_stack = [&new_esp](u32 value) {
new_esp -= 4;
Userspace<u32*> stack_ptr = new_esp;
- copy_to_user(stack_ptr, &value);
+ return copy_to_user(stack_ptr, &value);
};
auto push_aux_value_on_new_stack = [&new_esp](auxv_t value) {
new_esp -= sizeof(auxv_t);
Userspace<auxv_t*> stack_ptr = new_esp;
- copy_to_user(stack_ptr, &value);
+ return copy_to_user(stack_ptr, &value);
};
auto push_string_on_new_stack = [&new_esp](const String& string) {
new_esp -= round_up_to_power_of_two(string.length() + 1, 4);
Userspace<u32*> stack_ptr = new_esp;
- copy_to_user(stack_ptr, string.characters(), string.length() + 1);
+ return copy_to_user(stack_ptr, string.characters(), string.length() + 1);
};
Vector<FlatPtr> argv_entries;
@@ -869,18 +869,21 @@ String Thread::backtrace_impl()
if (Processor::get_context_frame_ptr(*this, stack_ptr, eip)) {
recognized_symbols.append({ eip, symbolicate_kernel_address(eip) });
for (;;) {
- if (!process.validate_read_from_kernel(VirtualAddress(stack_ptr), sizeof(void*) * 2))
- break;
FlatPtr retaddr;
if (is_user_range(VirtualAddress(stack_ptr), sizeof(FlatPtr) * 2)) {
- copy_from_user(&retaddr, &((FlatPtr*)stack_ptr)[1]);
+ if (!copy_from_user(&retaddr, &((FlatPtr*)stack_ptr)[1]))
+ break;
recognized_symbols.append({ retaddr, symbolicate_kernel_address(retaddr) });
- copy_from_user(&stack_ptr, (FlatPtr*)stack_ptr);
+ if (!copy_from_user(&stack_ptr, (FlatPtr*)stack_ptr))
+ break;
} else {
- memcpy(&retaddr, &((FlatPtr*)stack_ptr)[1], sizeof(FlatPtr));
+ void* fault_at;
+ if (!safe_memcpy(&retaddr, &((FlatPtr*)stack_ptr)[1], sizeof(FlatPtr), fault_at))
+ break;
recognized_symbols.append({ retaddr, symbolicate_kernel_address(retaddr) });
- memcpy(&stack_ptr, (FlatPtr*)stack_ptr, sizeof(FlatPtr));
+ if (!safe_memcpy(&stack_ptr, (FlatPtr*)stack_ptr, sizeof(FlatPtr), fault_at))
+ break;
}
}
}
@@ -901,11 +904,19 @@ Vector<FlatPtr> Thread::raw_backtrace(FlatPtr ebp, FlatPtr eip) const
ProcessPagingScope paging_scope(process);
Vector<FlatPtr, Profiling::max_stack_frame_count> backtrace;
backtrace.append(eip);
- for (FlatPtr* stack_ptr = (FlatPtr*)ebp; process.validate_read_from_kernel(VirtualAddress(stack_ptr), sizeof(FlatPtr) * 2) && MM.can_read_without_faulting(process, VirtualAddress(stack_ptr), sizeof(FlatPtr) * 2); stack_ptr = (FlatPtr*)*stack_ptr) {
- FlatPtr retaddr = stack_ptr[1];
+ FlatPtr stack_ptr_copy;
+ FlatPtr stack_ptr = (FlatPtr)ebp;
+ for (;;) {
+ void* fault_at;
+ if (!safe_memcpy(&stack_ptr_copy, (void*)stack_ptr, sizeof(FlatPtr), fault_at))
+ break;
+ FlatPtr retaddr;
+ if (!safe_memcpy(&retaddr, (void*)(stack_ptr + sizeof(FlatPtr)), sizeof(FlatPtr), fault_at))
+ break;
backtrace.append(retaddr);
if (backtrace.size() == Profiling::max_stack_frame_count)
break;
+ stack_ptr = stack_ptr_copy;
}
return backtrace;
}
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index f8f9d1ded0..5e766643d6 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -107,6 +107,7 @@ public:
const String& name() const { return m_name; }
void set_name(const StringView& s) { m_name = s; }
+ void set_name(String&& name) { m_name = move(name); }
void finalize();
@@ -430,7 +431,7 @@ public:
FPUState& fpu_state() { return *m_fpu_state; }
void set_default_signal_dispositions();
- void push_value_on_stack(FlatPtr);
+ bool push_value_on_stack(FlatPtr);
u32 make_userspace_stack_for_main_thread(Vector<String> arguments, Vector<String> environment, Vector<AuxiliaryValue>);
diff --git a/Kernel/UserOrKernelBuffer.cpp b/Kernel/UserOrKernelBuffer.cpp
new file mode 100644
index 0000000000..8d311b5a62
--- /dev/null
+++ b/Kernel/UserOrKernelBuffer.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/UserOrKernelBuffer.h>
+#include <Kernel/VM/MemoryManager.h>
+
+namespace Kernel {
+
+bool UserOrKernelBuffer::is_kernel_buffer() const
+{
+ return !is_user_address(VirtualAddress(m_buffer));
+}
+
+String UserOrKernelBuffer::copy_into_string(size_t size) const
+{
+ if (!m_buffer)
+ return {};
+ if (is_user_address(VirtualAddress(m_buffer))) {
+ char* buffer;
+ auto data_copy = StringImpl::create_uninitialized(size, buffer);
+ if (!copy_from_user(buffer, m_buffer, size))
+ return {};
+ return data_copy;
+ }
+
+ return String({ m_buffer, size });
+}
+
+bool UserOrKernelBuffer::write(const void* src, size_t offset, size_t len)
+{
+ if (!m_buffer)
+ return false;
+
+ if (is_user_address(VirtualAddress(m_buffer)))
+ return copy_to_user(m_buffer + offset, src, len);
+
+ memcpy(m_buffer + offset, src, len);
+ return true;
+}
+
+bool UserOrKernelBuffer::read(void* dest, size_t offset, size_t len) const
+{
+ if (!m_buffer)
+ return false;
+
+ if (is_user_address(VirtualAddress(m_buffer)))
+ return copy_from_user(dest, m_buffer + offset, len);
+
+ memcpy(dest, m_buffer + offset, len);
+ return true;
+}
+
+bool UserOrKernelBuffer::memset(int value, size_t offset, size_t len)
+{
+ if (!m_buffer)
+ return false;
+
+ if (is_user_address(VirtualAddress(m_buffer)))
+ return memset_user(m_buffer + offset, value, len);
+
+ ::memset(m_buffer + offset, value, len);
+ return true;
+}
+
+}
diff --git a/Kernel/UserOrKernelBuffer.h b/Kernel/UserOrKernelBuffer.h
new file mode 100644
index 0000000000..08e277341a
--- /dev/null
+++ b/Kernel/UserOrKernelBuffer.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <AK/Types.h>
+#include <AK/Userspace.h>
+#include <Kernel/StdLib.h>
+#include <Kernel/UnixTypes.h>
+#include <Kernel/VM/MemoryManager.h>
+#include <LibC/errno_numbers.h>
+
+namespace Kernel {
+
+class UserOrKernelBuffer {
+public:
+ UserOrKernelBuffer() = delete;
+
+ static UserOrKernelBuffer for_kernel_buffer(u8* kernel_buffer)
+ {
+ ASSERT(!kernel_buffer || !is_user_address(VirtualAddress(kernel_buffer)));
+ return UserOrKernelBuffer(kernel_buffer);
+ }
+
+ static Optional<UserOrKernelBuffer> for_user_buffer(u8* user_buffer, size_t size)
+ {
+ if (user_buffer && !is_user_range(VirtualAddress(user_buffer), size))
+ return {};
+ return UserOrKernelBuffer(user_buffer);
+ }
+
+ template<typename UserspaceType>
+ static Optional<UserOrKernelBuffer> for_user_buffer(UserspaceType userspace, size_t size)
+ {
+ if (!is_user_range(VirtualAddress(userspace.unsafe_userspace_ptr()), size))
+ return {};
+ return UserOrKernelBuffer(const_cast<u8*>((const u8*)userspace.unsafe_userspace_ptr()));
+ }
+
+ bool is_kernel_buffer() const;
+ const void* user_or_kernel_ptr() const { return m_buffer; }
+
+ UserOrKernelBuffer offset(ssize_t offset) const
+ {
+ if (!m_buffer)
+ return *this;
+ UserOrKernelBuffer offset_buffer = *this;
+ offset_buffer.m_buffer += offset;
+ ASSERT(offset_buffer.is_kernel_buffer() == is_kernel_buffer());
+ return offset_buffer;
+ }
+
+ String copy_into_string(size_t size) const;
+ [[nodiscard]] bool write(const void* src, size_t offset, size_t len);
+ [[nodiscard]] bool write(const void* src, size_t len)
+ {
+ return write(src, 0, len);
+ }
+ [[nodiscard]] bool read(void* dest, size_t offset, size_t len) const;
+ [[nodiscard]] bool read(void* dest, size_t len) const
+ {
+ return read(dest, 0, len);
+ }
+
+ [[nodiscard]] bool memset(int value, size_t offset, size_t len);
+ [[nodiscard]] bool memset(int value, size_t len)
+ {
+ return memset(value, 0, len);
+ }
+
+ template<size_t BUFFER_BYTES, typename F>
+ [[nodiscard]] ssize_t write_buffered(size_t offset, size_t len, F f)
+ {
+ if (!m_buffer)
+ return -EFAULT;
+ if (is_kernel_buffer()) {
+ // We're transferring directly to a kernel buffer, bypass
+ return f(m_buffer + offset, len);
+ }
+
+ // The purpose of using a buffer on the stack is that we can
+ // avoid a bunch of small (e.g. 1-byte) copy_to_user calls
+ u8 buffer[BUFFER_BYTES];
+ size_t nwritten = 0;
+ while (nwritten < len) {
+ auto to_copy = min(sizeof(buffer), len - nwritten);
+ ssize_t copied = f(buffer, to_copy);
+ if (copied < 0)
+ return copied;
+ ASSERT((size_t)copied <= to_copy);
+ if (!write(buffer, nwritten, (size_t)copied))
+ return -EFAULT;
+ nwritten += (size_t)copied;
+ if ((size_t)copied < to_copy)
+ break;
+ }
+ return (ssize_t)nwritten;
+ }
+ template<size_t BUFFER_BYTES, typename F>
+ [[nodiscard]] ssize_t write_buffered(size_t len, F f)
+ {
+ return write_buffered<BUFFER_BYTES, F>(0, len, f);
+ }
+
+ template<size_t BUFFER_BYTES, typename F>
+ [[nodiscard]] ssize_t read_buffered(size_t offset, size_t len, F f) const
+ {
+ if (!m_buffer)
+ return -EFAULT;
+ if (is_kernel_buffer()) {
+ // We're transferring directly from a kernel buffer, bypass
+ return f(m_buffer + offset, len);
+ }
+
+ // The purpose of using a buffer on the stack is that we can
+ // avoid a bunch of small (e.g. 1-byte) copy_from_user calls
+ u8 buffer[BUFFER_BYTES];
+ size_t nread = 0;
+ while (nread < len) {
+ auto to_copy = min(sizeof(buffer), len - nread);
+ if (!read(buffer, nread, to_copy))
+ return -EFAULT;
+ ssize_t copied = f(buffer, to_copy);
+ if (copied < 0)
+ return copied;
+ ASSERT((size_t)copied <= to_copy);
+ nread += (size_t)copied;
+ if ((size_t)copied < to_copy)
+ break;
+ }
+ return nread;
+ }
+ template<size_t BUFFER_BYTES, typename F>
+ [[nodiscard]] ssize_t read_buffered(size_t len, F f) const
+ {
+ return read_buffered<BUFFER_BYTES, F>(0, len, f);
+ }
+
+private:
+ explicit UserOrKernelBuffer(u8* buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ u8* m_buffer;
+};
+
+}
diff --git a/Kernel/VM/InodeVMObject.cpp b/Kernel/VM/InodeVMObject.cpp
index 8c5b07d413..c63417fab0 100644
--- a/Kernel/VM/InodeVMObject.cpp
+++ b/Kernel/VM/InodeVMObject.cpp
@@ -89,7 +89,7 @@ void InodeVMObject::inode_size_changed(Badge<Inode>, size_t old_size, size_t new
});
}
-void InodeVMObject::inode_contents_changed(Badge<Inode>, off_t offset, ssize_t size, const u8* data)
+void InodeVMObject::inode_contents_changed(Badge<Inode>, off_t offset, ssize_t size, const UserOrKernelBuffer& data)
{
(void)size;
(void)data;
diff --git a/Kernel/VM/InodeVMObject.h b/Kernel/VM/InodeVMObject.h
index 727199ff7e..94e7073709 100644
--- a/Kernel/VM/InodeVMObject.h
+++ b/Kernel/VM/InodeVMObject.h
@@ -39,7 +39,7 @@ public:
Inode& inode() { return *m_inode; }
const Inode& inode() const { return *m_inode; }
- void inode_contents_changed(Badge<Inode>, off_t, ssize_t, const u8*);
+ void inode_contents_changed(Badge<Inode>, off_t, ssize_t, const UserOrKernelBuffer&);
void inode_size_changed(Badge<Inode>, size_t old_size, size_t new_size);
size_t amount_dirty() const;
diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp
index 88bb451435..fc5114f296 100644
--- a/Kernel/VM/MemoryManager.cpp
+++ b/Kernel/VM/MemoryManager.cpp
@@ -767,39 +767,6 @@ bool MemoryManager::validate_user_stack(const Process& process, VirtualAddress v
return region && region->is_user_accessible() && region->is_stack();
}
-bool MemoryManager::validate_kernel_read(const Process& process, VirtualAddress vaddr, size_t size) const
-{
- ScopedSpinLock lock(s_mm_lock);
- return validate_range<AccessSpace::Kernel, AccessType::Read>(process, vaddr, size);
-}
-
-bool MemoryManager::can_read_without_faulting(const Process& process, VirtualAddress vaddr, size_t size) const
-{
- // FIXME: Use the size argument!
- UNUSED_PARAM(size);
- ScopedSpinLock lock(s_mm_lock);
- auto* pte = const_cast<MemoryManager*>(this)->pte(process.page_directory(), vaddr);
- if (!pte)
- return false;
- return pte->is_present();
-}
-
-bool MemoryManager::validate_user_read(const Process& process, VirtualAddress vaddr, size_t size) const
-{
- if (!is_user_address(vaddr))
- return false;
- ScopedSpinLock lock(s_mm_lock);
- return validate_range<AccessSpace::User, AccessType::Read>(process, vaddr, size);
-}
-
-bool MemoryManager::validate_user_write(const Process& process, VirtualAddress vaddr, size_t size) const
-{
- if (!is_user_address(vaddr))
- return false;
- ScopedSpinLock lock(s_mm_lock);
- return validate_range<AccessSpace::User, AccessType::Write>(process, vaddr, size);
-}
-
void MemoryManager::register_vmobject(VMObject& vmobject)
{
ScopedSpinLock lock(s_mm_lock);
diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h
index f3f4bbb90c..d9823377ab 100644
--- a/Kernel/VM/MemoryManager.h
+++ b/Kernel/VM/MemoryManager.h
@@ -100,12 +100,6 @@ public:
void enter_process_paging_scope(Process&);
bool validate_user_stack(const Process&, VirtualAddress) const;
- bool validate_user_read(const Process&, VirtualAddress, size_t) const;
- bool validate_user_write(const Process&, VirtualAddress, size_t) const;
-
- bool validate_kernel_read(const Process&, VirtualAddress, size_t) const;
-
- bool can_read_without_faulting(const Process&, VirtualAddress, size_t) const;
enum class ShouldZeroFill {
No,
diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp
index d3b4d02676..a1d39daf24 100644
--- a/Kernel/VM/Region.cpp
+++ b/Kernel/VM/Region.cpp
@@ -439,13 +439,24 @@ PageFaultResponse Region::handle_cow_fault(size_t page_index_in_region)
klog() << "MM: handle_cow_fault was unable to allocate a physical page";
return PageFaultResponse::OutOfMemory;
}
- auto physical_page_to_copy = move(page_slot);
+
u8* dest_ptr = MM.quickmap_page(*page);
const u8* src_ptr = vaddr().offset(page_index_in_region * PAGE_SIZE).as_ptr();
#ifdef PAGE_FAULT_DEBUG
- dbg() << " >> COW " << page->paddr() << " <- " << physical_page_to_copy->paddr();
+ dbg() << " >> COW " << page->paddr() << " <- " << page_slot->paddr();
#endif
- copy_from_user(dest_ptr, src_ptr, PAGE_SIZE);
+ {
+ SmapDisabler disabler;
+ void* fault_at;
+ if (!safe_memcpy(dest_ptr, src_ptr, PAGE_SIZE, fault_at)) {
+ if ((u8*)fault_at >= dest_ptr && (u8*)fault_at <= dest_ptr + PAGE_SIZE)
+ dbg() << " >> COW: error copying page " << page_slot->paddr() << "/" << VirtualAddress(src_ptr) << " to " << page->paddr() << "/" << VirtualAddress(dest_ptr) << ": failed to write to page at " << VirtualAddress(fault_at);
+ else if ((u8*)fault_at >= src_ptr && (u8*)fault_at <= src_ptr + PAGE_SIZE)
+ dbg() << " >> COW: error copying page " << page_slot->paddr() << "/" << VirtualAddress(src_ptr) << " to " << page->paddr() << "/" << VirtualAddress(dest_ptr) << ": failed to read from page at " << VirtualAddress(fault_at);
+ else
+ ASSERT_NOT_REACHED();
+ }
+ }
page_slot = move(page);
MM.unquickmap_page();
set_should_cow(page_index_in_region, false);
@@ -489,7 +500,8 @@ PageFaultResponse Region::handle_inode_fault(size_t page_index_in_region)
sti();
u8 page_buffer[PAGE_SIZE];
auto& inode = inode_vmobject.inode();
- auto nread = inode.read_bytes((first_page_index() + page_index_in_region) * PAGE_SIZE, PAGE_SIZE, page_buffer, nullptr);
+ auto buffer = UserOrKernelBuffer::for_kernel_buffer(page_buffer);
+ auto nread = inode.read_bytes((first_page_index() + page_index_in_region) * PAGE_SIZE, PAGE_SIZE, buffer, nullptr);
if (nread < 0) {
klog() << "MM: handle_inode_fault had error (" << nread << ") while reading!";
return PageFaultResponse::ShouldCrash;
@@ -506,7 +518,15 @@ PageFaultResponse Region::handle_inode_fault(size_t page_index_in_region)
}
u8* dest_ptr = MM.quickmap_page(*vmobject_physical_page_entry);
- memcpy(dest_ptr, page_buffer, PAGE_SIZE);
+ {
+ void* fault_at;
+ if (!safe_memcpy(dest_ptr, page_buffer, PAGE_SIZE, fault_at)) {
+ if ((u8*)fault_at >= dest_ptr && (u8*)fault_at <= dest_ptr + PAGE_SIZE)
+ dbg() << " >> inode fault: error copying data to " << vmobject_physical_page_entry->paddr() << "/" << VirtualAddress(dest_ptr) << ", failed at " << VirtualAddress(fault_at);
+ else
+ ASSERT_NOT_REACHED();
+ }
+ }
MM.unquickmap_page();
remap_page(page_index_in_region);
diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h
index 5480e186de..68d40e53c3 100644
--- a/Kernel/VM/Region.h
+++ b/Kernel/VM/Region.h
@@ -79,6 +79,7 @@ public:
unsigned access() const { return m_access; }
void set_name(const String& name) { m_name = name; }
+ void set_name(String&& name) { m_name = move(name); }
const VMObject& vmobject() const { return *m_vmobject; }
VMObject& vmobject() { return *m_vmobject; }
diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp
index f2fe6a379c..cf6643e736 100644
--- a/Libraries/LibC/unistd.cpp
+++ b/Libraries/LibC/unistd.cpp
@@ -96,8 +96,8 @@ int execve(const char* filename, char* const argv[], char* const envp[])
auto copy_strings = [&](auto& vec, size_t count, auto& output) {
output.length = count;
for (size_t i = 0; vec[i]; ++i) {
- output.strings.ptr()[i].characters = vec[i];
- output.strings.ptr()[i].length = strlen(vec[i]);
+ output.strings[i].characters = vec[i];
+ output.strings[i].length = strlen(vec[i]);
}
};
diff --git a/Libraries/LibELF/Loader.cpp b/Libraries/LibELF/Loader.cpp
index 42740f95e2..8f7ccc722f 100644
--- a/Libraries/LibELF/Loader.cpp
+++ b/Libraries/LibELF/Loader.cpp
@@ -81,7 +81,10 @@ bool Loader::layout()
failed = true;
return;
}
- do_memcpy(tls_image, program_header.raw_data(), program_header.size_in_image());
+ if (!do_memcpy(tls_image, program_header.raw_data(), program_header.size_in_image())) {
+ failed = false;
+ return;
+ }
#endif
return;
}
@@ -117,7 +120,10 @@ bool Loader::layout()
// Accessing it would definitely be a bug.
auto page_offset = program_header.vaddr();
page_offset.mask(~PAGE_MASK);
- do_memcpy((u8*)allocated_section + page_offset.get(), program_header.raw_data(), program_header.size_in_image());
+ if (!do_memcpy((u8*)allocated_section + page_offset.get(), program_header.raw_data(), program_header.size_in_image())) {
+ failed = false;
+ return;
+ }
} else {
auto* mapped_section = map_section_hook(
program_header.vaddr(),
diff --git a/Libraries/LibPthread/pthread.cpp b/Libraries/LibPthread/pthread.cpp
index 68af2fff21..218c175039 100644
--- a/Libraries/LibPthread/pthread.cpp
+++ b/Libraries/LibPthread/pthread.cpp
@@ -383,7 +383,7 @@ int pthread_attr_getstack(const pthread_attr_t* attributes, void** p_stack_ptr,
if (!attributes_impl || !p_stack_ptr || !p_stack_size)
return EINVAL;
- *p_stack_ptr = attributes_impl->m_stack_location.ptr();
+ *p_stack_ptr = attributes_impl->m_stack_location;
*p_stack_size = attributes_impl->m_stack_size;
return 0;