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
- 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.
- Run a container with a guest that supports block rootfs (Linux, Rumprun, Unikraft, Hermit all implement
SupportsFS()), with the annotations that trigger getBlockVolumes().
- 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.
- 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
Description
getMountInfo()inpkg/unikontainers/block.goreads/proc/self/mountinfoand 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:Problem is,
preDash[4]comes straight from/proc/self/mountinfo, and the kernel octal-escapes spaces, tabs, newlines and backslashes in that file (\040for a space, etc, seeDocumentation/filesystems/proc.rst).pathon 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\040volumewhilepathis/mnt/my volume.Nothing in
block.gounescapes either side before comparing, so this isn't caught anywhere.getMountInforeturnsErrMountpoint, andgetBlockVolumes()(same file, around line 205) just treats that as "not a real mount" and skips it:No error, no log, the volume just doesn't get attached.
Steps to reproduce
/mnt/my volume.SupportsFS()), with the annotations that triggergetBlockVolumes().InitialSetup()callgetMountInfo("/mnt/my volume"). The corresponding mountinfo line has the mount point written as/mnt/my\040volume, so the match fails andErrMountpointcomes back even though it genuinely is a mount point.Expected behavior
getMountInfoshould 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 comparingpreDash[4](andpostDash[1]) to real paths.moby/sys/mountinfois already a dependency and is used elsewhere in the same file (mountinfo.Mounted, line 257), probably cleanest to parse/proc/self/mountinfothrough that instead of the hand-rolled split logic here.Environment
SupportsFS()(Linux, Rumprun, Unikraft, Hermit)