-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstackprotector.rs
More file actions
82 lines (77 loc) · 2.89 KB
/
Copy pathstackprotector.rs
File metadata and controls
82 lines (77 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! linux-parity: partial
//! linux-source: vendor/linux/kernel/panic.c
//! test-origin: linux:vendor/linux/lib/test_stackinit.c
//! GCC/Clang kernel stack-protector ABI for vendor-built modules.
use crate::kernel::module::{export_symbol, find_symbol};
use crate::log_error;
/// LLVM's global-guard ABI for the bare-metal Rust kernel.
///
/// The 64-bit boot entry randomizes this object before its first call into
/// stack-protected Rust. Vendor C modules use their separate Linux per-CPU
/// `%gs:__ref_stack_chk_guard` ABI and therefore remain byte-for-byte
/// unchanged.
#[unsafe(no_mangle)]
pub static mut __stack_chk_guard: usize = 0x6c75_706f_735f_7300;
pub fn register_module_exports() {
if find_symbol("__stack_chk_fail").is_none() {
export_symbol("__stack_chk_fail", __stack_chk_fail as usize, false);
}
if find_symbol("__stack_chk_guard").is_none() {
export_symbol(
"__stack_chk_guard",
core::ptr::addr_of!(__stack_chk_guard) as usize,
false,
);
}
if find_symbol("__ref_stack_chk_guard").is_none() {
export_symbol(
"__ref_stack_chk_guard",
crate::arch::x86::kernel::setup_percpu::stack_chk_guard_symbol(),
false,
);
}
}
/// Called by compiler-generated epilogues after a canary mismatch.
///
/// Keep this trampoline naked: the failing function's continuation is at the
/// original `[rsp]`, before any Rust prologue can move the stack. The regular
/// implementation below can then log that return PC without treating its own
/// frame as the failing caller's frame.
#[unsafe(naked)]
#[unsafe(export_name = "__stack_chk_fail")]
pub unsafe extern "C" fn __stack_chk_fail() -> ! {
core::arch::naked_asm!(
"mov rdi, [rsp]",
"jmp {impl}",
impl = sym stack_chk_fail_impl,
)
}
#[inline(never)]
extern "C" fn stack_chk_fail_impl(caller: usize) -> ! {
let sp: usize;
unsafe {
core::arch::asm!("mov {}, rsp", out(reg) sp, options(nomem, preserves_flags));
log_error!(
"stack-protector",
"stack-protector: canary caller={:#018x} rsp={:#018x}",
caller,
sp,
);
let current = crate::kernel::sched::get_current();
if !current.is_null() {
let stack_top = (*current).stack as usize;
let stack_bottom = stack_top.saturating_sub(crate::kernel::sched::KTHREAD_STACK_SIZE);
log_error!(
"stack-protector",
"stack-protector: task-stack=[{:#018x},{:#018x}) free-below-rsp={:#x}",
stack_bottom,
stack_top,
sp.saturating_sub(stack_bottom),
);
if (*current).comm.starts_with(b"pipewire") {
crate::arch::x86::kernel::switch::dump_pipewire_switch_diagnostics();
}
}
}
panic!("stack-protector: Kernel stack is corrupted")
}