nix-rust / nix

Rust friendly bindings to *nix APIs
MIT License
2.62k stars 660 forks source link

Discussion on the possible implementation of objects referring to fanotify groups identifying files by their handles #2486

Open ChrysoliteAzalea opened 1 week ago

ChrysoliteAzalea commented 1 week ago

Hello everyone!

On Linux, there is the filesystem monitoring facility called fanotify, that allows monitoring (and sometimes blocking) filesystem operations using a fanotify group file descriptor. For most events, the file may be identified with a file descriptor -- that is, when the watching process reads an event notification from fanotify file descriptor, a FD pointing to the target file is opened in the watching process, which can be used to identify the file and operate on it. However, some fanotify operation modes require a fanotify group that identifies files and directories by file handles -- opaque byte arrays that can be passed to open_by_handle_at() to retrieve a file descriptor for the target. I've made a crate with bindings to name_to_handle_at() and open_by_handle_at() system calls, which encapsulates the file handle and allows to work safely with it (however, since the size of a file handle is not known before requesting it, and requesting it consists of two name_to_handle_at() calls -- the first is to get the requested size and the second is to obtain the handle itself -- my crate stores the file handle on the heap and the LinuxFileHandle only stores a Vec pointing to the handle) -- something similar could be done for the fanotify module.

It should be noted that open_by_handle_at() requires CAP_DAC_READ_SEARCH to be effective for the calling process -- therefore, fanotify-based apps that want to identify files by their handles should be granted it and keep it at least for the lifetime of the fanotify group (unlike CAP_SYS_ADMIN, which may be dropped after calling fanotify_init(), as long as the application doesn't plan to use it for calling fanotify_init() for second time or use other features that require that capability, such as mounting filesystems).

SteveLauC commented 1 week ago

Hi, thanks for the issue!

We can definitely implement it, in the original fanotify(2) PR, we did discuss this a little bit. Nix always uses interfaces from the libc crate, we need to add them to the libc crate if the needed interfaces do not exist there unless there are no libc (glibc) wrappers, which enforces the use of raw syscall.

ChrysoliteAzalea commented 1 week ago

As far as I know, reading such events requires just plain read(). We can store fanotify metadata and file handle in one structure (the file handle is an opaque byte array, libc just needs to expose name_to_handle_at() and open_by_handle_at()).

SteveLauC commented 1 week ago

As far as I know, reading such events requires just plain read().

Right

We can store fanotify metadata and file handle in one structure (the file handle is an opaque byte array,

If possible, we should also consider that pidfd structs as well🤔

libc just needs to expose name_to_handle_at() and open_by_handle_at()).

As well as the structs that will be used, seems that they have been added to the libc crate though, I haven't taken a closer look at them.