Commit Diff


commit - 9f442e154ffb1bf9c7bf317327fea00ee2d385e8
commit + 1e18d00d2fa0e623ef0d612616fcb6d01f2a2c10
blob - 5b24930828c6a570ce2dfcdf0c719d5c23630c1c
blob + 47890b492261bb487177b977cfe95e004065c75e
--- kernel/sched/task.c
+++ kernel/sched/task.c
@@ -50,7 +50,7 @@
 #include "arch/fpu.h"
 #include "sync/spinlock.h"
 
-#define SCHED_STACK_PAGES	4U
+#define SCHED_STACK_PAGES	16U
 #define SCHED_STACK_SIZE	(SCHED_STACK_PAGES * 4096U)
 
 enum sched_state {
@@ -139,6 +139,7 @@ static bool	__attribute__((unused)) name_equals(const 
 #if defined(LENIX_DEBUG_EXIT)
 /* Enable LENIX_DEBUG_EXIT_VERBOSE to re-enable noisy exit/wait logging. */
 #endif
+static bool	sched_ctx_valid_kernel_ret(const struct sched_task *task);
 
 #if defined(__x86_64__)
 struct switch_frame {
@@ -189,6 +190,11 @@ static struct sched_task *task_list_head;
 static void	sched_task_trampoline(void) __attribute__((noreturn));
 static void	sched_user_launch(void *) __attribute__((noreturn));
 static void	sched_idle(void *);
+static bool	addr_canonical(uint64_t addr);
+static bool	sched_ctx_valid_kernel_ret(const struct sched_task *task);
+static bool	sched_ctx_sp_in_range(const struct sched_task *task);
+static void	sched_ctx_dump(const struct sched_task *task, const char *tag);
+static bool	sched_current_sp_in_range(const struct sched_task *task);
 static void	sched_request_reschedule(uint32_t cpu);
 static void	sched_reschedule_ipi(uint32_t cpu, enum smp_ipi_reason reason);
 static uint32_t sched_pick_cpu(void);
@@ -202,6 +208,10 @@ static void	exit_status_clear_pid(uint64_t pid);
 #ifdef LENIX_DEBUG_EXIT
 static void	exit_status_table_dump(const char *tag);
 #endif
+#if defined(__x86_64__)
+extern char __kernel_text_start[];
+extern char __kernel_text_end[];
+#endif
 #ifdef LENIX_DEBUG_EXIT
 static void	debug_serial_write_u64(uint64_t v);
 static void	debug_serial_write_i64(int64_t v);
@@ -337,6 +347,124 @@ sched_stack_prepare(void *stack_mem)
 	return (uint64_t *)top;
 }
 
+static bool
+addr_canonical(uint64_t addr)
+{
+	uint64_t hi = addr >> 47;
+
+	return hi == 0 || hi == 0x1ffffULL;
+}
+
+static bool
+sched_ctx_valid_kernel_ret(const struct sched_task *task)
+{
+#if defined(__x86_64__)
+	uint64_t sp;
+	struct switch_frame *frame;
+	uint64_t ret;
+	uint64_t text_lo = (uint64_t)(uintptr_t)__kernel_text_start;
+	uint64_t text_hi = (uint64_t)(uintptr_t)__kernel_text_end;
+
+	if (task == NULL || task->ctx.sp == NULL)
+		return true;
+	sp = (uint64_t)(uintptr_t)task->ctx.sp;
+	if (!addr_canonical(sp))
+		return false;
+	frame = (struct switch_frame *)task->ctx.sp;
+	ret = frame->ret;
+	if (!addr_canonical(ret))
+		return false;
+	if (ret < text_lo || ret >= text_hi)
+		return false;
+	return true;
+#else
+	(void)task;
+	return true;
+#endif
+}
+
+static bool
+sched_ctx_sp_in_range(const struct sched_task *task)
+{
+	uint64_t sp;
+	uint64_t base;
+	uint64_t limit;
+
+	if (task == NULL || task->stack_base == NULL || task->ctx.sp == NULL)
+		return true;
+	base = (uint64_t)(uintptr_t)task->stack_base;
+	limit = base + SCHED_STACK_SIZE;
+	sp = (uint64_t)(uintptr_t)task->ctx.sp;
+	if (!addr_canonical(sp))
+		return false;
+	return (sp >= base) && (sp <= limit);
+}
+
+static bool
+sched_current_sp_in_range(const struct sched_task *task)
+{
+	uint64_t rsp;
+	uint64_t base;
+	uint64_t limit;
+
+	if (task == NULL || task->stack_base == NULL)
+		return true;
+	__asm__ __volatile__("mov %%rsp, %0" : "=r"(rsp));
+	if (!addr_canonical(rsp))
+		return false;
+	base = (uint64_t)(uintptr_t)task->stack_base;
+	limit = base + SCHED_STACK_SIZE;
+	return (rsp >= base) && (rsp <= limit);
+}
+
+static void
+sched_ctx_dump(const struct sched_task *task, const char *tag)
+{
+	printk("  ctx_dump ");
+	if (tag != NULL)
+		printk(tag);
+	printk("\n");
+	if (task == NULL) {
+		printk("    task=NULL\n");
+		return;
+	}
+	printk("    task=");
+	trap_print_hex64("", (uint64_t)(uintptr_t)task);
+	printk(" id=");
+	trap_print_hex64("", sched_task_id(task));
+	printk(" name=");
+	if (task->name != NULL)
+		printk(task->name);
+	else
+		printk("(none)");
+	printk("\n");
+	printk("    kstack base=");
+	trap_print_hex64("", (uint64_t)(uintptr_t)task->stack_base);
+	printk(" sp=");
+	trap_print_hex64("", (uint64_t)(uintptr_t)task->ctx.sp);
+	printk(" size=");
+	trap_print_hex64("", (uint64_t)SCHED_STACK_SIZE);
+#if defined(__x86_64__)
+	if (task->stack_base != NULL && task->ctx.sp != NULL) {
+		uint64_t base = (uint64_t)(uintptr_t)task->stack_base;
+		uint64_t top = base + SCHED_STACK_SIZE;
+		uint64_t sp = (uint64_t)(uintptr_t)task->ctx.sp;
+		printk(" sp_offset=");
+		if (sp >= base && sp <= top)
+			trap_print_hex64("", sp - base);
+		else if (sp < base)
+			trap_print_hex64(" -", base - sp);
+		else
+			printk("above");
+	}
+	if (task->ctx.sp != NULL) {
+		struct switch_frame *f = (struct switch_frame *)task->ctx.sp;
+		trap_print_hex64(" ret=", f->ret);
+	}
+#endif
+	printk("\n");
+}
+
 /* sched_enqueue - append @task to the run queue if it is not the idle thread. */
 static void
 sched_enqueue(struct sched_cpu_state *state, struct sched_task *task)
@@ -516,6 +644,15 @@ sched_switch(bool requeue_prev)
 #endif
 	prev->state = (prev->is_idle) ? SCHED_STATE_RUNNING : prev->state;
 	arch_fpu_save(&prev->ctx);
+	if (!sched_ctx_sp_in_range(next) || !sched_ctx_valid_kernel_ret(next)) {
+		printk("[sched] FATAL: next context invalid (sp/ret)\n");
+		sched_ctx_dump(next, "next");
+		panic("sched_switch invalid ctx");
+	}
+	if (!sched_current_sp_in_range(prev)) {
+		printk("[sched] WARN: current stack pointer out of range\n");
+		sched_ctx_dump(prev, "current");
+	}
 	arch_fpu_restore(&next->ctx);
 	arch_switch_context(&prev->ctx, &next->ctx);
 }
blob - dbfad6f1bbf8ba403824ac4c1dff6e3309e13c96
blob + 005090e453a921b37ccd862f12c01917bc1db58b
--- kernel/sys/syscall.c
+++ kernel/sys/syscall.c
@@ -614,8 +614,22 @@ syscall_memset(void *dst, uint8_t value, size_t len)
 static void
 sys_fd_table_destroy(void *ptr)
 {
-	if (ptr != NULL)
-		kmem_free(ptr);
+	struct sys_fd_table *table = (struct sys_fd_table *)ptr;
+
+	if (table == NULL)
+		return;
+
+	/* Close any lingering VFS handles so servers can release resources. */
+	for (int fd = 0; fd < SYS_MAX_FDS; fd++) {
+		if (!table->entries[fd].in_use)
+			continue;
+		if (table->entries[fd].vfs_handle != 0)
+			(void)sys_vfs_handle_close(table->entries[fd].vfs_handle);
+		table->entries[fd].in_use = false;
+		table->entries[fd].vfs_handle = 0;
+	}
+
+	kmem_free(table);
 }
 
 /*