Luna/kernel/src/sys/exec.cpp

134 lines
3.8 KiB
C++
Raw Normal View History

#include "ELF.h"
#include "Log.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include "thread/ThreadImage.h"
#include <bits/modes.h>
2023-03-24 20:19:24 +00:00
#include <bits/open-flags.h>
#include <luna/CString.h>
#include <luna/ScopeGuard.h>
2023-03-18 20:55:16 +00:00
#include <luna/Vector.h>
static Result<Vector<String>> copy_string_vector_from_userspace(u64 address)
2023-03-18 20:55:16 +00:00
{
Vector<String> result;
2023-03-18 20:55:16 +00:00
const u64* user_vector = (const u64*)address;
u64 string_addr;
2023-03-18 20:55:16 +00:00
while (true)
{
if (!MemoryManager::copy_from_user_typed(user_vector, &string_addr)) return err(EFAULT);
if (!string_addr) break;
2023-03-18 20:55:16 +00:00
auto string = TRY(MemoryManager::strdup_from_user(string_addr));
2023-03-18 20:55:16 +00:00
TRY(result.try_append(move(string)));
user_vector++;
}
return result;
}
Result<u64> sys_execve(Registers* regs, SyscallArgs args)
{
auto path = TRY(MemoryManager::strdup_from_user(args[0]));
2023-03-18 20:55:16 +00:00
auto argv = TRY(copy_string_vector_from_userspace(args[1]));
auto envp = TRY(copy_string_vector_from_userspace(args[2]));
2023-03-18 20:55:16 +00:00
auto current = Scheduler::current();
// FIXME: Make sure argv & envp are not too big.
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
kinfoln("exec: attempting to replace current image with %s", path.chars());
2023-03-18 21:25:19 +00:00
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
auto image = TRY(ThreadImage::try_load_from_elf(inode));
2023-03-18 21:25:19 +00:00
kdbgln("exec: copying argv to image memory (argc = %zu)", argv.size());
u64 user_argv = TRY(image->push_string_vector_on_stack(argv));
2023-03-18 21:25:19 +00:00
usize user_argc = argv.size();
kdbgln("exec: copying envp to image memory (envc = %zu)", envp.size());
u64 user_envp = TRY(image->push_string_vector_on_stack(envp));
usize user_envc = envp.size();
// From now on, nothing should fail.
kinfoln("exec: image load ok, will now replace existing process image");
2023-03-18 21:25:19 +00:00
guard.deactivate();
2023-03-24 20:19:24 +00:00
for (int i = 0; i < FD_MAX; i++)
{
auto& descriptor = current->fd_table[i];
if (!descriptor.has_value()) continue;
2023-03-24 20:19:24 +00:00
if (descriptor->flags & O_CLOEXEC) descriptor = {};
}
MMU::delete_userspace_page_directory(current->directory);
if (VFS::is_setuid(inode)) current->auth.euid = current->auth.suid = inode->uid();
if (VFS::is_setgid(inode)) current->auth.egid = current->auth.sgid = inode->gid();
current->name = path.chars();
2023-03-24 20:05:38 +00:00
image->apply(current);
MMU::switch_page_directory(current->directory);
current->set_arguments(user_argc, user_argv, user_envc, user_envp);
2023-03-18 21:25:19 +00:00
memcpy(regs, &current->regs, sizeof(*regs));
kinfoln("exec: done");
return 0;
}
2023-03-18 22:45:48 +00:00
Result<u64> sys_fork(Registers* regs, SyscallArgs)
{
auto current = Scheduler::current();
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
kinfoln("fork: trying to duplicate process %lu", current->id);
memcpy(&current->regs, regs, sizeof(*regs));
auto current_directory_path = TRY(current->current_directory_path.clone());
2023-03-18 22:45:48 +00:00
auto image = TRY(ThreadImage::clone_from_thread(current));
auto thread = TRY(new_thread());
thread->state = ThreadState::Runnable;
thread->is_kernel = false;
thread->parent_id = current->id;
2023-03-18 22:45:48 +00:00
thread->fp_data.save();
2023-04-07 12:02:36 +00:00
thread->name = current->name;
thread->auth = current->auth;
thread->current_directory = current->current_directory;
thread->current_directory_path = move(current_directory_path);
2023-03-18 22:45:48 +00:00
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
image->apply(thread);
memcpy(&thread->regs, regs, sizeof(*regs));
thread->set_return(0);
Scheduler::add_thread(thread);
return thread->id;
}