Skip to content

Silent truncation of mount options containing null bytes (\u0000) #2105

Description

@74suiko

Description: I noticed that crun (v1.28) behaves differently from the latest versions of runc (v1.4.2) and youki (v0.6.0) when parsing mount options that contain a null byte (\u0000).

When mounting filesystems such as cgroup, mqueue, sysfs, or when mounting tmpfs to shm, appending a null byte to a mount option (e.g., nosuid\u0000) causes crun to successfully create the container, whereas runc and youki error out.

Specification and Security Basis: While JSON allows \u0000 in strings, Linux mount(2) treats null bytes as C-string terminators. It appears that crun silently truncates the mount option at the null byte and proceeds with the operation. This behavior might be inconsistent with expected configuration fidelity and poses a potential security risk: if additional security-critical mount options follow the null byte, they might be silently discarded without alerting the user.

Steps to reproduce the issue:

  1. Use the following minimal config.json snippet where \u0000 is injected into the mount options:

config.json snippet

"mounts": [
    {
        "destination": "/proc",
        "type": "proc",
        "source": "proc"
    },
    {
        "destination": "/dev",
        "type": "tmpfs",
        "source": "tmpfs",
        "options": [
            "nosuid",
            "strictatime",
            "mode=755",
            "size=65536k"
        ]
    },
    {
        "destination": "/dev/pts",
        "type": "devpts",
        "source": "devpts",
        "options": [
            "nosuid",
            "noexec",
            "newinstance",
            "ptmxmode=0666",
            "mode=0620",
            "gid=5"
        ]
    },
    {
        "destination": "/dev/shm",
        "type": "tmpfs",
        "source": "shm",
        "options": [
            "nosuid",
            "noexec",
            "nodev",
            "mode=1777",
            "size=65536k"
        ]
    },
    {
        "destination": "/dev/mqueue",
        "type": "mqueue",
        "source": "mqueue",
        "options": [
            "nosuid",
            "noexec",
            "nodev"
        ]
    },
    {
        "destination": "/sys",
        "type": "sysfs",
        "source": "sysfs",
        "options": [
            "nosuid",
            "noexec",
            "nodev",
            "ro"
        ]
    },
    {
        "destination": "/sys/fs/cgroup",
        "type": "cgroup2",
        "source": "cgroup2",
        "options": [
            "nosuid\u0000",
            "noexec",
            "nodev",
            "relatime",
            "ro",
            "nsdelegate"
        ]
    }
]
  1. Run the container creation command:
sudo crun create -b . mycontainer

Describe the results you received and expected:

  • Expected behavior: crun should explicitly reject mount options containing null bytes and error out immediately, preventing silent configuration truncation (similar to how runc and youki handle it).
  • Actual behavior: crun silently ignores the null byte (and anything following it), and successfully creates the container.

Logs and Outputs:

Output from crun:

Returns exit code 0 and successfully creates the container

For comparison, output from runc and youki (which behave correctly by throwing an error indicating the invalid argument):

runc output:

ERRO[0000] runc create failed: unable to start container process: error during container init: error mounting "cgroup2" to rootfs at "/sys/fs/cgroup": mount src=cgroup2, dst=/sys/fs/cgroup, dstFd=/proc/thread-self/fd/11, flags=MS_RDONLY|MS_NODEV|MS_NOEXEC|MS_RELATIME, data=nosuid,nsdelegate: invalid argument

youki output:

ERROR libcontainer::rootfs::mount: failed to mount Mount { destination: "/sys/fs/cgroup", typ: Some("cgroup2"), source: Some("cgroup2"), options: Some(["nosuid\0", "noexec", "nodev", "relatime", "ro", "nsdelegate"]), uid_mappings: None, gid_mappings: None }: syscall
ERROR libcontainer::process::init::process: failed to prepare rootfs err=Mount(Syscall(Nix(EINVAL)))
ERROR libcontainer::process::container_intermediate_process: failed to initialize container process: failed to prepare rootfs

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