summaryrefslogtreecommitdiff
path: root/Kernel/Syscalls
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2021-06-28 17:42:29 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-28 22:29:28 +0200
commitd4c0d28035c1424b3c7680a7aadc907f3cdca59c (patch)
treefd66f6135618ca2d040e7a0d3875afe67ab430be /Kernel/Syscalls
parent158355e0d773d1121286bf7a51575b554be98806 (diff)
downloadserenity-d4c0d28035c1424b3c7680a7aadc907f3cdca59c.zip
Kernel: Properly set up the userland context for new processes on x86_64
Diffstat (limited to 'Kernel/Syscalls')
-rw-r--r--Kernel/Syscalls/execve.cpp66
1 files changed, 37 insertions, 29 deletions
diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp
index 9f27bfaf83..1be665b3ed 100644
--- a/Kernel/Syscalls/execve.cpp
+++ b/Kernel/Syscalls/execve.cpp
@@ -69,49 +69,50 @@ static bool validate_stack_size(const Vector<String>& arguments, const Vector<St
return true;
}
-static KResultOr<FlatPtr> make_userspace_stack_for_main_thread(Region& region, Vector<String> arguments, Vector<String> environment, Vector<ELF::AuxiliaryValue> auxiliary_values)
+static KResultOr<FlatPtr> make_userspace_context_for_main_thread([[maybe_unused]] ThreadRegisters& regs, Region& region, Vector<String> arguments,
+ Vector<String> environment, Vector<ELF::AuxiliaryValue> auxiliary_values)
{
- FlatPtr new_esp = region.range().end().get();
+ FlatPtr new_sp = region.range().end().get();
// Add some bits of randomness to the user stack pointer.
- new_esp -= round_up_to_power_of_two(get_fast_random<u32>() % 4096, 16);
+ new_sp -= round_up_to_power_of_two(get_fast_random<u32>() % 4096, 16);
- auto push_on_new_stack = [&new_esp](u32 value) {
- new_esp -= 4;
- Userspace<u32*> stack_ptr = new_esp;
+ auto push_on_new_stack = [&new_sp](FlatPtr value) {
+ new_sp -= sizeof(FlatPtr);
+ Userspace<FlatPtr*> stack_ptr = new_sp;
return copy_to_user(stack_ptr, &value);
};
- auto push_aux_value_on_new_stack = [&new_esp](auxv_t value) {
- new_esp -= sizeof(auxv_t);
- Userspace<auxv_t*> stack_ptr = new_esp;
+ auto push_aux_value_on_new_stack = [&new_sp](auxv_t value) {
+ new_sp -= sizeof(auxv_t);
+ Userspace<auxv_t*> stack_ptr = new_sp;
return copy_to_user(stack_ptr, &value);
};
- auto push_string_on_new_stack = [&new_esp](const String& string) {
- new_esp -= round_up_to_power_of_two(string.length() + 1, 4);
- Userspace<u32*> stack_ptr = new_esp;
+ auto push_string_on_new_stack = [&new_sp](const String& string) {
+ new_sp -= round_up_to_power_of_two(string.length() + 1, sizeof(FlatPtr));
+ Userspace<FlatPtr*> stack_ptr = new_sp;
return copy_to_user(stack_ptr, string.characters(), string.length() + 1);
};
Vector<FlatPtr> argv_entries;
for (auto& argument : arguments) {
push_string_on_new_stack(argument);
- if (!argv_entries.try_append(new_esp))
+ if (!argv_entries.try_append(new_sp))
return ENOMEM;
}
Vector<FlatPtr> env_entries;
for (auto& variable : environment) {
push_string_on_new_stack(variable);
- if (!env_entries.try_append(new_esp))
+ if (!env_entries.try_append(new_sp))
return ENOMEM;
}
for (auto& value : auxiliary_values) {
if (!value.optional_string.is_empty()) {
push_string_on_new_stack(value.optional_string);
- value.auxv.a_un.a_ptr = (void*)new_esp;
+ value.auxv.a_un.a_ptr = (void*)new_sp;
}
}
@@ -123,28 +124,35 @@ static KResultOr<FlatPtr> make_userspace_stack_for_main_thread(Region& region, V
push_on_new_stack(0);
for (ssize_t i = env_entries.size() - 1; i >= 0; --i)
push_on_new_stack(env_entries[i]);
- FlatPtr envp = new_esp;
+ FlatPtr envp = new_sp;
push_on_new_stack(0);
for (ssize_t i = argv_entries.size() - 1; i >= 0; --i)
push_on_new_stack(argv_entries[i]);
- FlatPtr argv = new_esp;
+ FlatPtr argv = new_sp;
// NOTE: The stack needs to be 16-byte aligned.
- new_esp -= new_esp % 16;
+ new_sp -= new_sp % 16;
+
+#if ARCH(I386)
// GCC assumes that the return address has been pushed to the stack when it enters the function,
// so we need to reserve an extra pointer's worth of bytes below this to make GCC's stack alignment
// calculations work
- new_esp -= sizeof(void*);
+ new_sp -= sizeof(void*);
- push_on_new_stack((FlatPtr)envp);
- push_on_new_stack((FlatPtr)argv);
- push_on_new_stack((FlatPtr)argv_entries.size());
- push_on_new_stack(0);
+ push_on_new_stack(envp);
+ push_on_new_stack(argv);
+ push_on_new_stack(argv_entries.size());
+#else
+ regs.rdi = argv;
+ regs.rsi = argv_entries.size();
+ regs.rdx = envp;
+#endif
+ push_on_new_stack(0); // return address
- VERIFY((new_esp + sizeof(void*)) % 16 == 0);
+ VERIFY((new_sp + sizeof(void*)) % 16 == 0);
- return new_esp;
+ return new_sp;
}
struct RequiredLoadRange {
@@ -596,10 +604,10 @@ KResult Process::do_exec(NonnullRefPtr<FileDescription> main_program_description
// NOTE: We create the new stack before disabling interrupts since it will zero-fault
// and we don't want to deal with faults after this point.
- auto make_stack_result = make_userspace_stack_for_main_thread(*load_result.stack_region.unsafe_ptr(), move(arguments), move(environment), move(auxv));
+ auto make_stack_result = make_userspace_context_for_main_thread(new_main_thread->regs(), *load_result.stack_region.unsafe_ptr(), move(arguments), move(environment), move(auxv));
if (make_stack_result.is_error())
return make_stack_result.error();
- FlatPtr new_userspace_esp = make_stack_result.value();
+ FlatPtr new_userspace_sp = make_stack_result.value();
if (wait_for_tracer_at_next_execve()) {
// Make sure we release the ptrace lock here or the tracer will block forever.
@@ -647,10 +655,10 @@ KResult Process::do_exec(NonnullRefPtr<FileDescription> main_program_description
regs.fs = GDT_SELECTOR_DATA3 | 3;
regs.gs = GDT_SELECTOR_TLS | 3;
regs.eip = load_result.entry_eip;
- regs.esp = new_userspace_esp;
+ regs.esp = new_userspace_sp;
#else
regs.rip = load_result.entry_eip;
- regs.rsp = new_userspace_esp;
+ regs.rsp = new_userspace_sp;
#endif
regs.cr3 = space().page_directory().cr3();