libav - anti-virus library interface Frantisek Hrbata The av library is intended to be used by anti-virus vendors for so-called on-access scanning on GNU/Linux systems. It contains a simple interface allowing a user-space application to decide, based on some kind of malware analysis, whether access to a file can be granted or not. This library allows application just to handle events generated by the avflt. It doesn't provide interface for setting paths or caches. For this you should use the avfltctl utility or if you require to manage the avflt from your application you should use the libavfltctl library. So as you can see there are two libraries, one for handling avflt's events and second for controlling the avflt. The av library uses the avflt, anti-virus filter, for the redirfs framework and it provides front-end to the avflt char device. All libav functions return 0 on success. When an error occurred libav functions return -1 and the errno value is set appropriately. registration - struct av_connection - int av_register(struct av_connection *conn) First of all you will need to register your application with the av_register function. For each av_register call you have to define the av_connection structure. Only one av_connection structure and only one call of the av_register function is needed for each process. If you are going to use libav in a multi-threaded application you don't need to, although you can, register each thread. On the other hand, if you are going to use some kind of pre-forked model for on-access scanning you will have to register each process. The av_connection structure keeps connection to the avflt. Basically it contains just a file descriptor for the avflt char device, which is set during the av_register call. You should not access the av_connection structure directly. It is used internally by the libav. For each av_register you have to call av_unregister, which is described later. After successful registration you have to start handle file access events as soon as possible, because Linux kernel will wait for responses from your application. It is important to realize that the avflt starts to generate events under following condition: at least one process is registered and at least one file path is included for scanning. If this condition is not satisfied no events are generated. event - struct av_event Each file access event is described by the av_event structure. It contains all information needed by a user-space application for the on-access scanning. You can access this structure directly, but only for reading. Only item which can be modified is result and you should modify it only with the av_set_result function, which is described later. int id Event id used internally by avflt. This is used by the avflt to find out corresponding kernel event. Do not modify this. int type There are two event types, open and close, defined as AV_EVENT_OPEN and AV_EVENT_CLOSE. You can use this to distinguish event type if you need it. int fd The file descriptor of the file which need to be scanned. It is opened for the user-space application by the avflt in a read-only mode and in a context of the original process. You can still get a full filename of the accessed file via the av_get_filename function, but it is strongly recommended to use the file descriptor for scanning only. Using the filename to open the file by yourself will lead to needless overhead and possible inconsistence if the file is renamed just before you open it. pid_t pid; It contains a pid of a process accessing the file. Each process/thread has it own unique pid. pid_t tgid; It contains a tgid of a process accessing the file. The tgid is the same for each thread started by the same process. Actually the tgid is a pid of the process. You can use this to identify a whole process without distinguish process's threads. int res; This it the only item you can modify. By default it has the 0 value, which means "unknown" result and in this case avflt will allow access to the file. You should set the result with the av_set_result function. You can set it to AV_ACCESS_ALLOW or AV_ACCESS_DENY to allow or deny access to the file. getting event - int av_request(struct av_connection *conn, struct av_event *event, int timeout) This function will block until a new event is available and then it fills the event structure with the event information. You can specify a timeout in milliseconds. When the new event is not available during the timeout period this function returns -1 and the errno value is set to ETIMEDOUT. If the timeout is set to the 0 value then this function will block infinitely until the new event is available. You can use the timeout for periodic check if your application is requested to terminate. When this function successfully returns it means that the new event is available and the avflt is waiting for your response. You have to call the av_reply function, which is described later, for each successful av_request call. The avflt uses a in-kernel-cache so only modified files or files which were not scanned yet are send to the user-space application. This should rapidly improve performance. setting result - int av_set_result(struct av_event *event, int res) When your application is done with the file scanning you should set the result by this function. If you don't set the result avflt will allow access to the file. Your application can allow access to the file by setting result to the AV_ACCESS_ALLOW or deny access to the file by setting result to the AV_ACCESS_DENY. returning event - int av_reply(struct av_connection *conn, struct av_event *event) This function returns the event with proper result of your scanning to the avflt. Note you have to call this function even when some error occurred(e.g. during file scan). The avflt will wait and block access to the file until you call the av_reply function. unregistration - int av_unregister(struct av_connection *conn) When your application is no more interested in events(e.g. it is going to be terminated) you should call the av_unregister function. This will tell the avflt that your application will no longer be handling events. Your application will be correctly unregistered even if it crashes, since all file descriptors are closed when a process terminates. getting filename - int av_get_filename(struct av_event *event, char *buf, int size) You can use this function to get full filename of the accessed file. This can be used when you need to report that the file is infected. Do not rely on the filename since it can be changed. For file scanning use the file descriptor in the event structure. trusted application - int av_register_trusted(struct av_connection *conn) - int av_unregister_trusted(struct av_connection *conn) When a process is registered as a trusted with the av_register_trusted function, no file access from this process and its threads will be sent for check and access to the file will be automatically allowed by the avflt. You need to call the av_register_trusted function just once for each process. As for the av_register function you need to have defined the av_connection structure and you should call the av_unregister_trusted for each av_register_trusted call. The trusted interface has to be used for example when events are handled by one process, but the scanning is physically done in a different process. Then the scanning process has to be registered as trusted otherwise you will end with dead-lock. process1(handling events) process2(scanning) av_register av_register_trusted while (!exit) { while (!exit) { av_request copy fd(cmgs) send fd for scanning ---------------> scan fd send scan result wait for result <--------------- send scan result av_set_result close fd av_reply } } av_unregister av_unregister_trusted If the process2 doesn't use the av_register_trusted function then the "close fd" operation in process2 will trigger another scan request in avflt and this request will be send to the process1. In this situation process1 will be stuck in the "wait for result" operation and process2 will be stuck in the "close fd" operation. So as you can see in this case it is necessary to register process2 as trusted. example You can use the avtest source code as an example how to write your application. It is available as a package at the redirfs's download page.