Skip to content

Fix fork-shaped private-file mmap restore; record backing classes and advance apk runtime progress - #98

Merged
thanks-cohn merged 2 commits into
mainfrom
codex/execute-batch-32u-plan-with-repairs
Aug 16, 2026
Merged

Fix fork-shaped private-file mmap restore; record backing classes and advance apk runtime progress#98
thanks-cohn merged 2 commits into
mainfrom
codex/execute-batch-32u-plan-with-repairs

Conversation

@thanks-cohn

Copy link
Copy Markdown
Owner

Motivation

  • Repair the inherited PR fix: bound file-backed MAP_PRIVATE EOF/protection semantics and add private-file backing pool #97 fork/child-exec/parent-restore defect where private-file MAP_PRIVATE backing bytes, class, and allocation cursor were not preserved across child exec/reset, causing corrupted parent mappings.
  • Make the smallest general, bounded runtime changes required to identify and fix the first real /sbin/apk --version libcrypto ENOMEM and then iterate real QEMU apk pressure causally.
  • Preserve existing PREPARE→COMMIT, rollback, ownership, and W+X=0 guarantees while making the parent-restore invariant permanently testable.

Description

  • Add explicit backing identity and offsets to runtime mappings by introducing BackingClass and per-mapping backing_start, and new mapping operations: setLastBacking, replaceBackingRange, protectRange, mappingAt, and replaceBackingRange in bounded_runtime_mappings.zig.
  • Implement fork-private backing snapshot/restore helpers in bounded_fork_private_backing.zig, and wire snapshot/restore of the private-file pool and its cursor into the fork (clone) and parent restore (terminate) paths in freestanding_riscv64.zig.
  • Change file MAP_PRIVATE planner/map path to accept/prepare a backing_start and record private-file backing on commit, and add stage-labeled ENOMEM diagnostics via externalMmapNoMemory in linux_rv64_file_mmap.zig and caller sites.
  • Add ownership-aware mprotect handling and validate that protection changes only apply to pages owned by the process (image/interpreter/break/runtime mappings), preserving physical backing, rejecting W+X, and issuing SFENCE.VMA/FENCE.I in freestanding_riscv64.zig.
  • Improve namespace symlink resolution to handle relative final symlinks and parent-relative .. traversal with bounded buffers and traversal limits in bounded_namespace_lookup.zig.
  • Increase class-specific bounds and layout to match observed pressure: private_file_mapping_pages increased (2,048 → 3,072), prepared_table_pages increased, and caller-artifact linker transport relocated to avoid overlap.
  • Add focused tests that prove: snapshot/restore preserves private bytes and cursor, fixed replacement records private backing atomically, release/protect splits retain backing offsets, plan/prepare/map behavior for file-backed private pages, and mapping-table invariants.
  • Add compact, stage-specific runtime diagnostics for the mmap path (ZIGREF_MMAP_ENOMEM) and richer syscall trace context to help classify the first libcrypto ENOMEM and subsequent blockers.

Testing

  • Ran repository bootstrapping and doctor checks with python3 tools/query-reference.py agent bootstrap and python3 tools/query-reference.py agent doctor, which passed after creating the Python venv. (PASS)
  • Built and unit-tested the recipe: zig build test-recipe-run-hosted-morphic-runtime and zig build check --summary all, and executed python3 tools/developer-command.py validate-repository and PYTHONDONTWRITEBYTECODE=1 python3 tools/check-command-reference.py --check; these validation steps completed successfully. (PASS)
  • Performed the canonical real-pressure loop: built and installed the namespace-backed Morphic machine and exercised real QEMU runs under /sbin/apk --version, --help, and apk info. The working loop found and recorded stage-specific failures, implemented bounded repairs, and re-ran until progress. /sbin/apk --version succeeded (printed apk-tools 2.14.9, compiled for riscv64), --help was reached, and apk info was executed and advanced into dependency loads but then faulted in musl memset (PC ~0x4004df9a, store to 0x8), which is the single next causal blocker to fix. (apk version/help: PASS; apk info: progressed but not fully successful)
  • The Playable Alpine persistent-shell gate was re-proved under real QEMU and produced the expected interactive outputs (morphic, second, /, 3.22.0, /tmp, hello, hello, still-alive). (PASS)

Files changed: COMMANDS.md, recipes/run-hosted-morphic-runtime/freestanding-riscv64.ld, and multiple sources under recipes/run-hosted-morphic-runtime/src/ including bounded_fork_private_backing.zig, bounded_namespace_lookup.zig, bounded_runtime_mappings.zig, freestanding_riscv64.zig, and linux_rv64_file_mmap.zig, and the new report docs/reports/AGENTIC_SNOWBALL_BATCH_32U.md documenting causal progress and the next blocker.

Next action (evidence-backed): diagnose and repair the musl memset store-fault in the apk info run (store address 0x8 at PC 0x4004df9a), fix the smallest causal producer of that null-derived destination, then rerun the unchanged apk info and the multi-child restoration ladder immediately.


Codex Task

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 21c7225213

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

};
var page = address;
while (page < address + mapped_length) : (page += frames.PageSize) {
const leaf = batch26_builder.query(page) catch shutdown();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Back accessible mprotect transitions before querying absent leaves

When a supported MAP_FIXED | MAP_ANONYMOUS PROT_NONE reservation is later changed to readable or writable with mprotect, externalProcessOwnsPage accepts it via the runtime mapping table, but the reservation deliberately has no page-table leaf. This query therefore returns error.InvalidEntry and the catch shuts down the entire VM instead of allocating backing or returning an error to the guest. The same failure occurs when a backed mapping is changed to PROT_NONE and subsequently re-enabled.

AGENTS.md reference: AGENTS.md:L80-L84

Useful? React with 👍 / 👎.

while (page < page_count) : (page += 1) {
const virtual = address + page * frames.PageSize;
if (externalPageOccupied({}, virtual)) _ = batch26_builder.unmapPage(virtual, .page_4k) catch shutdown();
_ = batch26_builder.mapPage(virtual, @intFromPtr(&external_prepared_backing[external_next_backing + page]), .page_4k, .{ .read = true, .write = true, .user = true, .accessed = true, .dirty = true }) catch shutdown();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Roll back fixed anonymous mappings when page-table allocation fails

When the bounded page-table frame pool is exhausted during a supported fixed anonymous replacement, this catch shutdown() powers off the whole runtime without a diagnostic or Linux ENOMEM. The mapping table has already been reclassified and earlier pages may already have been installed, so this path also lacks the rollback used by the non-fixed anonymous mapping transaction; prepare/map should remain failure-atomic and return the syscall error instead.

AGENTS.md reference: AGENTS.md:L80-L84

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Holding merge on current head 21c722521308ad836a300921a80ebf61259afa34. The Batch 32U progress is substantial and CI is green, but two P1 correctness defects from review 4945289041 remain on this exact head and are visible in the current runtime code:

  1. Review comment 3790836052: mprotect on a runtime-owned PROT_NONE reservation can call batch26_builder.query(page) where no leaf exists, causing error.InvalidEntry to hit catch shutdown() instead of allocating/reusing backing or returning a Linux error. Re-enabling a mapping after PROT_NONE has the same problem.
  2. Review comment 3790836053: fixed anonymous replacement reclassifies the mapping table and begins installing pages, but page-table allocation failure still uses catch shutdown() with no rollback or Linux ENOMEM, violating PREPARE -> COMMIT/failure atomicity.

Please repair only these two general semantics on the existing PR branch, add focused regressions for PROT_NONE -> accessible mprotect and mid-map fixed-anonymous failure rollback, rerun the recipe/validation gates and Playable Alpine, then immediately rerun the real apk ladder. Preserve the earned /sbin/apk --version success and continue from the current apk info musl memset/store-to-0x8 frontier only after these correctness repairs are proven.

@thanks-cohn
thanks-cohn merged commit 2bbe272 into main Aug 16, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant