Skip to content

Linux bwrap: allowWrite paths become read-only when allowRead parent overlaps under a denyRead region #263

Description

@yehsuf

Summary

When the filesystem config specifies denyRead and allowRead on overlapping regions, allowWrite paths nested under an allowRead ancestor silently become read-only. The sandbox command fails with EROFS or Read-only file system on write operations that should be permitted.

Reproduction

Config

import { wrapCommandWithSandboxLinux } from './src/sandbox/linux-sandbox-utils.js'

const wrapped = await wrapCommandWithSandboxLinux({
  command: 'touch /tmp/srt-test/workspace/project/hello.txt',
  needsNetworkRestriction: false,
  readConfig: {
    denyOnly: ['/tmp/srt-test'],
    allowWithinDeny: ['/tmp/srt-test/workspace'],
  },
  writeConfig: {
    allowOnly: ['/tmp/srt-test/workspace/project'],
    denyWithinAllow: [],
  },
})

Setup

mkdir -p /tmp/srt-test/workspace/project

Command

eval "$wrapped"
# → touch: cannot touch '/tmp/srt-test/workspace/project/hello.txt': Read-only file system

Expected vs Actual Behavior

Expected: /tmp/srt-test/workspace/project/hello.txt is created successfully. allowWrite paths should remain writable regardless of allowRead configuration.

Actual: The write fails with Read-only file system. The allowWrite path is silently downgraded to read-only.

Root Cause

In generateFilesystemArgs() (src/sandbox/linux-sandbox-utils.ts), when processing a denyRead directory, the function:

  1. Mounts --tmpfs over the denied path (wiping everything under it)
  2. Re-binds allowWrite paths with --bind (writable)
  3. Re-allows allowRead paths with --ro-bind (read-only)

Since bwrap processes mounts in argument order, a later mount on a parent path hides earlier mounts on child paths. When allowRead is a parent of allowWrite, step 3's --ro-bind overwrites step 2's --bind:

--tmpfs /tmp/srt-test
--bind /tmp/srt-test/workspace/project /tmp/srt-test/workspace/project
--ro-bind /tmp/srt-test/workspace /tmp/srt-test/workspace              ← HIDES the --bind above

Fix

Swap the loop order: emit allowRead ro-binds before allowWrite re-binds. Write mounts then layer on top and remain writable.

Environment

  • OS: Linux (any distro with bubblewrap)
  • bwrap version: any (mount ordering is fundamental to bwrap's design)
  • sandbox-runtime: current main

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions