Kernel Configuration: There are two kernel config options that control the level of audit support compiled into the kernel. The options are: CONFIG_AUDIT: This enables the base level of audit support required by SELinux. CONFIG_AUDITSYSCALL: This enables the ptrace hooks for the full syscall audit trace. The currently supported architectures include X86, PPC64, S390, IA64, X86_64. Kernel Command Line Parameters: There is only one audit related kernel command line option, "audit". The "audit" option enables and disables the audit syscall support. The "audit" parameter does not control the audit support required by SELinux. You cannot disable the audit support that SELinux depends on without recompiling the kernel with CONFIG_AUDIT disabled. System call auditing can have a performance impact on the system, since each system call can be audited. When audit=0 is passed on the command line, only the logging facilities of the audit system are enabled, and performance is only impacted (slightly) when SELinux is emitting audit records. Examples of the various options, and what gets logged to the console, follows. With audit=1 appended to the kernel command line: Aug 4 09:55:39 dhcp83-26 kernel: Kernel command line: ro root=LABEL=/ rhgb quiet audit=1 Aug 4 09:55:39 dhcp83-26 kernel: audit: enabled (after initialization) Aug 4 09:55:39 dhcp83-26 kernel: audit: initializing netlink socket (enabled) Aug 4 09:55:39 dhcp83-26 kernel: audit(1091613289.775:0): initialized With audit=0 appended to the kernel command line: Aug 4 10:02:42 dhcp83-26 kernel: Kernel command line: ro root=LABEL=/ rhgb quiet audit=0 Aug 4 10:02:42 dhcp83-26 kernel: audit: disabled (after initialization) Aug 4 10:02:43 dhcp83-26 kernel: audit: initializing netlink socket (disabled) Aug 4 10:02:43 dhcp83-26 kernel: audit(1091613713.134:0): initialized The default case, no audit specific information appended to the kernel command line. Aug 3 11:11:47 dhcp83-26 kernel: Kernel command line: ro root=LABEL=/ rhgb quiet Aug 3 11:11:48 dhcp83-26 kernel: audit: initializing netlink socket (disabled) Aug 3 11:11:48 dhcp83-26 kernel: audit(1091531456.171:0): initialized Unless you specify audit=0, or audit=1, on the kernel command line you will not get the "kernel: audit: disabled (after initialization)" output logged to the console or syslog. Appending "audit=0" to the kernel command line is functionaly equivalent to the default case. The first audit record logged is "kernel: audit(1091531456.171:0): initialized". The format of the audit record includes the current time, (1091531456.171 = seconds.milli-seconds)", the serial number assigned to the audit record, (:0 = serial number), and the text passed in by the initial audit_log() call, ("initialized"). User Space Commands You will need to build the latest audit user space commands. You can obtain the latest user space tar.gz file from http://people.redhat.com/peterm/audit. The latest version is auditd-0.5.tar.gz. This is the last version that the original author, Rik Faith, wrote. Look for newer versions with the same filename format in the future. Uncompress the tar.gz file and isuue the configure command with the proper path to your 2.6 Linux kernel include directory, e.g.; bash# ./configure --with-audith=/usr/src/linux/include After configure has a chance to run follow it up with a make. Run the auditctl command with the -s option to verify that audit is enabled in your kernel. bash# ./auditctl -s AUDIT_STATUS: enabled=0 failure=1 pid=0 rate_limit=0 backlog_limit=64 lost=0 backlog=0 If it is not enabled, i.e. enabled=0, then enable audit support with the -e option; bash# ./auditctl -e 1 AUDIT_STATUS: enabled=1 failure=1 pid=0 rate_limit=0 backlog_limit=64 lost=0 backlog=0 The -a option allows specific rules to be added for syscal auditing. To audit the read system call as an example; bash# ./auditctl -a entry,always -S read AUDIT_LIST: entry always syscall=read NLMSG_DONE Available rule lists include task, entry, and exit. Available actions include always, possible, and never. During runtime you can verify the current list of syscalls being audited with the -l option; bash# ./auditctl -l AUDIT_LIST: entry always syscall=read NLMSG_DONE To monitor all system calls you would use: ./auditctl -a entry,always -S all For reference the auditctl usage information can be displayed with the -h option; bash# ./auditctl -h usage: auditctl [options] -h Help -s Report status -e [0|1] Set enabled flag -f [0..2] Set failure flag 0=silent 1=printk 2=panic -p Set pid of auditd (testing only) -r Set limit in messages/sec (0=none) -l List rules -a Add rule at end of ist with ction -A Add rule at beginning ist with ction -d Delete rule from ist with ction l=task,entry,exit a=never,possible,always -S syscall Build rule: syscall name or number -F f=v Build rule: field name, value -m text Send a user-space message -L uid,txt Set login uid and send login message Audit State: During runtime you can determine if audit syscall support is active by using the auditctl command with the -s option. The message type which returns the status information is AUDIT_GET. An example follows: bash# ./auditctl -s AUDIT_STATUS: enabled=0 failure=1 pid=0 rate_limit=0 backlog_limit=64 lost=0 backlog=0 The fields are defined as follows: enabled: This is the syscall audit enabled flag, 0=not enabled, 1=enabled. This is the audit_enabled variable in audit.c. failure: This determines what audit will do if it encounters an error and cannot proceed. This is the audit_failure variable in audit.c. The various options are: AUDIT_FAIL_PRINTK: Log the audit record using printk if you cannot communicate over the netlink socket. This is the default action. AUDIT_FAIL_SILENT: Do nothing, report nothing, just skip logging the record and continue. AUDIT_FAIL_PANIC: Call panic() with the pending audit record text. pid: This is the PID that audit is writing netlink socket information to. This is the audit_pid variable in audit.c. rate_limit: If non-zero, this is the maximum number of messages sent per second. The default is zero, not enabled. This is the audit_rate_limit variable in audit.c. backlog_limit: This is the maximum number of outstanding audit buffers allowed. The default is 64. This is the audit_rate_limit variable in audit.c. lost: The number of lost audit records. This is the audit_rate_limit variable in audit.c. backlog: The number of outstanding audit buffers. The value needs to be kept below audit_backlog_limit in order to avoid dropping audit records. This is the audit_backlog variable in audit.c. Task Filtering: You can audit specific system calls by adding the entries into one of the three linked lists as discussed in an earlier. To track a specific task you would use: ./auditctl -a exit, always -S all -F loginuid=1000 ./auditctl -L 1000,"auditing loginuid 1000" The second line is not required, it just generates an syslog entry when the auditing on the specified uid starts. The supported field names include: pid, uid, euid, suid, fsuid, gid, egid, sgid, fsgid, loginuid, pers, devmajor, devminor, inode, exit, success, a0, a1, a2, a3. The following sections describe where the field entries originate from. The pid, uid, euid, suid, fsuid, gid, egid, sgid, fsgid, and pers, (short for "pesonality"), are from task_struct defined in include/linux/sched.h. struct task_struct { ... unsigned long personality; ... pid_t pid; ... uid_t uid,euid,suid,fsuid; gid_t gid,egid,sgid,fsgid; ... struct audit_context *audit_context; ... }; The loginuid, devmajor, devminor, inode, exit, success, a0, a1, a2, and a3 fields are from the audit_context structure off of task_struct. struct audit_context { ... uid_t loginuid; /* login uid (identity) */ ... unsigned long argv[4]; /* syscall arguments */ ... int return_code;/* syscall return code */ ... struct audit_names names[AUDIT_NAMES]; /* inode and devs */ ... }; Loginuid field is contained in the audit_context loginuid. The a0-a3 field names are contained in the audit_context argv[] array. The exit and success fields share the audit_context return_code entry. The remaining fields, (inode, devmajor, devminor), are contained in the audit_names struct. struct audit_names { const char *name; unsigned long ino; dev_t rdev; }; The inode field is contained in the audit_names ino unsigned long, the devmajor and devminor fields share the audit_names rdev dev_t entry. Lost Audit Records: Audit records can be lost due to the following reasons. Audit cannot allocate an audit buffer, cannot obtain an socket buffer, exceeded the value set in audit_rate_limit, exceeded the backlog limit specified in audit_backlog_limit. SELinux: Kernel AVC, (Access Vector Cache), SELinux routines use the audit_buffer struct for display support via the avc_dump_av(), avc_dump_query(), and avc_dump_cache() functions. SELinux allocates an audit_buffer for its own use by calling audit_log_start(), builds up the msg using audit_log_format(), fills in the dentry using audit_log_d_path(), and sends the completed avc record to user space, or /var/log/message, by calling audit_log_end(). The main SELinux routine is selinux/avc.c:avc_audit(). avc_audit() calls avc_dump_av() to gather access vector information and avc_dump_query() to obtain the source security identifier(SSID), target security identifier(TSID), and the target security class(TCLASS). SELinux installs targeted policy by default in Fedora Core 3 Test 1. You can check to see if SELinux is active on your system by adding a "-Z" option to one of the os commands. You can also check for a mounted SELinux file system, in a RedHat distribution the mount point would be /selinux. As an example, with SELinux enabled, "ls -lZ /etc/passwd" will show the following output: -rw-r--r-- root root system_u:object_r:etc_t /etc/passwd The fourth field in the ls output is the security context associated with the file. It is stored in the extended attributes of the file system. SELinux uses the security context when checking access rights. To setup a specific filter to generate audit records for any access to /etc/passwd you need to use the SELinux information displayed by using the "-Z" command line option. The ls output tells us that the /etc/passwd file is of type etc_t. Once you know the type of the file to be audited you will need to create a domain file to enable auditing specifically for that type, in our case etc_t. On the RedHat installation disk disk #4 you will need to install the selinux-policy-targeted-sources RPM, e.g. "rpm -Uhv /mnt/cdrom/Fedora/RPMS/selinux-policy-targeted-sources-1.14.1-5.noarch.rpm". In the /src/policy/domains directory you will need to create an audit.te, ( the audit type enforcement file), with the following contents: auditallow * etc_t:file *; The fields in the audit.te file can be broken down as follows. "auditallow" tells SELinux to send an audit message anytime it matches the rest of the sentence. The second field "*" means match any domain. In SELinux processes also have types, but for historical reasons, they are also referred to in that case as having domains. This does not apply to non-processes. "etc_t" refers to the domain, "file" describes the object. The final "*" says match any access. The example audit.te policy tells SELinux to audit all access by any domain of files marked with the security context etc_t. You will need to rebuild SELinux policy to include your new rule. From /etc/ selinux/targeted/src/policy you need to "make load; make -W users load". Executing the "ls -lZ /etc/passwd" command now results in several audit records being logged by SELinux, (the records have been broken up to avoid line wrap): Aug 4 14:25:15 dhcp83-26 kernel: audit(1091643915.064:0): avc: granted { read } for pid=4940 exe=/bin/ls name=passwd dev=hda3 ino=1454372 scontext= root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file Aug 4 14:25:15 dhcp83-26 kernel: audit(1091643915.065:0): avc: granted { getattr } for pid=4940 exe=/bin/ls path=/etc/passwd dev=hda3 ino=1454372 scontext=root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file Aug 4 14:25:15 dhcp83-26 kernel: audit(1091643915.065:0): avc: granted { read } for pid=4940 exe=/bin/ls path=/etc/passwd dev=hda3 ino=1454372 scontext=root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file Executing "cat /etc/passwd" produces the following output: Aug 4 14:25:07 dhcp83-26 kernel: audit(1091643907.561:0): avc: granted { read } for pid=4937 exe=/bin/cat name=passwd dev=hda3 ino=1454372 scontext=root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file Aug 4 14:25:07 dhcp83-26 kernel: audit(1091643907.561:0): avc: granted { getattr } for pid=4937 exe=/bin/cat path=/etc/passwd dev=hda3 ino=1454372 scontext=root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file Aug 4 14:25:07 dhcp83-26 kernel: audit(1091643907.562:0): avc: granted { read } for pid=4937 exe=/bin/cat path=/etc/passwd dev=hda3 ino=1454372 scontext=root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file Aug 4 14:25:07 dhcp83-26 kernel: audit(1091643907.563:0): avc: granted { read } for pid=4937 exe=/bin/cat path=/etc/passwd dev=hda3 ino=1454372 scontext=root:system_r:unconfined_t tcontext=system_u:object_r:etc_t tclass=file The problem with using SELinux to control what groups get flagged for auditing is that the domains can include a large number of objects. Enabling the etc_t domain caused any access to any file in /etc to be logged. For more granular auditing you need to create rules outside of SELinux specific to audit. Audit Kernel routines: The kernel routines for audit consist of kernel/audit.c and kernel/auditsc.c. audit.c contains the generic logging code. auditsc.c contains the syscall auditing code. EXPORTED SYMBOLS: audit_set_rate_limit, audit_set_backlog_limit, audit_set_enabled, audit_set_failure, audit_log_sdtart, audit_log_format, audit_log_end_irq, audit_log_end_fast, audit_log_end, audit_log, audit_log_d_path, auditsc.c:audit_alloc, auditsc.c:audit_free, auditsc.c:audit_syscall_entry, auditsc.c:audit_syscall_exit, auditsc.c:audit_getname, auditsc.c:audit_putname, auditsc.c:audit_inode. FUNCTIONS: audit_panic() - Switches on mode specified in audit_failure. Current modes are AUDIT_FAIL_SILENT, AUDIT_FAIL_PRINTK, AUDIT_FAIL_PANIC. CALLED BY: audit_log_lost(), audit_init(). CALLS: audit_rate_check() - Checks to make sure we are below msg log limits. CALLED BY: audit_log_start(), audit_log_end_fast(). CALLS: audit_log_lost() - Prints at least one log msg per second regardless of rate check. CALLED BY: audit_log_move(), audit_log_drain(), audit_log_start(), audit_log_start(), audit_log_end_fast(), auditsc.c:audit_alloc(). CALLS: audit_panic(). audit_set_rate_limit() - Sets the static int audit_rate_limit to the specified number of messages per second. CALLED BY: audit_receive_msg(). CALLS: audit_log(). audit_set_backlog_limit() - Sets the static int audit_backlog_limit to the number of outstanding audit buffers. Default is 64. CALLED BY: audit_receive_msg(). CALLS: audit_log(). audit_set_enabled() - Sets the specified audit state in the global audit_enabled. CALLED BY: audit_receive_msg(). CALLS: audit_log(). audit_set_failure() - Sets the specified failure state in static audit_failure. Valid states are AUDIT_FAIL_SILENT, AUDIT_FAIL_PRINTK, AUDIT_FAIL_PANIC. CALLED BY: audit_receive_msg(). CALLS: audit_log(). audit_send_reply() - Sends msg to netlink socket. CALLED BY: audit_receive_msg(). CALLS: audit_receive_msg() - Processes received sk_buff. Valid types include AUDIT_GET, AUDIT_SET, AUDIT_USER, AUDIT_LOGIN, AUDIT_LIST, AUDIT_ADD, AUDIT_DEL. CALLED BY: audit_receive_skb(). CALLS: audit_send_reply(), audit_set_enabled(), audit_set_failure(), audit_log(), audit_set_rate_limit(), audit_set_backlog_limit(), audit_log_start(), audit_log_format(), audit_log_end(), audit_set_loginuid(), audit_receive_filter(). audit_receive_skb() - Get msg from sk_buff. CALLED BY: audit_receive(). CALLS: audit_receive_msg(). audit_receive() - Receive msg from netlink socket. Receive function associated with netlink socket. CALLED BY: CALLS: audit_receive_skb(). audit_log_move() - Move data from tmp bufer into skb, or printk the audit_buffer if CONFIG_NET is not set. CALLED BY: audit_log_vformat(), audit_log_d_path(), audit_log_end_fast(). CALLS: audit_log_lost(). audit_log_drain() - Process sk_buffs in the audit_buffer, send contents to user space, or return 0 if CONFIG_NET is not set. CALLED BY: audit_log_end_fast(). CALLS: audit_log_end_irq(). audit_init() - Audit initialization routine, allocates netlink socket if CONFIG_NET is set, sets global audit_enabled to static audit_default. CALLED BY: CALLS: audit_panic(), audit_log(). audit_enable() - Sets audit_default based on kernel command line boot args, e.g.audit=0, audit=1. CALLED BY: CALLS: audit_log_start() - Obtains the audit_buffer under lock protection. CALLED BY: auditsc.c:audit_log_exit(), audit_receive_msg(), audit_log(), selinux/avc:avc_audit(). CALLS: audit_rate_check(), audit_log_lost(), audit_get_stamp(), audit_log_format(). audit_log_vformat() - Format the audit msg into the audit_buffer. CALLED BY: audit_log_format(), audit_log(). CALLS: audit_log_move(). audit_log_format() - Verifies audit_buffer. CALLED BY: audit_receive_msg(), audit_log_start(), audit_log_d_path(), auditsc.c:audit_log_exit(), selinux/avc:avc_dump_av(), selinux/avc:avc_dump_query(), selinux/avc:avc_print_ipv6_addr(), selinux/avc:avc_print_ipv4_addr(), selinux/avc:avc_audit(). CALLS: audit_log_vformat(). audit_log_d_path() - Prints the d_path. CALLED BY: selinux/avc:avc_audit(). CALLS: audit_log_format(). audit_tasklet_handler() - Remove msgs from the audit_txlist queue and send to user space. CALLED BY: CALLS: audit_log_end_fast(). audit_log_end_irq() - Schedules the audit_tasklet to remove queued msgs from the audit_txlist queue via audit_tasklet_handler(). CALLED BY: audit_log_drain(), audit_log_end() CALLS: audit_tasklet_handler(via schedule). audit_log_end_fast() - Send the msg in the audit_buffer to user space. Cannot be called in irq context. CALLED BY: audit_tasklet_handler(), audit_log_end() CALLS: audit_rate_check(), audit_log_lost(), audit_log_move(), audit_log_drain(). audit_log_end() - Send or queue the msg in the audit_buffer to user space, context independent. CALLED BY: audit_receive_msg(), audit_log_drain(), audit_tasklet_handler(), audit_log(), auditsc.c:audit_log_exit(), selinux:avc:avc_audit(). CALLS: audit_log_end_irq(), audit_log_end_fast(). audit_log() - Logs an audit record in any context. CALLED BY: audit_set_rate_limit(), audit_set_backlog_limit(), audit_set_enabled(), audit_set_failure(), audit_receive_msg(), audit_init(), selinux/ss/services:compute_sid_handle_invalid_context(). selinux/avc:avc_init(). CALLS: audit_log_start(), audit_log_vformat(), audit_log_end(). auditsc.c:audit_compare_rule() - Check two rules to see if they are identical. Called from audit_del_rule during AUDIT_DEL. CALLED BY: auditsc.c:audit_del_rule() CALLS: auditsc.c:audit_add_rule() - Add a rule to the list. CALLED BY: auditsc.c:audit_receive_rule() CALLS: auditsc.c:audit_free_rule() - Free rule. CALLED BY: auditsc.c:audit_del_rule() CALLS: auditsc.c:audit_del_rule() - Remove a rule from the list. CALLED BY: auditsc.c:audit_receive_filter() CALLS: auditsc.c:audit_compare_rule(). auditsc.c:audit_copy_rule() - Copy rule from user space, called during AUDIT_ADD. Supported actions include AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS. CALLED BY: auditsc.c:audit_receive_filter() CALLS: auditsc.c:audit_receive_filter() - Process filter request from user space. Supported actions include AUDIT_LIST, AUDIT_ADD, AUDIT_DEL. CALLED BY: audit_receive_msg(). CALLS: auditsc.c:audit_del_rule(), auditsc.c:audit_add_rule(), audit_send_reply(). auditsc.c:audit_filter_rules() - Check on a match between an audit rule and a task_struct. Supported matches include AUDIT_PID, AUDIT_UID, AUDIT_EUID, AUDIT_SUID, AUDIT_FSUID, AUDIT_GID, AUDIT_EGID, AUDIT_SGID, AUDIT_FSGID, AUDIT_PERS, AUDIT_EXIT, ADUIT_SUCCESS, AUDIT_DEVMAJOR, AUDIT_DEVMINOR, AUDIT_INODE, AUDIT_LOGINUID, AUDIT_ARG0, AUDIT_ARG1, AUDIT_ARG2, ADUIT_ARG3, ADUIT_NEVER, AUDIT_ALWAYS, AUDIT_POSSIBLE. CALLED BY: auditsc.c:audit_filter_task(), auditsc.c:audit_filter_syscall(). CALLS: auditsc.c:audit_filter_task() - Check a task to determine if system-call auditing is enabled. CALLED BY: auditsc.c:audit_alloc(). CALLS: audtisc:audit_filter_rules(). auditsc.c:audit_filter_syscall() - Called at syscall entry and exit to determine if the audit record needs to be written. CALLED BY: audtisc:audit_get_context(), auditsc.c:audit_syscall_entry(). CALLS: auditsc.c:audit_filter_rules(). auditsc.c:audit_get_context() - Retreive context and set proper auditable context. CALLED BY: auditsc.c:audit_syscall_exit(), auditsc.c:audit_free(). CALLS: auditsc.c:audit_filter_syscall(). auditsc.c:audit_free_names() - Calls putname for the name fields in the audit_context record. CALLED BY: auditsc.c:audit_free_context(), auditsc.c:audit_syscall_exit(). CALLS: auditsc.c:audit_zero_context() - Initializes a audit_context record. CALLED BY: auditsc.c:audit_alloc_context(), auditsc.c:audit_syscall_entry(), auditsc.c:audit_syscall_exit().. CALLS: auditsc.c:audit_alloc_context() - Allocates and audit_context entry. CALLED BY: auditsc.c:audit_alloc(), auditsc.c:audit_syscall_entry(). CALLS: auditsc.c:audit_zero_context(). auditsc.c:audit_alloc() - Filter on a the task information and allocate a per-task audit context as required. CALLED BY: kernel/fork(). CALLS: audit_filter_task(), audit_alloc_context(). auditsc.c:audit_free_context() - Walk the list on contexts and free the name entry. CALLED BY: auditsc.c:audit_free(), auditsc.c:audit_syscall_exit(). CALLS: auditsc.c:audit_free_names(). auditsc.c:audit_log_exit() - Log the audit record on syscall exit. CALLED BY: auditsc.c:audit_free(), auditsc.c:audit_syscall_exit(). CALLS: audit_log_start(), audit_log_format(), audit_log_end(). auditsc.c:audit_free() - Free the per-task audit context, called from copy_process and put_task_struct. CALLED BY: kernel/fork:copy_process(). CALLS: audit_get_context(), audit_log_exit(), audit_free_context(). auditsc.c:audit_serial() - Compute the 24 bit serial number for the audit record. CALLED BY: auditsc.c:audit_syscall_entry(). CALLS: auditsc.c:audit_syscall_entry() - Fill in the audit context at syscall entry. CALLED BY: arch/[i386,mips,ppc64,s390,x86_64]/kernel/ ptrace:do_syscall_trace() CALLS: audit_alloc_context(), audit_zero_context(), audit_filter_syscall(), audit_serial(). auditsc.c:audit_syscall_exit() - clean up after system call. CALLED BY: arch/[i386,mips,ppc64,s390,x86_64]/kernel/ptrace: do_syscall_trace() CALLS: audit_get_context(), audit_log_exit(), audit_free_context(), audit_zero_context(), audit_free_names(). auditsc.c:audit_getname() - Add a name to the audit_context context. Called from fs/namei.c:getname(). CALLED BY: fs/namei:getname(). CALLS: auditsc.c:audit_putname() - Intercept a putname request. Called from include/ linux/fs.h:putname(). CALLED BY: include/linux/fs.h:putname(). CALLS: auditsc.c:audit_inode() - Store the inode and device information. Called from fs/namei.c:path_lookup(). CALLED BY: fs/namei:path_lookup(). CALLS: auditsc.c:audit_get_stamp() - Get the current time stamp information. CALLED BY: audit_log_start(). CALLS: auditsc.c:audit_set_loginuid() - Set the login uid in the current context. CALLED BY: audit_receive_msg() CALLS: