-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
removeDirectoryRecursive symlink TOCTOU #97
Comments
I think it's possible to use It would necessary to have |
Any such implementation would need to support Windows. I think it is possible, given that Cygwin implements it, but it involves touching some rather exotic APIs like It's also important to define the behavior of If we directly expose the ability to read directories with an optional |
Symlinks are much more common on unix than Windows, and this is a security hole, so IMHO it should be fixed ASAP on unixes that support Also, Rust recently fixed the same issue, and their patches might provide some useful pointers for eg Windows. https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html https://github.com/rust-lang/wg-security-response/blob/master/patches/CVE-2022-21658/0001-Fix-CVE-2022-21658-for-Windows.patch The complexity of that Windows patch, oof. |
(Misread, please ignore.) |
|
removeDirectoryRecursive and removePathForcibly are supposed to never traverse symbolic links, which would avoid unintended deletion of files outside the specified directory tree. The previous implementation did not "lock onto" the directory while enumerating its entries, allowing concurrent processes to replace the directory with a symlink right before or during the enumeration and tricking the deleter into traversing the symlink (haskell#97). This commit mitigates the issue on POSIX systems by acquiring file descriptors to every directory it traverses.
Yep, that is no longer a blocker. |
removeDirectoryRecursive and similar are supposed to avoid following symlinks. However, they all appear to have a TOCTOU flaw that exposes them to a race condition that could lead to deleting symlinked directory trees.
Ie, in a call
removePathRecursive "foo"
, iffoo
is a directory at the stat call, and then gets replaced with a symlink before removeContentsRecursive callslistDirectory
, then it will get a list of the files in the symlinked directory, and proceed to delete them.This could be a security problem if deleting a directory that is writable by another user, or perhaps by a containerized, untrusted process that has been given write access to the directory. Security aside, this kind of race can lead to unexpected data loss, though the probability of the right sequence of events is of course lower.
I checked how rm -r (from coreutils) handles this, and it uses open with
O_NOFOLLOW
when opening directories, and so avoids listing the contents of directory symlinks.I think that a similar fix could work here, if
listDirectory
usedO_NOFOLLOW
it seems it would nicely solve the problem. (It would also speed it up by avoiding needing to stat every directory it traverses.)openDirStream does not currently have a way to pass that flag, so it would need to be patched first.
The text was updated successfully, but these errors were encountered: