Named disk volume locks leak into unrelated sandboxes' supervisors, permanently blocking restarts

Author: zfy0701Created Sep 11, 2026Updated Sep 12, 2026
LabelsVolumesRuntime

Version: microsandbox 0.6.17, Node SDK (napi, in-process), local backend, Linux x86_64 with KVM.

Summary

lock_disk_image_unix() clears CLOEXEC on the flock it takes for each named disk volume, so the lock survives into the VM child it is about to spawn. But the fd also stays open in the SDK host process for the rest of the start, which means every other process spawned from that host process during the window inherits it too — including the msb sandbox supervisor of a different sandbox.

flock is released only when every fd referring to that open file description is closed, so the unrelated sibling supervisor keeps the lock alive for its whole lifetime. Once the owning sandbox stops, it can never start again:

invalid config: volume "<name>" is already attached with an incompatible disk mode

Stopping or restarting the host application does not help — detached supervisors survive it. The only way out is stopping the unrelated VM that happens to hold the fd.

Where

sdk/rust/lib/runtime/spawn.rs

  • lock_disk_mounts() locks the rootfs disk image and every VolumeMount::Named resolving to VolumeKind::Disk
  • lock_disk_image_unix()flock(fd, LOCK_EX | LOCK_NB), then clear_cloexec(file.as_raw_fd())
  • the Vec<File> is handed to ProcessHandle and stays open in the host process until the handle drops

Reproduce

In one process, local backend:

  1. Create two sandboxes A and B, each with a named disk volume (volume(path, v => v.namedWith("vol-a", "create", "disk", 1024))), and start them concurrently. Both start fine — each volume is fresh and unlocked.
  2. Confirm the leak: ls -l /proc/<B supervisor pid>/fd lists A's .../volumes/vol-a/disk.raw.
  3. Stop A. Its own supervisor exits, but the lock stays (B's supervisor still holds a copy of the fd).
  4. Start A again → invalid config: volume "vol-a" is already attached with an incompatible disk mode.

Expected: a stopped sandbox's disk volume is not held by an unrelated sandbox's supervisor, and step 4 succeeds.

Field impact

A host running several sandboxes restarted its supervising application, which recreated 8 sandboxes within the same second. All 8 started. As idle reclaim stopped the quiet ones, 13 disks belonging to stopped sandboxes stayed locked — held by the two VMs that happened to still be running. One supervisor process held 19 volume fds, 6 of them belonging to other sandboxes. The host process itself held none, so this is entirely about the inherited copies. Every sandbox whose VM had been reclaimed was permanently unstartable; stopping the two survivors released all 13 locks at once and the rest recovered immediately.

Suggested fix

Keep CLOEXEC on the lock fds and pass them explicitly to the VM child at spawn time — the same mechanism already used for --config-fd, --startup-fd and --lifecycle-lock-fd — so a lock can only ever reach the child that owns it. Alternatively, have the child acquire its own lock and drop the parent's copy once the handoff is confirmed.

Happy to test a patch against the reproduction above.

Source: superradcompany/microsandbox