Kernel: Make copy_to/from_user safe and remove unnecessary checks

Since the CPU already does almost all necessary validation steps
for us, we don't really need to attempt to do this. Doing it
ourselves doesn't really work very reliably, because we'd have to
account for other processors modifying virtual memory, and we'd
have to account for e.g. pages not being able to be allocated
due to insufficient resources.

So change the copy_to/from_user (and associated helper functions)
to use the new safe_memcpy, which will return whether it succeeded
or not. The only manual validation step needed (which the CPU
can't perform for us) is making sure the pointers provided by user
mode aren't pointing to kernel mappings.

To make it easier to read/write from/to either kernel or user mode
data add the UserOrKernelBuffer helper class, which will internally
either use copy_from/to_user or directly memcpy, or pass the data
through directly using a temporary buffer on the stack.

Last but not least we need to keep syscall params trivial as we
need to copy them from/to user mode using copy_from/to_user.
This commit is contained in:
Tom 2020-09-11 21:11:07 -06:00 committed by Andreas Kling
parent 7d1b8417bd
commit c8d9f1b9c9
149 changed files with 1585 additions and 1244 deletions

View file

@ -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;
}

View file

@ -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();

View file

@ -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"

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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:

View file

@ -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();

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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:

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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"; }

View file

@ -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

View file

@ -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;
}

View file

@ -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(); }

View file

@ -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;
}

View file

@ -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:

View file

@ -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; }

View file

@ -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);
}

View file

@ -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"; }

View file

@ -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);

View file

@ -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();

View file

@ -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());
}

View file

@ -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" };

View file

@ -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;
}

View file

@ -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(); }

View file

@ -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);

View file

@ -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"; }

View file

@ -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.

View file

@ -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(); }

View file

@ -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()

View file

@ -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,

View file

@ -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);
}

View file

@ -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"; }

View file

@ -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;
}
}

View file

@ -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; }

View file

@ -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;
});

View file

@ -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 };

View file

@ -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();
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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;

View file

@ -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());

View file

@ -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;

View file

@ -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); }

View file

@ -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();
}

View file

@ -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();

View file

@ -34,6 +34,7 @@
#include <Kernel/KResult.h>
#include <Kernel/Lock.h>
#include <Kernel/UnixTypes.h>
#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {

View file

@ -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);

View file

@ -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();

View file

@ -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) {

View file

@ -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;

View file

@ -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);
}

View file

@ -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"; };

View file

@ -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();

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -68,6 +68,7 @@ class TCPSocket;
class TTY;
class Thread;
class UDPSocket;
class UserOrKernelBuffer;
class VFS;
class VMObject;
class WaitQueue;

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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());
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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())

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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));

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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())

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

Some files were not shown because too many files have changed in this diff Show more