From eb251af8672e033f29322253f136e09c76f2b0a3 Mon Sep 17 00:00:00 2001 From: Minep Date: Mon, 27 Jun 2022 01:24:40 +0100 Subject: [PATCH] fix: race condition and partial state issue on injecting signal context into user stack refactor: reduce the system timer frequency to 1024. refactor: make the kprintf re-entrance and reduce the buffer size. improve: better debugging experience with qemu. improve: more information when debugging with iret. --- lunaix-os/includes/lunaix/timer.h | 2 +- lunaix-os/kernel/asm/x86/interrupt.S | 1 + lunaix-os/kernel/kprintf.c | 14 ++++++-------- lunaix-os/kernel/sched.c | 3 ++- lunaix-os/kernel/signal.c | 25 ++++++++++++++++++++++++- lunaix-os/makefile | 4 ++-- 6 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lunaix-os/includes/lunaix/timer.h b/lunaix-os/includes/lunaix/timer.h index c02d7f6..b499f3f 100644 --- a/lunaix-os/includes/lunaix/timer.h +++ b/lunaix-os/includes/lunaix/timer.h @@ -4,7 +4,7 @@ #include #include -#define SYS_TIMER_FREQUENCY_HZ 2048 +#define SYS_TIMER_FREQUENCY_HZ 1024 #define TIMER_MODE_PERIODIC 0x1 diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index 8a43aa7..dc5c4c3 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -118,6 +118,7 @@ movl %eax, %esp #ifdef __ASM_INTR_DIAGNOSIS + movl %eax, (debug_resv + 8) movl 56(%esp), %eax movl %eax, (debug_resv + 4) #endif diff --git a/lunaix-os/kernel/kprintf.c b/lunaix-os/kernel/kprintf.c index 374fff2..75b9fc4 100644 --- a/lunaix-os/kernel/kprintf.c +++ b/lunaix-os/kernel/kprintf.c @@ -3,14 +3,13 @@ #include #include -#define MAX_KPRINTF_BUF_SIZE 1024 -#define MAX_XFMT_SIZE 1024 - -static char buf[MAX_KPRINTF_BUF_SIZE]; +#define MAX_KPRINTF_BUF_SIZE 512 +#define MAX_XFMT_SIZE 512 void __kprintf(const char* component, const char* fmt, va_list args) { + char buf[MAX_KPRINTF_BUF_SIZE]; if (!fmt) return; char log_level = '0'; @@ -74,16 +73,15 @@ __kprintf(const char* component, const char* fmt, va_list args) void kprint_panic(const char* fmt, ...) { + char buf[MAX_KPRINTF_BUF_SIZE]; va_list args; va_start(args, fmt); tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_RED); - tty_clear_line(10); - tty_clear_line(11); - tty_clear_line(12); + tty_clear_line(24); __sprintf_internal(buf, fmt, MAX_KPRINTF_BUF_SIZE, args); - tty_put_str_at(buf, 0, 11); + tty_put_str_at(buf, 0, 24); va_end(args); } \ No newline at end of file diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index 5081ccf..8e089d6 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -59,7 +59,8 @@ run(struct proc_info* proc) apic_done_servicing(); asm volatile("pushl %0\n" - "jmp switch_to\n" ::"r"(proc)); // kernel/asm/x86/interrupt.S + "jmp switch_to\n" ::"r"(proc) + : "memory"); // kernel/asm/x86/interrupt.S } int diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c index de83438..cb47e8d 100644 --- a/lunaix-os/kernel/signal.c +++ b/lunaix-os/kernel/signal.c @@ -22,6 +22,7 @@ void* default_handlers[_SIG_NUM] = { [_SIGINT] = default_sighandler_term, }; +volatile isr_param __temp_save; // Referenced in kernel/asm/x86/interrupt.S void* signal_dispatch() @@ -58,7 +59,29 @@ signal_dispatch() struct proc_sig* sig_ctx = (struct proc_sig*)(ustack - sizeof(struct proc_sig)); - sig_ctx->prev_context = __current->intr_ctx; + /* + 这是一个相当恶心的坑。 + 问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面 + 这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。 + + 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的 + 注入,而需要走page fault handler进行动态分页。 + + 竞态条件就出现在这里! + + 假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断, + 那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的 + 上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回, + 拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系 + (因为此时的intr_ctx已经不是之前的intr_ctx了!) + 而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时 + 触发#GP。 + + 解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。 + */ + __temp_save = __current->intr_ctx; + sig_ctx->prev_context = __temp_save; + sig_ctx->sig_num = sig_selected; sig_ctx->signal_handler = __current->sig_handler[sig_selected]; diff --git a/lunaix-os/makefile b/lunaix-os/makefile index 0666dc4..f1a6dce 100644 --- a/lunaix-os/makefile +++ b/lunaix-os/makefile @@ -51,13 +51,13 @@ clean: @sleep 2 run: $(BUILD_DIR)/$(OS_ISO) - @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & + @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) -d cpu_reset -monitor telnet::$(QEMU_MON_PORT),server,nowait & @sleep 1 @telnet 127.0.0.1 $(QEMU_MON_PORT) debug-qemu: all-debug @${TOOLCHAIN}/i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg - @qemu-system-i386 -m 1G -rtc base=utc -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & + @qemu-system-i386 -m 1G -rtc base=utc -d cpu_reset -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & @sleep 1 @$(QEMU_MON_TERM) -- telnet 127.0.0.1 $(QEMU_MON_PORT) @gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234" -- 2.27.0