faccess
Basic cross-platform file accessibility checks for Rust
faccess
adds file accessbility checks for file paths to Rust:
Usage
For the simple case:
use PathBuf;
use PathExt;
let path = from;
if path.readable
More complex needs, such as reporting precisely why the file isn’t deemed
accessible in the desired manner, the underlying access
method can be used:
use PathBuf;
use ;
let path = from;
match path.access ;
Technical Details
On Unix platforms, this is basically trivial – just exposing a safe
interface to faccessat(2)
via the libc
crate:
On Windows, there’s AccessCheck
, which… is both more fiddly and has more special-cases to worry about.
For example, you can’t just ask if the current process can read or write a file
or directory, beacuse that would be silly – instead, you want to check if you
can access a given SECURITY_DESCRIPTOR
that idenfities the resource you wish
to check, and check it against an “impersonation token” with TOKEN_QUERY
access.
I’m still not entirely happy with what I’ve got – not least because it simply falls back to just trying to open a file in the common case.
This is particularly awkward for me as it interacts badly with Windows Overlay Filter compressed files (as created by Compactor), because checking if such a file is writable will–in opening the file for writing–also uncompress it.
Security Considerations: TOCTOU
This style of file accessibility check is the poster child of so-called “time-of-check to time-of-use” bugs. Here’s Wikipedia’s main example:
if
fd = ;
;
In this C program, file
is checked using access
in a setuid program to
determine if the real user (as opposed to the effective user–setuid programs
run as the owner of the executable rather than the actual user running it) is
permitted to write to it–basically attempting to replicate the standard file
permissions in userspace.
In a multitasking environment this races against other processes on the system,
which may manipulate file
in between the original access
check and the
open
and write
call, causing the program to misuse its elevated permissions
to overwrite a file it shouldn’t have had access to.
Happily we can now reproduce such security concerns in Rust, so they can at least be memory-safe. You’re welcome.