syscalls: fix execve to use heap and make it work better with fork

This commit is contained in:
2025-12-10 00:47:46 +03:00
parent 51dc254aa3
commit 53e380e510
+40 -43
View File
@@ -331,68 +331,68 @@ extern void execve_return(TrapFrame *tf);
/**
* this might be a not really good implementation as it only supports
* 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
* kernel_envp
* string
*/
int sys_execve(TrapFrame *tf) {
const char* filename = (const char*)tf->ebx;
char **argv = (char**)tf->ecx;
char **envp = (char**)tf->edx;
int argc = 0;
while(argv[argc] != NULL) argc++;
int envc = 0;
while(envp[envc] != NULL) envc++;
while(argv[argc] != NULL)
{
argc++;
}
while(envp[envc] != NULL)
{
envc++;
}
char** kernel_argv = malloc((argc + 1) * sizeof(char*));
if (!kernel_argv) return -1;
//TODO: check why was there a triple fault when I tried using malloc
char kernel_argv[argc][EXECVE_MAX_ARGUMENT_SIZE];
char kernel_envp[envc][EXECVE_MAX_ARGUMENT_SIZE];
for(int i = 0; i < argc; i++)
{
for(int i = 0; i < argc; i++) {
kernel_argv[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE);
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]);
}
kernel_envp[envc] = NULL;
uint8_t* file_buffer;
int err = vfs_read_file_by_path(filename, &file_buffer);
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;
}
Elf32_Ehdr *elf_header = (Elf32_Ehdr*)file_buffer;
if (memcmp(elf_header->e_ident, "\x7F" "ELF", 4) != 0) {
debug_log("execve: '%s' is not a valid ELF file\n", filename);
free(file_buffer);
// TODO: Free resources
return -1;
}
uint32_t* new_page_dir = create_page_dir();
if (!new_page_dir) {
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;
if (!new_page_dir) return -1;
set_page_dir(new_page_dir_phys);
current->pagedir = new_page_dir;
uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)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);
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;
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) {
uint32_t start_addr = p_header->p_vaddr;
uint32_t end_addr = start_addr + p_header->p_memsz;
uint32_t start_page = start_addr & ~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) {
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) {
highest_vaddr = p_header->p_vaddr + p_header->p_memsz;
}
if (end_addr > highest_vaddr) highest_vaddr = end_addr;
}
}
@@ -426,7 +423,6 @@ int sys_execve(TrapFrame *tf) {
uint32_t user_esp = USER_STACK_TOP;
//push environment strings
uint32_t envp_pointers[envc + 1];
for (int i = envc - 1; i >= 0; i--) {
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);
envp_pointers[i] = user_esp;
}
envp_pointers[envc] = 0;//null terminator
envp_pointers[envc] = 0;
//push argument strings
uint32_t argv_pointers[argc + 1];
for (int i = argc - 1; i >= 0; i--) {
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);
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);
memcpy((void*)user_esp, envp_pointers, (envc + 1) * sizeof(uint32_t));
//push argv pointers
user_esp -= (argc + 1) * sizeof(uint32_t);
memcpy((void*)user_esp, argv_pointers, (argc + 1) * sizeof(uint32_t));
//push argc
user_esp -= sizeof(uint32_t);
*((uint32_t*)user_esp) = argc;
current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE);
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);
tf->gs = SEG_UDATA | DPL_USER;
@@ -475,7 +473,6 @@ int sys_execve(TrapFrame *tf) {
tf->usermode_ss = SEG_UDATA | DPL_USER;
execve_return(tf);
return 0;
}