Kernel: Cleanup file descriptor validation

This commit is contained in:
apio 2022-10-25 18:35:17 +02:00
parent ec2c314234
commit af46b8d9ac
3 changed files with 60 additions and 58 deletions

View File

@ -79,4 +79,6 @@ struct Task
void resume_read(); void resume_read();
bool is_still_blocking(); bool is_still_blocking();
Descriptor* descriptor_from_fd(int fd, int& error);
}; };

View File

@ -27,18 +27,14 @@
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg) void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
{ {
if (fd >= TASK_MAX_FDS || fd < 0)
{
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task(); Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open()) int err;
Descriptor* file = current_task->descriptor_from_fd(fd, err);
if (!file)
{ {
context->rax = -EBADF; context->rax = -err;
return; return;
} }
Descriptor& file = current_task->files[fd];
if (command == FCNTL_DUPFD) if (command == FCNTL_DUPFD)
{ {
if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS) if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS)
@ -52,14 +48,14 @@ void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
context->rax = -EMFILE; context->rax = -EMFILE;
return; return;
} }
current_task->files[dupfd] = file; current_task->files[dupfd] = *file;
context->rax = dupfd; context->rax = dupfd;
kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd); kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd);
return; return;
} }
else if (command == FCNTL_ISTTY) else if (command == FCNTL_ISTTY)
{ {
VFS::Node* node = file.node(); VFS::Node* node = file->node();
if (node->tty) { context->rax = 1; } if (node->tty) { context->rax = 1; }
else else
context->rax = -ENOTTY; context->rax = -ENOTTY;
@ -79,24 +75,19 @@ void sys_seek(Context* context, int fd, long offset, int whence)
context->rax = -EINVAL; context->rax = -EINVAL;
return; return;
} }
if (fd >= TASK_MAX_FDS || fd < 0) int err;
Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err);
if (!file)
{ {
context->rax = -EBADF; context->rax = -err;
return; return;
} }
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
long new_offset; long new_offset;
if (whence == SEEK_SET) new_offset = offset; if (whence == SEEK_SET) new_offset = offset;
else if (whence == SEEK_CUR) else if (whence == SEEK_CUR)
new_offset = offset + file.offset(); new_offset = offset + file->offset();
else if (whence == SEEK_END) else if (whence == SEEK_END)
new_offset = file.length() + offset; new_offset = file->length() + offset;
else else
__builtin_unreachable(); __builtin_unreachable();
if (new_offset < 0) if (new_offset < 0)
@ -104,12 +95,12 @@ void sys_seek(Context* context, int fd, long offset, int whence)
context->rax = -EINVAL; // FIXME: Is this the right error? context->rax = -EINVAL; // FIXME: Is this the right error?
return; return;
} }
if (new_offset == file.offset()) if (new_offset == file->offset())
{ {
context->rax = new_offset; context->rax = new_offset;
return; return;
} }
int result = file.seek(new_offset); int result = file->seek(new_offset);
if (result < 0) if (result < 0)
{ {
context->rax = result; context->rax = result;
@ -126,24 +117,19 @@ void sys_write(Context* context, int fd, size_t size, const char* addr)
context->rax = -EFAULT; context->rax = -EFAULT;
return; return;
} }
if (fd >= TASK_MAX_FDS || fd < 0) int err;
Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err);
if (!file)
{
context->rax = -err;
return;
}
if (!file->can_write())
{ {
context->rax = -EBADF; context->rax = -EBADF;
return; return;
} }
Task* current_task = Scheduler::current_task(); ssize_t result = file->write(size, (const char*)VMM::get_physical((uint64_t)addr));
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& file = current_task->files[fd];
if (!file.can_write())
{
context->rax = -EBADF;
return;
}
ssize_t result = file.write(size, (const char*)VMM::get_physical((uint64_t)addr));
context->rax = (size_t)result; context->rax = (size_t)result;
return; return;
} }
@ -213,52 +199,50 @@ void sys_read(Context* context, int fd, size_t size, char* buffer)
context->rax = -EFAULT; context->rax = -EFAULT;
return; return;
} }
if (fd >= TASK_MAX_FDS || fd < 0) int err;
Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err);
if (!err)
{
context->rax = -err;
return;
}
if (!file->is_open() || !file->can_read())
{ {
context->rax = -EBADF; context->rax = -EBADF;
return; return;
} }
Task* current_task = Scheduler::current_task(); if (VFS::would_block(file->node()))
if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read())
{ {
context->rax = -EBADF; if (!file->able_to_block())
return;
}
if (VFS::would_block(current_task->files[fd].node()))
{
if (!current_task->files[fd].able_to_block())
{ {
context->rax = -EAGAIN; context->rax = -EAGAIN;
return; return;
} }
Task* current_task = Scheduler::current_task();
current_task->state = current_task->Blocking; current_task->state = current_task->Blocking;
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 = (char*)VMM::get_physical((uint64_t)buffer); // FIXME: Handle errors.
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 = current_task->files[fd].read( ssize_t result =
size, (char*)VMM::get_physical((uint64_t)buffer)); // FIXME: Handle errors, and big buffers which may not be file->read(size, (char*)VMM::get_physical((uint64_t)buffer)); // FIXME: Handle errors, and big buffers which may
// across continuous physical pages. // not be across continuous physical pages.
context->rax = (size_t)result; context->rax = (size_t)result;
return; return;
} }
void sys_close(Context* context, int fd) void sys_close(Context* context, int fd)
{ {
if (fd >= TASK_MAX_FDS || fd < 0) int err;
Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err);
if (!err)
{ {
context->rax = -EBADF; context->rax = -err;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return; return;
} }
kdbgln("close(): releasing file descriptor %d", fd); kdbgln("close(): releasing file descriptor %d", fd);
current_task->files[fd].close(); file->close();
context->rax = 0; context->rax = 0;
return; return;
} }

View File

@ -3,6 +3,7 @@
#include "thread/Task.h" #include "thread/Task.h"
#include "log/Log.h" #include "log/Log.h"
#include "memory/VMM.h" #include "memory/VMM.h"
#include "std/errno.h"
#include "std/string.h" #include "std/string.h"
void Task::restore_context(Context* context) void Task::restore_context(Context* context)
@ -83,3 +84,18 @@ bool Task::is_still_blocking()
{ {
return VFS::would_block(files[blocking_read_info.fd].node()); return VFS::would_block(files[blocking_read_info.fd].node());
} }
Descriptor* Task::descriptor_from_fd(int fd, int& error)
{
if (fd < 0 || fd >= TASK_MAX_FDS)
{
error = EBADF;
return nullptr;
}
if (!files[fd].is_open())
{
error = EBADF;
return nullptr;
}
return &files[fd];
}