Skip to content

Writable files in allowWrite fail for programs using atomic writes (e.g. ~/.claude.json) #62

@tito

Description

@tito

Description

Files listed in allowWrite (such as ~/.claude.json) appear as read-only inside the sandbox when the sandboxed program uses atomic file writes. This affects Claude Code login, which writes to ~/.claude.json, and likely other tools that follow the same pattern (ssh writing known_hosts, git config, etc.).

Steps to Reproduce

  1. Add ~/.claude.json to allowWrite in a greywall profile
  2. Run greywall -- claude login (or any command that triggers a write to ~/.claude.json)
  3. Claude reports "read only file system" for ~/.claude.json

Root Cause

Many programs use atomic file writes: they write to a temporary file (e.g. ~/.claude.json.tmp.PID.TIMESTAMP), then rename() the temp file over the target. This pattern breaks in greywall's Linux sandbox at two layers:

1. Bwrap: Cross-filesystem rename (EXDEV)

In DefaultDenyRead mode, the home directory is a tmpfs (--dir /home/user). Writable files get individual bind mounts from the host (--bind ~/.claude.json ~/.claude.json). When the program creates a temp file, it lands on the tmpfs. The target file is on the host filesystem (bind-mounted). rename() across different filesystems fails with EXDEV.

2. Landlock: No MAKE_REG on parent directory

When Landlock adds write rules for individual files (not directories), it strips directory-only rights like MAKE_REG, REMOVE_FILE, and REFER from the access mask. The file only gets WRITE_FILE + TRUNCATE (0x4002). Creating temp files in the parent directory is blocked by Landlock because the parent directory doesn't have MAKE_REG permission.

Impact

Any program that uses atomic writes to individually-listed writable files outside of CWD will fail. This includes:

  • Claude Code (~/.claude.json)
  • SSH (~/.ssh/known_hosts)
  • Various CLI tools that write config files atomically

Environment

  • Linux with Landlock (kernel 5.13+)
  • DefaultDenyRead mode enabled
  • Writable files listed individually in allowWrite (not inside an already-writable directory like CWD)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglinux

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions