1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:48:12 +00:00

Kernel: Activate SUID/SGID credentials earlier in sys$execve()

Switch on the new credentials before loading the new executable into
memory. This ensures that attempts to ptrace() the program from an
unprivileged process will fail.

This covers one bug that was exploited in the 2020 HXP CTF:
https://hxp.io/blog/79/hxp-CTF-2020-wisdom2/

Thanks to yyyyyyy for finding the bug! :^)
This commit is contained in:
Andreas Kling 2020-12-20 18:35:29 +01:00
parent 5505159a94
commit 9bf02c32c0

View file

@ -237,12 +237,42 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
dbg() << "Process " << pid().value() << " exec: PD=" << m_page_directory.ptr() << " created";
#endif
// NOTE: We switch credentials before altering the memory layout of the process.
// This ensures that ptrace access control takes the right credentials into account.
// FIXME: This still feels rickety. Perhaps it would be better to simply block ptrace
// clients until we're ready to be traced? Or reject them with EPERM?
auto main_program_metadata = main_program_description->metadata();
auto old_euid = m_euid;
auto old_suid = m_suid;
auto old_egid = m_egid;
auto old_sgid = m_sgid;
ArmedScopeGuard cred_restore_guard = [&] {
m_euid = old_euid;
m_suid = old_suid;
m_egid = old_egid;
m_sgid = old_sgid;
};
if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) {
if (main_program_metadata.is_setuid())
m_euid = m_suid = main_program_metadata.uid;
if (main_program_metadata.is_setgid())
m_egid = m_sgid = main_program_metadata.gid;
}
int load_rc = load(main_program_description, interpreter_description);
if (load_rc) {
klog() << "do_exec: Failed to load main program or interpreter";
return load_rc;
}
// We can commit to the new credentials at this point.
cred_restore_guard.disarm();
kill_threads_except_self();
#ifdef EXEC_DEBUG
@ -257,15 +287,6 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
m_veil_state = VeilState::None;
m_unveiled_paths.clear();
auto main_program_metadata = main_program_description->metadata();
if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) {
if (main_program_metadata.is_setuid())
m_euid = m_suid = main_program_metadata.uid;
if (main_program_metadata.is_setgid())
m_egid = m_sgid = main_program_metadata.gid;
}
current_thread->set_default_signal_dispositions();
current_thread->clear_signals();