feat: debug kernel stack (#1176)

* feat: debug kernel stack

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* fix: Create guard pages for the kstack through remap

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* feat(arch/x86_64): 启用内核态写保护功能

添加enable_kernel_wp函数来设置CR0的WP位,防止内核错误写入只读页面

Signed-off-by: longjin <longjin@DragonOS.org>

* fix(x86_64/mm): 在内核地址错误处理中添加RIP寄存器信息

Signed-off-by: longjin <longjin@DragonOS.org>

* fix: Fixed the error introduced by enabling WP flag on x86

Restore accidentally deleted functions.

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* refactor: 移除kstack_protect默认特性并优化内存管理

- 从default特性中移除kstack_protect
- 为X86_64MMBootstrapInfo添加kernel_rodata_start字段
- 调整内核页标志对rodata区域的判断逻辑

Signed-off-by: longjin <longjin@DragonOS.org>

* fix(mm): 解决加载二进制文件到用户空间的时候,忘记关闭wp的问题

Signed-off-by: longjin <longjin@DragonOS.org>

* fix

Signed-off-by: longjin <longjin@DragonOS.org>

---------

Signed-off-by: Godones <chenlinfeng25@outlook.com>
Signed-off-by: longjin <longjin@DragonOS.org>
Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
linfeng
2025-06-14 20:42:58 +08:00
committed by GitHub
parent bb79f7fe3c
commit 799e573259
12 changed files with 293 additions and 72 deletions

View File

@ -137,6 +137,10 @@ impl MemoryManagementArch for LoongArch64MMArch {
fn make_entry(paddr: crate::mm::PhysAddr, page_flags: usize) -> usize {
todo!()
}
fn enable_kernel_wp() {}
fn disable_kernel_wp() {}
}
/// 获取内核地址默认的页面标志

View File

@ -284,6 +284,10 @@ impl MemoryManagementArch for RiscV64MMArch {
const PAGE_READONLY_EXEC: usize = 0;
const PROTECTION_MAP: [EntryFlags<MMArch>; 16] = protection_map();
fn enable_kernel_wp() {}
fn disable_kernel_wp() {}
}
const fn protection_map() -> [EntryFlags<MMArch>; 16] {

View File

@ -149,18 +149,37 @@ impl X86_64MMArch {
/// - `error_code`: 错误标志
/// - `address`: 发生缺页异常的虚拟地址
pub fn do_kern_addr_fault(
_regs: &'static TrapFrame,
regs: &'static TrapFrame,
error_code: X86PfErrorCode,
address: VirtAddr,
) {
unsafe { crate::debug::traceback::lookup_kallsyms(regs.rip, 0xff) };
let pcb = crate::process::ProcessManager::current_pcb();
let kstack_guard_addr = pcb.kernel_stack().guard_page_address();
if let Some(guard_page) = kstack_guard_addr {
let guard_page_size = pcb.kernel_stack().guard_page_size().unwrap();
if address.data() >= guard_page.data()
&& address.data() < guard_page.data() + guard_page_size
{
// 发生在内核栈保护页上
error!(
"kernel stack guard page fault at {:#x}, guard page range: {:#x} - {:#x}",
address.data(),
guard_page.data(),
guard_page.data() + guard_page_size
);
}
}
panic!(
"do_kern_addr_fault has not yet been implemented,
fault address: {:#x},
fault address: {:#x},
rip: {:#x},
error_code: {:#b},
pid: {}\n",
address.data(),
regs.rip,
error_code,
crate::process::ProcessManager::current_pid().data()
pcb.pid().data()
);
//TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#do_kern_addr_fault
}

View File

@ -42,12 +42,14 @@ static mut INITIAL_CR3_VALUE: PhysAddr = PhysAddr::new(0);
static INNER_ALLOCATOR: SpinLock<Option<BuddyAllocator<MMArch>>> = SpinLock::new(None);
#[allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub struct X86_64MMBootstrapInfo {
kernel_load_base_paddr: usize,
kernel_code_start: usize,
kernel_code_end: usize,
kernel_data_end: usize,
kernel_rodata_start: usize,
kernel_rodata_end: usize,
start_brk: usize,
}
@ -134,6 +136,7 @@ impl MemoryManagementArch for X86_64MMArch {
fn _text();
fn _etext();
fn _edata();
fn _rodata();
fn _erodata();
fn _end();
fn _default_kernel_load_base();
@ -146,6 +149,7 @@ impl MemoryManagementArch for X86_64MMArch {
kernel_code_start: _text as usize,
kernel_code_end: _etext as usize,
kernel_data_end: _edata as usize,
kernel_rodata_start: _rodata as usize,
kernel_rodata_end: _erodata as usize,
start_brk: _end as usize,
};
@ -158,15 +162,14 @@ impl MemoryManagementArch for X86_64MMArch {
boot_callbacks()
.early_init_memory_blocks()
.expect("init memory area failed");
debug!("bootstrap info: {:?}", unsafe { BOOTSTRAP_MM_INFO });
debug!("bootstrap info: {:#x?}", unsafe { BOOTSTRAP_MM_INFO });
debug!("phys[0]=virt[0x{:x}]", unsafe {
MMArch::phys_2_virt(PhysAddr::new(0)).unwrap().data()
});
// 初始化内存管理器
unsafe { allocator_init() };
Self::enable_kernel_wp();
send_to_default_serial8250_port("x86 64 mm init done\n\0".as_bytes());
}
@ -366,10 +369,35 @@ impl MemoryManagementArch for X86_64MMArch {
const PAGE_WRITE: usize = 0;
const PAGE_WRITE_EXEC: usize = 0;
const PAGE_EXEC: usize = 0;
/// 启用 内核态的 Write Protect
/// 这样即使在内核态CPU也会检查页面的写保护位
/// 防止内核错误地写入只读页面
fn enable_kernel_wp() {
unsafe {
use x86::controlregs::{cr0, cr0_write, Cr0};
let mut cr0_val = cr0();
cr0_val.insert(Cr0::CR0_WRITE_PROTECT);
cr0_write(cr0_val);
// log::debug!("CR0.WP bit enabled for kernel write protection");
}
}
/// 禁用 内核态的 Write Protect
fn disable_kernel_wp() {
unsafe {
use x86::controlregs::{cr0, cr0_write, Cr0};
let mut cr0_val = cr0();
cr0_val.remove(Cr0::CR0_WRITE_PROTECT);
cr0_write(cr0_val);
// log::debug!("CR0.WP bit disabled for kernel write protection");
}
}
}
/// 获取保护标志的映射表
///
/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/pgprot.c#8
///
/// ## 返回值
/// - `[usize; 16]`: 长度为16的映射表
@ -681,7 +709,7 @@ pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(virt: VirtAddr) -> Entr
if virt.data() >= info.kernel_code_start && virt.data() < info.kernel_code_end {
// Remap kernel code execute
return EntryFlags::new().set_execute(true).set_write(true);
} else if virt.data() >= info.kernel_data_end && virt.data() < info.kernel_rodata_end {
} else if virt.data() >= info.kernel_rodata_start && virt.data() < info.kernel_rodata_end {
// Remap kernel rodata read only
return EntryFlags::new().set_execute(true);
} else {