Kernel: Use copy_from_user() and copy_to_user() in read/write

This is huge. Finally, we can do proper reads/writes with invalid addresses, or big buffers.
This commit is contained in:
apio 2022-11-06 15:19:23 +01:00
parent 04ae97a6ec
commit 44815b08c7
4 changed files with 34 additions and 11 deletions

View File

@ -32,6 +32,9 @@ struct Descriptor
ssize_t read(size_t size, char* buffer); ssize_t read(size_t size, char* buffer);
ssize_t write(size_t size, const char* buffer); ssize_t write(size_t size, const char* buffer);
ssize_t user_read(size_t size, char* buffer);
ssize_t user_write(size_t size, const char* buffer);
uintptr_t mmap(uintptr_t addr, size_t size, int prot, off_t offset); uintptr_t mmap(uintptr_t addr, size_t size, int prot, off_t offset);
long ioctl(int cmd, uintptr_t arg); long ioctl(int cmd, uintptr_t arg);

View File

@ -1,5 +1,7 @@
#include "fs/FileDescriptor.h" #include "fs/FileDescriptor.h"
#include "std/errno.h" #include "std/errno.h"
#include "std/stdlib.h"
#include "sys/UserMemory.h"
Descriptor::Descriptor() : m_is_open(false) Descriptor::Descriptor() : m_is_open(false)
{ {
@ -37,17 +39,39 @@ ssize_t Descriptor::write(size_t size, const char* buffer)
return result; return result;
} }
ssize_t Descriptor::user_read(size_t size, char* buffer)
{
char* buf = (char*)kmalloc(size);
if (!buf) return -ENOMEM;
ssize_t result = read(size, buf);
if (!copy_to_user(buffer, buf, size)) result = -EFAULT;
kfree(buf);
return result;
}
ssize_t Descriptor::user_write(size_t size, const char* buffer)
{
char* buf = (char*)kmalloc(size);
if (!buf) return -ENOMEM;
ssize_t result;
if (!copy_from_user(buffer, buf, size)) result = -EFAULT;
else
result = write(size, buf);
kfree(buf);
return result;
}
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) #define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset) uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset)
{ {
if(!m_node->mmap_func) return MAP_FAIL(ENOTSUP); if (!m_node->mmap_func) return MAP_FAIL(ENOTSUP);
return m_node->mmap_func(m_node, addr, size, prot, offset); return m_node->mmap_func(m_node, addr, size, prot, offset);
} }
long Descriptor::ioctl(int cmd, uintptr_t arg) long Descriptor::ioctl(int cmd, uintptr_t arg)
{ {
if(!m_node->ioctl_func) return MAP_FAIL(ENOTSUP); if (!m_node->ioctl_func) return MAP_FAIL(ENOTSUP);
return m_node->ioctl_func(m_node, cmd, arg); return m_node->ioctl_func(m_node, cmd, arg);
} }

View File

@ -155,9 +155,7 @@ void sys_write(Context* context, int fd, size_t size, const char* addr)
context->rax = -EBADF; context->rax = -EBADF;
return; return;
} }
ssize_t result = file->write( ssize_t result = file->user_write(size, addr);
size, (const char*)VMM::get_physical((uint64_t)addr)); // FIXME: Handle buffers bigger than one page, which may
// not be contiguous in physical memory.
context->rax = (size_t)result; context->rax = (size_t)result;
return; return;
} }
@ -298,13 +296,11 @@ void sys_read(Context* context, int fd, size_t size, char* buffer)
current_task->state = current_task->Blocking; current_task->state = current_task->Blocking;
current_task->block_reason = BlockReason::Reading; current_task->block_reason = BlockReason::Reading;
current_task->blocking_read_info.fd = fd; current_task->blocking_read_info.fd = fd;
current_task->blocking_read_info.buf = (char*)VMM::get_physical((uint64_t)buffer); // FIXME: Handle errors. current_task->blocking_read_info.buf = buffer;
current_task->blocking_read_info.size = size; current_task->blocking_read_info.size = size;
return Scheduler::task_yield(context); return Scheduler::task_yield(context);
} }
ssize_t result = ssize_t result = file->user_read(size, buffer);
file->read(size, (char*)VMM::get_physical((uint64_t)buffer)); // FIXME: Handle big buffers which may
// not be across continuous physical pages.
context->rax = (size_t)result; context->rax = (size_t)result;
return; return;
} }

View File

@ -74,7 +74,7 @@ bool Task::has_died()
void Task::resume_read() void Task::resume_read()
{ {
regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf); regs.rax = files[blocking_read_info.fd].user_read(blocking_read_info.size, blocking_read_info.buf);
} }
bool Task::is_read_still_blocking() bool Task::is_read_still_blocking()
@ -86,7 +86,7 @@ void Task::resume()
{ {
VMM::switch_back_to_kernel_address_space(); VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space(); VMM::apply_address_space();
VMM::switch_to_previous_user_address_space(); VMM::switch_to_user_address_space(address_space);
switch (block_reason) switch (block_reason)
{ {
case BlockReason::None: return; case BlockReason::None: return;