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 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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user