2022-10-12 15:42:01 +00:00
|
|
|
#define MODULE "exec"
|
|
|
|
|
|
|
|
#include "interrupts/Interrupts.h"
|
2022-10-16 16:23:33 +00:00
|
|
|
#include "log/Log.h"
|
2022-10-26 16:57:06 +00:00
|
|
|
#include "memory/Memory.h"
|
2022-10-12 15:42:01 +00:00
|
|
|
#include "memory/MemoryManager.h"
|
2022-10-12 17:22:08 +00:00
|
|
|
#include "memory/PMM.h"
|
2022-10-13 20:13:04 +00:00
|
|
|
#include "memory/VMM.h"
|
2022-10-19 15:41:23 +00:00
|
|
|
#include "std/assert.h"
|
|
|
|
#include "std/errno.h"
|
2022-10-12 16:04:20 +00:00
|
|
|
#include "std/stdlib.h"
|
|
|
|
#include "std/string.h"
|
2022-10-13 20:13:04 +00:00
|
|
|
#include "sys/Syscall.h"
|
2022-10-19 15:13:16 +00:00
|
|
|
#include "sys/UserMemory.h"
|
2022-10-12 15:42:01 +00:00
|
|
|
#include "sys/elf/ELFLoader.h"
|
|
|
|
#include "thread/Scheduler.h"
|
|
|
|
|
2022-10-17 16:43:35 +00:00
|
|
|
void sys_fork(Context* context)
|
2022-10-12 15:42:01 +00:00
|
|
|
{
|
2022-10-17 16:43:35 +00:00
|
|
|
kinfoln("fork(): attempting fork");
|
|
|
|
|
|
|
|
Task* parent = Scheduler::current_task();
|
|
|
|
|
|
|
|
Task* child = Scheduler::create_user_task();
|
|
|
|
if (!child)
|
|
|
|
{
|
|
|
|
context->rax = -ENOMEM;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!child->allocator.inherit(parent->allocator))
|
|
|
|
{
|
|
|
|
child->state = child->Exited;
|
|
|
|
child->exit_status = -127; // so the reaper reaps it on next reaping
|
|
|
|
context->rax = -ENOMEM;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
child->save_context(context);
|
|
|
|
child->save_floating();
|
2022-10-14 14:46:00 +00:00
|
|
|
|
2022-10-17 16:43:35 +00:00
|
|
|
for (int i = 0; i < TASK_MAX_FDS; i++) { child->files[i] = parent->files[i]; }
|
|
|
|
|
|
|
|
child->address_space = parent->address_space.clone();
|
|
|
|
|
2022-10-18 15:18:37 +00:00
|
|
|
child->ppid = parent->id;
|
|
|
|
|
2022-10-28 15:06:13 +00:00
|
|
|
child->uid = parent->uid;
|
|
|
|
child->euid = parent->euid;
|
|
|
|
child->gid = parent->gid;
|
|
|
|
child->egid = parent->egid;
|
|
|
|
|
2022-10-17 16:43:35 +00:00
|
|
|
child->regs.rax = 0;
|
|
|
|
context->rax = child->id;
|
|
|
|
|
2022-10-17 17:12:47 +00:00
|
|
|
strlcpy(child->name, parent->name, sizeof(child->name));
|
|
|
|
|
2022-10-17 16:43:35 +00:00
|
|
|
child->state = child->Running;
|
|
|
|
|
|
|
|
kinfoln("fork(): forked parent %ld into child %ld", parent->id, child->id);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-26 16:57:06 +00:00
|
|
|
void push_on_user_stack(uint64_t* rsp, char* value,
|
|
|
|
size_t size) // FIXME: Handle segments of stack that extend beyond one page.
|
|
|
|
{
|
|
|
|
(*rsp) -= size;
|
|
|
|
char* kvalue = (char*)VMM::get_physical(*rsp);
|
|
|
|
ASSERT(kvalue != (char*)UINT64_MAX);
|
|
|
|
memcpy(kvalue, value, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sys_execv(Context* context, const char* pathname, char** argv)
|
2022-10-17 16:43:35 +00:00
|
|
|
{
|
2022-10-19 15:13:16 +00:00
|
|
|
char* kpathname = strdup_from_user(pathname);
|
2022-10-13 20:13:04 +00:00
|
|
|
if (!kpathname)
|
2022-10-12 15:42:01 +00:00
|
|
|
{
|
2022-10-12 17:25:35 +00:00
|
|
|
context->rax = -EFAULT;
|
2022-10-12 15:42:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:13:04 +00:00
|
|
|
kinfoln("exec(): executing %s", kpathname);
|
2022-10-12 15:42:01 +00:00
|
|
|
|
2022-10-13 20:13:04 +00:00
|
|
|
VFS::Node* program = VFS::resolve_path(kpathname);
|
2022-10-12 15:42:01 +00:00
|
|
|
if (!program)
|
|
|
|
{
|
2022-10-13 20:13:04 +00:00
|
|
|
kfree(kpathname);
|
2022-10-12 15:42:01 +00:00
|
|
|
context->rax = -ENOENT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-12 16:43:48 +00:00
|
|
|
if (program->type == VFS_DIRECTORY)
|
2022-10-12 15:42:01 +00:00
|
|
|
{
|
2022-10-13 20:13:04 +00:00
|
|
|
kfree(kpathname);
|
2022-10-12 16:43:48 +00:00
|
|
|
context->rax = -EISDIR;
|
2022-10-12 15:42:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-28 15:10:28 +00:00
|
|
|
if (!VFS::can_execute(program, Scheduler::current_task()->euid, Scheduler::current_task()->egid))
|
|
|
|
{
|
|
|
|
kfree(kpathname);
|
|
|
|
context->rax = -EACCES;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-12 17:22:08 +00:00
|
|
|
long memusage;
|
|
|
|
if ((memusage = ELFLoader::check_elf_image(program)) < 0)
|
2022-10-12 15:42:01 +00:00
|
|
|
{
|
2022-10-13 20:13:04 +00:00
|
|
|
kfree(kpathname);
|
2022-10-12 17:15:44 +00:00
|
|
|
context->rax = -ENOEXEC;
|
2022-10-12 16:43:48 +00:00
|
|
|
return;
|
2022-10-12 15:42:01 +00:00
|
|
|
}
|
|
|
|
|
2022-10-12 18:02:25 +00:00
|
|
|
if ((uint64_t)memusage > PMM::get_free())
|
2022-10-12 17:22:08 +00:00
|
|
|
{
|
2022-10-13 20:13:04 +00:00
|
|
|
kfree(kpathname);
|
2022-10-12 17:22:08 +00:00
|
|
|
context->rax = -ENOMEM;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-26 16:57:06 +00:00
|
|
|
uint64_t kargc = 0;
|
|
|
|
char** kargv = nullptr;
|
|
|
|
char** arg;
|
|
|
|
|
|
|
|
auto free_kernel_argv_copy = [&]() {
|
|
|
|
for (uint64_t i = 0; i < kargc; i++)
|
|
|
|
{
|
|
|
|
if (kargv[i]) kfree(kargv[i]);
|
|
|
|
}
|
|
|
|
if (kargv) kfree(kargv);
|
|
|
|
};
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (Memory::is_kernel_address((uintptr_t)argv))
|
|
|
|
{
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
context->rax = -EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
arg = (char**)VMM::get_physical((uint64_t)argv);
|
|
|
|
if (arg == (char**)UINT64_MAX)
|
|
|
|
{
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
context->rax = -EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kargv = (char**)krealloc(kargv, (kargc + 1) * sizeof(char*));
|
|
|
|
if (!kargv)
|
|
|
|
{
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
context->rax = -ENOMEM;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (*arg)
|
|
|
|
{
|
|
|
|
char* kcopy = strdup_from_user(*arg);
|
|
|
|
if (!kcopy)
|
|
|
|
{
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
context->rax = -ENOMEM;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kargv[kargc] = kcopy;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kargv[kargc] = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
kargc++;
|
|
|
|
argv++;
|
|
|
|
} while (arg != nullptr);
|
|
|
|
|
|
|
|
kinfoln("Copied %lu arguments from user process", kargc);
|
|
|
|
|
|
|
|
size_t stack_size = 0;
|
|
|
|
for (uint64_t i = 0; i <= kargc; i++)
|
|
|
|
{
|
|
|
|
stack_size += sizeof(char*);
|
2022-10-26 18:05:24 +00:00
|
|
|
if (kargv[i])
|
|
|
|
{
|
|
|
|
stack_size += strlen(kargv[i]) + 1; // count the null byte
|
|
|
|
}
|
2022-10-26 16:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (stack_size >
|
|
|
|
((TASK_PAGES_IN_STACK / 2) *
|
|
|
|
PAGE_SIZE)) // FIXME: Maybe we should allocate a larger stack in this case, but still set a larger upper limit.
|
|
|
|
{
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
context->rax = -E2BIG;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char** user_argv = (char**)kcalloc(kargc + 1, sizeof(char*));
|
|
|
|
if (!user_argv)
|
|
|
|
{
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
context->rax = -ENOMEM;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-12 15:42:01 +00:00
|
|
|
Interrupts::disable();
|
|
|
|
ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive.
|
|
|
|
|
|
|
|
Task* task = Scheduler::current_task();
|
|
|
|
ASSERT(task);
|
|
|
|
|
|
|
|
// At this point, pretty much nothing can fail.
|
|
|
|
|
2022-10-17 16:43:35 +00:00
|
|
|
task->allocator.free();
|
|
|
|
task->allocator
|
|
|
|
.init(); // If we had enough space for the old bitmap, we should have enough space for the new bitmap.
|
|
|
|
|
|
|
|
task->address_space.clear();
|
|
|
|
task->allocated_stack = (uint64_t)MemoryManager::get_pages_at(
|
|
|
|
0x100000, TASK_PAGES_IN_STACK,
|
Kernel: Introduce page ownership
Some pages, such as framebuffer pages, are not physical memory frames reserved for the current process.
Some, such as the framebuffer, may be shared between all processes.
Yet, on exit() or on exec(), a process frees all frames mapped into its address spaces.
And on fork(), it copies all data between frames. So how could we map framebuffers.
Simple: we use one of the bits in page table entries which are available to the OS, and mark whether that page is owned by the current process.
If it is owned, it will be:
- Freed on address space destruction
- Its data will be copied to a new page owned by the child process on fork()
If it is not owned, it will be:
- Left alone on address space destruction
- On fork(), the child's virtual page will be mapped to the same physical frame as the parent
This still needs a bit more work, such as keeping a reference of how many processes use a page to free it when all processes using it exit/exec.
This should be done for MAP_SHARED mappings, for example, since they are not permanent forever,
unlike the framebuffer for example.
2022-11-02 18:32:28 +00:00
|
|
|
MAP_USER | MAP_READ_WRITE | MAP_AS_OWNED_BY_TASK); // If we had enough space for the old stack, there should be enough space for the
|
2022-10-17 16:43:35 +00:00
|
|
|
// new stack.
|
|
|
|
|
2022-10-12 16:43:48 +00:00
|
|
|
ELFImage* image = ELFLoader::load_elf_from_vfs(program);
|
|
|
|
ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly
|
|
|
|
// wrong.
|
|
|
|
|
2022-10-28 15:10:28 +00:00
|
|
|
if (VFS::is_setuid(program)) task->uid = program->uid;
|
|
|
|
if (VFS::is_setgid(program)) task->gid = program->gid;
|
|
|
|
|
2022-10-17 17:12:47 +00:00
|
|
|
strlcpy(task->name, kpathname, sizeof(task->name));
|
|
|
|
|
2022-10-12 15:42:01 +00:00
|
|
|
Scheduler::reset_task(task, image);
|
|
|
|
|
2022-10-22 08:28:02 +00:00
|
|
|
for (int i = 0; i < TASK_MAX_FDS; i++)
|
|
|
|
{
|
|
|
|
Descriptor& file = task->files[i];
|
|
|
|
if (file.close_on_exec()) { file.close(); }
|
|
|
|
}
|
|
|
|
|
2022-10-26 16:57:06 +00:00
|
|
|
for (uint64_t i = 0; i <= kargc; i++)
|
|
|
|
{
|
|
|
|
if (kargv[i])
|
|
|
|
{
|
|
|
|
push_on_user_stack(&task->regs.rsp, kargv[i], strlen(kargv[i]) + 1);
|
|
|
|
user_argv[i] = (char*)task->regs.rsp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
user_argv[i] = nullptr;
|
|
|
|
}
|
|
|
|
push_on_user_stack(&task->regs.rsp, (char*)user_argv, (kargc + 1) * sizeof(char*));
|
|
|
|
task->regs.rdi = kargc; // argc
|
|
|
|
task->regs.rsi = task->regs.rsp; // argv
|
|
|
|
|
|
|
|
task->regs.rsp &= (UINT64_MAX ^ 15); // align it
|
|
|
|
|
|
|
|
free_kernel_argv_copy();
|
|
|
|
|
|
|
|
kfree(user_argv);
|
2022-10-12 15:42:01 +00:00
|
|
|
|
2022-10-13 20:13:04 +00:00
|
|
|
kfree(kpathname);
|
|
|
|
|
2022-10-26 16:57:06 +00:00
|
|
|
task->restore_context(context);
|
|
|
|
|
2022-10-14 16:00:33 +00:00
|
|
|
return;
|
2022-10-12 15:42:01 +00:00
|
|
|
}
|