Safe MountInfo

Linux /proc/self/mountinfo is the per-process kernel-published mount table. The format is fixed per [kernel Documentation/filesystems/proc.rst §3.5](https://www.kernel.org/doc/Documentation/filesystems/proc.txt):

[...] -

The field (positional index 3, 0-based) is "root within source FS" — "/" for a regular mount, a non-root path for a bind-mount (e.g. /Users/me/data mounted onto /data inside a container). Bind-mount detection MUST consult this field; ad-hoc parsers that scan the options string for the word "bind" miss the truth (kernel doesn't emit "bind" as an option — bind state is observable ONLY via field 4).

Pre-v0.11.6 the only lib/ caller (lib/watcher.js) parsed mountinfo correctly inline. Future callers — container-escape detection, sealed-store path validation, sandbox auto-probe — would have to re-derive the discipline. This primitive centralizes it: a single canonical parser that ALWAYS reads field 4, ALWAYS handles the " - " optional-fields separator, ALWAYS skips malformed lines without throwing.

Refusal posture: - safe-mount-info/read-failed — /proc/self/mountinfo unreadable (non-Linux, restricted sandbox, host filesystem hidden). Operators get the typed error AND opts.fallback value (default null) to take. - safe-mount-info/parse-failed — single malformed line within /proc/self/mountinfo. Silent-skip (per-line) by default; opts.strict: true upgrades to throw on first malformed line.

Threat model: - **Container-escape detection** (CVE-2019-5736 Docker / CVE-2022-0185 fsconfig / CVE-2024-21626 leaky-vessels) — bind-mount + root-field analysis is the canonical signal. Wrong-field readers (operations on field 5 / 6 / options- indexOf-"bind") miss escape-attempt patterns. - **Sealed-store integrity** — sealed dbs / vault state atop a bind-mounted host directory cross trust boundaries on container restart. Detection requires reading field 4 and matching the mount-point against operator-trusted paths.

Composes: - lib/safe-decompress / lib/audit — operator-supplied audit handle receives system.safe_mount_info.refused events on read-failed and parse-failed (drop-silent — observability emission must not crash the hot path that emitted the event).

RFC / kernel-doc citations: - [Linux Documentation/filesystems/proc.rst §3.5 — /proc//mountinfo](https://www.kernel.org/doc/Documentation/filesystems/proc.txt) - [CVE-2024-21626](https://nvd.nist.gov/vuln/detail/CVE-2024-21626) — runc leaky-vessels (bind-mount detection) - [CVE-2022-0185](https://nvd.nist.gov/vuln/detail/CVE-2022-0185) — fsconfig integer underflow

b.safeMountInfo.parse(text, opts?) #

stable0.11.6
{
  strict:  boolean,        // default false; throw on malformed line
  maxLines: number,        // default 4096; cap to bound parser work
}

Parse /proc/self/mountinfo text bytes into structured entries. Each entry carries { id, parent, devMajMin, root, mountPoint, options, fstype, source, superOptions }root is the positional field 4 ("root within source FS") that bind-mount detection requires.

Malformed lines are skipped by default (operator's mountinfo MAY contain a stray line during a concurrent mount/unmount). Set opts.strict: true to throw on first malformed line.

var entries = b.safeMountInfo.parse(rawText);
var bindMounts = entries.filter(function (e) { return e.root !== "/"; });

b.safeMountInfo.read(opts?) #

stable0.11.6
{
  path:     string,        // override path (default /proc/self/mountinfo)
  fallback: any,           // returned on read failure (default null)
  audit:    object,        // optional b.audit handle for refusal events
  strict:   boolean,       // forwarded to parse()
  maxLines: number,        // forwarded to parse()
}

Read + parse /proc/self/mountinfo in one call. Returns the same array shape as parse(text). On non-Linux platforms (where /proc doesn't exist) returns opts.fallback (default null); audit emission per safe-mount-info.refused with code read-failed.

var entries = b.safeMountInfo.read();
if (entries === null) {
  // non-Linux / sandboxed / no /proc
}

b.safeMountInfo.bestMatch(entries, path) #

stable0.11.6

Find the mountinfo entry whose mountPoint is the longest prefix of path. Returns null when no entry covers path. The "longest prefix" semantic is what bind-mount detection / sealed-store-path validation needs — a mounted subdir wins over the root mount.

var entries  = b.safeMountInfo.read();
var atPath   = b.safeMountInfo.bestMatch(entries, "/var/lib/blamejs");
if (atPath && atPath.root !== "/") {
  // path lives on a bind-mount (potentially crossing host/guest)
}

b.safeMountInfo.isBindMount(entry) #

stable0.11.6

true when the mountinfo entry's root field is something other than "/" (i.e. the mount is a bind from a non-root path within the source filesystem). The canonical bind-mount test — does NOT consult the options string (the kernel doesn't emit "bind" there).

var entries = b.safeMountInfo.read();
var atData  = b.safeMountInfo.bestMatch(entries, "/data");
var isBind  = b.safeMountInfo.isBindMount(atData);

Last updated 2026-08-08T16:39:49.652Z by seeder.