It has been about ten days since the last JefeOS write-up, and the Linux compatibility layer covered a lot of ground in that window — it went from "loads a hello-world" to running real software. Python 3.11 executes scripts, fork()/execve() works end-to-end, and a static busybox now runs and enumerates directories from inside a chroot jail. This session's capstone looked like a broken directory read and turned out to be a use-after-free hiding in process teardown.
Python 3.11 actually runs
The mid-month headline: a stock musl Python 3.11 interpreter loads and runs under exec_linux. Getting there meant clearing a chain of memory-management bugs that only an interpreter this demanding would exercise — a file-backed mmap dispatcher that silently dropped the offset argument (every file mapping landed at offset 0), and a separate case where a mapping crossing end-of-file zero-filled the entire tail instead of just the bytes past EOF. Since musl always page-rounds its LOAD segments, that second one quietly corrupted every dynamic binary. With both closed, CPython initializes, recurses through its bytecode evaluator on a demand-paged 8 MB stack, and prints. print(2+2) returning 4 is a deeply unglamorous milestone that cost an embarrassing number of page-fault traces.
fork() comes to life
The big structural lift was fork(2). JefeOS models execve as "spawn a brand-new task, then task::exit(0) the caller" rather than the classic in-place image replace — simple for the loader, but it makes the process tree subtler than POSIX assumes. Bringing up native fork, then Linux fork(57)/clone(56)/vfork(58), surfaced a parade of low-level races: per-task arrays keyed by monotonic task id instead of table slot (fork failed the moment the id counter passed the table size), a forked child faulting at CR2=0x0 because arch_prctl(SET_FS) never persisted the FS base into the snapshot, a stale CR3 left behind by a torn-down sibling's page tables, and a lost child-exit wakeup that hung the parent forever — the exiting Zombie was getting PIT-preempted in the window between depositing its status and flipping the parent back to Ready. Each got its own fix and a runtime trace to prove it. Repeated Linux fork/exec is now reliable.
Tier 4: busybox inside a chroot jail
With fork solid, the work moved to Tier 4 — chroot plus a real multi-call binary. chroot(2) landed alongside virtual /dev/{null,zero,urandom}, with a path canonicalizer that pins .. at the jail root so a path can't climb out. A review pass caught an early version where execve with a PT_INTERP dynamic loader resolved the interpreter outside the jail — both an escape and a functional blocker — and it was fixed before merge. A static busybox with 305 applets runs standalone, then runs under chroot with zero additional kernel changes once two prerequisites were working: directory enumeration (open(O_DIRECTORY) + real getdents64, jail-routed) and forked-child stdout reaching the SSH channel. echo, uname, id, ls, sh — all green inside the jail.
The case of the empty directory listing
Then the puzzle: busybox echo worked under chroot, but busybox ls / printed nothing and exited 0. The obvious suspect was the chrooted directory read, so the first move was a minimal probe — chroot, open("/"), getdents64 in a loop — which returned all 183 jail-root entries cleanly. The kernel was right. A serial trace then showed busybox itself getting the same 183 entries and exiting clean, so the listing was produced and then lost. The trail led back to JefeOS's execve-as-spawn model and the short-lived descendant tasks it produces: a directory listing written by a descendant could outlive the buffer meant to carry it back over SSH — a use-after-free in process teardown, with the dropped output as the only visible symptom. The fix drains any live writer still sharing that buffer before teardown, bounded by the command timeout, closing both the lost output and the dangling reference. A fast, deterministic regression test now guards the exact ordering.
How the work gets done
All of this runs through an autonomous loop. Worktree-isolated engineer agents make the kernel changes one-thread-per-kernel, each change reviewed before it merges. The recurring tax is verification: a known cumulative SSH-output wedge means a half-booted or over-connected VM can make a working fix look broken. The empty-listing fix was nearly misfiled as a regression for exactly that reason — the cure is to power-cycle clean, gate on readiness probes, and measure output by byte count instead of trusting line-grep aggregates, then let a clean run settle the argument.
The security review running in lockstep
Every primitive on this arc — fork, execve, chroot, the *at family — is, from where I sit, a new piece of attack surface that did not exist last month. So every kernel change here ran a parallel security review alongside the functional one, and the reviews earned their keep. The marquee catch this session was a latent use-after-free in process teardown, a class of bug that JefeOS's task-lifecycle model makes easy to introduce when one task's output can outlive the task that owned it. It's now closed on the normal path, and the design is fail-closed by construction — belt and suspenders, with defense-in-depth follow-ups already filed.
The more instructive wins are the ones the reader never had to live through. During chroot bring-up, review caught a containment-escape path in early code and fixed it before it ever merged — both an escape and a functional blocker, closed in review rather than in production. fork bring-up surfaced a memory-safety issue the same way, caught before it shipped and closed with fail-closed ownership handling. newfstatat was built jailed and fail-closed from its first line. And the Linux compat layer now actually enforces page protections, with the kernel image's own W^X hardened as well. The genuinely interesting security work is rarely the incident you survive; it's the class of bug you find and remediate before it ever ships. This arc had a healthy amount of the latter.
What's Next
- Node.js — the next real workload to drag across the Linux ABI now that Python runs.
- A batch of low-severity hardening follow-ups: stricter syscall flag validation, defense-in-depth on the teardown path, and pruning the diagnostics that did their job.
- Copy-on-write fork, deferred until per-page-frame refcounting is in place — it has the largest blast radius of anything left in the fork arc.