Virtio-fs escape outside of specified vm directory
In the current form, it is possible to escape out of directories exposed by the libkruns "fs" device. In fact, there is even a warning in the source code: https://github.com/containers/libkrun/blob/9041aaa4cb7f80e463ed82ec3bf1a9301174217d/src/devices/src/virtio/fs/linux/passthrough.rs#L311-L316
But we don't provide any warning to the user here: https://github.com/containers/libkrun/blob/45563e9c78cdae42aad48d7633ea13941a21976c/include/libkrun.h#L61-L71
And here: https://github.com/containers/libkrun/blob/9041aaa4cb7f80e463ed82ec3bf1a9301174217d/include/libkrun.h#L198-L208
The main issue stems from the fact that we basically trust the guest kernel that when it gives us a filename it is actually a filename and not a path. In order to exploit this you need to modify the guest kernel, which should be possible within the VM since you have root access. This is because the normal user-space API obviously resolves path for you and doesn't allow you to attempt to create files with invalid names.
I made a patch for the libkrunfw kernel to play around with this from userspace:
https://gist.github.com/mtjhrc/964e009b2a18e7f1b7311df4b7d8696d
This hacky patch allows you to issue weird fs request from userspace with invalid "filenames" containing / and ... This changes % into / and :: into .. in virtio-fs requests.
I tested this on Linux host, but I think this should also be exploitable on macOS (with slightly different behavior).
I found 2 related variants of this bug:
-
putting a path with
..and/in filename of virtio-fs commands:Run this inside the VM to create a file named
HACKEDin your/tmpon the host filesystem:# touch ::%::%::%::%::%::%tmp%HACKED(The kernel patch changes this to../../../../../../tmp/HACKED)The fix for this should be straight forward - refuse to process fs request from the guest with
/in filenames in libkrun. -
resolving
..of/I feel like this is slightly different than the first issue, because it could make sense for the guest to use..to refer to parent directories that are still inside the VM directory (but I'm not sure, if this is a valid FUSE operation).You can try this with this python script:
# python3 -c 'import os; os.write(os.open("HACKED", os.O_WRONLY | os.O_CREAT, dir_fd=os.open("::", os.O_PATH)), b"HACKED!");'- this should create a file namedHACKED1 level outside of the root directory of the VM.The fix for this should probably be more nuanced and resolve
..of/to just another reference to/, but for other directories,..can be left to work normally (maybe?). I don't know what is the proper fix is - should..be disallowed completely or just the path carefully resolved for root directory?
Note that this effects more that just the fuse LOOKUP operation - it also effects: unlink, symlink and anything else that deals with filenames.