actl - control the system call audit mechanism of the Linux kernel


actl [--add PATHNAME [--flags "SYSCALL=b,t [SYSCALL=b,t ...]" ]] [--delete PATHNAME] [--getflags PATHNAME] [--help] [--howmany] [--passwdoff PASSWORD] [--passwdon PASSWORD] [--reset] [--setflags PATHNAME --flags "SYSCALL=b,t [SYSCALL=b,t ...]" ] [--timeadd CMD- NAME=[+-]OFFSET] [--timedel CMDNAME] [--timeget CMDNAME] [--timeset CMDNAME=[+-]OFFSET] [--version] [--wildcardget] [--wildcardset --flags "SYSCALL=b,t [SYSCALL=b,t ...]" ]


This manual page documents the experimental version of actl, a user space application to control the Linux system call audit mechanism, and it also describes the audit mechanism itself to some extent. actl needs the `audit' loadable kernel module (audit.o) in order to function. The module upon successful loading will use the `audit' device ( /dev/audit, a character device with major number 61 ) as one of its interfaces with user space, another being the proc filesystem entry /proc/audit. Audit is thus a dynamically loadable facility which allows the super-user to trail and/or block the use of certain system calls on a per-file, per-system call basis. It also makes it possible to show different system times (a time in `future' or in `history') on a per-binary basis. This is managed entirely within the module, and the kernel source in the Linux source tree need not be changed. It is also not required to recompile the kernel. The module, once it resides in the kernel, toggles re-routing of system calls on and off according to need (as long as there is some entry in the audit list necessisating the re-routing of a system call, that call remains re-routed - when its use count drops to zero, the kernel's original system call is restored). The internals of the scheme are described further in later sections. actl, which is simply one possible user-interface to the audit mechanism, has been written in Perl, mainly because it is more convenient to do argument parsing in Perl. actl requires a recent version of the Perl interpreter to run (version 5.005 was used for development).


--add PATHNAME [--flags """SYSCALL=b,t [SYSCALL=b,t ...]"""]
Add the file specified by PATHNAME to the kernel audit list. Optionally specify audit control flags with the --flags option, which takes a string consisting of whitespace separated entries of the form "SYSCALL=b,t""" where SYSCALL is the name of an auditable system call, and `b' and `t' are boolean flags (1 or 0) indicating whether the system call is to be blocked (in which case the caller of the system call will get an -EPERM, that is, an `operation not permitted' error), or trailed (in which case each invocation of the system call will generate an audit message in the kernel, consisting of the filename, the uid, gid, pid and the process command name involved). Both the `b' and the `t' flags can be in effect simultaneously, or any other combination thereof. The default values of both these flags are 0. Here is an example of the usage:
# actl --add /foo --flags "open=0,1 read=0,1 execve=1,1"
which would add an entry for file `/foo', and set audit flags so that all invocations of the open and read system calls are logged, and an invocation of the execve system call on the file fails (it cannot be executed regardless of the file permissions), and a message is logged when an attempt is made.
--delete PATHNAME
Deletes an entry for PATHNAME if it exists in the kernel audit list.
--flags """SYSCALL=b,t [SYSCALL=b,t ...]"""
Specify audit control flags. This option can only be used in conjunction with the --add or the --setflags options.
--getflags PATHNAME
Show the flags for PATHNAME if the entry exists in the kernel audit list. The flags are displayed both as a hexadecimal number as well as a 32-bit binary string (a `1' or a `0' for each flag bit set or unset, respectively). For a visually meaningful display of the information represented by the flags, /proc/audit should be referred to.
Display a help message and exit.
Shows the number of entries in the kernel audit list (including the number of entries in the kernel modified time list).
--passwdoff PASSWORD
Turn off the password for the audit kernel module, where PASSWORD is the current password. If the password is set, the module cannot be unloaded, even by the super-user. Moreover, the kernel does not store the cleartext password in memory. Instead, a MD5 hash of the password is stored. The MD5 routines are contained in the audit module, and have been adapted from those in the FreeBSD kernel.
--passwdon PASSWORD
Turn on the password for the audit kernel module, and set it to PASSWORD. Once the password is set, the module cannot be unloaded, unless the password is turned off by the --passwdoff option, which needs PASSWORD to authenticate. The kernel handles the MD5 processing internally, and this, as some would note, puts the cleartext string in kernel memory for a little while, and in theory this could lead to a compromise of security, but that possibility has been disregarded for now.
Reset all kernel audit/modified-time list(s) to NULL. All the entries are discarded, and all re-routed system calls are restored to the kernel's original. The effect is the same (to the user) as would the unloading and reloading of the module.
--setflags PATHNAME --flags """SYSCALL=b,t [SYSCALL=b,t ...]"""
Set the audit control flags for PATHNAME as specified by the flags option, if PATHNAME appears in the kernel audit list.
--timeadd """CMDname=[+-]OFFSET"""
Adds an entry for CMDNAME in the kernel's modified-time list, with OFFSET (in seconds) as the time modification offset. This would result in the time system calls (time and gettimeofday) to return a modified time (modified by the offset, positive or negative as it is) if the caller is CMDNAME.
--timedel CMDNAME
Deletes the entry for CMDNAME in the kernel's modified-time list, if it exists.
--timeget CMDNAME
Get the current time offset (in seconds) for CMDNAME, if it appears in the kernel's modified-time list. This information can also be seen in /proc/audit.
--timeset """CMDname=[+-]OFFSET"""
Set the time offset to OFFSET seconds (positive or negative as indicated by the sign) of CMDNAME, if it appears in the kernel's modified-time list.
Print version information on standard output and exit successfully.


The audit loadable module creates a proc filesystem entry called /proc/audit, which contains a textual representation of the current syscall audit list and the modified-time list. /proc/audit is read-only, and presents the internal audit state in a readily understable form. All changes to the audit state may be made only through the IOCTL interface, by operating on /dev/audit. The information in /proc/audit is divided into three sections, one labelled `mtime' another labelled `audit', and the third labelled `wildcard trail' Each entry under mtime is for a binary for which the system time will be offset by the value displayed in front of it. Each entry under audit is for a file with its table of blocked/trailed system calls displayed. The wildcard section shows which system calls are being trailed on a wildcard basis. Shown below is an example for a situation where there are three entries in the modified-time list (`historical' times for popular binaries, and a `futuristic' time for testing, perhaps). Also, there is one audit entry for a file called `/tmp/test/foo', with the `chmod', `chown' and `execve' syscalls blocked and trailed, and the `read' system call not blocked but only trailed. Finally, from the wildcard section, it is seen that all invocations of the `rename' system call are being trailed.

mtime: netscape -10000000 realplayer -90000000 futuredate +50000000 audit: /tmp/test/foo (inode = 27271) syscall b t syscall b t syscall b t syscall b t chmod 1 1 chown 1 1 execve 1 1 fchmod 0 0 fchown 0 0 link 0 0 mkdir 0 0 mount 0 0 open 0 0 read 0 1 rename 0 0 rmdir 0 0 symlink 0 0 umount 0 0 unlink 0 0 write 0 0 wildcard: chmod 0 chown 0 execve 0 fchmod 0 fchown 0 link 0 mkdir 0 mount 0 open 0 read 0 rename 0 rmdir 0 symlink 0 umount 0 unlink 0 write 0

Rerouting of System Calls

The loadable kernel module audit.o is central to the audit mechanism. The module provides functionality to re-route system calls in a running system, so that in order to use modifed system calls, one does not have to recompile the Linux kernel. The module maintains a height balanced binary tree in the kernel for holding audit entries, and a doubly linked circular list for holding modified-time entries. All the commands to the module are sent by performing IOCTL's on the audit device, viz, /dev/audit. The system calls are re-routed only when the need arises, that is, if no audit entry has its `b' or `t' (or both) flags set for a system call foo, then the kernel's original system call is used. Whenever a change to an entry's flags causes a need to re-route a system call (or frees a system call from the need to be re-routed), the kernel's syscall table is updated to ensure minimum call invocation overhead. Moreover, apart from the memory required for its initial tables (of the re-routed system calls, for example), the module does not statically allocate memory for its data-structures, but dynamically allocates and frees memory according to need.

Programming Interface

It is fairly easy to introduce further system calls into the auditable set. Also, the concept of an `audit-trail' is user configurable, since the user can change the action that is to be performed when a system call with an `on' trail bit is invoked. The default action is to make a kernel log with useful information about the caller. The following IOCTL's are currently supported:

IOCTL Description IOC_AUDIT_RESET Reset the kernel audit/modified-time lists. IOC_AUDIT_ADD Add an entry to the kernel audit list. IOC_AUDIT_DEL Delete an entry from the kernel audit list. IOC_AUDIT_GETFL Get flags for an audit entry. IOC_AUDIT_SETFL Set flags for an audit entry. IOC_AUDIT_MTIMEADD Add an entry to the kernel mtime list. IOC_AUDIT_MTIMEDEL Delete an entry from the kernel mtime list. IOC_AUDIT_MTIMEGET Get mtime offset for a mtime entry. IOC_AUDIT_MTIMESET Set mtime offset for a mtime entrys. IOC_AUDIT_HOWMANY Get number of entries in the kernel lists. IOC_AUDIT_PASSWDON Enable module password in kernel. IOC_AUDIT_PASSWDOFF Disable module password in kernel. IOC_AUDIT_WCARDGET Get flags for wildcard trailing. IOC_AUDIT_WCARDSET Set flags for wildcard trailing.

All ioctl's take an audit_entry structure as the final argument, which is defined as follows:

struct audit_entry { char *path; struct flags flags; unsigned long i_ino; };

the Auditable/Re-routable System Calls

Auditable and Re-Routable

Auditable and re-routable chmod chown execve fchmod fchown link mkdir mount open read rename rmdir symlink umount unlink write Re-routable but not auditable time gettimeofday


$MODULEPATH/audit.o The loadable kernel module /proc/audit The /proc filesystem interface /dev/audit The audit device and programming interface <audit/*.h> Header files actl The Perl script for controlling audit The Perl header file for IOCTL support (including the AUDIT ioctls)


The mechanism has been developed under the Linux 2.1.X series, which means that it uses internal kernel routines and data structures that differ in significant places from those in the 2.0.X or earlier versions. Though it should not be hard to `port' the code backwards, no such support is provided as of now. A generic image of a recent 2.1.X kernel has been provided with the module for those who wish to experiment with it but do not have access to Linux 2.1.X

Some Suggested Uses

System Security
The mechanism is a powerful one for special purpose control of the filesystem on a per-file basis. The super-user can keep an eye on specific system calls invoked on a particular file, and can optionally block whatever he chooses to. Since the module can be optionally locked into the kernel using a password, and since even the reboot system call could be blocked by this scheme (it is currently not in the auditable set), there is little harm that a malicious user could cause (in theory, and almost in practice) to the system, with audit enabled.
System Call Statistics
It is very easy to enable gathering of system call statistics (the number of reads, for example) on a per-syscall basis, which could be useful to people intersted in disk access strategies, databases, and other areas where the number of system calls of a particular type being made is important.
Learning Operating System Concepts
If one enables the trailing of all common system calls, one can see a clear(er) picture of `what happens when something happens' in UNIX (for example, executing a binary file doesn't cause an open, but executing a shell script does) - Similarly, more complicated concepts could be driven home by seeing for oneself the behavior of the system rather than just reading about it.
Experimenting With Time
Re-routing of the time system calls enables one to experiment with times in future and in history on a per-file basis, without hampering the sanity of the entire system. This could be useful for people experimenting with problems like the Y2K, and it will allow expired copies of software (that refuse to run after a certain date) to be run without modifying the system time.


Though the code no longer crashes my system, I cannot guarantee that it will not crash yours. Otherwise, the concept is fairly frozen. The overhead could be reduced if the original system call implementation were modified, but that is not as neat and convenient as loading a module. I am yet to run benchmarks and quantize the re-routing overhead. All bugs and suggestions may be kindly emailed to yours truly.



© Copyright 1998 Amit Singh. All Rights Reserved.