Skip to content

Validate mount options for null bytes (\u0000) early to provide clearer error messages #5320

@74suiko

Description

@74suiko

Description: I noticed that while runc (v1.4.2) correctly rejects mount options containing null bytes (\u0000), the failure occurs very late in the lifecycle—at the syscall level—resulting in a somewhat generic and cryptic error.

When injecting a null byte into mount options (e.g., nosuid\u0000) for filesystems like cgroup, mqueue, sysfs, and tmpfs, the unvalidated string is passed down to the mount(2) syscall, causing the kernel to return an EINVAL (Invalid Argument) error.

(For context, youki v0.6.0 exhibits similar behavior, whereas crun v1.28 silently strips everything after the null byte and proceeds).

The Proposal: It might be beneficial to add early validation during the configuration parsing phase. If the parser explicitly checks for and rejects \u0000 in mount options, it could return a much more actionable and user-friendly error message (e.g., Error: mount option 'nosuid\u0000' contains illegal null byte), rather than relying on the kernel to catch it.

Steps to reproduce:

  1. Use the following 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 (using sudo):

Bash

sudo runc create mycontainer

Current Logs and Outputs:

Currently, the runtime passes the string to the kernel and crashes with a syscall error.

Plaintext

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

Expected Behavior:

The runtime should catch the null byte during the spec validation phase (before executing syscalls) and print a clear error indicating that null bytes are not allowed in string parameters.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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