From ac13be4291aefc3b7e0c17544289e8a4521f9b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Sat, 30 Dec 2023 23:45:10 +0000 Subject: [PATCH] Initial version of sys_fork, sys_execve and sys_wait4. It is not fully working yet, in particular child programs have broken initial stack and argv returns garbage. --- posix-runner/posix-runner.c | 271 ++++++++++++++++++++++++++++++++---- posix-runner/syscalls.c | 97 ------------- 2 files changed, 246 insertions(+), 122 deletions(-) delete mode 100644 posix-runner/syscalls.c diff --git a/posix-runner/posix-runner.c b/posix-runner/posix-runner.c index 8ac1eb0..c5891c1 100644 --- a/posix-runner/posix-runner.c +++ b/posix-runner/posix-runner.c @@ -10,29 +10,90 @@ #include #include -#include "syscalls.c" - #define MSR_EFER 0x60000080 + 0x60000000 #define MSR_STAR 0x60000081 + 0x60000000 #define MSR_LSTAR 0x60000082 + 0x60000000 -int extract_field(char *file_data, int position, int length) +void* syscall_table; + +#define MAX_PROC 16 +#define MAX_MIB_PER_PROC 128 +#define MAX_SAVED_MIB 1024 + +struct mem_block { + void* address; + int length; +}; + +struct process { + struct process* parent; + void* entry_point; + void* brk; + void* saved_brk; + void* stack; + void* saved_stack_pointer; + void* memory; + mem_block program; + mem_block saved_stack; + mem_block saved_memory; + int child_exit_code; + int forked; +}; +struct process* current_process; + +void* _get_stack() { - void *data; + asm("mov_rax,rsp"); +} + +void* get_stack() +{ + /* Adjust to stack depth of _get_stack function */ + return _get_stack() + (7 * sizeof(void*)); +} + +int extract_field(char* file_data, int position, int length) +{ + void* data; memcpy(&data, file_data + position, length); return data; } -void jump(void *start_address, int argc, char **argv, char **envp) +int load_elf(FILE* file_in, struct process* current) { - char *temp; - for (; *envp != 0; envp += sizeof(char *)) - { + int file_size = fseek(file_in, 0, SEEK_END); + char* file_data = calloc(1, file_size + 0x1000); /* Allocate extra space in case application tries to use it */ + rewind(file_in); + fread(file_data, 1, file_size, file_in); + fclose(file_in); + + if ((file_data[0] != 0x7F) || (file_data[1] != 'E') || + (file_data[2] != 'L') || (file_data[3] != 'F')) { + return 1; + } + current->program.address = file_data; + current->program.length = file_size; + return 0; +} + +void* entry_point(char* raw_elf) +{ + int entry_point = extract_field(raw_elf, 24, 8); + int header_table = extract_field(raw_elf, 32, 8); + int base_address = extract_field(raw_elf, header_table + 0x10, 8); + return entry_point - base_address + raw_elf; +} + +void jump(void* start_address, int argc, char** argv, char** envp) +{ + current_process->stack = get_stack(); + char* temp; + asm("push !0"); + for (; *envp != 0; envp += sizeof(char *)) { temp = *envp; asm("push_rax"); } asm("push !0"); - unsigned i; for (i = argc; i > 0; i -= 1) { temp = argv[i]; @@ -48,6 +109,173 @@ void jump(void *start_address, int argc, char **argv, char **envp) ); } +int sys_read(int fd, char* buf, unsigned count, void, void, void) +{ + return read(fd, buf, count); +} + +int sys_write(int fd, char* buf, unsigned count, void, void, void) +{ + return write(fd, buf, count); +} + +int sys_open(char* name, int flag, int mode, void, void, void) +{ + fputs(name, stderr); + fputc('\n', stderr); + return open(name, flag, mode); +} + +int sys_close(int fd, void, void, void, void, void) +{ + return close(fd); +} + +int sys_lseek(int fd, int offset, int whence, void, void, void) +{ + return lseek(fd, offset, whence); +} + +int sys_brk(void* addr, void, void, void, void, void) +{ + if (current_process->brk == NULL) { + current_process->brk = calloc(1, MAX_MIB_PER_PROC * 1024 * 1024); + if (current_process->brk == NULL) { + return addr; + } + current_process->memory = current_process->brk; + } + if (addr == NULL) { + return current_process->brk; + } + else { + current_process->brk = addr; + return current_process->brk; + } +} + +int sys_access(char* pathname, int mode, void, void, void, void) +{ + return access(pathname, mode); +} + +int sys_fork(void, void, void, void, void, void) +{ + current_process->saved_brk = current_process->brk; + current_process->saved_stack_pointer = get_stack(); + current_process->forked = TRUE; + current_process->saved_stack.length = current_process->stack - current_process->saved_stack_pointer; + current_process->saved_stack.address = malloc(current_process->saved_stack.length); + memcpy(current_process->saved_stack.address, current_process->saved_stack_pointer, current_process->saved_stack.length); + current_process->saved_memory.length = current_process->brk - current_process->memory; + current_process->saved_memory.address = malloc(current_process->saved_memory.length); + memcpy(current_process->saved_memory.address, current_process->memory, current_process->saved_memory.length); + + return 0; /* return as child */ +} + +int sys_execve(char* file_name, char** argv, char** envp, void, void, void) +{ + if (current_process->forked) { + struct process* new = calloc(1, sizeof(process)); + new->parent = current_process; + current_process->forked = FALSE; /* fork was handled */ + current_process = new; + } + // else { + // restore_stack(current_process->saved_stack); // FIXME + // } + FILE* file_in; + file_in = fopen(file_name, "r"); + if (file_in == NULL) { + return -1; + } + int rval; + rval = load_elf(file_in, current_process); + if (rval == 1) { + return -1; + } + current_process->entry_point = entry_point(current_process->program.address); + + char** iter = argv; + int argc; + while(*iter != 0) { + iter += sizeof(char *); + argc += 1; + } + + jump(current_process->entry_point, argc, argv, envp); +} + +void sys_exit(unsigned value, void, void, void, void, void) +{ + if (current_process->parent == NULL) { + exit(value); + } + current_process->parent->child_exit_code = value; + struct process* child = current_process; + current_process = current_process->parent; + // free(child); // FIXME + + memcpy(current_process->saved_stack_pointer, current_process->saved_stack.address, current_process->saved_stack.length); + memcpy(current_process->memory, current_process->saved_memory.address, current_process->saved_memory.length); + // free(current_process->saved_stack); // FIXME + // free(current_process->saved_memory); // FIXME + current_process->brk = current_process->saved_brk; + current_process->saved_stack_pointer; + /* Simulate return from sys_fork() */ + asm("mov_rsp,rax" + "mov_rax, %1" + "ret" + ); +} + +int sys_wait4(int pid, int* status_ptr, int options) +{ + *status_ptr = current_process->child_exit_code << 8; + return 0; +} + +int sys_getcwd(char* buf, int size, void, void, void, void) +{ + return getcwd(buf, size); +} + +int sys_chdir(char* path, void, void, void, void, void) +{ + return chdir(path); +} + +int sys_mkdir(char const* a, mode_t b, void, void, void, void) +{ + return mkdir(a, b); +} + +int sys_unlink(char* filename, void, void, void, void, void) +{ + return unlink(filename); +} + +void init_syscalls() +{ + syscall_table = calloc(256, sizeof(void *)); + syscall_table[0] = sys_read; + syscall_table[1] = sys_write; + syscall_table[2] = sys_open; + syscall_table[3] = sys_close; + syscall_table[8] = sys_lseek; + syscall_table[12] = sys_brk; + syscall_table[21] = sys_access; + syscall_table[57] = sys_fork; + syscall_table[59] = sys_execve; + syscall_table[60] = sys_exit; + syscall_table[61] = sys_wait4; + syscall_table[79] = sys_getcwd; + syscall_table[80] = sys_chdir; + syscall_table[83] = sys_mkdir; + syscall_table[87] = sys_unlink; +} + void wrmsr(unsigned msr, int low, int high) { asm("lea_rcx,[rbp+DWORD] %-8" @@ -77,7 +305,7 @@ ulong rdmsrl(unsigned msr) void _entry_syscall(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { - FUNCTION *process_syscall = syscall_table[syscall]; + FUNCTION process_syscall = syscall_table[syscall]; if(process_syscall != NULL) { return process_syscall(arg1, arg2, arg3, arg4, arg5, arg6); } @@ -132,7 +360,7 @@ void entry_syscall() asm("jmp_rcx"); } -int main(int argc, char **argv, char **envp) +int main(int argc, char** argv, char** envp) { if (argc < 2) { fputs("Usage: ", stderr); @@ -141,29 +369,22 @@ int main(int argc, char **argv, char **envp) exit(1); } - FILE *file_in = fopen(argv[1], "r"); + FILE* file_in = fopen(argv[1], "r"); if (file_in == NULL) { fputs("Error opening input file.\n", stderr); exit(2); } - /* Load binary into memory */ - int file_size = fseek(file_in, 0, SEEK_END); - char *file_data = calloc(file_size + 0x1000); /* Allocate extra space in case application tries to use it */ - rewind(file_in); - fread(file_data, 1, file_size, file_in); - fclose(file_in); + current_process = calloc(1, sizeof(process)); - if ((file_data[0] != 0x7F) || (file_data[1] != 'E') || - (file_data[2] != 'L') || (file_data[3] != 'F')) { + /* Load binary into memory */ + int rval = load_elf(file_in, current_process); + if (rval == 1) { fputs("ELF magic header was not found.\n", stderr); exit(3); } - int entry_point = extract_field(file_data, 24, 8); - int header_table = extract_field(file_data, 32, 8); - int base_address = extract_field(file_data, header_table + 0x10, 8); - void *start_address = entry_point - base_address + file_data; + current_process->entry_point = entry_point(current_process->program.address); ulong msr_efer = rdmsrl(MSR_EFER); msr_efer |= 1; /* Enable syscalls */ @@ -175,7 +396,7 @@ int main(int argc, char **argv, char **envp) wrmsrl(MSR_LSTAR, entry_syscall); init_syscalls(); - jump(start_address, argc - 1, argv, envp); + jump(current_process->entry_point, argc - 1, argv, envp); return 1; } diff --git a/posix-runner/syscalls.c b/posix-runner/syscalls.c deleted file mode 100644 index 8b77ea3..0000000 --- a/posix-runner/syscalls.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Andrius Štikonas - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -void *syscall_table; -void *_brk; - -int sys_read(int fd, char* buf, unsigned count, void, void, void) -{ - return read(fd, buf, count); -} - -int sys_write(int fd, char* buf, unsigned count, void, void, void) -{ - return write(fd, buf, count); -} - -int sys_open(char* name, int flag, int mode, void, void, void) -{ - return open(name, flag, mode); -} - -int sys_close(int fd, void, void, void, void, void) -{ - return close(fd); -} - -int sys_lseek(int fd, int offset, int whence, void, void, void) -{ - return lseek(fd, offset, whence); -} - -int sys_access(char* pathname, int mode, void, void, void, void) -{ - return access(pathname, mode); -} - -int sys_brk(void* addr, void, void, void, void, void) -{ - if (_brk == NULL) { - _brk = calloc(1, 128 * 1024 * 1024); - if (_brk == NULL) { - return addr; - } - } - if (addr == NULL) { - return _brk; - } - else { - _brk = addr; - return _brk; - } -} - -void sys_exit(unsigned value, void, void, void, void, void) -{ - exit(value); -} - -int sys_getcwd(char* buf, int size, void, void, void, void) -{ - return getcwd(buf, size); -} - -int sys_chdir(char* path, void, void, void, void, void) -{ - return chdir(path); -} - -int sys_mkdir(char const* a, mode_t b, void, void, void, void) -{ - return mkdir(a, b); -} - -int sys_unlink(char* filename, void, void, void, void, void) -{ - return unlink(filename); -} - -void init_syscalls() -{ - syscall_table = calloc(256, sizeof(void*)); - syscall_table[0] = sys_read; - syscall_table[1] = sys_write; - syscall_table[2] = sys_open; - syscall_table[3] = sys_close; - syscall_table[8] = sys_lseek; - syscall_table[12] = sys_brk; - syscall_table[21] = sys_access; - syscall_table[60] = sys_exit; - syscall_table[79] = sys_getcwd; - syscall_table[80] = sys_chdir; - syscall_table[83] = sys_mkdir; - syscall_table[87] = sys_unlink; -}