commit - 9f442e154ffb1bf9c7bf317327fea00ee2d385e8
commit + 1e18d00d2fa0e623ef0d612616fcb6d01f2a2c10
blob - 5b24930828c6a570ce2dfcdf0c719d5c23630c1c
blob + 47890b492261bb487177b977cfe95e004065c75e
--- kernel/sched/task.c
+++ kernel/sched/task.c
#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 {
#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 {
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);
#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);
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)
#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
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);
}
/*