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 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);
long ioctl(int cmd, uintptr_t arg);

View File

@ -1,5 +1,7 @@
#include "fs/FileDescriptor.h"
#include "std/errno.h"
#include "std/stdlib.h"
#include "sys/UserMemory.h"
Descriptor::Descriptor() : m_is_open(false)
{
@ -37,6 +39,28 @@ ssize_t Descriptor::write(size_t size, const char* buffer)
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)
uintptr_t Descriptor::mmap(uintptr_t addr, size_t size, int prot, off_t offset)

View File

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

View File

@ -74,7 +74,7 @@ bool Task::has_died()
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()
@ -86,7 +86,7 @@ void Task::resume()
{
VMM::switch_back_to_kernel_address_space();
VMM::apply_address_space();
VMM::switch_to_previous_user_address_space();
VMM::switch_to_user_address_space(address_space);
switch (block_reason)
{
case BlockReason::None: return;