Skip to content

Linux interactive PTY on Bubblewrap: session policy + runtime-dir compatibility improvements #61

@raphaeldavidf

Description

@raphaeldavidf

Hi @jy-tan 👋

I would like to propose a Linux-focused improvement that consolidates a set of regressions (on v0.1.32) and edge cases I validated in real usage (including WSL and native Linux distributions).

The goal is to keep the sandbox secure while restoring reliable interactive shell behavior.

What users are seeing

In Linux interactive mode (for example fence bash with allowPty: true), we observed multiple issues depending on policy/session setup:

  1. PTY startup failures in some flows:
    • Error: failed to start command: fork/exec /usr/bin/sh: operation not permitted
  2. Job-control warnings/degraded shell UX when using strict --new-session:
    • cannot set terminal process group
    • no job control in this shell
  3. Tooling compatibility failures for runtime directories in read-only mounts (example with fnm):
    • Can't create the symlink for multishells ... Read-only file system

Why this happens

1) --new-session trade-off

bwrap --new-session is a strong mitigation for TIOCSTI-style attacks, but it also changes controlling-TTY/session semantics, which can degrade job control for interactive shells.

References:

2) Runtime directory mount mismatch

Some tools expect writable XDG runtime/state paths. In sandboxed sessions, inherited host runtime paths may become read-only according to the effective mount plan.

Concrete references:

Proposed/implemented policy

Linux interactive session policy

  • Default interactive PTY path (Linux): allow operation without mandatory --new-session.
  • Apply seccomp rule to block ioctl(TIOCSTI) (narrow rule, not global ioctl blocking).
  • Keep strict override support:
    • CLI flag: --force-new-session
    • settings field: forceNewSession
    • precedence: CLI > settings > default policy

Flatpak precedent for TIOCSTI-specific seccomp filtering:

Runtime-dir compatibility (Linux interactive)

  • Evaluate inherited XDG_RUNTIME_DIR against the effective writable mount plan.
  • Preserve it when it is writable in sandbox.
  • Otherwise, use private fallback (e.g. /tmp/fence-runtime-<uid>-<pid>) with 0700.
  • Apply only to the sandboxed child environment, not the parent shell.

This is intentionally conservative: writability is only assumed when it maps to a real writable mount in the sandbox plan, to avoid false positives.

Why this is necessary

  • Restores predictable interactive shell behavior on Linux.
  • Preserves security posture with explicit TIOCSTI mitigation.
  • Provides strict mode for operators who require guaranteed --new-session.
  • Improves compatibility with developer tooling that expects writable XDG runtime/state paths.
  • Avoids broad host write exposure as a workaround.

Test/validation expectations

  • Linux interactive PTY sessions start reliably (no fork/exec EPERM regression).
  • Job control behavior is improved in the default interactive path.
  • --force-new-session preserves strict behavior for hardening-sensitive environments.
  • Runtime-dir-dependent tools (like fnm) do not fail due to read-only inherited runtime mounts.
  • Seccomp still blocks ioctl(TIOCSTI).

I gave this idea a try and put together a draft patch that seems to work on my machine. I am not assuming this is the best or final approach, but I wanted to share it in case it is useful for discussion.
seccomp.json

If this direction seems reasonable to you, I would be happy to submit a PR for your review and iterate based on your feedback.

Thank you for the great work maintaining the project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions