mirror of
https://github.com/RhapsodiOS/RhapsodiOS.git
synced 2026-11-03 22:01:40 -07:00
[GH-ISSUE #73] kernel: i386 trap.c turns a kernel page fault on a user address into an endless, unkillable loop #65
Labels
No labels
bug
documentation
enhancement
enhancement
good first issue
help wanted
help wanted
pull-request
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
github-starred/RhapsodiOS#65
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @raynorpat on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/73
Symptom
A kernel-mode page fault at an address below
KERNEL_LINEAR_BASE(for example a NULL or garbage pointer dereference inside a system call) never panics. The thread loops forever taking the same fault; the process leavesallprocon exit (P_WEXIT) sopscannot see it, and it can't be killed. In #67 a bad socket pointer insosendproduced exactly this, and the stress watchdog was the only sign.Cause
machdep/i386/trap.c~243-270,T_PAGE_FAULTfrom kernel mode: whenvm_faulton the user map fails andkernel_try_recoverfinds no recovery point (no copyin/copyout in progress), the code assumes the fault came from returning to user mode with a bad LDT entry. It callskernel_recover_threadandexception_from_kernel, thenthread_exception_return, which re-runs the kernel instruction that faulted.Fix direction
Take that path only for the case it was written for (the fault is on the return-to-user path / segment load, which the code can recognise from the faulting EIP), and panic with the trap frame for any other kernel fault on a user address, as other kernel faults already do.
Found by the #67 investigation.
@raynorpat commented on GitHub (Oct 20, 2026):
Fixed by
1978123ac, merged into ffs-perf inf5d9d290f.What the branch was for. The kernel page-fault path that sends the thread back to user mode exists for one case only:
RETURNinlocore.sreloading user segment registers (popl %gs/%fs/%es/%ds … iret) from a private LDT that lives in user memory. That code runs from__return_with_stateand from the user-mode return ofinterrupt, with the stack inside the thread's save area, which is whatkernel_recover_threadrelies on.Fix. A new
on_user_return(state)is TRUE only when the trap frame's stack pointer is inside the user save area, betweenregs.gsandframe.eip. The recovery runs only then; any other kernel fault on a user address goes to the existing "unexpected kernel trap" path (kdp_raise_exceptionorpanic).Verified on the base kernel (#67 fix, cksum 606865771) and the fixed kernel (cksum 1518819907):
fdfreeduring exit gives the endless loop: the process vanishes fromps, its parent never returns, and the load average stays near 2. The same injection ingetpgrpturned into a user SIGSEGV._fdfree+0xc/_getpgrp+9) in the kernel debugger.%fsfrom a private LDT in a page it then deallocates faults at__return_with_state+0x12(popl %fs) and dies with SIGSEGV on both kernels.check-vm,check-proc,check-misc,check-threadpass;soak -t 600 -j 4has 0 failures.Left open: the general-protection / segment-not-present / stack-fault branch for
ERR_LDTerrors doesn't check that it came from the return to user mode either.