This article is more than 1 year old
Google Project Zero zeroes in on Google project: Security hole spotted in gVisor sandbox fence
Horn flags up flaw that can be exploited to breakout out of software containers
Google's gVisor sandboxed kernel had a bug that would allow an attacker to escape their container and overwrite files in the host filesystem – according to Google Project Zero's Jann Horn.
Horn popped his advisory up once Google's open-source folk posted fixes for the software at its GitHub repository.
The high-severity bug, Horn wrote, "can be used to overwrite files in the host filesystem (/etc/crontab
in my PoC) from inside a Docker container that uses gVisor's runsc
".
For those not familiar with *nix architecture, "everything is a file", as the saying goes – disks, keyboards, mice, displays are filesystem entries, so if you can write to any file, you can wreak a lot of harm. In Horn's proof-of-concept, writing to the host system's crontab
(a list of task schedules) means someone supposed to be confined to their Docker container could tell the host system to run software.
Horn tweeted the advisory with a little commentary:
two interesting bug patterns in this one https://t.co/hTWHlOIb0V :
— Jann Horn (@tehjh) October 31, 2018
- temporarily drop mutex, revalidate state afterwards, but miss an aspect
- de-synchronization of multiple layers of directory entry caches leads to symlink traversal
The advisory said the breakout occurs via a "filesystem cache desync", continuing: "The VFS layer in the sandboxed helper process attempts to ensure consistency between its dentry
cache, the hostPaths
in the unsandboxed helper, and the host filesystem."
(Dentry
associates filenames with inode numbers; hostPaths
mounts a file or directory from the host for access by the user.)
Horn discovered that "there is a race condition that can be abused to desynchronize the dentry cache of the sandboxed helper such that two dentries refer to the same backing file".
To trigger this, my PoC does the following: - create a working directory for the attack and chdir() into it - mkdir("old_") - create a file "old_/file" - rename "old_" to "old"; this forces the dentry for "old_/file" to be flushed via .Busy(), which in turn causes the dentry for "old_" / "old" to no longer have any strong references; therefore, after rename, the dentry disappears - perform the following two operations in parallel: - open "old" as `dirfd`, with O_PATH - rename "old" to "new" - verify that the race was successful by attempting to open "{dirfd}/file" for writing. if the race was successful, this will fail with -ENOENT.
Horn found the bug in August, and the patches were completed last week – so if you're a gVisor user, get the fix. ®