Adding auditing to new system calls or applications

Security event auditing is a complex topic, but the quick of it is that audit logs security-relevant events. Most frequently these events relate to access control, successful or failed user authentication, and system administration events.

Audit describes each event using an audit record, which records information such as the time of the event, what authenticated user caused the event, and other event-specific information, such as the objects that were manipulated -- files, network ports, users, etc.

The purpose of the audit trail has historically been to allow post-mortem analysis following a compromise; more recently, audit systems have become sources of data for intrusion detection. The FreeBSD and Mac OS X audit implementations are well-suited to both tasks, providing two possible destinations for audit records:

What events are auditable

When auditing is added in the context of a security evaluation, such as CAPP, the evaluation Security Target will identify what is security-relevant. Outside the context of an evaluation, auditing will generally apply to any event that involves authentication or access control, such as password checking, privilege checks, permission evaluation, and so on. In practice the following types of things in operating system tend to require auditing:

Audit context

Events are considered to be "attributable" if they occur as a result of a specific request from a process acting on behalf of an authenticated identity, and otherwise "non-attributable". When an audit record is generated as a result of an attributable event, it must reliably represent the authenticated identity and other audit context:

This information is sometimes derived implicitly from the context, such as from the process credential, but sometimes will be managed explicitly by applications (such as when auditing successful authentication before the process credential is updated). It is useful to think about auditable events occuring in one of four types of contexts:

Description

Example

Context source

Attributable

Entirely outside of an audit session

System boot or shutdown

Implicit

No

During login, before authentication

sshd

Implicit

No

During login, after authentication, before credentials set

sshd

Explicit

Yes

During login, after authentication, after credentials set

sshd

Implicit

Yes

User session after login

passwd

Implicit

Yes

Outside audit session but direct result of request inside audit session

cron, launchd

Depends

Yes

The last case is tricky: events are auditable and attributable, but the process credential may not reflect authentication and audit context appropriate to the audit event. In these cases, the service will have to explicit set up audit state for the purpose of the generated record, and perhaps replicate some portion of the login-time audit setup for services it launches.

Privilege to write to the audit trail

Writing to the audit trail requires privilege; for system call auditing, this is not a problem, as the kernel does it automatically from a kernel context with sufficient privilege. For userspace event auditing, this requires special privilege, typically represented by having an effective uid of 0 (or, when fine-grained privileged are used, the PRIV_AUDIT_SUBMIT privilege).

What audit event identifier to use

Event identifiers will be used by users and applications to identify and interpret records in the audit trail. A single event identifier may describe more than one "event" in that argument tokens included in the record may further narrow down what happened -- perhaps by object name, flags passed to the event, etc. However, all events captured by a single event identifier should have similar properties and be relatively granular, as event identifiers are one of the ways in which pre-selection, or selecting which administrators will select what events get audited.

For example: both the Linux and FreeBSD fstat(2) system calls share a single event identifier, AUE_FSTAT, as they describe the same operation despite being independent syscalls. On the other hand, AUE_STAT is not the same as AUE_FSTAT, as the former accepts a path argument to name the target object, and the latter accepts a file descriptor. For application records, it is often the case that an application will use one event type, named after the application, for all events it audits, distinguishing them using different description strings in an AUT_STRING token. This is not necessarily a good idea, despite being a common practice.

What to include in an audit record

Audit records consist of a header token, a series of tokens describing the specifics of the event, and a trailer token:

What information to include in a record depends on the specifics of the event; it is always necessary to include a subject token for attributable events, and recommended that one be included even for non-attributable ones so that the process ID and credential are available in the trail. Argument tokens should include any security-relevant information, but particularly, object names or identifiers, file descriptor numbers, permission or access control information, users, or groups affected by the event. Some information is not considered security-relevant, which typically includes pointer values, file offsets, amounts of data written etc. If an evaluation Security Target is being used to identify audit events, then it will provide some guidance on what arguments are considered security-critical.

Adding auditing to simple applications

For simple setuid binaries, or for tools run only as root already within an audit session, the utility function audit_submit(3). The following example, from the audit_submit(3) man page, is representative of a typical use:

           #include <bsm/audit.h>
           #include <bsm/libbsm.h>
           #include <bsm/audit_uevents.h>

           #include <stdio.h>
           #include <stdarg.h>
           #include <errno.h>

...

#ifdef USE_BSM_AUDIT
        if (getauid(&auid) < 0 && errno != ENOSYS) {
                syslog(LOG_AUTH | LOG_ERR, "getauid: %s", strerror(errno));
                errx(1, "Permission denied");
        }
#endif

...

        retcode = pam_authenticate(pamh, 0);
        if (retcode != PAM_SUCCESS) {
#ifdef USE_BSM_AUDIT
                if (audit_submit(AUE_su, auid, EPERM, 1, "bad su %s to %s on %s",
                    username, user, mytty))
                        errx(1, "Permission denied");
#endif

XXX: More text here

Adding auditing to applications that log users in and out

XXX: More text here

Adding auditing to applications that execute in deferred or delegated contexts

XXX: More text here

Adding auditing to system calls

Most system calls are considered "auditable" events, meaning that they are security-relevant and of interest to audit consumers. Here is the process for adding the required auditing for a new (or existing) system call:

Identify or allocate BSM audit event identifier

Each possible event in the system is assigned a unique event identifier, prefixed with AUE_. Most system calls will have an AUE_ event name similar to the system call name, such as AUE_LISTEN, AUE_CLOSE, etc. Compat system calls or semantically identical system calls will share the same identifier -- for example, all variants on the fstat(2) system call use the same AUE_FSTAT identifier.

If an existing BSM event appears to be a good match for the new system call in sys/bsm/audit_kevents.h. If so, use that event. If not, contact RobertWatson for assistance as it will need to be added in the OpenBSM before being merged to the FreeBSD base source tree. This is necessary to avoid allocating conflicting events with other systems that use OpenBSM, so the OpenBSM version of the file is considered authoritative.

Some system calls are not considered auditable, and may simply use AUE_NULL. However, this is unusual, as most system calls involve some sort of access control.

Hook up the event identifier in relevant system call tables

The syscalls.master file format has an audit identifier for each system call. Make sure to find all instances in all files, such as compat32, etc. Make sure to rebuild the sysent vector.

Audit any desired arguments

It is often desirable to audit arguments passed to a system call, not just that the system call occurred. This is typically done using a series of type-based macros:

AUDIT_ARG(fd, args->fd);

Possible types can be found in src/sys/security/audit/audit.h; contact RobertWatson if you require additional types.

Add BSM encoding of record type and argument

When audit records are written to disk (or sent to processes), they are converted from an in-kernel data structure to the BSM format. This is done on a per-event type basis in audit_bsm.c:kaudit_to_bsm(). Each supported event identifier appears once in the switch, and for each expected (or optional) argument, the type is converted to a BSM token and added to the in-progress record. Contact RobertWatson if you need any advice here.

Test

Test by configuring auditing of the event, generating the system call, and viewing the trail (or using an auditpipe) to confirm that the system call and any required arguments are properly captured in the trail.

AddingAuditEvents (last edited 2009-04-03T22:43:06+0000 by RobertWatson)