user message limits
by LC Bruzenak
I know I can go look at the code, however I figured I'd ask here first
about the limits on the user message in both audit_log_user_message and
ausearch.
With audit_log_user_message the maximum length allowed appears to be
around MAX_AUDIT_MESSAGE_LENGTH-100. I think it may depend on the
executable name length (and other stuff auto-pushed into the string)
which is why I say "around".
Even when I get a successful return value (from audit_log_user_message),
I don't get my string back out in "ausearch" unless it is WAY smaller -
~1K or less I think.
Any ideas/thoughts?
This is the latest (1.7.11-2) audit package.
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny(a)magitekltd.com
11 years, 1 month
linux-audit: reconstruct path names from syscall events?
by John Feuerstein
Hi,
I would like to audit all changes to a directory tree using the linux
auditing system[1].
# auditctl -a exit,always -F dir=/etc/ -F perm=wa
It seems like the GNU coreutils are enough to break the audit trail.
The resulting SYSCALL events provide CWD and multiple PATH records,
depending on the syscall. If one of the PATH records is relative, I can
reconstruct the absolute path using the CWD record.
However, that does not work for the whole *at syscall family
(unlinkat(2), renameat(2), linkat(2), ...); accepting paths relative to
a given directory file descriptor. GNU coreutils are prominent users,
for example "rm -r" making use of unlinkat(2) to prevent races.
Things like dup(2) and fd passing via unix domain sockets come to mind.
It's the same old story again: mapping fds to path names is ambiguous at
best, if not impossible.
I wonder why such incomplete file system auditing rules are considered
sufficient in the CAPP/LSPP/NISPOM/STIG rulesets?
Here's a simplified example:
$ cd /tmp
$ mkdir dir
$ touch dir/file
$ ls -ldi /tmp /tmp/dir /tmp/dir/file
2057 drwxrwxrwt 9 root root 380 Sep 17 00:02 /tmp
58781 drwxr-xr-x 2 john john 40 Sep 17 00:02 /tmp/dir
56228 -rw-r--r-- 1 john john 0 Sep 17 00:02 /tmp/dir/file
$ cat > unlinkat.c
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int dirfd = open("dir", O_RDONLY);
unlinkat(dirfd, "file", 0);
return 0;
}
^D
$ make unlinkat
cc unlinkat.c -o unlinkat
$ sudo autrace ./unlinkat
Waiting to execute: ./unlinkat
Cleaning up...
Trace complete. You can locate the records with 'ausearch -i -p 32121'
$ ls -li dir
total 0
Now, looking at the resulting raw SYSCALL event for unlinkat(2):
type=SYSCALL msg=audit(1316210542.899:779): arch=c000003e syscall=263 success=yes exit=0 a0=3 a1=400690 a2=0 a3=0 items=2 ppid=32106 pid=32121 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts12 ses=36 comm="unlinkat" exe="/tmp/unlinkat" key=(null)
type=CWD msg=audit(1316210542.899:779): cwd="/tmp"
type=PATH msg=audit(1316210542.899:779): item=0 name="/tmp" inode=58781 dev=00:0e mode=040755 ouid=1000 ogid=1000 rdev=00:00
type=PATH msg=audit(1316210542.899:779): item=1 name="file" inode=56228 dev=00:0e mode=0100644 ouid=1000 ogid=1000 rdev=00:00
type=EOE msg=audit(1316210542.899:779):
- From this event alone, there's no way to answer "Who unlinked
/tmp/dir/file?". For what it's worth, the provided path names would be
exactly the same if we had unlinked "/tmp/dir/dir/dir/dir/dir/file".
- PATH item 0 reports the inode of "/tmp/dir" (58781, see ls output
above), however, the reported path name is "/tmp" (bug?).
In this example I've used autrace, which traces everything, so I could
possibly search for a previous open(2) of inode 58781. And indeed, there
it is:
type=SYSCALL msg=audit(1316210542.899:778): arch=c000003e syscall=2 success=yes exit=3 a0=40068c a1=0 a2=7fff22724fc8 a3=0 items=1 ppid=32106 pid=32121 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts12 ses=36 comm="unlinkat" exe="/tmp/unlinkat" key=(null)
type=CWD msg=audit(1316210542.899:778): cwd="/tmp"
type=PATH msg=audit(1316210542.899:778): item=0 name="dir" inode=58781 dev=00:0e mode=040755 ouid=1000 ogid=1000 rdev=00:00
type=EOE msg=audit(1316210542.899:778):
Great, so inode 58781 was opened using "/tmp/dir", and therefore, the relative
path "file" given to unlinkat(2) above could possibly translate to
"/tmp/dir/path"... not really feeling confident here.
- All file system auditing rules in various rulesets and the examples in
the documentation add the "-F perm=wa" (or similar) filter, so the
open(2) wouldn't even make it into the audit trail.
- If you can handle the volume and log all open(2), what happens if the
open(2) was done hours, days, weeks, ... ago?
- What if the open(2) was done by another process which passed the fd
on a unix domain socket?
It looks like the kernel auditing code should provide
... item=0 name="/tmp/dir" inode=58781 ...
in the unlinkat(2) syscall event above. Looking up the unlinkat(2)
documentation:
int unlinkat(int dirfd, const char *pathname, int flags);
If the pathname given in pathname is relative, then it is
interpreted relative to the directory referred to by the file
descriptor dirfd (rather than relative to the current working
directory of the calling process, as is done by unlink(2) and
rmdir(2) for a relative pathname).
If the pathname given in pathname is relative and dirfd is the
special value AT_FDCWD, then pathname is interpreted relative
to the current working directory of the calling process (like
unlink(2) and rmdir(2)).
As you might see, there's not only the fd->pathname problem, but
also the special case for AT_FDCWD. In this case the kernel side should
probably just duplicate CWD's path name into item 0's path name. But
that's just unlinkat(2), there are a lot more.
What am I missing here? Is there no way to audit a directory tree?
I've looked at alternatives: Inotify watches won't scale to big trees
and events lack so much detail that they can't be used for auditing.
Fanotify, while providing the pid, still lacks a lot of events and
passes fds; the example code relies on readlink("/proc/self/fd/...").
Thanks,
John
[1] http://people.redhat.com/sgrubb/audit/
--
John Feuerstein <john(a)feurix.com>
12 years
AUDIT_SIGNAL_INFO
by Matthew Booth
Under what circumstances will the RHEL 4 kernel generate a message of
type AUDIT_SIGNAL_INFO? My understanding is that it should be sent when
a process sends a signal to the audit daemon, however I have not
observed that. Any ideas?
Thanks,
Matt
--
Matthew Booth, RHCA, RHCSS
Red Hat, Global Professional Services
M: +44 (0)7977 267231
GPG ID: D33C3490
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
12 years, 4 months
Near Term Audit Road Map
by Steve Grubb
Hi,
With the proposals sent to the list, I wanted to talk about how this might
play out code-wise. With regard to the current code base, I am working on a
1.8 release. This would represent finishing the remote logging app and
nothing more. The 1.8 series would become just an update series just like the
1.0.x series did.
In parallel with finishing remote logging, I would release a 2.0 version.
Patches applied to 1.8 would also be applied to 2.0. A 2.1 release would
signify the completion of remote logging that branch. I would recommend this
branch for all distributions pulling new code in.
The 2.0 branch will also have a couple more changes. I want to split up the
audit source code a little bit. I want to drop the system-config-audit code
and let it become standalone package updated and distributed separately.
I also want to drop all audispd-plugins in the 2.0 branch and have them
released separately. They cause unnecessary build dependencies for the audit
package.
During the work for a 2.2 release, I would also like to pull the audispd
program inside auditd. In the past, I tried to keep auditd lean and single
purpose, but with adding remote logging and kerberos support, we already have
something that is hard to analyze. So, to improve performance and decrease
system load, the audit daemon will also do event dispatching.
Would this proposal impact anyone in a Bad Way?
Thanks,
-Steve
12 years, 4 months
test patch for auditctl inter-field comparisons on euid/uid, egid/gid
by Peter Moody
This patch extends Eric's test patch from 11/17 (
http://www.redhat.com/archives/linux-audit/2011-November/msg00045.html).
This turns -C into a long opt with similar syntax to -F.
This allows uid/euid and gid/egid to be compared, like
auditctl -a exit,always -F arch=b64 -C 'euid!=uid' -S execve -F 'euid!=0'
-F 'success=1'
which would audit on someone executing a setuid binary if the binary isn't
setuid root.
You can also check for writes to overly permissive files like
auditctl -a exit,always -F arch=b64 -C 'obj_uid!=uid' -F 'uid!=0' -F
'dir=/home/' -F 'success=1' -S open -F 'a2&=2'
This functionality is helpful in detecting user compromises across a shared
fleet; eg, attacker finds a world-writable shell script
(/home/victim/.bashrc, it's happened...) and inserts "cp /bin/bash /tmp/;
chmod 7777 /tmp/bash". After victim executes this, attacker executes
/tmp/bash -p and becomes victim.
One strange thing related to this patch: auditd seems to be reporting
success for a normal user process (gklrellm) opening /proc/meminfo (mode
444) O_RDWR, and I don't see how this is possible. eg:
type=SYSCALL msg=audit(1323540255.146:97): arch=c000003e syscall=2
success=yes exit=13 a0=4b1972 a1=0 a2=1b6 a3=0 items=1 ppid=1704 pid=1797
auid=11532 uid=11532 gid=5000 euid=11532 suid=11532 fsuid=11532 egid=5000
sgid=5000 fsgid=5000 tty=(none) ses=1 comm="gkrellm" exe="/usr/bin/gkrellm"
key="permissive"
type=CWD msg=audit(1323540255.146:97): cwd="/home/pmoody"
type=PATH msg=audit(1323540255.146:97): item=0 name="/proc/meminfo" inode=
4026532008 dev=00:03 mode=0100444 ouid=0 ogid=0 rdev=00:00
hopefully someone with more auditd internal knowledge can explain what's
going on.
auditctl -l doesn't know how to report this yet; if this patch is generally
acceptable, I can try to fix that and update the manpage, etc.
Signed-off-by: Peter Moody <pmoody(a)google.com>
---
trunk/auparse/typetab.h | 1 +
trunk/lib/fieldtab.h | 1 +
trunk/lib/libaudit.c | 144
+++++++++++++++++++++++++++++++++++++++++++
trunk/lib/libaudit.h | 2 +
trunk/src/auditctl.c | 19 +++++-
trunk/src/ausearch-report.c | 1 +
6 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/trunk/auparse/typetab.h b/trunk/auparse/typetab.h
index 746573c..3e6c6d1 100644
--- a/trunk/auparse/typetab.h
+++ b/trunk/auparse/typetab.h
@@ -32,6 +32,7 @@ _S(AUPARSE_TYPE_UID, "iuid" )
_S(AUPARSE_TYPE_UID, "id" )
_S(AUPARSE_TYPE_UID, "inode_uid" )
_S(AUPARSE_TYPE_UID, "sauid" )
+_S(AUPARSE_TYPE_UID, "obj_uid" )
_S(AUPARSE_TYPE_GID, "gid" )
_S(AUPARSE_TYPE_GID, "egid" )
_S(AUPARSE_TYPE_GID, "sgid" )
diff --git a/trunk/lib/fieldtab.h b/trunk/lib/fieldtab.h
index ad95814..e053df6 100644
--- a/trunk/lib/fieldtab.h
+++ b/trunk/lib/fieldtab.h
@@ -55,6 +55,7 @@ _S(AUDIT_WATCH, "path" )
_S(AUDIT_PERM, "perm" )
_S(AUDIT_DIR, "dir" )
_S(AUDIT_FILETYPE, "filetype" )
+_S(AUDIT_OBJ_UID, "obj_uid" )
_S(AUDIT_ARG0, "a0" )
_S(AUDIT_ARG1, "a1" )
diff --git a/trunk/lib/libaudit.c b/trunk/lib/libaudit.c
index 9a5070c..b10f984 100644
--- a/trunk/lib/libaudit.c
+++ b/trunk/lib/libaudit.c
@@ -783,6 +783,148 @@ int audit_rule_syscallbyname_data(struct
audit_rule_data *rule,
}
hidden_def(audit_rule_syscallbyname_data)
+int audit_rule_interfield_fieldpair_data(struct audit_rule_data **rulep,
+ const char *pair,
+ int flags) {
+ const char *f = pair;
+ char *v;
+ int op;
+ int field1, field2;
+ int vlen;
+ int offset;
+ struct audit_rule_data *rule = *rulep;
+
+ if (f == NULL)
+ return -1;
+
+ /* look for 2-char operators first
+ then look for 1-char operators afterwards
+ when found, null out the bytes under the operators to split
+ and set value pointer just past operator bytes
+ */
+ if ( (v = strstr(pair, "!=")) ) {
+ *v++ = '\0';
+ *v++ = '\0';
+ op = AUDIT_NOT_EQUAL;
+ } else if ( (v = strstr(pair, "=")) ) {
+ *v++ = '\0';
+ op = AUDIT_EQUAL;
+ } else {
+ fprintf(stderr, "only =, != comparisons are allowed in interfield\n");
+ return -1;
+ }
+
+ if (v == NULL)
+ return -1;
+
+ if (*f == 0)
+ return -22;
+
+ if (*v == 0)
+ return -20;
+
+ if ((field1 = audit_name_to_field(f)) < 0)
+ return -2;
+
+ if ((field2 = audit_name_to_field(v)) < 0)
+ return -2;
+
+ /* Exclude filter can be used only with MSGTYPE field */
+ if (flags == AUDIT_FILTER_EXCLUDE && field1 != AUDIT_MSGTYPE)
+ return -12;
+
+ // It should always be AUDIT_FIELD_COMPARE
+ rule->fields[rule->field_count] = AUDIT_FIELD_COMPARE;
+ rule->fieldflags[rule->field_count] = op;
+ switch (field1)
+ {
+ case AUDIT_UID:
+ switch(field2) {
+ case AUDIT_EUID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID;
+ break;
+ case AUDIT_OBJ_UID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_EUID:
+ switch(field2) {
+ case AUDIT_UID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_OBJ_UID:
+ switch(field2) {
+ case AUDIT_UID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_OBJ_GID:
+ switch(field2) {
+ case AUDIT_GID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_GID:
+ switch(field2) {
+ case AUDIT_EGID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID;
+ break;
+ case AUDIT_OBJ_GID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_EGID:
+ switch(field2) {
+ case AUDIT_OBJ_GID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ /* fallthrough */
+ default:
+ if (field1 == AUDIT_INODE) {
+ if (!(op == AUDIT_NOT_EQUAL ||
+ op == AUDIT_EQUAL))
+ return -13;
+ }
+
+ if (field1 == AUDIT_PPID && !(flags == AUDIT_FILTER_EXIT
+ || flags == AUDIT_FILTER_ENTRY))
+ return -17;
+
+ if (!isdigit((char)*(v)))
+ return -21;
+
+ if (field1 == AUDIT_INODE)
+ rule->values[rule->field_count] =
+ strtoul(v, NULL, 0);
+ else
+ rule->values[rule->field_count] =
+ strtol(v, NULL, 0);
+ break;
+ }
+ rule->field_count++;
+ return 0;
+}
+
int audit_rule_fieldpair_data(struct audit_rule_data **rulep, const char
*pair,
int flags)
{
@@ -857,6 +999,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
case AUDIT_SUID:
case AUDIT_FSUID:
case AUDIT_LOGINUID:
+ case AUDIT_OBJ_UID:
+ case AUDIT_OBJ_GID:
// Do positive & negative separate for 32 bit systems
vlen = strlen(v);
if (isdigit((char)*(v)))
diff --git a/trunk/lib/libaudit.h b/trunk/lib/libaudit.h
index 8feaa39..911bce4 100644
--- a/trunk/lib/libaudit.h
+++ b/trunk/lib/libaudit.h
@@ -428,6 +428,8 @@ extern int audit_rule_syscallbyname_data(struct
audit_rule_data *rule,
* adding new fields */
extern int audit_rule_fieldpair_data(struct audit_rule_data **rulep,
const char *pair, int flags);
+extern int audit_rule_interfield_fieldpair_data(struct audit_rule_data
**rulep,
+ const char *pair, int flags);
extern void audit_rule_free_data(struct audit_rule_data *rule);
#ifdef __cplusplus
diff --git a/trunk/src/auditctl.c b/trunk/src/auditctl.c
index 34b7935..d7ec998 100644
--- a/trunk/src/auditctl.c
+++ b/trunk/src/auditctl.c
@@ -482,7 +482,7 @@ static int setopt(int count, int lineno, char *vars[])
keylen = AUDIT_MAX_KEY_LEN;
while ((retval >= 0) && (c = getopt(count, vars,
- "hislDvte:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:")) != EOF) {
+ "hislDvtC:e:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:")) != EOF) {
int flags = AUDIT_FILTER_UNSET;
rc = 10; // Init to something impossible to see if unused.
switch (c) {
@@ -731,7 +731,6 @@ static int setopt(int count, int lineno, char *vars[])
retval = -1;
break;
}
-
rc = audit_rule_fieldpair_data(&rule_new,optarg,flags);
if (rc != 0) {
audit_number_to_errmsg(rc, optarg);
@@ -743,6 +742,22 @@ static int setopt(int count, int lineno, char *vars[])
}
break;
+ case 'C':
+ if (add != AUDIT_FILTER_UNSET)
+ flags = add & AUDIT_FILTER_MASK;
+ else if (del != AUDIT_FILTER_UNSET)
+ flags = del & AUDIT_FILTER_MASK;
+
+ rc = audit_rule_interfield_fieldpair_data(&rule_new, optarg, flags);
+ if (rc != 0) {
+ audit_number_to_errmsg(rc, optarg);
+ retval = -1;
+ } else {
+ if (rule_new->fields[rule_new->field_count - 1] ==
+ AUDIT_PERM)
+ audit_permadded = 1;
+ }
+ break;
case 'm':
if (count > 3) {
fprintf(stderr,
diff --git a/trunk/src/ausearch-report.c b/trunk/src/ausearch-report.c
index d50c732..62e1ae0 100644
--- a/trunk/src/ausearch-report.c
+++ b/trunk/src/ausearch-report.c
@@ -333,6 +333,7 @@ static struct nv_pair typetab[] = {
{T_UID, "id"},
{T_UID, "inode_uid"},
{T_UID, "sauid"},
+ {T_UID, "obj_uid"},
{T_GID, "gid"},
{T_GID, "egid"},
{T_GID, "sgid"},
--
1.7.3.1
--
Peter Moody Google 1.650.253.7306
Security Engineer pgp:0xC3410038
12 years, 8 months
[PATCH] auvirt: a new tool for reporting events related to virtual machines
by Marcelo Cerri
This patch adds a new tool to extract information related to virtual machines
from the audit log files. It can output a summary with information about the
number of events found with details by type of record and operation. The tool
can also output the filtered records as found in the audit log.
Using the --avc option auvirt tries to correlate AVC records to the guests
based on its security context. It's also possible to select records related to
just one guest using the UUID or the guest name.
This tool is based on the proposal sent in the RFC:
https://www.redhat.com/archives/linux-audit/2011-November/msg00014.html
Signed-off-by: Marcelo Cerri <mhcerri(a)linux.vnet.ibm.com>
---
audit.spec | 2 +
configure.ac | 2 +-
tools/Makefile.am | 2 +-
tools/auvirt/Makefile.am | 34 +++
tools/auvirt/auvirt-map-llist.c | 181 +++++++++++++
tools/auvirt/auvirt-map.h | 50 ++++
tools/auvirt/auvirt.8 | 107 ++++++++
tools/auvirt/auvirt.c | 541 +++++++++++++++++++++++++++++++++++++++
8 files changed, 917 insertions(+), 2 deletions(-)
create mode 100644 tools/auvirt/Makefile.am
create mode 100644 tools/auvirt/auvirt-map-llist.c
create mode 100644 tools/auvirt/auvirt-map.h
create mode 100644 tools/auvirt/auvirt.8
create mode 100644 tools/auvirt/auvirt.c
diff --git a/audit.spec b/audit.spec
index 383bed1..a9940b4 100644
--- a/audit.spec
+++ b/audit.spec
@@ -172,6 +172,7 @@ fi
%attr(644,root,root) %{_mandir}/man8/autrace.8.gz
%attr(644,root,root) %{_mandir}/man8/aulast.8.gz
%attr(644,root,root) %{_mandir}/man8/aulastlog.8.gz
+%attr(644,root,root) %{_mandir}/man8/auvirt.8.gz
%attr(644,root,root) %{_mandir}/man8/ausyscall.8.gz
%attr(644,root,root) %{_mandir}/man7/audit.rules.7.gz
%attr(644,root,root) %{_mandir}/man5/auditd.conf.5.gz
@@ -186,6 +187,7 @@ fi
%attr(755,root,root) %{_bindir}/aulast
%attr(755,root,root) %{_bindir}/aulastlog
%attr(755,root,root) %{_bindir}/ausyscall
+%attr(755,root,root) %{_bindir}/auvirt
%attr(755,root,root) /etc/rc.d/init.d/auditd
%attr(750,root,root) %dir %{_var}/log/audit
%attr(750,root,root) %dir /etc/audit
diff --git a/configure.ac b/configure.ac
index c1cf96f..b7f7fcd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -255,7 +255,7 @@ AC_SUBST(libev_LIBS)
AC_SUBST(LIBPRELUDE_CFLAGS)
AC_SUBST(LIBPRELUDE_LDFLAGS)
-AC_OUTPUT(Makefile lib/Makefile lib/test/Makefile auparse/Makefile auparse/test/Makefile src/Makefile src/mt/Makefile src/libev/Makefile src/test/Makefile swig/Makefile docs/Makefile init.d/Makefile audisp/Makefile audisp/plugins/Makefile audisp/plugins/builtins/Makefile audisp/plugins/prelude/Makefile audisp/plugins/remote/Makefile audisp/plugins/zos-remote/Makefile bindings/Makefile bindings/python/Makefile tools/Makefile tools/aulast/Makefile tools/aulastlog/Makefile tools/ausyscall/Makefile)
+AC_OUTPUT(Makefile lib/Makefile lib/test/Makefile auparse/Makefile auparse/test/Makefile src/Makefile src/mt/Makefile src/libev/Makefile src/test/Makefile swig/Makefile docs/Makefile init.d/Makefile audisp/Makefile audisp/plugins/Makefile audisp/plugins/builtins/Makefile audisp/plugins/prelude/Makefile audisp/plugins/remote/Makefile audisp/plugins/zos-remote/Makefile bindings/Makefile bindings/python/Makefile tools/Makefile tools/aulast/Makefile tools/aulastlog/Makefile tools/ausyscall/Makefile tools/auvirt/Makefile)
echo .
echo "
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 3b7acfe..15ba254 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -22,5 +22,5 @@
CONFIG_CLEAN_FILES = *.loT *.rej *.orig
-SUBDIRS = aulast aulastlog ausyscall
+SUBDIRS = aulast aulastlog ausyscall auvirt
diff --git a/tools/auvirt/Makefile.am b/tools/auvirt/Makefile.am
new file mode 100644
index 0000000..4ee2ca7
--- /dev/null
+++ b/tools/auvirt/Makefile.am
@@ -0,0 +1,34 @@
+#
+# Makefile.am --
+# Copyright (c) 2011 IBM Corp.
+# All Rights Reserved.
+#
+# This software may be freely redistributed and/or modified under the
+# terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# Authors:
+# Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
+#
+
+CONFIG_CLEAN_FILES = *.loT *.rej *.orig
+AUTOMAKE_OPTIONS = no-dependencies
+EXTRA_DIST = $(man_MANS)
+INCLUDES = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/auparse -I${top_srcdir}/src
+LIBS = -L${top_builddir}/auparse -lauparse
+AM_CFLAGS = -D_GNU_SOURCE
+bin_PROGRAMS = auvirt
+noinst_HEADERS = auvirt-map.h
+man_MANS = auvirt.8
+
+auvirt_SOURCES = auvirt.c auvirt-map-llist.c ${top_srcdir}/src/ausearch-time.c
diff --git a/tools/auvirt/auvirt-map-llist.c b/tools/auvirt/auvirt-map-llist.c
new file mode 100644
index 0000000..af55a41
--- /dev/null
+++ b/tools/auvirt/auvirt-map-llist.c
@@ -0,0 +1,181 @@
+/*
+ * auvirt-map-llist.c --
+ * Copyright (c) 2011 IBM Corp.
+ * All Rights Reserved.
+ *
+ * This software may be freely redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors:
+ * Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
+ */
+
+
+#include "auvirt-map.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct _map_t {
+ map_it_t *head;
+ map_it_t *tail;
+};
+
+struct _map_it_t{
+ char *key;
+ char *val;
+ map_it_t *prev;
+ map_it_t *next;
+};
+
+map_t *map_new()
+{
+ map_t *m = malloc(sizeof(map_t));
+ if (m == NULL)
+ return NULL;
+ m->head = NULL;
+ m->tail = NULL;
+ return m;
+}
+
+void free_node(map_it_t *it)
+{
+ if (it) {
+ free(it->key);
+ free(it->val);
+ free(it);
+ }
+}
+
+void map_free(map_t *m)
+{
+ if (m != NULL) {
+ map_it_t *it = m->head;
+ while (it && it->next) {
+ it = it->next;
+ free_node(it->prev);
+ }
+ free_node(it);
+ free(m);
+ }
+}
+
+int map_add(map_t *m, const char *k, const char *v)
+{
+ map_it_t *it = NULL;
+ if (m == NULL || k == NULL || v == NULL || map_get(m, k) != NULL)
+ goto error;
+
+ it = malloc(sizeof(map_it_t));
+ if (it == NULL)
+ goto error;
+ memset(it, 0, sizeof(map_it_t));
+ it->key = strdup(k);
+ if (it->key == NULL)
+ goto error;
+ it->val = strdup(v);
+ if (it->val == NULL)
+ goto error;
+
+ if (m->tail == NULL) {
+ m->head = m->tail = it;
+ return 0;
+ }
+
+ it->prev = m->tail;
+ m->tail->next = it;
+ m->tail = it;
+ return 0;
+
+error:
+ free_node(it);
+ return 1;
+}
+
+int map_set(map_t *m, map_it_t *it, const char *v)
+{
+ char *str = NULL;
+ if (m == NULL || it == NULL || v == NULL)
+ return 1;
+ if (v) {
+ str = strdup(v);
+ if (str == NULL)
+ return 1;
+ }
+ free(it->val);
+ it->val = str;
+ return 0;
+}
+
+int map_del(map_t *m, map_it_t *it)
+{
+ if (m == NULL || it == NULL)
+ return 1;
+ if (m->head == it)
+ m->head = it->next;
+ if (m->tail == it)
+ m->tail = it->prev;
+ if (it->next)
+ it->next->prev = it->prev;
+ if (it->prev)
+ it->prev->next = it->next;
+ free_node(it);
+ return 0;
+}
+
+map_it_t *map_get(map_t *m, const char *k)
+{
+ map_it_t *it = NULL;
+ if (m == NULL || k == NULL)
+ return NULL;
+ for (it = m->head; it; it = it->next)
+ if (strcmp(it->key, k) == 0)
+ return it;
+ return NULL;
+}
+
+map_it_t *map_next(const map_t *m, map_it_t *last)
+{
+ if (m == NULL)
+ return NULL;
+ if (last == NULL)
+ return m->head;
+ return last->next;
+}
+
+map_it_t *map_next_val(const map_t *m, const char *v, map_it_t *last)
+{
+ map_it_t *it = NULL;
+ if (m == NULL)
+ return NULL;
+ it = (last) ? last->next : m->head;
+ for (; it; it = it->next)
+ if (strcmp(it->val, v) == 0)
+ return it;
+ return NULL;
+}
+
+const char *map_it_key(const map_it_t *it)
+{
+ if (it)
+ return it->key;
+ return NULL;
+}
+
+const char *map_it_val(const map_it_t *it)
+{
+ if (it)
+ return it->val;
+ return NULL;
+}
+
diff --git a/tools/auvirt/auvirt-map.h b/tools/auvirt/auvirt-map.h
new file mode 100644
index 0000000..92fdb1a
--- /dev/null
+++ b/tools/auvirt/auvirt-map.h
@@ -0,0 +1,50 @@
+/*
+ * auvirt-map.h --
+ * Copyright (c) 2011 IBM Corp.
+ * All Rights Reserved.
+ *
+ * This software may be freely redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors:
+ * Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
+ */
+
+
+#ifndef AUVIRTMAP_HEADER
+#define AUVIRTMAP_HEADER
+
+struct _map_t;
+typedef struct _map_t map_t;
+struct _map_it_t;
+typedef struct _map_it_t map_it_t;
+
+map_t *map_new();
+void map_free(map_t *m);
+int map_add(map_t *m, const char *k, const char *v);
+int map_set(map_t *m, map_it_t *it, const char *v);
+int map_del(map_t *m, map_it_t *it);
+map_it_t *map_get(map_t *m, const char *k);
+map_it_t *map_next(const map_t *m, map_it_t *last);
+map_it_t *map_next_val(const map_t *m, const char *v, map_it_t *last);
+const char *map_it_key(const map_it_t *it);
+const char *map_it_val(const map_it_t *it);
+
+static inline const char *map_get_val(map_t *m, const char *k)
+{
+ return map_it_val(map_get(m, k));
+}
+
+#endif
+
diff --git a/tools/auvirt/auvirt.8 b/tools/auvirt/auvirt.8
new file mode 100644
index 0000000..1fc629b
--- /dev/null
+++ b/tools/auvirt/auvirt.8
@@ -0,0 +1,107 @@
+.TH AUVIRT 8 "Dec 2011" "IBM Corp" "System Administration Utilities"
+.SH NAME
+auvirt - a program that reports data related to virtual machines
+
+.SH SYNOPSIS
+.B auvirt
+[ \fIOPTIONS\fP ]
+[ \fIUUID\fP | \fIVM-NAME\fP ]
+
+.SH DESCRIPTION
+\fBauvirt\fP is a program that prints a summary of all virtualization related
+events found in the audit logs. If a guest is specified, only the events
+related to that guest is considered. To specify a guest, both UUID or VM name
+can be given.
+
+The summary contains the number of virtualization related events
+found, the number of events by type (AVC, machine id, control and resource),
+and the number of start, stop and suspend operations found.
+
+By default, auvirt reads records from the system audit log file. But
+\fB--stdin\fP and \fB--file\fP options can be specified to change this
+behavior.
+
+.SH OPTIONS
+.TP
+\fB-a\fP, \fB--avc\fP
+When this option is given the tool tries to correlate AVC records to a
+guest based on the security context. As the security context can be
+automatically changed on guest's start, the tool just correlates an AVC record
+to a guest if the record was generated during the period time that guest was
+running. This option causes auvirt to count AVC records and show the result in
+the summary. If \fB--raw\fP is specified together with this option, the AVC
+records considered
+will be printed.
+.TP
+\fB--debug\fP
+Print debug messages to standard output.
+.TP
+\fB-f\fP, \fB--file\fP \fIfile\fP
+Reads records from the given \fIfile\fP instead from the system audit log file.
+.TP
+\fB-h\fP, \fB--help\fP
+Print help message and exit.
+.TP
+\fB--raw\fP
+Print to standard output the filtered records as shown in the audit log.
+.TP
+\fB--stdin\fP
+Reads records from the standard input instead from the system audit log file.
+This option cannot be informed with \fB--file\fP.
+.TP
+\fB--summary\fP
+Prints a summary with information about the records found. This is the default
+behavior.
+.TP
+.BR \-te ,\ \-\-end \ [\fIend-date\fP]\ [\fIend-time\fP]
+Search for events with time stamps equal to or before the given end time. The
+format of end time depends on your locale. If the date is omitted,
+.B today
+is assumed. If the time is omitted,
+.B now
+is assumed. Use 24 hour clock time rather than AM or PM to specify time.
+An example date using the en_US.utf8 locale is 09/03/2009. An example of time
+is 18:00:00. The date format accepted is influenced by the LC_TIME
+environmental variable.
+
+You may also use the word: \fBnow\fP, \fBrecent\fP, \fBtoday\fP,
+\fByesterday\fP, \fBthis\-week\fP, \fBweek\-ago\fP, \fBthis\-month\fP,
+\fBthis\-year\fP. \fBToday\fP means starting now. \fBRecent\fP is 10 minutes
+ago. \fBYesterday\fP is 1 second after midnight the previous day.
+\fBThis\-week\fP means starting 1 second after midnight on day 0 of the week
+determined by your locale (see \fBlocaltime\fP). \fBThis\-month\fP means 1
+second after midnight on day 1 of the month. \fBThis\-year\fP means the 1
+second after midnight on the first day of the first month.
+.TP
+.BR \-ts ,\ \-\-start \ [\fIstart-date\fP]\ [\fIstart-time\fP]
+Search for events with time stamps equal to or after the given end time. The
+format of end time depends on your locale. If the date is omitted,
+.B today
+is assumed. If the time is omitted,
+.B midnight
+is assumed. Use 24 hour clock time rather than AM or PM to specify time. An
+example date using the en_US.utf8 locale is 09/03/2009. An example of time is
+18:00:00. The date format accepted is influenced by the LC_TIME environmental
+variable.
+
+You may also use the word: \fBnow\fP, \fBrecent\fP, \fBtoday\fP,
+\fByesterday\fP, \fBthis\-week\fP, \fBthis\-month\fP, \fBthis\-year\fP.
+\fBToday\fP means starting at 1 second after midnight. \fBRecent\fP is 10
+minutes ago. \fBYesterday\fP is 1 second after midnight the previous day.
+\fBThis\-week\fP means starting 1 second after midnight on day 0 of the week
+determined by your locale (see \fBlocaltime\fP). \fBThis\-month\fP means 1
+second after midnight on day 1 of the month. \fBThis\-year\fP means the 1
+second after midnight on the first day of the first month.
+
+.SH EXAMPLES
+To see all the records in this month for a guest
+
+\fBauvirt --raw --avc --start this-month GuestVmName\fP
+
+.SH SEE ALSO
+.BR aulast (8),
+.BR ausearch (8),
+.BR aureport (8).
+
+.SH AUTHOR
+Marcelo Cerri
diff --git a/tools/auvirt/auvirt.c b/tools/auvirt/auvirt.c
new file mode 100644
index 0000000..3e5b630
--- /dev/null
+++ b/tools/auvirt/auvirt.c
@@ -0,0 +1,541 @@
+/*
+ * auvirt.c - A tool to extract data related to virtualization.
+ * Copyright (c) 2011 IBM Corp.
+ * All Rights Reserved.
+ *
+ * This software may be freely redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors:
+ * Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <locale.h>
+#include <string.h>
+#include <regex.h>
+#include <time.h>
+#include "auparse.h"
+#include "libaudit.h"
+#include "auvirt-map.h"
+#include "ausearch-time.h"
+
+/* command line parameters */
+static int help_flag = 0;
+static int stdin_flag = 0;
+static int raw_flag = 0;
+static int summary_flag = 0;
+static int avc_flag = 0;
+/* id stores the given UUID or VM name. */
+static const char *id = NULL;
+static const char *file = NULL;
+static enum { UUID=0, VMNAME } id_type;
+static int debug = 0;
+/*
+ * The start time and end time given in the command line is stored respectively
+ * in the variables start_time and end_time that are declared/defined in the
+ * files ausearch-time.h and ausearch-time.c. These files are reused from the
+ * ausearch tool source code:
+ *
+ * time_t start_time = 0;
+ * time_t end_time = 0;
+ */
+
+/* state variables */
+static map_t *seclevel_map = NULL;
+static struct {
+ long n_records;
+ long n_virt_records;
+ long n_res_records;
+ long n_mach_id_records;
+ long n_avc_records;
+ long n_errors;
+ time_t start_time;
+ time_t end_time;
+ struct {
+ long n_start;
+ long n_stop;
+ } by_type;
+} summary = { 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, { 0L, 0L } };
+
+char *rstrip(char *s)
+{
+ size_t i;
+ if (s) {
+ for (i = 0; s[i] && s[i + 1]; i++);
+ for (; isspace(s[i]); i--) {
+ s[i] = 0;
+ if (i == 0)
+ break;
+ }
+ }
+ return s;
+}
+
+int parse_args(int argc, char **argv)
+{
+ /* based on http://www.ietf.org/rfc/rfc4122.txt */
+ const char *uuid_pattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-"
+ "[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";
+ int i, rc = 0;
+ regex_t uuid_regex;
+
+ if (regcomp(&uuid_regex, uuid_pattern, REG_EXTENDED)) {
+ fprintf(stderr, "Failed to initialize program.\n");
+ return 1;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (arg[0] != '-') {
+ /* parse UUID or VM name */
+ if (id != NULL) {
+ fprintf(stderr, "Only one UUID or VM name "
+ "must be specified.\n");
+ goto error;
+ }
+ if (regexec(&uuid_regex, arg, 0, NULL, 0) == 0) {
+ id_type = UUID;
+ } else {
+ id_type = VMNAME;
+ }
+ id = arg;
+ } else if (strcmp("--raw", arg) == 0 ||
+ strcmp("-r", arg) == 0) {
+ raw_flag = 1;
+ } else if (strcmp("--summary", arg) == 0 ||
+ strcmp("-s", arg) == 0) {
+ summary_flag = 1;
+ } else if (strcmp("--file", arg) == 0 ||
+ strcmp("-f", arg) == 0) {
+ if ((i + 1) >= argc || argv[i + 1][0] == '-') {
+ fprintf(stderr, "\"%s\" option requires "
+ "an argument.\n", arg);
+ goto error;
+ }
+ file = argv[++i];
+ } else if (strcmp("--stdin", arg) == 0) {
+ stdin_flag = 1;
+ } else if (strcmp("--help", arg) == 0 ||
+ strcmp("-h", arg) == 0) {
+ help_flag = 1;
+ goto exit;
+ } else if (strcmp("--start", arg) == 0 ||
+ strcmp("-ts", arg) == 0) {
+ const char *date, *time = NULL;
+ if ((i + 1) >= argc || argv[i + 1][0] == '-') {
+ fprintf(stderr, "\"%s\" option requires at "
+ "least one argument.\n", arg);
+ goto error;
+ }
+ date = argv[++i];
+ if ((i + 1) < argc && argv[i + 1][0] != '-')
+ time = argv[++i];
+ /* this will set start_time */
+ if(ausearch_time_start(date, time))
+ goto error;
+ } else if (strcmp("--end", arg) == 0 ||
+ strcmp("-te", arg) == 0) {
+ const char *date, *time = NULL;
+ if ((i + 1) >= argc || argv[i + 1][0] == '-') {
+ fprintf(stderr, "\"%s\" option requires at "
+ "least one argument.\n", arg);
+ goto error;
+ }
+ date = argv[++i];
+ if ((i + 1) < argc && argv[i + 1][0] != '-')
+ time = argv[++i];
+ /* this will set end_time */
+ if (ausearch_time_end(date, time))
+ goto error;
+ } else if (strcmp("--avc", arg) == 0 ||
+ strcmp("-a", arg) == 0) {
+ avc_flag = 1;
+ } else if (strcmp("--debug", arg) == 0) {
+ debug = 1;
+ } else {
+ fprintf(stderr, "Unknown option \"%s\".\n", arg);
+ goto error;
+ }
+ }
+
+ /* validate conflicting options */
+ if (stdin_flag && file) {
+ fprintf(stderr, "\"--sdtin\" and \"--file\" options "
+ "must not be specified together.\n");
+ goto error;
+ }
+ if (raw_flag && summary_flag) {
+ fprintf(stderr, "\"--raw\" and \"--summary\" options "
+ "must not be specified together.\n");
+ goto error;
+ }
+
+ /* summary is default */
+ if (!raw_flag && !summary_flag)
+ summary_flag = 1;
+
+ if (debug) {
+ fprintf(stdout, "help_flag='%i'\n", help_flag);
+ fprintf(stdout, "stdin_flag='%i'\n", stdin_flag);
+ fprintf(stdout, "raw_flag='%i'\n", raw_flag);
+ fprintf(stdout, "summary_flag='%i'\n", summary_flag);
+ fprintf(stdout, "avc_flag='%i'\n", avc_flag);
+ fprintf(stdout, "id='%s'\n", id);
+ fprintf(stdout, "file='%s'\n", file );
+ fprintf(stdout, "id_type='%i'\n", id_type);
+ fprintf(stdout, "start_time='%s'\n", (start_time == 0L) ?
+ "" : rstrip(ctime(&start_time)));
+ fprintf(stdout, "end_time='%s'\n", (end_time == 0L) ?
+ "" : rstrip(ctime(&end_time)));
+ }
+
+exit:
+ regfree(&uuid_regex);
+ return rc;
+error:
+ rc = 1;
+ goto exit;
+}
+
+auparse_state_t *init_auparse()
+{
+ auparse_state_t *au = NULL;
+ if (stdin_flag) {
+ au = auparse_init(AUSOURCE_FILE_POINTER, stdin);
+ } else if (file) {
+ au = auparse_init(AUSOURCE_FILE, file);
+ } else {
+ if (getuid()) {
+ fprintf(stderr, "You probably need to be root for "
+ "this to work\n");
+ }
+ au = auparse_init(AUSOURCE_LOGS, NULL);
+ }
+ if (au == NULL) {
+ fprintf(stderr, "Error: %s\n", strerror(errno));
+ }
+ return au;
+}
+
+/* create a criteria to search for the virtualization related records.
+ * */
+int create_search_criteria(auparse_state_t *au)
+{
+ char *error = NULL;
+ char expr[1024];
+ sprintf(expr, "(\\record_type >= %d && \\record_type <= %d)",
+ AUDIT_FIRST_VIRT_MSG, AUDIT_LAST_VIRT_MSG);
+ if (ausearch_add_expression(au, expr, &error, AUSEARCH_RULE_CLEAR)) {
+ fprintf(stderr, "Criteria error: %s\n", error);
+ free(error);
+ return 1;
+ }
+ if (id) {
+ char tmp[1024];
+ char *field_name = (id_type == UUID) ? "uuid" : "vm";
+ /*
+ * If a field has its value quoted in the audit log, for
+ * example:
+ * vm="guest-name"
+ *
+ * auparse will consider the field value with quotes when
+ * matching a rule. For example, using the example above the
+ * following rule will not match:
+ * ausearch_add_item(au, "vm", "=", "guest-name", how);
+ *
+ * But this rule will match:
+ * ausearch_add_item(au, "vm", "=", "\"guest-name\", how);
+ *
+ * TODO use a better approach for this problem...
+ */
+ if (id_type == VMNAME)
+ snprintf(tmp, sizeof(tmp), "\"%s\"", id);
+ if (ausearch_add_item(au, field_name, "=", tmp,
+ AUSEARCH_RULE_AND)) {
+ fprintf(stderr, "Criteria error: id\n");
+ return 1;
+ }
+ }
+ if (avc_flag) {
+ if (ausearch_add_item(au, "type", "=", "AVC",
+ AUSEARCH_RULE_OR)) {
+ fprintf(stderr, "Criteria error: AVC\n");
+ return 1;
+ }
+ }
+ if (start_time) {
+ if (ausearch_add_timestamp_item(au, ">=", start_time, 0,
+ AUSEARCH_RULE_AND)) {
+ fprintf(stderr, "Criteria error: start_time\n");
+ return 1;
+ }
+ }
+ if (end_time) {
+ if (ausearch_add_timestamp_item(au, "<=", end_time, 0,
+ AUSEARCH_RULE_AND)) {
+ fprintf(stderr, "Criteria error: end_time\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void usage(FILE *output)
+{
+ fprintf(output, "usage: auvirt [--stdin] [--avc] [--raw|--summary] "
+ "[--start start-date [start-time]] "
+ "[--end end-date [end-time]] [--file file-name] "
+ "[uuid|vm-name]\n");
+}
+
+/* return label and categories from a security context. */
+const char *get_seclevel(const char *seclabel)
+{
+ /*
+ * system_u:system_r:svirt_t:s0:c107,c434
+ * \____ _____/
+ * '
+ * level + cat
+ */
+ int c = 0;
+ for (;seclabel && *seclabel; seclabel++) {
+ if (*seclabel == ':')
+ c += 1;
+ if (c == 3)
+ return seclabel + 1;
+ }
+ return NULL;
+}
+
+/* keep track of which security level is associated to each uuid */
+int update_seclevel(auparse_state_t *au)
+{
+ const char *uuid, *seclabel, *seclevel;
+
+ uuid = auparse_find_field(au, "uuid");
+ if (uuid == NULL) {
+ if (debug)
+ fprintf(stdout, "Warning: record without UUID\n");
+ return 0;
+ }
+
+ seclabel = auparse_find_field(au, "vm-ctx");
+ seclevel = get_seclevel(seclabel);
+ if (seclevel == NULL) {
+ if (debug)
+ fprintf(stdout, "Invalid security level for label: "
+ "'%s'.\n", seclabel);
+ return 0;
+ }
+ if (debug)
+ fprintf(stdout, "Using seclevel '%s' for '%s'\n",
+ seclevel, uuid);
+
+ map_it_t *it = map_get(seclevel_map, uuid);
+ if (it) {
+ if (debug)
+ fprintf(stdout, "Warning: overwriting seclevel for id "
+ "'%s'\n", uuid);
+ return map_set(seclevel_map, it, seclevel);
+ }
+ return map_add(seclevel_map, uuid, seclevel);
+}
+
+/* check and discard sec level associated to a stopped guest. */
+int remove_seclevel(auparse_state_t *au)
+{
+ const char *uuid, *op;
+
+ uuid = auparse_find_field(au, "uuid");
+ if (uuid == NULL) {
+ if (debug)
+ fprintf(stdout, "Warning: record without UUID\n");
+ return 0;
+ }
+
+ auparse_first_field(au);
+ op = auparse_find_field(au, "op");
+ if (op == NULL) {
+ if (debug)
+ fprintf(stdout, "Warning: record without 'op' "
+ "field\n");
+ return 0;
+ }
+ if (strcmp("stop", op) == 0) {
+ map_it_t *it = map_get(seclevel_map, uuid);
+ if (it) {
+ if (debug)
+ fprintf(stdout, "Discarding seclevel '%s'\n",
+ map_it_val(it));
+ map_del(seclevel_map, it);
+ } else if (debug)
+ fprintf(stdout, "No seclevel to discard\n");
+ }
+ return 0;
+}
+
+void process_record(auparse_state_t *au)
+{
+ if (raw_flag)
+ printf("%s\n", auparse_get_record_text(au));
+
+ if (summary_flag) {
+ const char *op;
+ int type = auparse_get_type(au);
+ switch (type) {
+ case AUDIT_FIRST_VIRT_MSG ... AUDIT_LAST_VIRT_MSG:
+ summary.n_virt_records += 1;
+ /* update time period from records if not informed */
+ time_t t = auparse_get_time(au);
+ if (summary.start_time == 0L ||
+ summary.start_time > t) {
+ summary.start_time = t;
+ }
+ if (summary.end_time == 0L ||
+ summary.end_time < t) {
+ summary.end_time = t;
+ }
+ /* count start and stop */
+ switch (type) {
+ case AUDIT_VIRT_RESOURCE:
+ summary.n_res_records += 1;
+ break;
+ case AUDIT_VIRT_MACHINE_ID:
+ summary.n_mach_id_records += 1;
+ break;
+ case AUDIT_VIRT_CONTROL:
+ op = auparse_find_field(au, "op");
+ if (strcmp("start", op) == 0)
+ summary.by_type.n_start += 1;
+ else if (strcmp("stop", op) == 0)
+ summary.by_type.n_stop += 1;
+ break;
+ }
+ break;
+ case AUDIT_AVC:
+ summary.n_avc_records += 1;
+ break;
+ }
+ summary.n_records += 1;
+ }
+}
+
+void print_summary()
+{
+ time_t time = 0;
+ printf("Total records: %ld\n", summary.n_records);
+ printf("Virt records: %ld\n", summary.n_virt_records);
+ printf("Resource records: %ld\n", summary.n_res_records);
+ printf("Machine ID records: %ld\n", summary.n_mach_id_records);
+ printf("AVC records: %ld\n", summary.n_avc_records);
+ printf("Operations:\n");
+ printf(" Start: %ld\n", summary.by_type.n_start);
+ printf(" Stop: %ld\n", summary.by_type.n_stop);
+ printf("Considered time:\n");
+ time = (start_time) ? start_time : summary.start_time;
+ printf(" Start: %s\n", (time) ? rstrip(ctime(&time)) : "-");
+ time = (end_time) ? end_time : summary.end_time;
+ printf(" End: %s\n", (time) ? rstrip(ctime(&time)) : "-");
+}
+
+int main(int argc, char **argv)
+{
+ int rc = 0;
+ auparse_state_t *au = NULL;
+
+ setlocale(LC_ALL, "");
+ if (parse_args(argc, argv))
+ goto error;
+ if (help_flag) {
+ usage(stdout);
+ goto exit;
+ }
+
+ /* initialize auparse */
+ au = init_auparse();
+ if (au == NULL)
+ goto error;
+ if (create_search_criteria(au))
+ goto error;
+
+ if (avc_flag) {
+ seclevel_map = map_new();
+ if (seclevel_map == NULL)
+ goto unexpected_error;
+ }
+
+ while (ausearch_next_event(au) > 0) {
+ const char *seclabel = NULL, *seclevel = NULL;
+ int type = auparse_get_type(au);
+ switch (type) {
+ case AUDIT_FIRST_VIRT_MSG ... AUDIT_LAST_VIRT_MSG:
+ /* when the --avc option is given the tool will keep
+ * track of the security label associated to each guest
+ * to be able to filter the AVC records. */
+ if (avc_flag) {
+ if (type == AUDIT_VIRT_MACHINE_ID) {
+ /* When a start event is read, an entry
+ * is added or update in a map for that
+ * guest. */
+ if (update_seclevel(au))
+ goto unexpected_error;
+ } else if (type == AUDIT_VIRT_CONTROL) {
+ /* When a stop event is read, the entry
+ * associated to that guest is removed
+ * from the map. */
+ if (remove_seclevel(au))
+ goto unexpected_error;
+ }
+ }
+ process_record(au);
+ break;
+ case AUDIT_AVC:
+ /* process AVC records with security level used by
+ * a known guest. */
+ if (avc_flag) {
+ seclabel = auparse_find_field(au, "tcontext");
+ seclevel = get_seclevel(seclabel);
+ }
+ if (seclevel) {
+ if (map_next_val(seclevel_map, seclevel, NULL))
+ process_record(au);
+ }
+ break;
+ }
+ auparse_next_event(au);
+ }
+
+ if (summary_flag)
+ print_summary();
+
+exit:
+ if (au)
+ auparse_destroy(au);
+ map_free(seclevel_map);
+ seclevel_map = NULL;
+ if (debug)
+ fprintf(stdout, "Exit code: %d\n", rc);
+ return rc;
+
+unexpected_error:
+ fprintf(stderr, "Unexpected error\n");
+error:
+ rc = 1;
+ goto exit;
+}
+
--
1.7.1
12 years, 9 months
Path ignored but syscall event still logged
by Max Williams
Hi All,
I have a system that is logging many events for a path that I think should be ignored...
[root@host1 ~]# auditctl -l
LIST_RULES: exit,always dir=/etc/audit (0xa) perm=wa key=auditd_configuration
LIST_RULES: exit,always dir=/etc/audisp (0xb) perm=wa key=auditd_configuration
LIST_RULES: exit,always watch=/etc/libaudit.conf perm=wa key=auditd_configuration
LIST_RULES: exit,always watch=/etc/sysconfig/auditd perm=wa key=auditd_configuration
LIST_RULES: exit,never dir=/etc/lvm/cache (0xe) syscall=all
LIST_RULES: exit,never dir=/opt (0x4) syscall=all
LIST_RULES: exit,never dir=/tmp (0x4) syscall=all
LIST_RULES: exit,never dir=/naab1 (0x6) syscall=all
LIST_RULES: exit,never dir=/naab2 (0x6) syscall=all
LIST_RULES: exit,never dir=/ab1 (0x4) syscall=all
LIST_RULES: exit,never dir=/ab2 (0x4) syscall=all
LIST_RULES: exit,always perm=a key=file_attributes
LIST_RULES: exit,always arch=3221225534 (0xc000003e) a1=1074292226 (0x40086602) key=file_attributes syscall=ioctl
LIST_RULES: exit,always arch=3221225534 (0xc000003e) a1=-2146933247 (0x80086601) key=file_attributes syscall=ioctl
LIST_RULES: exit,always arch=3221225534 (0xc000003e) exit=-13 (0xfffffff3) key=invalid_logical_access syscall=open
LIST_RULES: exit,always dir=/bin (0x4) perm=wa key=bin_modification
LIST_RULES: exit,always dir=/boot (0x5) perm=wa key=boot_modification
LIST_RULES: exit,always dir=/etc (0x4) perm=wa key=etc_modification
LIST_RULES: exit,always dir=/home (0x5) perm=wa key=home_modification
LIST_RULES: exit,always dir=/lib (0x4) perm=wa key=lib_modification
LIST_RULES: exit,always dir=/lib64 (0x6) perm=wa key=lib64_modification
LIST_RULES: exit,always dir=/root (0x5) perm=wa key=root_modification
LIST_RULES: exit,always dir=/sbin (0x5) perm=wa key=sbin_modification
LIST_RULES: exit,always dir=/usr (0x4) perm=wa key=usr_modification
LIST_RULES: exit,always dir=/var/spool/at (0xd) perm=wa key=misc_var
LIST_RULES: exit,always dir=/var/spool/cron (0xf) perm=wa key=misc_var
LIST_RULES: exit,never dir=/var (0x4) syscall=all
LIST_RULES: exit,always arch=3221225534 (0xc000003e) key=dir_operations syscall=mkdir,rmdir,unlinkat
LIST_RULES: exit,always arch=3221225534 (0xc000003e) key=link_operation syscall=rename,link,unlink,symlink
LIST_RULES: exit,always arch=3221225534 (0xc000003e) key=special_device_creation syscall=mknod,mknodat
LIST_RULES: exit,always arch=3221225534 (0xc000003e) key=mount_operation syscall=mount,umount2
LIST_RULES: exit,always arch=3221225534 (0xc000003e) key=kernel_module syscall=create_module,init_module,delete_module
LIST_RULES: exclude,always msgtype=CRED_ACQ (0x44f)
LIST_RULES: exclude,always msgtype=CRED_DISP (0x450)
LIST_RULES: exclude,always msgtype=CRYPTO_KEY_USER (0x964)
LIST_RULES: exclude,always msgtype=CRYPTO_SESSION (0x967)
LIST_RULES: exclude,always msgtype=LOGIN (0x3ee)
LIST_RULES: exclude,always msgtype=USER_ACCT (0x44d)
LIST_RULES: exclude,always msgtype=USER_AUTH (0x44c)
LIST_RULES: exclude,always msgtype=USER_CMD (0x463)
LIST_RULES: exclude,always msgtype=USER_END (0x452)
LIST_RULES: exclude,always msgtype=USER_LOGIN (0x458)
LIST_RULES: exclude,always msgtype=USER_START (0x451)
[root@host1 ~]# tail /var/log/audit/audit.log
node=host1.domain type=PATH msg=audit(1324401918.113:223550509): item=3 name="checkpoint.1568280a-4eef7e3f-38e9.102.138" inode=30958573 dev=fd:0d mode=0100660 ouid=3534 ogid=9001 rdev=00:00
node=host1.domain type=PATH msg=audit(1324401918.113:223550510): item=2 name="temp_checkpoint.checkpoint.1568280a-4eef7e3f-38d2.76.138" inode=30958636 dev=fd:0d mode=0100660 ouid=3534 ogid=9001 rdev=00:00
node=host1.domain type=PATH msg=audit(1324401918.113:223550510): item=3 name="checkpoint.1568280a-4eef7e3f-38d2.76.138" inode=30958614 dev=fd:0d mode=0100660 ouid=3534 ogid=9001 rdev=00:00
node=host1.domain type=PATH msg=audit(1324401918.113:223550509): item=4 name="checkpoint.1568280a-4eef7e3f-38e9.102.138" inode=30958644 dev=fd:0d mode=0100660 ouid=3534 ogid=9001 rdev=00:00
node=host1.domain type=PATH msg=audit(1324401918.113:223550510): item=4 name="checkpoint.1568280a-4eef7e3f-38d2.76.138" inode=30958636 dev=fd:0d mode=0100660 ouid=3534 ogid=9001 rdev=00:00
node=host1.domain type=SYSCALL msg=audit(1324401918.113:223550511): arch=c000003e syscall=82 success=yes exit=0 a0=7ecdb0 a1=7d10e0 a2=7f6c0782dcd4 a3=0 items=4 ppid=14614 pid=16951 auid=7463 uid=3534 gid=9001 euid=3534 suid=3534 fsuid=3534 egid=9001 sgid=9001 fsgid=9001 tty=(none) ses=9372 comm="db-update.impl." exe="/var/some-app/some-app-V3-0-3/gcc4p64/db_v2/bin/db-update.impl.gcc4p64" key="link_operation"
node=host1.domain type=SYSCALL msg=audit(1324401918.113:223550512): arch=c000003e syscall=82 success=yes exit=0 a0=9a6e50 a1=92e9f0 a2=7fe84e682cd4 a3=0 items=4 ppid=14595 pid=14937 auid=7463 uid=3534 gid=9001 euid=3534 suid=3534 fsuid=3534 egid=9001 sgid=9001 fsgid=9001 tty=(none) ses=10226 comm="multitool.impl." exe="/var/some-app/some-app-V3-0-3/gcc4p64/bin/multitool" key="link_operation"
node=host1.domain type=CWD msg=audit(1324401918.113:223550511): cwd="/naab1/serial/data/dir1/serial/dir2/abc_load/temp/some-app/.WORK-serial/1568280a-4eef7e3f-3873"
node=host1.domain type=CWD msg=audit(1324401918.113:223550512): cwd="/naab1/serial/data/dir1/serial/dir2/abc_load/temp/some-app/.WORK-serial/1568280a-4ef0423c-38fe"
node=host1.domain type=PATH msg=audit(1324401918.113:223550511): item=0 name="/naab1/serial/data/dir1/serial/dir2/abc_load/temp/some-app/.WORK-serial/1568280a-4eef7e3f-3873" inode=30932995 dev=fd:0d mode=040755 ouid=3534 ogid=9001 rdev=00:00
[root@host1 ~]#
I'm referring to event ID 223550511 (key is link_operation) in the logs which is using a path of '/naab1/...'
How come this event is not ignored due to the 8th rule? I think I'm missing something.
Many thanks,
Max
________________________________________________________________________
In order to protect our email recipients, Betfair Group use SkyScan from
MessageLabs to scan all Incoming and Outgoing mail for viruses.
________________________________________________________________________
12 years, 9 months
Question - Rule Syntax
by Bryan Jacobs
All,
New auditd list member here. I just started playing around with auditd.
I was wondering if someone might be kind enough to answer a question I
have. I am attempting to create a rule that will audit privileged
commands for UID's greater than 500 but ignore one particular user that
falls under this rule. The user I am trying to ignore is the only user
that should be touching the file.
Below is the rule.
#### BEGIN RULE SNIP ####
## Ensure auditd Collects Information on the Use of Privileged Commands
-a always,exit -F path=/opt/varonis1.6.0106/bin/ls -F perm=x -F
auid>=500 -F auid!=4294967295 -F auid!=505 -k privileged
#### END RULE SNIP ####
Is the rule syntax above correct? If not how would I audit all users
with UID above 500 but still ignore one particular user?
Thank you and happy holidays,
--
BKJ
----------------------------------------------------
Virus Free -- Scanned By MailSecurity
----------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain confidential and privileged information. Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message. Any views expressed in this message are those of the author, except where the sender specifically states them to be the views of BBG, Inc.
12 years, 10 months
[PATCH] Inter-field comparisons between uid/euid and gid/egid
by Peter Moody
Not sure if this is the right way to go about this, but I've got a couple
of patches I'd like to be considered for inclusion.
This builds off of Eric's patches from November. Specifically the following
patches:
[01/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00019.html)
[02/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00020.html)
[16/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00034.html)
[17/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00035.html)
[18/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00036.html)
[19/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00037.html)
[20/26] (
http://www.redhat.com/archives/linux-audit/2011-November/msg00038.html)
Signed-off-by: Peter Moody <pmoody(a)google.com>
---
include/linux/audit.h | 4 +++-
kernel/auditsc.c | 18 ++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 4c5437f..cce8f35 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -182,8 +182,10 @@
/* AUDIT_FIELD_COMPARE rule list */
#define AUDIT_COMPARE_UID_TO_OBJ_UID 1
#define AUDIT_COMPARE_GID_TO_OBJ_GID 2
+#define AUDIT_COMPARE_UID_TO_EUID 3
+#define AUDIT_COMPARE_GID_TO_EGID 4
-#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_GID_TO_OBJ_GID
+#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_GID_TO_EGID
/* Rule fields */
/* These are useful when checking the
* task structure at task creation time
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 2be8bf3..08c8736 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -514,6 +514,24 @@ static int audit_field_compare(struct task_struct *tsk,
return audit_compare_id(cred, offsetof(struct cred, gid),
name, offsetof(struct audit_names, gid),
f, ctx);
+ case AUDIT_COMPARE_UID_TO_EUID:
+ if(name)
+ return audit_comparator(cred->euid, f->op, cred->uid);
+ else if(ctx) {
+ struct audit_names *n;
+ list_for_each_entry(n, &ctx->names_list, list)
+ return audit_comparator(cred->euid, f->op, cred->uid);
+ }
+ break;
+ case AUDIT_COMPARE_GID_TO_EGID:
+ if(name)
+ return audit_comparator(cred->egid, f->op, cred->gid);
+ else if(ctx) {
+ struct audit_names *n;
+ list_for_each_entry(n, &ctx->names_list, list)
+ return audit_comparator(cred->egid, f->op, cred->gid);
+ }
+ break;
default:
return 0;
}
--
1.7.3.1
--
Peter Moody Google 1.650.253.7306
Security Engineer pgp:0xC3410038
12 years, 10 months
[PATCH] Added support for virtualization related fields to ausearch.
by Marcelo Cerri
This patch adds support to ausearch for searching for events related to a
guest, as proposed in the RFC:
https://www.redhat.com/archives/linux-audit/2011-November/msg00014.html
Two new options were added:
--uuid uuid
Search for an event with the given guest UUID. The given uuid is
compared to the value from the "uuid" field of a record.
--vmname name
Search for an event with the given guest name. The given name is
compared to the value from the "vm" field of a record.
Signed-off-by: Marcelo Cerri <mhcerri(a)linux.vnet.ibm.com>
---
docs/ausearch.8 | 6 ++++++
src/aureport-options.c | 4 ++++
src/ausearch-common.h | 4 ++++
src/ausearch-llist.c | 8 ++++++++
src/ausearch-llist.h | 8 ++++++--
src/ausearch-match.c | 18 ++++++++++++++++++
src/ausearch-options.c | 42 +++++++++++++++++++++++++++++++++++++++++-
src/ausearch-parse.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 134 insertions(+), 3 deletions(-)
diff --git a/docs/ausearch.8 b/docs/ausearch.8
index 54018ae..704fb52 100644
--- a/docs/ausearch.8
+++ b/docs/ausearch.8
@@ -129,9 +129,15 @@ Search for an event with the given \fIuser ID\fP.
.BR \-ul ,\ \-\-loginuid \ \fIlogin-id\fP
Search for an event with the given \fIlogin user ID\fP. All entry point programs that are pamified need to be configured with pam_loginuid required for the session for searching on loginuid (auid) to be accurate.
.TP
+.BR \-uu ,\ \-\-uuid \ \fIguest-uuid\fP
+Search for an event with the given \fIguest UUID\fP.
+.TP
.BR \-v ,\ \-\-version
Print the version and exit
.TP
+.BR \-vm ,\ \-\-vm-name \ \fIguest-name\fP
+Search for an event with the given \fIguest name\fP.
+.TP
.BR \-w ,\ \-\-word
String based matches must match the whole word. This category of matches include: filename, hostname, terminal, and SE Linux context.
.TP
diff --git a/src/aureport-options.c b/src/aureport-options.c
index 9786043..72a1d15 100644
--- a/src/aureport-options.c
+++ b/src/aureport-options.c
@@ -1,5 +1,6 @@
/* aureport-options.c - parse commandline options and configure aureport
* Copyright 2005-08,2010-11 Red Hat Inc., Durham, North Carolina.
+ * Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +19,7 @@
*
* Authors:
* Steve Grubb <sgrubb(a)redhat.com>
+ * Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*/
#include "config.h"
@@ -49,6 +51,8 @@ const char *event_hostname = NULL;
const char *event_terminal = NULL;
const char *event_subject = NULL;
const char *event_object = NULL;
+const char *event_uuid = NULL;
+const char *event_vmname = NULL;
int event_exit = 0, event_exit_is_set = 0;
int event_ppid = -1, event_session_id = -2;
diff --git a/src/ausearch-common.h b/src/ausearch-common.h
index f9d0d9b..2ee1f33 100644
--- a/src/ausearch-common.h
+++ b/src/ausearch-common.h
@@ -1,5 +1,6 @@
/* ausearch-common.h --
* Copyright 2006-08,2010 Red Hat Inc., Durham, North Carolina.
+ * Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +19,7 @@
*
* Authors:
* Steve Grubb <sgrubb(a)redhat.com>
+ * Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*
*/
@@ -42,6 +44,8 @@ extern int event_syscall;
extern const char *event_exe;
extern int event_ua, event_ga;
extern int event_exit, event_exit_is_set;
+extern const char *event_uuid;
+extern const char *event_vmname;
typedef enum { F_BOTH, F_FAILED, F_SUCCESS } failed_t;
typedef enum { C_NEITHER, C_ADD, C_DEL } conf_act_t;
diff --git a/src/ausearch-llist.c b/src/ausearch-llist.c
index 32cda7e..5d25e7c 100644
--- a/src/ausearch-llist.c
+++ b/src/ausearch-llist.c
@@ -1,6 +1,7 @@
/*
* ausearch-llist.c - Minimal linked list library
* Copyright (c) 2005-2008, 2011 Red Hat Inc., Durham, North Carolina.
+* Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This software may be freely redistributed and/or modified under the
@@ -19,6 +20,7 @@
*
* Authors:
* Steve Grubb <sgrubb(a)redhat.com>
+* Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*/
#include <stdlib.h>
@@ -55,6 +57,8 @@ void list_create(llist *l)
l->s.arch = 0;
l->s.syscall = 0;
l->s.session_id = -2;
+ l->s.uuid = NULL;
+ l->s.vmname = NULL;
l->s.exit = 0;
l->s.exit_is_set = 0;
}
@@ -197,6 +201,10 @@ void list_clear(llist* l)
l->s.arch = 0;
l->s.syscall = 0;
l->s.session_id = -2;
+ free(l->s.uuid);
+ l->s.uuid = NULL;
+ free(l->s.vmname);
+ l->s.vmname = NULL;
l->s.exit = 0;
l->s.exit_is_set = 0;
}
diff --git a/src/ausearch-llist.h b/src/ausearch-llist.h
index a77d800..4ab6f14 100644
--- a/src/ausearch-llist.h
+++ b/src/ausearch-llist.h
@@ -1,6 +1,7 @@
/*
* ausearch-llist.h - Header file for ausearch-llist.c
* Copyright (c) 2005-2008 Red Hat Inc., Durham, North Carolina.
+* Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This software may be freely redistributed and/or modified under the
@@ -19,6 +20,7 @@
*
* Authors:
* Steve Grubb <sgrubb(a)redhat.com>
+* Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*/
#ifndef AULIST_HEADER
@@ -62,8 +64,10 @@ typedef struct
slist *key; // key field
char *terminal; // terminal
char *comm; // comm name
- alist *avc; // avcs for the event
- char *acct; // account used when uid is invalid
+ alist *avc; // avcs for the event
+ char *acct; // account used when uid is invalid
+ char *uuid; // virtual machine unique universal identifier
+ char *vmname; // virtual machine name
} search_items;
/* This is the node of the linked list. Any data elements that are per
diff --git a/src/ausearch-match.c b/src/ausearch-match.c
index 24b9320..18e52cb 100644
--- a/src/ausearch-match.c
+++ b/src/ausearch-match.c
@@ -1,6 +1,7 @@
/*
* ausearch-match.c - Extract interesting fields and check for match
* Copyright (c) 2005-08, 2011 Red Hat Inc., Durham, North Carolina.
+* Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This software may be freely redistributed and/or modified under the
@@ -19,6 +20,7 @@
*
* Authors:
* Steve Grubb <sgrubb(a)redhat.com>
+* Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*/
#include "config.h"
@@ -201,6 +203,22 @@ int match(llist *l)
return 0;
}
}
+ if (event_vmname) {
+ if (l->s.vmname == NULL) {
+ return 0;
+ }
+ if (strmatch(event_vmname, l->s.vmname) == 0) {
+ return 0;
+ }
+ }
+ if (event_uuid) {
+ if (l->s.uuid == NULL) {
+ return 0;
+ }
+ if (strmatch(event_uuid, l->s.uuid) == 0) {
+ return 0;
+ }
+ }
if (context_match(l) == 0)
return 0;
return 1;
diff --git a/src/ausearch-options.c b/src/ausearch-options.c
index 8f4b64e..a92e23f 100644
--- a/src/ausearch-options.c
+++ b/src/ausearch-options.c
@@ -1,5 +1,6 @@
/* ausearch-options.c - parse commandline options and configure ausearch
* Copyright 2005-08,2010-11 Red Hat Inc., Durham, North Carolina.
+ * Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +20,7 @@
* Authors:
* Debora Velarde <dvelarde(a)us.ibm.com>
* Steve Grubb <sgrubb(a)redhat.com>
+ * Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*/
#include "config.h"
@@ -61,6 +63,8 @@ const char *event_hostname = NULL;
const char *event_terminal = NULL;
const char *event_subject = NULL;
const char *event_object = NULL;
+const char *event_uuid = NULL;
+const char *event_vmname = NULL;
report_t report_format = RPT_DEFAULT;
ilist *event_type;
@@ -77,7 +81,7 @@ S_HOSTNAME, S_INTERP, S_INFILE, S_MESSAGE_TYPE, S_PID, S_SYSCALL, S_OSUCCESS,
S_TIME_END, S_TIME_START, S_TERMINAL, S_ALL_UID, S_EFF_UID, S_UID, S_LOGINID,
S_VERSION, S_EXACT_MATCH, S_EXECUTABLE, S_CONTEXT, S_SUBJECT, S_OBJECT,
S_PPID, S_KEY, S_RAW, S_NODE, S_IN_LOGS, S_JUST_ONE, S_SESSION, S_EXIT,
-S_LINEBUFFERED };
+S_LINEBUFFERED, S_UUID, S_VMNAME};
static struct nv_pair optiontab[] = {
{ S_EVENT, "-a" },
@@ -141,10 +145,14 @@ static struct nv_pair optiontab[] = {
{ S_EFF_UID, "--uid-effective" },
{ S_UID, "-ui" },
{ S_UID, "--uid" },
+ { S_UUID, "-uu" },
+ { S_UUID, "--uuid" },
{ S_LOGINID, "-ul" },
{ S_LOGINID, "--loginuid" },
{ S_VERSION, "-v" },
{ S_VERSION, "--version" },
+ { S_VMNAME, "-vm" },
+ { S_VMNAME, "--vm-name" },
{ S_EXACT_MATCH, "-w" },
{ S_EXACT_MATCH, "--word" },
{ S_EXECUTABLE, "-x" },
@@ -199,7 +207,11 @@ static void usage(void)
"\t-ue,--uid-effective <effective User id> search based on Effective\n\t\t\t\t\tuser id\n"
"\t-ui,--uid <User Id>\t\tsearch based on user id\n"
"\t-ul,--loginuid <login id>\tsearch based on the User's Login id\n"
+ "\t-uu,--uuid <guest UUID>\t\tsearch for events related to the virtual\n"
+ "\t\t\t\t\tmachine with the given UUID.\n"
"\t-v,--version\t\t\tversion\n"
+ "\t-vm,--vm-name <guest name>\tsearch for events related to the virtual\n"
+ "\t\t\t\t\tmachine with the name.\n"
"\t-w,--word\t\t\tstring matches are whole word\n"
"\t-x,--executable <executable name> search based on excutable name\n"
);
@@ -997,6 +1009,34 @@ int check_params(int count, char *vars[])
}
c++;
break;
+ case S_UUID:
+ if (!optarg) {
+ fprintf(stderr,
+ "Argument is required for %s\n",
+ vars[c]);
+ retval = -1;
+ } else {
+ event_uuid = strdup(optarg);
+ if (event_uuid == NULL) {
+ retval = -1;
+ }
+ c++;
+ }
+ break;
+ case S_VMNAME:
+ if (!optarg) {
+ fprintf(stderr,
+ "Argument is required for %s\n",
+ vars[c]);
+ retval = -1;
+ } else {
+ event_vmname= strdup(optarg);
+ if (event_vmname == NULL) {
+ retval = -1;
+ }
+ c++;
+ }
+ break;
case S_VERSION:
printf("ausearch version %s\n", VERSION);
exit(0);
diff --git a/src/ausearch-parse.c b/src/ausearch-parse.c
index f7ec834..f9363d9 100644
--- a/src/ausearch-parse.c
+++ b/src/ausearch-parse.c
@@ -1,6 +1,7 @@
/*
* ausearch-parse.c - Extract interesting fields and check for match
* Copyright (c) 2005-08, 2011 Red Hat Inc., Durham, North Carolina.
+* Copyright (c) 2011 IBM Corp.
* All Rights Reserved.
*
* This software may be freely redistributed and/or modified under the
@@ -19,6 +20,7 @@
*
* Authors:
* Steve Grubb <sgrubb(a)redhat.com>
+* Marcelo Henrique Cerri <mhcerri(a)br.ibm.com>
*/
#include "config.h"
@@ -767,6 +769,50 @@ static int parse_user(const lnode *n, search_items *s)
return 13;
}
}
+ if (event_vmname) {
+ str = strstr(term, "vm=");
+ if (str) {
+ str += 3;
+ if (*str == '"') {
+ str++;
+ }
+ term = str;
+ while (*term != '"' && *term != ' ' &&
+ *term != ':' && *term != ',' &&
+ *term != 0) {
+ term++;
+ }
+ if (term == str) {
+ return 23;
+ }
+ saved = *term;
+ *term = 0;
+ s->vmname= strdup(str);
+ *term = saved;
+ }
+ }
+ if (event_uuid) {
+ str = strstr(term, "uuid=");
+ if (str) {
+ str += 5;
+ if (*str == '"') {
+ str++;
+ }
+ term = str;
+ while (*term != '"' && *term != ' ' &&
+ *term != ':' && *term != ',' &&
+ *term != 0) {
+ term++;
+ }
+ if (term == str) {
+ return 24;
+ }
+ saved = *term;
+ *term = 0;
+ s->uuid = strdup(str);
+ *term = saved;
+ }
+ }
// get uid - something has uid after auid ??
str = strstr(term, "uid=");
if (str != NULL) {
@@ -959,6 +1005,7 @@ static int parse_user(const lnode *n, search_items *s)
*term = ')';
}
}
+ /* last return code used = 24 */
return 0;
}
--
1.7.1
12 years, 10 months