isolation M1: ring 3 + a real /sbin/init, end to end
Ring 3 works: user GDT descriptors (sysret-ready layout), TSS.rsp0, U/S-bit user mappings (W^X preserved), an int 0x80 syscall gate with a mutable trap frame, and a setjmp-style enter/exit path. /sbin/init is a real freestanding Zig binary built from sbin/, shipped on the ESP, loaded by the bootloader (BootInfo.init_base/len), validated and mapped by an in-kernel user-ELF loader, and run at CPL 3 — syscalls: exit, ping, write. Tests: user, user-pf (U/S isolation proof, error code 0x5), init. Suite 27/27. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7501bd1703
commit
546dd44a2a
@@ -57,6 +57,8 @@ ARCHES = {
|
||||
],
|
||||
"efi_app": ("EFI/BOOT/BOOTX64.efi", "BOOTX64.efi"), # (dest in ESP, name in zig-out/bin)
|
||||
"kernel": ("kernel", "kernel"),
|
||||
# Further files shipped on the ESP: the init user program.
|
||||
"extra": [("sbin/init", "init")],
|
||||
# Built as a function so we can splice in per-run paths.
|
||||
"qemu_args": lambda a, esp, vars_fd, serial: [
|
||||
"-machine", "q35", "-m", "128M",
|
||||
@@ -148,6 +150,21 @@ CASES = [
|
||||
"expect": r"page fault \(vector 14\)",
|
||||
"fail": r"NX not enforced"},
|
||||
{"name": "fault-null", "expect": r"page fault \(vector 14\)"},
|
||||
# Ring 3: a user program runs at CPL 3, makes int 0x80 syscalls, survives
|
||||
# timer interrupts, and exits back into the kernel.
|
||||
{"name": "user",
|
||||
"expect": r"DANOS-TEST-RESULT: PASS",
|
||||
"fail": r"DANOS-TEST-RESULT: FAIL"},
|
||||
# Isolation: a ring-3 read of a kernel-only page must #PF with error code
|
||||
# 0x5 (present|user) at the user RIP. ([\s\S] spans lines; `.` doesn't.)
|
||||
{"name": "user-pf",
|
||||
"expect": r"page fault \(vector 14\)[\s\S]*error code : 0x5[\s\S]*RIP\s*: 0x00007000000000",
|
||||
"fail": r"DANOS-TEST-RESULT: FAIL"},
|
||||
# The real user binary: the bootloader ships sbin/init off the ESP, the
|
||||
# kernel loads the ELF and runs it in ring 3, and it writes + exits cleanly.
|
||||
{"name": "init",
|
||||
"expect": r"DANOS-TEST-RESULT: PASS",
|
||||
"fail": r"DANOS-TEST-RESULT: FAIL"},
|
||||
# The ACPI power path succeeds by QEMU *exiting* (S5 off / reset), so match the
|
||||
# pre-transition marker; the FAIL line only appears if the transition didn't take.
|
||||
{"name": "poweroff",
|
||||
@@ -179,6 +196,9 @@ def make_esp(arch):
|
||||
os.makedirs(os.path.join(esp, os.path.dirname(efi_dest)), exist_ok=True)
|
||||
shutil.copy(os.path.join(REPO, "zig-out", "bin", efi_name), os.path.join(esp, efi_dest))
|
||||
shutil.copy(os.path.join(REPO, "zig-out", "bin", kern_name), os.path.join(esp, kern_dest))
|
||||
for dest, name in arch.get("extra", []):
|
||||
os.makedirs(os.path.join(esp, os.path.dirname(dest)), exist_ok=True)
|
||||
shutil.copy(os.path.join(REPO, "zig-out", "bin", name), os.path.join(esp, dest))
|
||||
return esp
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user