syscalls: fix execve to use heap and make it work better with fork
This commit is contained in:
+41
-44
@@ -331,68 +331,68 @@ extern void execve_return(TrapFrame *tf);
|
|||||||
/**
|
/**
|
||||||
* this might be a not really good implementation as it only supports
|
* this might be a not really good implementation as it only supports
|
||||||
* up to EXECVE_MAX_ARGUMENT_SIZE characters in each argument or environment
|
* up to EXECVE_MAX_ARGUMENT_SIZE characters in each argument or environment
|
||||||
* string and for some reason I was unable to use malloc for kernel_argv and
|
* string
|
||||||
* kernel_envp
|
|
||||||
*/
|
*/
|
||||||
int sys_execve(TrapFrame *tf) {
|
int sys_execve(TrapFrame *tf) {
|
||||||
const char* filename = (const char*)tf->ebx;
|
const char* filename = (const char*)tf->ebx;
|
||||||
|
|
||||||
char **argv = (char**)tf->ecx;
|
char **argv = (char**)tf->ecx;
|
||||||
char **envp = (char**)tf->edx;
|
char **envp = (char**)tf->edx;
|
||||||
|
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
|
while(argv[argc] != NULL) argc++;
|
||||||
|
|
||||||
int envc = 0;
|
int envc = 0;
|
||||||
|
while(envp[envc] != NULL) envc++;
|
||||||
|
|
||||||
while(argv[argc] != NULL)
|
char** kernel_argv = malloc((argc + 1) * sizeof(char*));
|
||||||
{
|
if (!kernel_argv) return -1;
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
while(envp[envc] != NULL)
|
|
||||||
{
|
|
||||||
envc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: check why was there a triple fault when I tried using malloc
|
for(int i = 0; i < argc; i++) {
|
||||||
char kernel_argv[argc][EXECVE_MAX_ARGUMENT_SIZE];
|
kernel_argv[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE);
|
||||||
char kernel_envp[envc][EXECVE_MAX_ARGUMENT_SIZE];
|
|
||||||
|
|
||||||
for(int i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
strcpy(kernel_argv[i], argv[i]);
|
strcpy(kernel_argv[i], argv[i]);
|
||||||
}
|
}
|
||||||
|
kernel_argv[argc] = NULL;
|
||||||
|
|
||||||
for(int i = 0; i < envc; i++)
|
char** kernel_envp = malloc((envc + 1) * sizeof(char*));
|
||||||
{
|
if (!kernel_envp) return -1; // TODO: cleanup kernel_argv
|
||||||
|
|
||||||
|
for(int i = 0; i < envc; i++) {
|
||||||
|
kernel_envp[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE);
|
||||||
strcpy(kernel_envp[i], envp[i]);
|
strcpy(kernel_envp[i], envp[i]);
|
||||||
}
|
}
|
||||||
|
kernel_envp[envc] = NULL;
|
||||||
|
|
||||||
uint8_t* file_buffer;
|
uint8_t* file_buffer;
|
||||||
int err = vfs_read_file_by_path(filename, &file_buffer);
|
int err = vfs_read_file_by_path(filename, &file_buffer);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
debug_log("execve: failed to read file '%s'\n", filename);
|
// TODO: Free kernel_argv/envp
|
||||||
|
debug_log("execve: failed to read file\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Ehdr *elf_header = (Elf32_Ehdr*)file_buffer;
|
Elf32_Ehdr *elf_header = (Elf32_Ehdr*)file_buffer;
|
||||||
if (memcmp(elf_header->e_ident, "\x7F" "ELF", 4) != 0) {
|
if (memcmp(elf_header->e_ident, "\x7F" "ELF", 4) != 0) {
|
||||||
debug_log("execve: '%s' is not a valid ELF file\n", filename);
|
// TODO: Free resources
|
||||||
free(file_buffer);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t* new_page_dir = create_page_dir();
|
uint32_t* new_page_dir = create_page_dir();
|
||||||
if (!new_page_dir) {
|
if (!new_page_dir) return -1;
|
||||||
free(file_buffer);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)new_page_dir);
|
|
||||||
uint32_t* old_page_dir_to_free = current->pagedir;
|
|
||||||
|
|
||||||
set_page_dir(new_page_dir_phys);
|
uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)new_page_dir);
|
||||||
current->pagedir = new_page_dir;
|
|
||||||
|
void* process_phys = get_physaddr(current);
|
||||||
|
map_page_in_directory(new_page_dir, process_phys, current, PAGE_PRESENT | PAGE_RW);
|
||||||
|
|
||||||
void* kstack_phys = get_physaddr(current->kstack);
|
void* kstack_phys = get_physaddr(current->kstack);
|
||||||
map_page(kstack_phys, current->kstack, PAGE_PRESENT | PAGE_RW);
|
map_page_in_directory(new_page_dir, kstack_phys, current->kstack, PAGE_PRESENT | PAGE_RW);
|
||||||
|
|
||||||
|
void* argv_phys = get_physaddr(kernel_argv);
|
||||||
|
map_page_in_directory(new_page_dir, argv_phys, kernel_argv, PAGE_PRESENT | PAGE_RW);
|
||||||
|
|
||||||
|
uint32_t* old_page_dir_to_free = current->pagedir;
|
||||||
|
set_page_dir(new_page_dir_phys);
|
||||||
|
current->pagedir = new_page_dir;
|
||||||
|
|
||||||
uint32_t highest_vaddr = 0;
|
uint32_t highest_vaddr = 0;
|
||||||
for (int i = 0; i < elf_header->e_phnum; i++) {
|
for (int i = 0; i < elf_header->e_phnum; i++) {
|
||||||
@@ -400,7 +400,6 @@ int sys_execve(TrapFrame *tf) {
|
|||||||
if (p_header->p_type == PT_LOAD) {
|
if (p_header->p_type == PT_LOAD) {
|
||||||
uint32_t start_addr = p_header->p_vaddr;
|
uint32_t start_addr = p_header->p_vaddr;
|
||||||
uint32_t end_addr = start_addr + p_header->p_memsz;
|
uint32_t end_addr = start_addr + p_header->p_memsz;
|
||||||
|
|
||||||
uint32_t start_page = start_addr & ~0xFFF;
|
uint32_t start_page = start_addr & ~0xFFF;
|
||||||
uint32_t end_page = (end_addr - 1) & ~0xFFF;
|
uint32_t end_page = (end_addr - 1) & ~0xFFF;
|
||||||
|
|
||||||
@@ -413,9 +412,7 @@ int sys_execve(TrapFrame *tf) {
|
|||||||
if (p_header->p_memsz > p_header->p_filesz) {
|
if (p_header->p_memsz > p_header->p_filesz) {
|
||||||
memset((void*)(p_header->p_vaddr + p_header->p_filesz), 0, p_header->p_memsz - p_header->p_filesz);
|
memset((void*)(p_header->p_vaddr + p_header->p_filesz), 0, p_header->p_memsz - p_header->p_filesz);
|
||||||
}
|
}
|
||||||
if (p_header->p_vaddr + p_header->p_memsz > highest_vaddr) {
|
if (end_addr > highest_vaddr) highest_vaddr = end_addr;
|
||||||
highest_vaddr = p_header->p_vaddr + p_header->p_memsz;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +423,6 @@ int sys_execve(TrapFrame *tf) {
|
|||||||
|
|
||||||
uint32_t user_esp = USER_STACK_TOP;
|
uint32_t user_esp = USER_STACK_TOP;
|
||||||
|
|
||||||
//push environment strings
|
|
||||||
uint32_t envp_pointers[envc + 1];
|
uint32_t envp_pointers[envc + 1];
|
||||||
for (int i = envc - 1; i >= 0; i--) {
|
for (int i = envc - 1; i >= 0; i--) {
|
||||||
size_t len = strlen(kernel_envp[i]) + 1;
|
size_t len = strlen(kernel_envp[i]) + 1;
|
||||||
@@ -434,9 +430,8 @@ int sys_execve(TrapFrame *tf) {
|
|||||||
memcpy((void*)user_esp, kernel_envp[i], len);
|
memcpy((void*)user_esp, kernel_envp[i], len);
|
||||||
envp_pointers[i] = user_esp;
|
envp_pointers[i] = user_esp;
|
||||||
}
|
}
|
||||||
envp_pointers[envc] = 0;//null terminator
|
envp_pointers[envc] = 0;
|
||||||
|
|
||||||
//push argument strings
|
|
||||||
uint32_t argv_pointers[argc + 1];
|
uint32_t argv_pointers[argc + 1];
|
||||||
for (int i = argc - 1; i >= 0; i--) {
|
for (int i = argc - 1; i >= 0; i--) {
|
||||||
size_t len = strlen(kernel_argv[i]) + 1;
|
size_t len = strlen(kernel_argv[i]) + 1;
|
||||||
@@ -444,22 +439,25 @@ int sys_execve(TrapFrame *tf) {
|
|||||||
memcpy((void*)user_esp, kernel_argv[i], len);
|
memcpy((void*)user_esp, kernel_argv[i], len);
|
||||||
argv_pointers[i] = user_esp;
|
argv_pointers[i] = user_esp;
|
||||||
}
|
}
|
||||||
argv_pointers[argc] = 0;//null terminator
|
argv_pointers[argc] = 0;
|
||||||
|
|
||||||
//push envp pointers
|
|
||||||
user_esp -= (envc + 1) * sizeof(uint32_t);
|
user_esp -= (envc + 1) * sizeof(uint32_t);
|
||||||
memcpy((void*)user_esp, envp_pointers, (envc + 1) * sizeof(uint32_t));
|
memcpy((void*)user_esp, envp_pointers, (envc + 1) * sizeof(uint32_t));
|
||||||
|
|
||||||
//push argv pointers
|
|
||||||
user_esp -= (argc + 1) * sizeof(uint32_t);
|
user_esp -= (argc + 1) * sizeof(uint32_t);
|
||||||
memcpy((void*)user_esp, argv_pointers, (argc + 1) * sizeof(uint32_t));
|
memcpy((void*)user_esp, argv_pointers, (argc + 1) * sizeof(uint32_t));
|
||||||
|
|
||||||
//push argc
|
|
||||||
user_esp -= sizeof(uint32_t);
|
user_esp -= sizeof(uint32_t);
|
||||||
*((uint32_t*)user_esp) = argc;
|
*((uint32_t*)user_esp) = argc;
|
||||||
|
|
||||||
current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE);
|
current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE);
|
||||||
|
|
||||||
free(file_buffer);
|
free(file_buffer);
|
||||||
|
for(int i=0; i<argc; i++) free(kernel_argv[i]);
|
||||||
|
free(kernel_argv);
|
||||||
|
for(int i=0; i<envc; i++) free(kernel_envp[i]);
|
||||||
|
free(kernel_envp);
|
||||||
|
|
||||||
destroy_page_dir(old_page_dir_to_free);
|
destroy_page_dir(old_page_dir_to_free);
|
||||||
|
|
||||||
tf->gs = SEG_UDATA | DPL_USER;
|
tf->gs = SEG_UDATA | DPL_USER;
|
||||||
@@ -475,7 +473,6 @@ int sys_execve(TrapFrame *tf) {
|
|||||||
tf->usermode_ss = SEG_UDATA | DPL_USER;
|
tf->usermode_ss = SEG_UDATA | DPL_USER;
|
||||||
|
|
||||||
execve_return(tf);
|
execve_return(tf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user