Silent truncation of mount options containing null bytes (\u0000)
- Dominant language
- C
- Stars
- 4.1k
- Forks
- 444
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 43
Description
**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
```json
"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"
]
}
]
```
2. Run the container creation command:
```bash
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`:
```text
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:
```text
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:
```text
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
```
Contributor guide
Assessment
This issue has not been assessed yet.