FAVE-SPI FLAM Anti Virus Exit (FAVE) Service Provider Interface (SPI)

FAVE - Service Provider Interface

This service provider interface enables the possibility to write a custom converter for virus scanning when reading or writing original data with FLAM. Any malware solution can be used that offers some form of API. FLAM comes with default implementation for malware scanning using the ClamAV daemon.

A service provider interface implementation can be invoked as a conversion step during data processing. See example below:

    write.text(... avscan(
                          METHOD=DELETE/ERROR,TRACE,STATISTICS,
                          LIBRARY='favelib',
                          FUNC='clamav',
                          PARAMETER="clamav.daemon:3310'"
                          ) ...)

The different functions can have different parameter strings. All of them depend on the implementation of the custom anti virus exit according to this service provider interface.

# Implementation overview

The interface that must be implemented to create a custom exit is described in the FAVE function section. This interface function must be an external function of a DLL/SO or load module (z/OS). A conversion (`AVSCAN()/CNVAVS()`) object is used to configure how to call the custom exit routine.

First, the DLL/SO is loaded based on the specified library name or default name. Then the function address is determined based on the provided function name or default name). For load modules on z/OS, the function name is the load module name and the library name must be empty. It is also possible to use DLLs on z/OS.

If the function pointer is determined, the exit driver calls the exit function with the function code for opening (see function codes). A function-code-specific parameter structure ((see FaveOpn struct)) contains the parameter string from the exit call specification (`AVSCAN(PARAMETER="xxx")`). Additionally, a read or write indication, a compression indication, a re-open indication and trace/statistics flags (see here) are provided as input.

The re-open flag is set by the exit driver if another data stream must be scanned where no additional log information must be returned. The service provider should implement the opening function as fast as possible.

The first parameter of the exit function contains a handle. When it is first called with the function code for opening (FAVE_FUNC_OPN), the handle's value is NULL. This handle can be used to store state information that may be needed during data processing by the exit (i.e. subsequent calls with the FAVE_FUNC_RUN code). The exit function is responsible for allocating memory for the handle (if needed) when called with the function code for opening (FAVE_FUNC_OPN) and must release it (and all other resources) when called with the function code for closing the exit (FAVE_FUNC_CLS).

When called with the run function code (FAVE_FUNC_RUN), the exit function gets the input data length and a pointer to the input data as input (see FaveRun) and returns an error if malware is found. The exit driver provides 4096 byte in front and 4096 byte after the data chunk which can be used to prevent copying the data.

The exit function is called with the FAVE_FUNC_CLS function code to allow the release of all resources.

The run and close functions can return FLMRTC_VRS to indicate found malware.

All function code specific parameter structures contain a length and a buffer of size 4096 bytes for an error message. The error message is displayed to the user if the return code differs from zero. If the open and close function return with FLMRTC_OK (0-SUCCESS) and a message is defined then these message are printed as informational to the log of FLAM. This can be used to produce statistics at close or provide a version or identification information at open.

# Interface standards

The interface is built on one function with four parameters, a classic load module interface. All parameters of the function are call-by-reference. The function does not have a return value. The return code is the second parameter of the function. There are only two types of parameters:

    POINTER:   pointer to an address (usually 32 (PIC S9(9) COMP) or 64 bit)
    INTEGER:   pointer to a 32 bit number in two's complement (PIC S9(9) COMP)

The type INTEGER has local endianness. On mainframes, this is usually big endian and little endian on x86 platforms.

The POINTER type is used for the handle and the parameter structures. The handle is a black box to FLAM. The parameter structures are unions with the function code acting as selector (see structures section).

To support 64 bit RISC architectures, a strong alignment to 64 bit in the parameter structures is required. This requires a 32 bit dummy field behind each 32 bit length field. The trick with the dummy fields makes the parameter structures compatible between the different supported architectures of FLAM and prevents bus errors on certain platforms.

All strings passed to the exit function are null-terminated and the corresponding lengths are set to the string length in bytes without the null character. The exit driver does not expect null-termination from the exit function, but the length fields must be set correctly. For the error message, the length can be set to the size of the error message buffer (4096), respectively, if a null-terminated string is returned by the exit function.

# Return code handling

The return code of the function must be one of the defined FLAM return codes (see module return codes). The return code FLMRTC_VRS indicates that malware was found. The handling depends on the defined method. All other return codes will result in an error and FLAM aborts the remaining processing.

# Coding example for an FAVE

The standard implementation using the ClamAV daemon is deployed as sample C source (FAVECAV.c) in the installation package (SRCLIBC/ samples). This implementation uses an internal platform independent API for IP communication and must be linked with the FL5CORE library. It can be used as template for other implementations.

The implementation of an exit does not have to be done in C, but the binary interface of the compiled and linked DLL/SO or load module must be compatible to the C calling convention.