MOS Source Code
Loading...
Searching...
No Matches
execve.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
4#include "mos/mm/cow.hpp"
7#include "mos/tasks/elf.hpp"
11#include "mos/tasks/thread.hpp"
12
14#include <mos/types.hpp>
15#include <mos_stdlib.hpp>
16#include <mos_string.hpp>
17
18long process_do_execveat(fd_t dirfd, const char *path, const char *const argv[], const char *const envp[], int flags)
19{
20 auto thread = current_thread;
21 auto proc = current_process;
22
23 MOS_UNUSED(flags); // not implemented: AT_EMPTY_PATH, AT_SYMLINK_NOFOLLOW
24 auto f = vfs_openat(dirfd, path, open_flags(OPEN_READ | OPEN_EXECUTE));
25 if (f.isErr())
26 return f.getErr();
27
28 io_ref(&f->io);
29 elf_header_t header;
30 if (!elf_read_and_verify_executable(f.get(), &header))
31 {
32 pr_warn("failed to read elf header");
33 io_unref(&f->io);
34 return -ENOEXEC;
35 }
36
37 // backup argv and envp
38 const char **argv_copy = NULL;
39 const char **envp_copy = NULL;
40 const char *path_copy = strdup(path);
41
42 int argc = 0;
43 while (argv && argv[argc])
44 {
45 argc++;
46 argv_copy = krealloc(argv_copy, (argc + 1) * sizeof(char *));
47 argv_copy[argc - 1] = strdup(argv[argc - 1]);
48 }
49
50 if (!argv_copy)
51 {
52 argv_copy = kcalloc<const char *>(2);
53 argv_copy[0] = strdup(path);
54 argv_copy[1] = NULL;
55 argc = 1;
56 }
57
58 argv_copy[argc] = NULL;
59
60 int envc = 0;
61 while (envp && envp[envc])
62 {
63 envc++;
64 envp_copy = krealloc(envp_copy, (envc + 1) * sizeof(char *));
65 envp_copy[envc - 1] = strdup(envp[envc - 1]);
66 }
67
68 if (!envp_copy)
69 {
70 envp_copy = kcalloc<const char *>(1);
71 envp_copy[0] = NULL;
72 envc = 0;
73 }
74
75 envp_copy[envc] = NULL;
76
77 // !! ====== point of no return ====== !! //
78
79 proc->name = f->dentry->name; // set process name to the name of the executable
80 thread->name = f->dentry->name; // set thread name to the name of the executable
81
82 spinlock_acquire(&thread->state_lock);
83
84 for (const auto &t : proc->thread_list)
85 {
86 if (t != thread)
87 {
88 signal_send_to_thread(t, SIGKILL); // nice
89 thread_wait_for_tid(t->tid);
90 spinlock_acquire(&t->state_lock);
91 thread_destroy(std::move(t));
93 }
94 }
95
96 proc->main_thread = thread; // make current thread the only thread
98 spinlock_release(&thread->state_lock);
99
100 // free old memory
101 spinlock_acquire(&proc->mm->mm_lock);
102 list_foreach(vmap_t, vmap, proc->mm->mmaps)
103 {
104 spinlock_acquire(&vmap->lock);
105 vmap_destroy(vmap); // no need to unlock because it's destroyed
106 }
107 spinlock_release(&proc->mm->mm_lock);
108
109 // the userspace stack for the current thread will also be freed, so we create a new one
110 if (thread->mode == THREAD_MODE_USER)
111 {
112 const size_t ustack_size = MOS_STACK_PAGES_USER * MOS_PAGE_SIZE;
113 auto stack_vmap = cow_allocate_zeroed_pages(proc->mm, ustack_size / MOS_PAGE_SIZE, MOS_ADDR_USER_STACK, VALLOC_DEFAULT, VM_USER_RW);
114 if (stack_vmap.isErr())
115 {
116 pr_emerg("failed to allocate stack for new process");
117 process_exit(std::move(proc), 0, SIGKILL);
119 }
120
121 stack_init(&thread->u_stack, (void *) stack_vmap->vaddr, ustack_size);
123 }
124
125 elf_startup_info_t startup_info = {
126 .invocation = path_copy,
127 .auxv = { 0 },
128 .argc = argc,
129 .argv = argv_copy,
130 .envc = envc,
131 .envp = envp_copy,
132 };
133
134 const bool filled = elf_do_fill_process(proc, f.get(), header, &startup_info);
135 io_unref(&f->io);
136
137 // free old argv and envp
138 for (int i = 0; i < argc; i++)
139 kfree(argv_copy[i]);
140 kfree(argv_copy);
141 for (int i = 0; i < envc; i++)
142 kfree(envp_copy[i]);
143 kfree(envp_copy);
144 kfree(path_copy);
145
146 if (unlikely(!filled))
147 {
148 pr_emerg("failed to fill process, execve failed");
149 process_exit(std::move(proc), 0, SIGKILL);
151 }
152
153 memzero(proc->signal_info.handlers, sizeof(proc->signal_info.handlers)); // reset signal handlers
154
155 // close any files that are FD_CLOEXEC
156 for (int i = 0; i < MOS_PROCESS_MAX_OPEN_FILES; i++)
157 {
158 if (io_valid(proc->files[i].io) && (proc->files[i].flags & FD_FLAGS_CLOEXEC))
159 process_detach_fd(proc, i);
160 }
161
162 return 0;
163}
#define MOS_UNREACHABLE()
Definition assert.hpp:11
#define MOS_STACK_PAGES_USER
Definition autoconf.h:29
#define MOS_PROCESS_MAX_OPEN_FILES
Definition autoconf.h:26
#define MOS_ADDR_USER_STACK
Definition autoconf.h:1
#define MOS_PAGE_SIZE
Definition autoconf.h:6
PtrResult< vmap_t > cow_allocate_zeroed_pages(MMContext *handle, size_t npages, ptr_t vaddr, valloc_flags hints, vm_flags flags)
Allocate zero-on-demand pages at a specific address.
Definition cow.cpp:81
__nodiscard bool elf_read_and_verify_executable(file_t *file, elf_header_t *header)
Definition elf.cpp:351
__nodiscard bool elf_do_fill_process(Process *proc, file_t *file, elf_header_t elf, elf_startup_info_t *info)
Definition elf.cpp:243
long process_do_execveat(fd_t dirfd, const char *path, const char *const argv[], const char *const envp[], int flags)
Definition execve.cpp:18
@ FD_FLAGS_CLOEXEC
Definition fs_types.h:49
open_flags
Definition fs_types.h:26
@ OPEN_READ
Definition fs_types.h:28
@ OPEN_EXECUTE
Definition fs_types.h:30
MOSAPI void stack_init(downwards_stack_t *stack, void *mem_region_bottom, size_t size)
Definition stack.cpp:8
long signal_send_to_thread(Thread *target, signal_t signal)
Send a signal to a thread.
Definition signal.cpp:87
MOSAPI char * strdup(const char *src)
#define list_foreach(t, v, h)
Iterate over a list.
Definition list.hpp:89
void vmap_finalise_init(vmap_t *vmap, vmap_content_t content, vmap_type_t type)
Finalize the initialization of a vmap object.
Definition mm.cpp:250
void vmap_destroy(vmap_t *vmap)
Destroy a vmap object, and unmmap the region.
Definition mm.cpp:164
@ VMAP_TYPE_PRIVATE
Definition mm.hpp:32
@ VMAP_STACK
Definition mm.hpp:24
@ VALLOC_DEFAULT
Default allocation flags.
Definition paging.hpp:21
@ THREAD_MODE_USER
PtrResult< file_t > vfs_openat(int fd, const char *path, open_flags flags)
Open a file at a given path.
Definition vfs.cpp:581
io_t * io_ref(io_t *io)
Definition io.cpp:74
__nodiscard bool io_valid(const io_t *io)
Definition io.cpp:128
io_t * io_unref(io_t *io)
Definition io.cpp:93
const char ** argv
Definition kmain.cpp:34
size_t argc
Definition kmain.cpp:33
#define MOS_UNUSED(x)
Definition mos_global.h:65
#define unlikely(x)
Definition mos_global.h:40
#define NULL
Definition pb_syshdr.h:46
#define current_thread
Definition platform.hpp:32
@ VM_USER_RW
Definition platform.hpp:57
#define current_process
Definition platform.hpp:33
#define pr_warn(fmt,...)
Definition printk.hpp:38
#define pr_emerg(fmt,...)
Definition printk.hpp:39
void process_exit(Process *&&proc, u8 exit_code, signal_t signal)
Definition process.cpp:284
bool process_detach_fd(Process *process, fd_t fd)
Definition process.cpp:201
void platform_context_cleanup(Thread *thread)
#define memzero(ptr, size)
#define spinlock_acquire(lock)
Definition spinlock.hpp:64
#define spinlock_release(lock)
Definition spinlock.hpp:65
Definition mm.hpp:59
void thread_destroy(Thread *thread)
Definition thread.cpp:52
bool thread_wait_for_tid(tid_t tid)
Definition thread.cpp:189
s32 fd_t
Definition types.h:77