Monitoring Capabilities of CBFS Filter
Summary
CBFilter is a component of CBFS Filter, an SDK and library designed for monitoring and controlling various system activities, including filesystem operations, registry operations, and the life cycle of processes and threads. This component—available as a class, struct, or trait depending on your programming language—enables you to monitor and control all types of filesystem operations within your Windows applications. The article reviews the purpose, features, architecture, and applications of the CBFilter component.
Introduction
CBFilter fires events when handling filesystem requests. These events can occur in three ways:
- Synchronously, before the request reaches the filesystem (known as "Before* events")
- Synchronously, after the request is processed by the filesystem (known as "After* events")
- Asynchronously, at some point after the request has been processed by the filesystem (known as "Notify* events")
All Before* events have corresponding After* and Notify* events, but the information available to event handlers varies slightly based on the event type.
Before* events carry the parameters passed by the caller, that is, the application or system component that initiated the request. If another filesystem filter driver modifies the request before it reaches CBFilter, the parameters received by the event handler will reflect these changes. Most Before* events allow handlers to modify parameters before passing them further or to handle the request without forwarding it to the filesystem, which can include fulfilling the request successfully or returning an error code.
After* events typically include the same data as Before* events, with the addition of the data and status code (result or error code) set by the handler of the request—either the filesystem or a lower-level filter driver. The added data may include file data, metadata, security attributes, or extended attributes requested by the originating process. Most After* events allow handlers to modify parameters before they are returned to the request initiator, including changing the returned status code from success to failure or vice versa. By default, After* events are fired only when the request is completed successfully, but applications can adjust settings to trigger events for failed requests as well.
Notify* events contain the same information as all After* events, except for the NotifyReadFile and NotifyWriteFile events, in which case the actual data that were read or written are omitted for performance reasons. Also, the requests related to reparse tags, do not include the reparse buffer. In Notify* event handlers, it is not possible to alter or modify a request in any way.
Although monitoring is possible using all of these events, this article focuses on the minimal API set needed for monitoring. Control capabilities, available in synchronous events, are beyond the scope of this article.
Events and Available Parameters
All events may include the name of the file or directory associated with the request. An application can disable the passing of file names or enable the collection and transmission of all names related to the file or directory available to the filter driver. For detailed information about names and how to collect them, please refer to the relevant topic in the CBFilter documentation.
The following Notify* events are present in the component (listed in functional order):
- NotifyEnumerateDirectory - This event is fired after a request to enumerate the directory is sent to a filesystem. It is fired for each entry reported by the filesystem or a lower-level filter driver. The included parameters are the index of the entry in the directory, the name, the times, and attributes of an entry, the size and the allocation size of a file if the entry is a file, and an Id of the entry.
- NotifyQueryFileInfo - This event is fired after the detailed information about a file or directory is retrieved. An event handler receives the information class (the type of a structure with information) that was requested and a reference to the buffer with the requested information.
- NotifyGetFileSecurity - This event is fired after a file or directory’s security attributes are retrieved. The event parameters include the type of security information being requested and the buffer for this information.
- NotifyQueryEa - This event is fired after information about extended attributes of a file is retrieved. The parameters include the buffer for the extended attributes, and supplementary request parameters.
- NotifySetFileInfo - This event is fired after information about a file or directory is set. An event handler receives the information class (the type of the structure with information) that is being set and a reference to the buffer with the information.
- NotifySetFileAttributes - This event is fired after a file’s attributes or times are updated. The parameters include time and attribute values. This event is a simplified version of the NotifySetFileInfo event, which is fired in more cases.
- NotifySetFileSecurity - This event is fired after a file or directory’s security attributes are changed. The event parameters include the type of security information being set and the buffer with this information.
- NotifySetEa - This event is fired after an extended attribute is set on a file. The buffer with the extended attribute data is passed to an event handler.
- NotifyCanFileBeDeleted - This event is fired after the flesystem marks the file for deletion or removes such a mark. The event specifies which of the deletion mechanisms is used (these can be the FILE_FLAG_DELETE_ON_CLOSE flag during opening of a file or the Disposition flag set via the NtSetInformationFile function).
- NotifyDeleteFile - This event is fired after a file or directory is deleted. There is no system I/O Request Packet (IRP) for deletion of files and directories; they are deleted when the last handle to a file is closed. Thus, the event is emulated; it is fired by CBFilter before the NotifyCloseFile event is fired if there are no more open handles to the file.
- NotifyRenameOrMoveFile - This event is fired after a file or directory is renamed or moved. The parameters include the new name of the file or directory.
- NotifyCreateHardLink - This event is fired after a hard link to a file is created. The parameters include the name of the link.
- NotifyCreateFile and NotifyOpenFile - This event is fired when a process sends a file creation or opening request, after the file has been opened. The event notifies the handler about the file isolation mode (if one was set in the corresponding Before* event or if a file is known to be virtual) and includes the existing attributes of the file or directory being created/opened, DesiredAccess, Attributes, ShareMode, Options (the Flags part of the FlagsAndAttributes WinAPI parameter), CreateDisposition, and, optionally, a security descriptor that was passed with a request.
- NotifyReadFile - This event is fired after data are read from a file. The component passes the position in the file that the data were read from, the size of the requested data block, and the amount of data actually read. Additionally, the component indicates whether the data were to be read from the system cache or from the disk (or other medium).
- NotifyWriteFile - This event is fired after data are written to a file. The component passes the position in the file at which the data were written, the size of the data block, and the number of bytes written to the file. Additionally, the component indicates whether the data were to be written to the system cache or to the disk (or other medium).
- NotifySetAllocationSize - This event is fired after a file’s allocation size is changed. The event handler receives the new value of the allocation size.
- NotifySetFileSize - This event is fired after the size of the open file is changed, either explicitly (e.g., through truncation of a file) or implicitly (e.g., when new data are appended to the file). An event handler receives the new size value.
- NotifyLock - This event is fired after a range of bytes in a file is locked. An event handler receives the starting position and the length of the locked range, a key for the lock, and some supplementary information.
- NotifyUnlockAll, NotifyUnlockAllByKey, NotifyUnlockSingle - These events are fired after one or more file ranges, previously locked using a Lock File operation, were unlocked. The parameters include the key and the range to unlock (depending on the event).
- NotifyCleanupFile - This event is fired after a file handle is closed.
- NotifyCloseFile - This event is fired after a file is closed for the application. File closing takes place later than cleanup of a handle. One possible scenario occurs when an application maps a file into memory, and then closes the file handle and continues to use the memory mapping.
- NotifyGetReparsePoint - This event is fired after the information about the reparse point was provided by the filesystem or the lower-level filter driver.
- NotifySetReparsePoint - This event is fired after the reparse point was set or updated. The component passes the reparse tag in the request. The tag specifies the type of a reparse point and helps applications and system components recognize "their" reparse points.
- NotifyDeleteReparsePoint - This event is fired after the reparse point is deleted.
- NotifyFsctl - This event is fired after a custom request is sent using the IRP_MJ_FILE_SYSTEM_CONTROL request packet and processed by a filesystem. This IRP covers various rarely used operations on a filesystem. The control code, the input buffer with data, and the output data with the response data are made available to the event handler.
- NotifyIoctl - This event is fired before a custom request is sent using the IRP_MJ_DEVICE_CONTROL request packet. This IRP covers various rarely used operations on a device behind the filesystem. The control code, the input buffer with data, and the output buffer with the response data are made available to the event handler.
Information That Requires Synchronous Events
For performance reasons, Notify* events skip potentially large blocks of information, specifically:
- NotifyReadFile and NotifyWriteFile do not include the buffer with file data.
- NotifySetReparsePoint, NotifyGetReparsePoint, and NotifyDeleteReparsePoint do not include a reparse buffer (only the file name and a tag in the case of SetReparsePoint are included).
If you need this information for monitoring, it is necessary to use the maching After* events.
Additional Information About Requests
CBFilter can provide additional information about requests that is available to event handlers. This includes the following information:
- the name of the process that initiated the request (which may differ from the process which opened the handle);
- the PID (process Id) of the process that initiated the request (which may differ from the process that opened the handle);
- the Id of the thread that initiated the request (which may differ from the thread which opened the handle);
- the time when the request reached the filter; and
- the information about remote access if a local file was accessed over the network.
Notify* events do not include information about the process or user that opened a file handle related to the request. If you need this information, the corresponding After* events are a better choice.
Getting Started with CBFilter
You can find an evaluation version of the SDK for your platform and programming language in the Download Center. After downloading and installing the SDK, you will receive a library, sample code, and comprehensive documentation on your system. The documentation includes a "Getting Started" section with programming instructions. Additionally, free technical support is available during the evaluation phase.
We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@callback.com.