LibC: Move stack canary initialization before the global constructors

Once again, QEMU creates threads while running its constructors, which
is a recipe for disaster if we switch out the stack guard while that is
already running in the background.

To solve that, move initialization to our LibC initialization stage,
which is before any actual external initialization code runs.
This commit is contained in:
Tim Schumacher 2022-06-30 11:31:56 +02:00 committed by Brian Gianforcaro
parent cf0ad3715e
commit b9f7966e00
2 changed files with 6 additions and 16 deletions

View file

@ -32,17 +32,6 @@ NAKED void _start(int, char**, char**)
int _entry(int argc, char** argv, char** env)
{
size_t original_stack_chk = __stack_chk_guard;
// We can't directly overwrite __stack_chk_guard using arc4random_buf,
// as it doesn't know that the stack canary changed and it would instantly
// cause a stack protector failure when returning.
size_t new_stack_chk = 0;
arc4random_buf(&new_stack_chk, sizeof(new_stack_chk));
if (new_stack_chk != 0)
__stack_chk_guard = new_stack_chk;
environ = env;
__environ_is_malloced = false;
__begin_atexit_locking();
@ -55,11 +44,6 @@ int _entry(int argc, char** argv, char** env)
exit(status);
// We should never get here, but if we ever do, make sure to
// restore the stack guard to the value we entered _start with.
// Then we won't trigger the stack canary check on the way out.
__stack_chk_guard = original_stack_chk;
return 20150614;
}
}

View file

@ -259,6 +259,12 @@ static void initialize_libc(DynamicObject& libc)
VERIFY(res.has_value());
*((char***)res.value().address.as_ptr()) = s_envp;
// __stack_chk_guard should be initialized before anything significant (read: global constructors) is running.
// This is not done in __libc_init, as we definitely have to return from that, and it might affect Loader as well.
res = libc.lookup_symbol("__stack_chk_guard"sv);
VERIFY(res.has_value());
arc4random_buf(res.value().address.as_ptr(), sizeof(size_t));
res = libc.lookup_symbol("__environ_is_malloced"sv);
VERIFY(res.has_value());
*((bool*)res.value().address.as_ptr()) = false;