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:
parent
04ae97a6ec
commit
44815b08c7
@ -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);
|
||||
|
@ -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,17 +39,39 @@ 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user