From ba734c8d6b384dae99ef1579268efe8dbb81d434 Mon Sep 17 00:00:00 2001 From: linfeng Date: Thu, 22 May 2025 08:52:32 +0800 Subject: [PATCH] fix: Fix stack related errors (#1167) * fix: Fix stack related errors Increase kernel stack to 32k. Add a stack overflow test. Remove manual placement of guard pages Signed-off-by: Godones * fix: update userstack comments Signed-off-by: Godones --------- Signed-off-by: Godones --- kernel/src/arch/x86_64/mm/fault.rs | 48 +++---- kernel/src/mm/ucontext.rs | 168 ++++++++++--------------- user/apps/test_stack/.gitignore | 1 + user/apps/test_stack/Makefile | 20 +++ user/apps/test_stack/main.c | 13 ++ user/dadk/config/test_stack_0_1_0.toml | 32 +++++ 6 files changed, 159 insertions(+), 123 deletions(-) create mode 100644 user/apps/test_stack/.gitignore create mode 100644 user/apps/test_stack/Makefile create mode 100644 user/apps/test_stack/main.c create mode 100644 user/dadk/config/test_stack_0_1_0.toml diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index e21535d8..3122508a 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -1,9 +1,8 @@ +use alloc::sync::Arc; use core::{ intrinsics::{likely, unlikely}, panic, }; - -use alloc::sync::Arc; use log::error; use x86::{bits64::rflags::RFlags, controlregs::Cr4}; @@ -229,27 +228,28 @@ impl X86_64MMArch { flags |= FaultFlags::FAULT_FLAG_INSTRUCTION; } + let send_segv = || { + let pid = ProcessManager::current_pid(); + let mut info = SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); + Signal::SIGSEGV + .send_signal_info(Some(&mut info), pid) + .expect("failed to send SIGSEGV to process"); + }; + let current_address_space: Arc = AddressSpace::current().unwrap(); let mut space_guard = current_address_space.write_irqsave(); let mut fault; loop { let vma = space_guard.mappings.find_nearest(address); - // let vma = space_guard.mappings.contains(address); - let vma = match vma { Some(vma) => vma, None => { log::error!( - "can not find nearest vma, error_code: {:#b}, address: {:#x}", + "can not find nearest vma, error_code: {:?}, address: {:#x}", error_code, address.data(), ); - let pid = ProcessManager::current_pid(); - let mut info = - SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); - Signal::SIGSEGV - .send_signal_info(Some(&mut info), pid) - .expect("failed to send SIGSEGV to process"); + send_segv(); return; } }; @@ -260,40 +260,46 @@ impl X86_64MMArch { if !region.contains(address) { if vm_flags.contains(VmFlags::VM_GROWSDOWN) { + if !space_guard.can_extend_stack(region.start() - address) { + // exceeds stack limit + log::error!( + "stack limit exceeded, error_code: {:?}, address: {:#x}", + error_code, + address.data(), + ); + send_segv(); + return; + } space_guard .extend_stack(region.start() - address) .unwrap_or_else(|_| { panic!( - "user stack extend failed, error_code: {:#b}, address: {:#x}", + "user stack extend failed, error_code: {:?}, address: {:#x}", error_code, address.data(), ) }); } else { log::error!( - "No mapped vma, error_code: {:#b}, address: {:#x}, flags: {:?}", + "No mapped vma, error_code: {:?}, address: {:#x}, flags: {:?}", error_code, address.data(), flags ); log::error!("fault rip: {:#x}", regs.rip); - let pid = ProcessManager::current_pid(); - let mut info = - SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); - Signal::SIGSEGV - .send_signal_info(Some(&mut info), pid) - .expect("failed to send SIGSEGV to process"); + send_segv(); return; } } if unlikely(Self::vma_access_error(vma.clone(), error_code)) { - panic!( - "vma access error, error_code: {:#b}, address: {:#x}", + log::error!( + "vma access error, error_code: {:?}, address: {:#x}", error_code, address.data(), ); + send_segv(); } let mapper = &mut space_guard.user_mapper.utable; let message = PageFaultMessage::new(vma.clone(), address, flags, mapper); diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 0524301d..a4a24331 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -206,21 +206,51 @@ impl InnerAddressSpace { return Ok(new_addr_space); } + /// Check if the stack can be extended + pub fn can_extend_stack(&self, bytes: usize) -> bool { + let bytes = page_align_up(bytes); + let stack = self.user_stack.as_ref().unwrap(); + let new_size = stack.mapped_size + bytes; + if new_size > stack.max_limit { + // Don't exceed the maximum stack size + return false; + } + return true; + } + /// 拓展用户栈 /// ## 参数 /// /// - `bytes`: 拓展大小 - #[allow(dead_code)] pub fn extend_stack(&mut self, mut bytes: usize) -> Result<(), SystemError> { - // debug!("extend user stack"); + // log::debug!("extend user stack"); + + // Layout + // -------------- high->sp + // | stack pages| + // |------------| + // | stack pages| + // |------------| + // | not mapped | + // -------------- low + let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC; let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN; let stack = self.user_stack.as_mut().unwrap(); bytes = page_align_up(bytes); stack.mapped_size += bytes; - let len = stack.stack_bottom - stack.mapped_size; - self.map_anonymous(len, bytes, prot_flags, map_flags, false, false)?; + // map new stack pages + let extend_stack_start = stack.stack_bottom - stack.mapped_size; + + self.map_anonymous( + extend_stack_start, + bytes, + prot_flags, + map_flags, + false, + false, + )?; return Ok(()); } @@ -1734,6 +1764,8 @@ pub struct UserStack { mapped_size: usize, /// 栈顶地址(这个值需要仔细确定!因为它可能不会实时与用户栈的真实栈顶保持一致!要小心!) current_sp: VirtAddr, + /// 用户自定义的栈大小限制 + max_limit: usize, } impl UserStack { @@ -1753,117 +1785,43 @@ impl UserStack { let stack_bottom = stack_bottom.unwrap_or(Self::DEFAULT_USER_STACK_BOTTOM); assert!(stack_bottom.check_aligned(MMArch::PAGE_SIZE)); - // 分配用户栈的保护页 - let guard_size = Self::GUARD_PAGES_NUM * MMArch::PAGE_SIZE; - let actual_stack_bottom = stack_bottom - guard_size; + // Layout + // -------------- high->sp + // | stack pages| + // |------------| + // | not mapped | + // -------------- low - let mut prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE; - let map_flags = MapFlags::MAP_PRIVATE - | MapFlags::MAP_ANONYMOUS - | MapFlags::MAP_FIXED_NOREPLACE - | MapFlags::MAP_GROWSDOWN; - // debug!( - // "map anonymous stack: {:?} {}", - // actual_stack_bottom, - // guard_size - // ); - vm.map_anonymous( - actual_stack_bottom, - guard_size, - prot_flags, - map_flags, - false, - false, - )?; - // test_buddy(); - // 设置保护页只读 - prot_flags.remove(ProtFlags::PROT_WRITE); - // debug!( - // "to mprotect stack guard pages: {:?} {}", - // actual_stack_bottom, - // guard_size - // ); - vm.mprotect( - VirtPageFrame::new(actual_stack_bottom), - PageFrameCount::new(Self::GUARD_PAGES_NUM), - prot_flags, - )?; - - // debug!( - // "mprotect stack guard pages done: {:?} {}", - // actual_stack_bottom, - // guard_size - // ); - - let mut user_stack = UserStack { - stack_bottom: actual_stack_bottom, - mapped_size: guard_size, - current_sp: actual_stack_bottom - guard_size, - }; - - // debug!("extend user stack: {:?} {}", stack_bottom, stack_size); - // 分配用户栈 - user_stack.initial_extend(vm, stack_size)?; - // debug!("user stack created: {:?} {}", stack_bottom, stack_size); - return Ok(user_stack); - } - - fn initial_extend( - &mut self, - vm: &mut InnerAddressSpace, - mut bytes: usize, - ) -> Result<(), SystemError> { let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC; let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN; - bytes = page_align_up(bytes); - self.mapped_size += bytes; + let stack_size = page_align_up(stack_size); + + // log::info!( + // "UserStack stack_range: {:#x} - {:#x}", + // stack_bottom.data() - stack_size, + // stack_bottom.data() + // ); vm.map_anonymous( - self.stack_bottom - self.mapped_size, - bytes, + stack_bottom - stack_size, + stack_size, prot_flags, map_flags, false, false, )?; - return Ok(()); - } + let max_limit = core::cmp::max(Self::DEFAULT_USER_STACK_SIZE, stack_size); - /// 扩展用户栈 - /// - /// ## 参数 - /// - /// - `vm` 用户地址空间结构体 - /// - `bytes` 要扩展的字节数 - /// - /// ## 返回值 - /// - /// - **Ok(())** 扩展成功 - /// - **Err(SystemError)** 扩展失败 - #[allow(dead_code)] - pub fn extend( - &mut self, - vm: &mut InnerAddressSpace, - mut bytes: usize, - ) -> Result<(), SystemError> { - let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC; - let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS; + let user_stack = UserStack { + stack_bottom, + mapped_size: stack_size, + current_sp: stack_bottom, + max_limit, + }; - bytes = page_align_up(bytes); - self.mapped_size += bytes; - - vm.map_anonymous( - self.stack_bottom - self.mapped_size, - bytes, - prot_flags, - map_flags, - false, - false, - )?; - - return Ok(()); + return Ok(user_stack); } /// 获取栈顶地址 @@ -1883,11 +1841,17 @@ impl UserStack { stack_bottom: self.stack_bottom, mapped_size: self.mapped_size, current_sp: self.current_sp, + max_limit: self.max_limit, }; } /// 获取当前用户栈的大小(不包括保护页) pub fn stack_size(&self) -> usize { - return self.mapped_size - Self::GUARD_PAGES_NUM * MMArch::PAGE_SIZE; + return self.mapped_size; + } + + /// 设置当前用户栈的最大大小 + pub fn set_max_limit(&mut self, max_limit: usize) { + self.max_limit = max_limit; } } diff --git a/user/apps/test_stack/.gitignore b/user/apps/test_stack/.gitignore new file mode 100644 index 00000000..a1c1e2e6 --- /dev/null +++ b/user/apps/test_stack/.gitignore @@ -0,0 +1 @@ +test_stack \ No newline at end of file diff --git a/user/apps/test_stack/Makefile b/user/apps/test_stack/Makefile new file mode 100644 index 00000000..349124d1 --- /dev/null +++ b/user/apps/test_stack/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -static -o test_stack main.c + +.PHONY: install clean +install: all + mv test_stack $(DADK_CURRENT_BUILD_DIR)/test_stack + +clean: + rm test_stack *.o + +fmt: diff --git a/user/apps/test_stack/main.c b/user/apps/test_stack/main.c new file mode 100644 index 00000000..8bbb6323 --- /dev/null +++ b/user/apps/test_stack/main.c @@ -0,0 +1,13 @@ +#include + +void overflow(int depth) { + char buffer[1024 * 1024]; // 占用一些栈空间 + printf("Recursion depth: %d\n", depth); + overflow(depth + 1); // 递归调用 +} + +int main() { + overflow(1); + printf("This line will not be printed due to stack overflow.\n"); + return 0; +} diff --git a/user/dadk/config/test_stack_0_1_0.toml b/user/dadk/config/test_stack_0_1_0.toml new file mode 100644 index 00000000..90ee57ed --- /dev/null +++ b/user/dadk/config/test_stack_0_1_0.toml @@ -0,0 +1,32 @@ +# 用户程序名称 +name = "test_stack" +# 版本号 +version = "0.1.0" +# 用户程序描述信息 +description = "test_stack" +# 目标架构 +target-arch = ["x86_64"] + +# 任务源 +[task-source] +# 构建类型 +type = "build-from-source" +# 构建来源 +source = "local" +# 路径或URL +source-path = "user/apps/test_stack" + +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" + +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" + +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make clean" \ No newline at end of file