NAME

Linux::Fanotify - Perl interface to the Linux fanotify API

VERSION

Version 1.0

SYNOPSIS

    use Linux::Fanotify qw(:consts);
    use Fcntl;	# Provides O_* constants required for fanotify_init

    my $fanogrp = new Linux::Fanotify::FanotifyGroup(
	FAN_CLOEXEC | FAN_CLASS_CONTENT,
	O_RDONLY | O_LARGEFILE
    ) || die("Could not initialize fanotify: $!");

    $fanogrp->mark(
	FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_OPEN_PERM | FAN_CLOSE_WRITE, -1, $path
    ) || die("Could not mark $path: $!\n");

    while (1) {
	my @events = $fanogrp->read();
	foreach my $e (@events) {
	    if ($e->needsResponse()) {
	        print("Allowing a request:\n$e\n");
	    	$e->allow();
	    }
	}
    }

DESCRIPTION

The fanotify API is a filesystem monitoring interface in the Linux kernel. It is intended to be used by file scanners such as virus and malware scanners or file indexers.

fanotify has been part of the Linux kernel since 2.6.37 (but needs to be enabled in the kernel configuration).

This perl module provides a Perl binding for that API. The low level functions fanotify_init and fanotify_mark are available similarly to the original C functions, but provide a more abstract interface for easier usage in perl programs.

Linux::Fanotify provides a functional as well as an object oriented interface. The latter is the recommended way of interacting with the module.

fanotify basics

The fanotify kernel API provides two basic functions, plus a file (descriptor) based interface from which events can be read, and which is used to respond to such events.

The fanotify_init() call is used to "connect" the kernel, which responds with creating a notification group (also: fanotify event group, ...). Notification groups can then be used to fanotify_mark() file system objects, most prominently mount points, directories, or files. During marking, the type of requested events can be determined. This can be either a simple notification about operations, or a request for permission.

After marking such objects, a program can read from the notification group file descriptor to receive events; in case of permission requests, a response needs to be written to the notification group.

The currently available standard man pages for the fanotify operations are incomplete and in some cases downright incorrect. Please consult 3rd party fanotify man pages for more apt information.

About this module

This module's interface closely resembles the low level functionality. The fanotify functions can directly be accessed (although the OO interface is recommended).

The return values of the offered functions and methods are perl style (in case of error, 0 or undef is returned) rather than C style (where 0 is returned in case of success).

Calling fanotify_init requires the CAP_SYS_ADMIN capability ("you need root", except that you don't).

Object oriented interface

Package Linux::Fanotify

Property $Linux::Fanotify::default_response

This package-global variable triggers a default response for permission events in case no explicit response has been issued.

The variable can contain a value of FAN_ALLOW, FAN_DENY, -1, 0, or any other integer. Its default is -1.

Due to its system related nature, the fanotify API is good for all kinds of mess. When events are "lost" without properly responding to them, consecutive events can no longer properly answered (responses will allow/deny older events, rather than the ones they were intended to). I cannot imagine any case where one would want to trigger such a behavior intentionally, so its best to leave this variable untouched, and Linux::Fanotify will take care of not leaking any file descriptors, and answering them with a sensible default just in case.

However, if you intend to shoot yourself in the foot, you can set this variable to 0. This will result in not automatically responding to events being manually closed or going out of scope.

The default -1 results in Linux::Fanotify choosing its own default, currently FAN_DENY.

Class method init($flags, $event_f_flags)

Identical to the Linux::Fanotify::FanotifyGroup constructor. See the documentation below.

Package Linux::Fanotify::FanotifyGroup

Constructor new($flags, $event_f_flags)

Constructs and returns a new Linux::Fanotify::FanotifyGroup object.

Please consult the aforementioned man pages for information on $flags and $event_f_flags.

Returns undef in case of error; consult "$!" in perlvar in this case.

Object method mark($flags, $mask, $dirfd, $pathname)

Marks the given entity ($dirfd, $pathname) in the current notification group with the given properties.

Again, see the man pages for detailed information about the arguments.

$flags can be one of FAN_MARK_ADD, FAN_MARK_REMOVE, and FAN_MARK_FLUSH to describe the respective operation

$mask describes the operations for which the program listens.

$dirfd and $pathname describe the file system object to watch. Please note that $dirfd needs to be a numeric file descriptor (such as returned by sysopen and friends), in contrast to a perl file handle. The "fileno" in perlfunc function can be used to get a file descriptor for a perl file handle.

Returns true in case of success, undef otherwise (see "$!" in perlvar in that case).

Object method read([$count])

This function returns a list of ""Package Linux::Fanotify::Event" objects. The optional $count argument may limit the number of returned events. As the kernel uses an event queue, programs may read a list of events instead of sequentally reading single events for performance reasons.

See the ""Package Linux::Fanotify::Event" description below for more information about the returned objects.

The $count argument is optional, and defaults to a value that results in an average-sized internal buffer. Using a value of 1 is supported. This perl module limits the maximum value of $count to 4096.

Unless the FAN_NONBLOCK flag has been set while initializing the fanotify group, the read call blocks and never returns an empty list.

For non blocking reads, the empty list is returned, and errno is EAGAIN. Other cases are directly passed on from the low level calls.

Object method getfd()

Returns the file descriptor of the notification group.

Allows for all kinds of messing around; be careful. May be useful for poll() or select() calls on the returned file descriptor.

After a manual closing of a notification group, this will be -1.

Object method close()

Closes the notification group.

This method does not have to be called manually; the object's destruction will automatically close the file descriptor.

Any events present in the event queue will be flushed (that includes an implicit "allow" of queued permission events).

Returns true in case of success, undef in case of error.

Package Linux::Fanotify::Event

Linux::Fanotify::Event objects reflect event queue entries as returned by the system. Please note that event objects use an internal representation of the event meta data and can only be accessed via the described methods.

Use the getter methods listed below to get information about the event properties.

Object method close()

Closes the event's file descriptor. For non-permission events, this results in releasing the respective kernel data structures (only a limited amount of files can be kept open per process).

For permission events (FAN_OPEN_PERM, FAN_ACCESS_PERM), a default response is created in case no explicit response was issued. See above for more information about default responses.

Manually closing the file descriptor is normally not required; as soon as the event object is going out of scope, it will automatically be closed to prevent leaking file descriptors. If you intentionally want to keep a file descriptor open, store the event object in a variable of your choice.

Returns true in case of success, undef in case of error.

Object method needsResponse

Returns whether the event object (still) requires a response, i.e., it was (a) a FAN_OPEN_PERM or FAN_ACCESS_PERM in the first place, and (b) was not already responed.

Object method allow()

Respond to the event with a "FAN_ALLOW", allowing the operation.

Object method deny()

Respond to the event with a "FAN_DENY", denying the operation.

Getter methods

The following getter methods provide read only access to the properties of an event:

  • event_len

  • vers

  • metadata_len

  • mask

  • fd

  • pid

All getters directly return the original data structure's property unaltered. At the time of writing, event_len and metadata_len contain the length of an event meta data structure, 24 bytes.

To get the file name for the requested file descriptor, one can use a readlink() call on the process' proc entry:

readlink("/proc/self/fd/" . $event->fd);

Functional interface

Using the object oriented interface described above is recommended in all cases. Not all object methods (especially the event object getters) have functional counterparts. However, the low level functions can be accessed with normal function calls.

Function fanotify_init($flags, $event_f_flags)

Initializes and returns a fanotify group.

In case of an error, returns undef.

Function fanotify_mark($notgrp, $flags, $mask, $dirfd, $pathname)

Marks a file system object to be monitored via the given notgrp.

See the respective object method for information on the arguments.

Function fanotify_read($notgrp [, $max)

Read events from the queue described by $notgrp. Limited to $max if given, limited to a module default otherwise.

Function fanotify_write($event, $response

Respond to an event with FAN_ALLOW or FAN_DENY. No other responses are currently accepted.

Returns the number of bytes written to the fanotify group file descriptor on success (you can expect this to be true), undef otherwise.

EXPORTED SYMBOLS

Per default, no symbols are exported by this module. However, the constants as well as the functions of the "Functional interface" are exportable.

By using the export tags :consts and :funcs, all of the respective symbols are importable. Use

use Linux::Fanotify qw(:consts);

to import all constants.

The fanotify_init calls (new constructor, init class method, fanotify_init function) use O_* constants that are exported by the Fcntl module. In most cases, you want to use that module as well.

AUTHOR

Bastian Friedrich <bastian@cpan.org> or <bastian@friedrich.link>

COPYRIGHT and LICENSE

Copyright (C) 2014 Bastian Friedrich. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.