foo
This commit is contained in:
+89
-28
@@ -7,11 +7,12 @@
|
||||
#include <zinnia/pmap.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <zinnia/vma.h>
|
||||
#include <zinnia/vmo.h>
|
||||
#include <bits/elf.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <stdckdint.h>
|
||||
|
||||
struct exec_info {
|
||||
struct vma* space;
|
||||
@@ -21,11 +22,15 @@ struct exec_info {
|
||||
};
|
||||
|
||||
errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
errno_t status;
|
||||
errno_t err;
|
||||
|
||||
size_t read;
|
||||
struct elf_ehdr ehdr = {};
|
||||
vmo_read(info->file_obj, 0, &ehdr, sizeof(ehdr), &read);
|
||||
err = vmo_read(info->file_obj, 0, &ehdr, sizeof(ehdr), &read);
|
||||
if (err)
|
||||
return err;
|
||||
if (read != sizeof(ehdr))
|
||||
return ENOEXEC;
|
||||
|
||||
// Check if the file is an ELF.
|
||||
if (memcmp(ehdr.e_ident, ELF_MAG, sizeof(ELF_MAG)) != 0)
|
||||
@@ -40,13 +45,48 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
return EINVAL;
|
||||
if (ehdr.e_type != ET_EXEC)
|
||||
return EINVAL;
|
||||
if (!arch_mem_addr_is_user(ehdr.e_entry))
|
||||
return ENOEXEC;
|
||||
|
||||
const size_t phdrs_size = (size_t)ehdr.e_phnum * ehdr.e_phentsize;
|
||||
uintptr_t phdrs_end;
|
||||
if (ehdr.e_phentsize < sizeof(struct elf_phdr) || ehdr.e_phnum == 0 || phdrs_size > 64 * 1024)
|
||||
return ENOEXEC;
|
||||
if (ckd_add(&phdrs_end, ehdr.e_phoff, phdrs_size))
|
||||
return ENOEXEC;
|
||||
|
||||
const size_t page_size = arch_mem_page_size();
|
||||
uintptr_t phdr_addr = 0;
|
||||
|
||||
for (size_t i = 0; i < ehdr.e_phnum; i++) {
|
||||
struct elf_phdr phdr = {};
|
||||
vmo_read(info->file_obj, (ehdr.e_phoff + (i * ehdr.e_phentsize)), &phdr, sizeof(phdr), &read);
|
||||
err = vmo_read(info->file_obj, (ehdr.e_phoff + (i * ehdr.e_phentsize)), &phdr, sizeof(phdr), &read);
|
||||
if (err)
|
||||
return err;
|
||||
if (read != sizeof(phdr))
|
||||
return ENOEXEC;
|
||||
|
||||
if (phdr.p_type == PT_PHDR)
|
||||
phdr_addr = phdr.p_vaddr;
|
||||
|
||||
if (phdr.p_type == PT_LOAD) {
|
||||
if (phdr.p_memsz == 0)
|
||||
continue;
|
||||
if (phdr.p_filesz > phdr.p_memsz)
|
||||
return ENOEXEC;
|
||||
|
||||
uintptr_t seg_end;
|
||||
if (ckd_add(&seg_end, phdr.p_vaddr, phdr.p_memsz))
|
||||
return ENOEXEC;
|
||||
if (!arch_mem_addr_is_user(phdr.p_vaddr) || !arch_mem_addr_is_user(seg_end - 1))
|
||||
return ENOEXEC;
|
||||
|
||||
if (phdr.p_align > 1 && phdr.p_offset % phdr.p_align != phdr.p_vaddr % phdr.p_align)
|
||||
return ENOEXEC;
|
||||
|
||||
if (phdr_addr == 0 && ehdr.e_phoff >= phdr.p_offset && phdrs_end - phdr.p_offset <= phdr.p_filesz)
|
||||
phdr_addr = phdr.p_vaddr + (ehdr.e_phoff - phdr.p_offset);
|
||||
|
||||
enum prot_flags prot = 0;
|
||||
if (phdr.p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
@@ -55,8 +95,6 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
if (phdr.p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
assert(phdr.p_offset % phdr.p_align == phdr.p_vaddr % phdr.p_align, "");
|
||||
|
||||
const uintptr_t misalign = phdr.p_vaddr & (page_size - 1);
|
||||
const uintptr_t map_address = phdr.p_vaddr - misalign;
|
||||
const size_t backed_map_size = (phdr.p_filesz + misalign + page_size - 1) & ~(page_size - 1);
|
||||
@@ -64,18 +102,21 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
|
||||
// Copy the file data into its own mapping.
|
||||
struct paged_vmo* phdr_obj;
|
||||
status = vmo_new_phys(&phdr_obj);
|
||||
if (status)
|
||||
return status;
|
||||
err = vmo_new_phys(&phdr_obj);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
status = vmo_copy(&phdr_obj->object, phdr.p_offset, info->file_obj, phdr.p_offset, phdr.p_filesz, nullptr);
|
||||
if (status)
|
||||
return status;
|
||||
err = vmo_copy(&phdr_obj->object, phdr.p_offset, info->file_obj, phdr.p_offset, phdr.p_filesz, nullptr);
|
||||
if (err) {
|
||||
vmo_unref(&phdr_obj->object);
|
||||
return err;
|
||||
}
|
||||
|
||||
// We map more than we copied so the rest is filled with zeroed pages.
|
||||
status = vma_map(info->space, &phdr_obj->object, phdr.p_vaddr, phdr.p_memsz, prot, phdr.p_offset);
|
||||
if (status)
|
||||
return status;
|
||||
err = vma_map(info->space, &phdr_obj->object, phdr.p_vaddr, phdr.p_memsz, prot, phdr.p_offset);
|
||||
vmo_unref(&phdr_obj->object);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,9 +126,9 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
|
||||
// Allocate stack.
|
||||
struct paged_vmo* stack;
|
||||
status = vmo_new_phys(&stack);
|
||||
if (status)
|
||||
return status;
|
||||
err = vmo_new_phys(&stack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Fill in stack info.
|
||||
uintptr_t stack_off = stack_size;
|
||||
@@ -101,8 +142,21 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
for (const char** ptr = info->argv; *ptr != nullptr; ptr++) {
|
||||
num_argv++;
|
||||
}
|
||||
|
||||
size_t strings_size = 0;
|
||||
for (size_t env = 0; env < num_envp; env++)
|
||||
strings_size += strlen(info->envp[env]) + 1;
|
||||
for (size_t arg = 0; arg < num_argv; arg++)
|
||||
strings_size += strlen(info->argv[arg]) + 1;
|
||||
|
||||
uintptr_t* envp_offsets = mem_alloc(num_envp * sizeof(uintptr_t), 0);
|
||||
uintptr_t* argv_offsets = mem_alloc(num_argv * sizeof(uintptr_t), 0);
|
||||
if ((num_envp && !envp_offsets) || (num_argv && !argv_offsets)) {
|
||||
mem_free(envp_offsets);
|
||||
mem_free(argv_offsets);
|
||||
vmo_unref(&stack->object);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
for (size_t env = 0; env < num_envp; env++) {
|
||||
const char nul = 0;
|
||||
@@ -153,22 +207,24 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
WRITE_AUXV(AT_PHNUM, ehdr.e_phnum);
|
||||
WRITE_AUXV(AT_PHENT, ehdr.e_phentsize);
|
||||
WRITE_AUXV(AT_ENTRY, ehdr.e_entry);
|
||||
if (phdr_addr)
|
||||
WRITE_AUXV(AT_PHDR, phdr_addr);
|
||||
|
||||
// envp pointers.
|
||||
stack_off -= sizeof(uintptr_t);
|
||||
const uintptr_t zero = 0;
|
||||
vmo_write(&stack->object, stack_off, &zero, sizeof(zero), nullptr);
|
||||
for (size_t env = 0; env < num_envp; env++) {
|
||||
for (size_t env = num_envp; env > 0; env--) {
|
||||
stack_off -= sizeof(uintptr_t);
|
||||
vmo_write(&stack->object, stack_off, &envp_offsets[env], sizeof(envp_offsets[env]), nullptr);
|
||||
vmo_write(&stack->object, stack_off, &envp_offsets[env - 1], sizeof(envp_offsets[env - 1]), nullptr);
|
||||
}
|
||||
|
||||
// argv pointers.
|
||||
stack_off -= sizeof(uintptr_t);
|
||||
vmo_write(&stack->object, stack_off, &zero, sizeof(zero), nullptr);
|
||||
for (size_t arg = 0; arg < num_argv; arg++) {
|
||||
for (size_t arg = num_argv; arg > 0; arg--) {
|
||||
stack_off -= sizeof(uintptr_t);
|
||||
vmo_write(&stack->object, stack_off, &argv_offsets[arg], sizeof(argv_offsets[arg]), nullptr);
|
||||
vmo_write(&stack->object, stack_off, &argv_offsets[arg - 1], sizeof(argv_offsets[arg - 1]), nullptr);
|
||||
}
|
||||
|
||||
mem_free(envp_offsets);
|
||||
@@ -179,19 +235,24 @@ errno_t elf_load(struct exec_info* info, struct task** out) {
|
||||
uintptr_t argc = num_argv;
|
||||
vmo_write(&stack->object, stack_off, &argc, sizeof(argc), nullptr);
|
||||
|
||||
status = vma_map(info->space, &stack->object, stack_start, stack_size, PROT_READ | PROT_WRITE, 0);
|
||||
if (status)
|
||||
return status;
|
||||
err = vma_map(info->space, &stack->object, stack_start, stack_size, PROT_READ | PROT_WRITE, 0);
|
||||
vmo_unref(&stack->object);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
struct task_start_info* start_info = mem_alloc(sizeof(struct task_start_info), 0);
|
||||
if (!start_info)
|
||||
return ENOMEM;
|
||||
start_info->ip = ehdr.e_entry;
|
||||
start_info->sp = highest - stack_size + stack_off;
|
||||
start_info->arg = 0;
|
||||
|
||||
struct task* result;
|
||||
status = task_create(info->argv[0], info->space, sched_to_user, (uintptr_t)start_info, &result);
|
||||
if (status)
|
||||
return status;
|
||||
err = task_create(info->argv[0], info->space, sched_to_user, (uintptr_t)start_info, &result);
|
||||
if (err) {
|
||||
mem_free(start_info);
|
||||
return err;
|
||||
}
|
||||
|
||||
*out = result;
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user