Skip to content

getMountInfo() doesn't unescape /proc/self/mountinfo paths, so mount points with spaces/tabs/backslashes never match and block volumes get silently skipped #867

Description

@Anand-240

Description

getMountInfo() in pkg/unikontainers/block.go reads /proc/self/mountinfo and checks if a given bind-mount source is actually a mount point, so it can be handed to the guest as a raw block device. It does this with a plain string comparison:

// pkg/unikontainers/block.go, line 87
if preDash[4] == path {
    ...
    blockDev.Source = postDash[1]
    ...
}

Problem is, preDash[4] comes straight from /proc/self/mountinfo, and the kernel octal-escapes spaces, tabs, newlines and backslashes in that file (\040 for a space, etc, see Documentation/filesystems/proc.rst). path on the other hand is a normal, unescaped filesystem path. So if the mount point has any of those characters in it, this comparison can never be true. preDash[4] will look like /mnt/my\040volume while path is /mnt/my volume.

Nothing in block.go unescapes either side before comparing, so this isn't caught anywhere. getMountInfo returns ErrMountpoint, and getBlockVolumes() (same file, around line 205) just treats that as "not a real mount" and skips it:

mInfo, err := getMountInfo(m.Source)
if errors.Is(err, ErrMountpoint) {
    continue
}

No error, no log, the volume just doesn't get attached.

Steps to reproduce

  1. Bind-mount a block-backed volume (e.g. a loop-mounted ext2/ext4 image) at a host path containing a space, like /mnt/my volume.
  2. Run a container with a guest that supports block rootfs (Linux, Rumprun, Unikraft, Hermit all implement SupportsFS()), with the annotations that trigger getBlockVolumes().
  3. Watch InitialSetup() call getMountInfo("/mnt/my volume"). The corresponding mountinfo line has the mount point written as /mnt/my\040volume, so the match fails and ErrMountpoint comes back even though it genuinely is a mount point.
  4. Container still starts, but the expected block device is just missing. No error anywhere.

Expected behavior

getMountInfo should undo the kernel's octal escaping on the mountinfo fields before comparing them against real paths, so mounts at paths with spaces, tabs, newlines or backslashes get detected correctly.

Impact

Silent failure. The container comes up fine but is missing a storage device it should have, and there's no error or log pointing at why. Someone would have to already suspect the escaping issue to find this; otherwise it just looks like the volume "didn't attach" for no reason.

Suggested fix

Decode the octal escapes (\040, \011, \012, \134) before comparing preDash[4] (and postDash[1]) to real paths. moby/sys/mountinfo is already a dependency and is used elsewhere in the same file (mountinfo.Mounted, line 257), probably cleanest to parse /proc/self/mountinfo through that instead of the hand-rolled split logic here.

Environment

  • urunc: main branch
  • Hypervisor: applies to all backends, any guest with SupportsFS() (Linux, Rumprun, Unikraft, Hermit)
  • OS: Linux

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