diff --git a/arch/amd64/binfmt_elf.c b/arch/amd64/binfmt_elf.c index 11e4c07..24ffb47 100644 --- a/arch/amd64/binfmt_elf.c +++ b/arch/amd64/binfmt_elf.c @@ -105,6 +105,13 @@ static int elf_bzero(mm_space_t space, uintptr_t vma_dst, size_t size) { return 0; } +int binfmt_is_elf(const char *ident, size_t len) { + if (len < 4) { + return 0; + } + return !strncmp(ident, "\x7F""ELF", 4); +} + int elf_load(struct process *proc, struct vfs_ioctx *ctx, struct ofile *fd, uintptr_t *entry) { int res; ssize_t bread; diff --git a/include/sys/binfmt_elf.h b/include/sys/binfmt_elf.h index 1515d5f..45c9aea 100644 --- a/include/sys/binfmt_elf.h +++ b/include/sys/binfmt_elf.h @@ -5,3 +5,4 @@ struct process; struct ofile; int elf_load(struct process *proc, struct vfs_ioctx *ctx, struct ofile *fd, uintptr_t *entry); +int binfmt_is_elf(const char *guess, size_t len); diff --git a/sys/execve.c b/sys/execve.c index 7c85d60..d801cec 100644 --- a/sys/execve.c +++ b/sys/execve.c @@ -120,6 +120,7 @@ int sys_execve(const char *path, const char **argv, const char **envp) { _assert(thr); struct process *proc = thr->proc; _assert(proc); + char shebang[128]; if (proc->thread_count > 1) { panic("XXX: execve() in multithreaded process\n"); @@ -136,6 +137,47 @@ int sys_execve(const char *path, const char **argv, const char **envp) { return res; } + if ((res = vfs_open(&proc->ioctx, &fd, path, O_RDONLY, 0)) != 0) { + kerror("%s: %s\n", path, kstrerror(res)); + return res; + } + + if ((res = vfs_read(&proc->ioctx, &fd, shebang, sizeof(shebang))) <= 0) { + kerror("%s: %s\n", path, kstrerror(res)); + return res; + } + + if (!binfmt_is_elf(shebang, res)) { + // Try checking for shebang line + if (shebang[0] == '#' && shebang[1] == '!') { + char *e = strchr(shebang, '\n'); + if (!e) { + vfs_close(&proc->ioctx, &fd); + return -EINVAL; + } + *e = 0; + + int argc; + for (argc = 0; argv[argc]; ++argc); + // For interpreter + ++argc; + // Sanity check + _assert(argc <= 32); + const char *argv_new[argc + 1]; + argv_new[0] = shebang + 2; + for (int i = 1; i < argc; ++i) { + argv_new[i] = argv[i - 1]; + } + argv_new[argc] = NULL; + + for (int i = 0; i < argc; ++i) { + kdebug("[%d]: %s\n", i, argv_new[i]); + } + + return sys_execve(shebang + 2, argv_new, envp); + } + } + const char *e = strrchr(path, '/'); const char *name = e + 1; if (!e) { @@ -162,11 +204,6 @@ int sys_execve(const char *path, const char **argv, const char **envp) { panic("Failed to copy argp/envp to new process\n"); } - if ((res = vfs_open(&proc->ioctx, &fd, path, O_RDONLY, 0)) != 0) { - kerror("%s: %s\n", path, kstrerror(res)); - return res; - } - if (proc->space == mm_kernel) { // Have to allocate a new PID for kernel -> userspace transition proc->pid = process_alloc_pid(1); //thread_alloc_pid(1);