Prechádzať zdrojové kódy

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 <chenlinfeng25@outlook.com>

* fix: update userstack comments

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

---------

Signed-off-by: Godones <chenlinfeng25@outlook.com>
linfeng 1 deň pred
rodič
commit
ba734c8d6b

+ 27 - 21
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> = 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);

+ 66 - 102
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(());
-    }
-
-    /// 扩展用户栈
-    ///
-    /// ## 参数
-    ///
-    /// - `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;
-
-        bytes = page_align_up(bytes);
-        self.mapped_size += bytes;
+        let max_limit = core::cmp::max(Self::DEFAULT_USER_STACK_SIZE, stack_size);
 
-        vm.map_anonymous(
-            self.stack_bottom - self.mapped_size,
-            bytes,
-            prot_flags,
-            map_flags,
-            false,
-            false,
-        )?;
+        let user_stack = UserStack {
+            stack_bottom,
+            mapped_size: stack_size,
+            current_sp: stack_bottom,
+            max_limit,
+        };
 
-        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;
     }
 }

+ 1 - 0
user/apps/test_stack/.gitignore

@@ -0,0 +1 @@
+test_stack

+ 20 - 0
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:

+ 13 - 0
user/apps/test_stack/main.c

@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+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;
+}

+ 32 - 0
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"