If an untrusted party can cause a higher-level caller of crun to invoke it with a container identifier of "." or "..", this could cause crun to recursively delete files in a parent directory.
Summary
src/libcrun/status.c validates container IDs by rejecting /, but it does not reject . or ..:
That ID is then joined into state paths with append_paths():
- src/libcrun/status.c:111
- src/libcrun/status.c:135
The dangerous sink is the delete path:
libcrun_container_delete_status() opens the directory named by id relative to the runtime state root, then recursively deletes entries through rmdirfd():
Because id=".." is accepted, crun can be directed to operate on the parent of the state directory rather than the container’s own state directory.
dfd = openat (rundir_dfd, id, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
Impact
This becomes a filesystem traversal in a privileged cleanup path. In the worst
case, crun may:
- recursively unlink entries outside the intended container state directory
- attempt umount2(MNT_DETACH) on busy mountpoints encountered during cleanup
If an untrusted party can cause a higher-level caller of crun to invoke it with a container identifier of "." or "..", this could cause crun to recursively delete files in a parent directory.
Summary
src/libcrun/status.c validates container IDs by rejecting /, but it does not reject . or ..:
That ID is then joined into state paths with append_paths():
The dangerous sink is the delete path:
libcrun_container_delete_status() opens the directory named by id relative to the runtime state root, then recursively deletes entries through rmdirfd():
Because id=".." is accepted, crun can be directed to operate on the parent of the state directory rather than the container’s own state directory.
dfd = openat (rundir_dfd, id, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
Impact
This becomes a filesystem traversal in a privileged cleanup path. In the worst
case, crun may: