Skip to content

shell: the process sandbox closes the OctoSense home and the kernel's core dir last (G6) [skip ci] - #156

Merged
ymote merged 1 commit into
mainfrom
fix/g6-sandbox-octosense-home
Sep 29, 2026
Merged

ymote merged 1 commit into
mainfrom
fix/g6-sandbox-octosense-home

Conversation

@ymote

@ymote ymote commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

ADR 0004 gap review, G6 (medium). Follows #155 (G4).

The Terminal's macOS profile emitted home:rw after everything else, and nothing closed the OctoSense home again. A process app with a broad grant could read:

  • peer host tokens (app-peers/*.token);
  • every app's jail and secrets/<id>/ files;
  • the kernel's data.

What changed

  • Policy::private. The host's private directories:

    • the OctoSense home;
    • the apps and secrets roots (they may live elsewhere);
    • the kernel's core dir, and the kernel home around a .octos core dir.

    clients::sandbox_policy sets it for every process app.

  • macOS. After every grant, a final (deny file-read* file-write* ...) on those directories. Then only the app's own jail and secrets are opened again, with the metadata of their ancestors.

  • Linux (Landlock). Landlock cannot deny beneath an allowed directory, so a grant that contains a private directory is split. Each entry is granted on its own, recursing only toward the private directories, which get nothing. A link into one gets nothing either. The own jail and secrets are granted by themselves.

    • Documented limits: entries created later directly in a split directory (a new file in ~) are not covered, and the directories on the way cannot be listed.
    • Not run here: the dev machine is macOS, and a Linux cross-check needs a C cross toolchain it lacks. The Landlock split has a unit test that runs on Linux only.

Tests

  • home_rw_never_reaches_the_octosense_home_or_the_kernel, a real sandboxed child (as in ADR 0004: the peer link for process apps, process sandboxes, Restart tile for dead process apps [skip ci] #130). The child has home:rw over a scratch home that also holds the OctoSense home and the kernel home.
    • It reads the person's files and its own jail and secrets.
    • It is refused the peer token, another app's jail and secrets, the shell's settings, the kernel's core dir and kernel home, and writing into the OctoSense home. It cannot list other apps' jails.
  • the_macos_profile_closes_the_octosense_home_after_every_grant: rule order.
  • the_private_dirs_are_the_homes_roots_and_the_kernels
  • landlock_splits_a_grant_around_the_private_dirs (Linux only)

Local checks

These all passed:

  • cargo check for desktop (default and mobile-apps) and for phone (octosense-home --features mobile-apps)
  • cargo test -p octosense-shell --lib on desktop and on phone
  • app-peers (octos-core,ws) and ai-host (octos-core,llm) tests
  • tools/check-shell-graph.sh for both shells
  • tools/setup.py --check --cargo
  • tools/native_apps.py --check

🤖 Generated with Claude Code

… core dir last (G6) [skip ci]

The Terminal's macOS profile emitted `home:rw` after everything else, and
nothing closed the OctoSense home again, so a process app with a broad
grant could read peer host tokens (app-peers/*.token), every app's jail
and secrets files, and the kernel's data.

- Policy::private: the OctoSense home, the apps and secrets roots, the
  kernel's core dir (and the kernel home around a `.octos` core dir), set
  for every process app where the shell builds its sandbox.
- macOS: after every grant, `(deny file-read* file-write* ...)` on those,
  then only the app's own jail and secrets are opened again (with the
  metadata of their ancestors inside).
- Linux Landlock cannot deny beneath an allowed directory, so a grant that
  contains a private directory is split: each entry is granted on its own,
  recursing only toward the private ones, which get nothing; links into
  them get nothing either. Limits (documented): entries created later
  directly in a split directory are not covered, and the directories on
  the way cannot be listed. Not run here (macOS), unit-tested on Linux.
- Tests: a real sandboxed child with `home:rw` over a scratch home reads the
  person's files and its own jail and secrets, and is refused peer tokens,
  another app's jail and secrets, the shell's settings, the kernel's core
  dir and kernel home, and writing into the OctoSense home; the profile's
  rule order; the private dir list; the Landlock split (Linux only).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ymote
ymote merged commit bfaa993 into main Sep 29, 2026
chrislearn pushed a commit to chrislearn/OctoSense that referenced this pull request Oct 8, 2026
…me (G6 regression)

G6 (OctoSense-org#156) closes the OctoSense home last in the process sandbox. Desktop
builds put process apps' programs in <OctoSense home>/build, so the
Terminal lost read access to its own bundle: Metal's device setup then
crashed at start (SIGSEGV in IOSurface/CFBundleCopyBundleURL, 5 crash
reports on macOS). Reproduced with the generated profile (exit 139) and
fixed by re-allowing the program read-only after the private rules
(exit 0).

- macOS: after the private deny and the app's own jail, re-allow read
  only the program paths that lie inside a private directory.
- Linux (Landlock): program rules are no longer dropped inside private
  directories, like the app's own jail and secrets.
- Test: a program inside the OctoSense home is readable after the deny,
  read-only, and nothing else is reopened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant