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.
This commit is contained in:
parent
4f2a62fa34
commit
ac13be4291
|
@ -10,29 +10,90 @@
|
|||
#include <unistd.h>
|
||||
#include <bootstrappable.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andrius Štikonas <andrius@stikonas.eu>
|
||||
*
|
||||
* 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;
|
||||
}
|
Loading…
Reference in New Issue