[PATCH] audit syscall classes
by Alexander Viro
Allow to tie upper bits of syscall bitmap in audit rules to kernel-defined
sets of syscalls. Infrastructure, a couple of classes (with 32bit counterparts
for biarch targets) and actual tie-in on i386, amd64 and ia64.
Signed-off-by: Al Viro <viro(a)zeniv.linux.org.uk>
---
arch/i386/kernel/Makefile | 1 +
arch/i386/kernel/audit.c | 23 ++++++++++++++++++
arch/ia64/ia32/Makefile | 1 +
arch/ia64/ia32/audit.c | 11 +++++++++
arch/ia64/kernel/Makefile | 1 +
arch/ia64/kernel/audit.c | 29 +++++++++++++++++++++++
arch/x86_64/ia32/Makefile | 3 ++
arch/x86_64/ia32/audit.c | 11 +++++++++
arch/x86_64/kernel/Makefile | 1 +
arch/x86_64/kernel/audit.c | 29 +++++++++++++++++++++++
include/asm-generic/audit_change_attr.h | 18 ++++++++++++++
include/asm-generic/audit_dir_write.h | 14 +++++++++++
include/linux/audit.h | 7 ++++++
kernel/auditfilter.c | 39 +++++++++++++++++++++++++++++++
14 files changed, 188 insertions(+), 0 deletions(-)
create mode 100644 arch/i386/kernel/audit.c
create mode 100644 arch/ia64/ia32/audit.c
create mode 100644 arch/ia64/kernel/audit.c
create mode 100644 arch/x86_64/ia32/audit.c
create mode 100644 arch/x86_64/kernel/audit.c
create mode 100644 include/asm-generic/audit_change_attr.h
create mode 100644 include/asm-generic/audit_dir_write.h
b915543b46a2aa599fdd2169e51bcfd88812a12b
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 5e70c2f..cbc1184 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_VM86) += vm86.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_HPET_TIMER) += hpet.o
obj-$(CONFIG_K8_NB) += k8.o
+obj-$(CONFIG_AUDIT) += audit.o
EXTRA_AFLAGS := -traditional
diff --git a/arch/i386/kernel/audit.c b/arch/i386/kernel/audit.c
new file mode 100644
index 0000000..5a53c6f
--- /dev/null
+++ b/arch/i386/kernel/audit.c
@@ -0,0 +1,23 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+static int __init audit_classes_init(void)
+{
+ audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ return 0;
+}
+
+__initcall(audit_classes_init);
diff --git a/arch/ia64/ia32/Makefile b/arch/ia64/ia32/Makefile
index 61cb60a..baad8c7 100644
--- a/arch/ia64/ia32/Makefile
+++ b/arch/ia64/ia32/Makefile
@@ -4,6 +4,7 @@ #
obj-y := ia32_entry.o sys_ia32.o ia32_signal.o \
ia32_support.o ia32_traps.o binfmt_elf32.o ia32_ldt.o
+obj-$(CONFIG_AUDIT) += audit.o
# Don't let GCC uses f16-f31 so that save_ia32_fpstate_live() and
# restore_ia32_fpstate_live() can be sure the live register contain user-level state.
diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c
new file mode 100644
index 0000000..ab94f2e
--- /dev/null
+++ b/arch/ia64/ia32/audit.c
@@ -0,0 +1,11 @@
+#include <asm-i386/unistd.h>
+
+unsigned ia32_dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+unsigned ia32_chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 09a0dbc..0e4553f 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
+obj-$(CONFIG_AUDIT) += audit.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
# The gate DSO image is built using a special linker script.
diff --git a/arch/ia64/kernel/audit.c b/arch/ia64/kernel/audit.c
new file mode 100644
index 0000000..f251293
--- /dev/null
+++ b/arch/ia64/kernel/audit.c
@@ -0,0 +1,29 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+static int __init audit_classes_init(void)
+{
+#ifdef CONFIG_IA32_SUPPORT
+ extern __u32 ia32_dir_class[];
+ extern __u32 ia32_chattr_class[];
+ audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+#endif
+ audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ return 0;
+}
+
+__initcall(audit_classes_init);
diff --git a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
index e9263b4..62bc5f5 100644
--- a/arch/x86_64/ia32/Makefile
+++ b/arch/x86_64/ia32/Makefile
@@ -11,6 +11,9 @@ obj-$(CONFIG_IA32_EMULATION) += $(sysv-y
obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
+audit-class-$(CONFIG_AUDIT) := audit.o
+obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y)
+
$(obj)/syscall32_syscall.o: \
$(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
diff --git a/arch/x86_64/ia32/audit.c b/arch/x86_64/ia32/audit.c
new file mode 100644
index 0000000..ab94f2e
--- /dev/null
+++ b/arch/x86_64/ia32/audit.c
@@ -0,0 +1,11 @@
+#include <asm-i386/unistd.h>
+
+unsigned ia32_dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+unsigned ia32_chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index aeb9c56..819e84e 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o
obj-$(CONFIG_X86_VSMP) += vsmp.o
obj-$(CONFIG_K8_NB) += k8.o
+obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/x86_64/kernel/audit.c b/arch/x86_64/kernel/audit.c
new file mode 100644
index 0000000..a067aa4
--- /dev/null
+++ b/arch/x86_64/kernel/audit.c
@@ -0,0 +1,29 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+static int __init audit_classes_init(void)
+{
+#ifdef CONFIG_IA32_EMULATION
+ extern __u32 ia32_dir_class[];
+ extern __u32 ia32_chattr_class[];
+ audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+#endif
+ audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ return 0;
+}
+
+__initcall(audit_classes_init);
diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h
new file mode 100644
index 0000000..cb05bf6
--- /dev/null
+++ b/include/asm-generic/audit_change_attr.h
@@ -0,0 +1,18 @@
+__NR_chmod,
+__NR_fchmod,
+__NR_chown,
+__NR_fchown,
+__NR_lchown,
+__NR_setxattr,
+__NR_lsetxattr,
+__NR_fsetxattr,
+__NR_removexattr,
+__NR_lremovexattr,
+__NR_fremovexattr,
+__NR_fchownat,
+__NR_fchmodat,
+#ifdef __NR_chown32
+__NR_chown32,
+__NR_fchown32,
+__NR_lchown32,
+#endif
diff --git a/include/asm-generic/audit_dir_write.h b/include/asm-generic/audit_dir_write.h
new file mode 100644
index 0000000..161a7a5
--- /dev/null
+++ b/include/asm-generic/audit_dir_write.h
@@ -0,0 +1,14 @@
+__NR_rename,
+__NR_mkdir,
+__NR_rmdir,
+__NR_creat,
+__NR_link,
+__NR_unlink,
+__NR_symlink,
+__NR_mknod,
+__NR_mkdirat,
+__NR_mknodat,
+__NR_unlinkat,
+__NR_renameat,
+__NR_linkat,
+__NR_symlinkat,
diff --git a/include/linux/audit.h b/include/linux/audit.h
index c211f0a..b27d7de 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -127,6 +127,12 @@ #define AUDIT_BITMASK_SIZE 64
#define AUDIT_WORD(nr) ((__u32)((nr)/32))
#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
+#define AUDIT_SYSCALL_CLASSES 16
+#define AUDIT_CLASS_DIR_WRITE 0
+#define AUDIT_CLASS_DIR_WRITE_32 1
+#define AUDIT_CLASS_CHATTR 2
+#define AUDIT_CLASS_CHATTR_32 3
+
/* This bitmask is used to validate user input. It represents all bits that
* are currently used in an audit field constant understood by the kernel.
* If you are adding a new #define AUDIT_<whatever>, please ensure that
@@ -307,6 +313,7 @@ #define AUDITSC_INVALID 0
#define AUDITSC_SUCCESS 1
#define AUDITSC_FAILURE 2
#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
+extern int __init audit_register_class(int class, unsigned *list);
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
/* Public API */
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 7f2ea8b..5b4e162 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -279,6 +279,29 @@ static int audit_to_watch(struct audit_k
return 0;
}
+static __u32 *classes[AUDIT_SYSCALL_CLASSES];
+
+int __init audit_register_class(int class, unsigned *list)
+{
+ __u32 *p = kzalloc(AUDIT_BITMASK_SIZE * sizeof(__u32), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ while (*list != ~0U) {
+ unsigned n = *list++;
+ if (n >= AUDIT_BITMASK_SIZE * 32 - AUDIT_SYSCALL_CLASSES) {
+ kfree(p);
+ return -EINVAL;
+ }
+ p[AUDIT_WORD(n)] |= AUDIT_BIT(n);
+ }
+ if (class >= AUDIT_SYSCALL_CLASSES || classes[class]) {
+ kfree(p);
+ return -EINVAL;
+ }
+ classes[class] = p;
+ return 0;
+}
+
/* Common user-space to kernel rule translation. */
static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
{
@@ -322,6 +345,22 @@ #endif
for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
entry->rule.mask[i] = rule->mask[i];
+ for (i = 0; i < AUDIT_SYSCALL_CLASSES; i++) {
+ int bit = AUDIT_BITMASK_SIZE * 32 - i - 1;
+ __u32 *p = &entry->rule.mask[AUDIT_WORD(bit)];
+ __u32 *class;
+
+ if (!(*p & AUDIT_BIT(bit)))
+ continue;
+ *p &= ~AUDIT_BIT(bit);
+ class = classes[i];
+ if (class) {
+ int j;
+ for (j = 0; j < AUDIT_BITMASK_SIZE; j++)
+ entry->rule.mask[j] |= class[j];
+ }
+ }
+
return entry;
exit_err:
--
1.3.GIT
18 years, 4 months
Dispatcher - single line output (perl)
by Leigh Purdie
There have been a few requests on this list for a
single-line-per-event output format.
>From what I understand, supporting this feature in the kernel is a
little challenging due to the potential memory/cache requirements -
having to save off the 'pieces' of an event from initiation to exit,
could be quite expensive when we're talking in-kernel resources.
Hence, we're left with an audit output that could:
* Have an arbitrary number of lines per unique event,
* Be chronologically distributed in some cases (event lines may be
spread over several seconds),
* Be out of sequence (numerically - two lines from event A, might be
followed by 1 line from event B, then another line from event A,
followed by the rest of event B).
* Have multiple 'items' with the same name (eg: source/dest UID's for
a CHMOD have the same 'name/key', though they are on different lines).
(Please let me know if these assumptions are incorrect!)
However, the dispatcher infrastructure offers the potential to
implement this sort of functionality in user-space.
As such, I've been playing with some perl that should translate
SYSCALL events to something that should be reasonably parse-able by
follow-on processing applications that expect events in a single-line
form (eg: logwatch, a SQL-based data injector, Snare or Snare Server).
Here's a sample line. Note that events are in header/data format (tab
delimited between components, comma delimited within a component).
rhel4 LinuxKAudit event,11,20060509 06:36:25
user,0(root),0(root),0(root),0(root) process,25068,id
path,/usr/bin/id return,0,yes a0,9f96ba8 a1,9f96b28
a2,9f84b40 a3,9f96b28 arch,40000003 auid,4294967295
exe,/usr/bin/id fsgid,0 fsuid,0 items,2 sgid,0 suid,0
The program works roughly as follows:
while read line
break line up into key/value pairs
pop the key/value data into an associative array (with a key of the
event number)
if we have an items=x key/value pair saved off for this event
number, and we have 'x' PATH-related lines now, then we must have a
complete event. Push it out.
ALSO push out any events that we haven't had any new lines for, for
more than 15 seconds.
..
We also getpwname/getgrname (with an internal cache to avoid recursive
audit events), and an internal simple realpath() to turn
/path/to/blah/../../to/somewhere into /path/to/somewhere.
The raw perl is attached. Does anyone have any comments, or
suggestions? (I don't care about structure at this point - it's early
days yet - I'm sure perl aficionados could do the entire program in a
single line).
In particular, comments would be welcome on how to absolutely,
programatically determine when an 'event' is complete, and it is safe
to push out our final 'line'.
Regards,
Leigh.
18 years, 5 months
New List Member: Intro & comments
by Clif Flynt
Hi,
I'm primarily an applications developer, though I wear a
sys-admin/security-admin hat when necessary. I've done kernel hacking
on V-7 and System-3 in the bad old days, but mostly stick in userland
now.
My current goal is to get some OpenSuse 10.1 systems DSS certified.
I've been a RedHat user since about RH4 or 5, but this project decided
to standardize on SuSE. My focus for using auditd isn't so much to
make a truly secure and well audited system, but to answer the specific
DSS/NISPOM Chapter 8 requirements.
SuSE supports AppArmor and the auditd security products, but has
very little SELinux support.
As I read things, AppArmor doesn't support the file audit
requirements, but Auditd can meet the DSS requirements.
I've updated the standard SuSE 10.1 kernel to 2.6.17.6 and brought in
the 3.0 glibc kernel headers. With these hacks, I can get the 1.2.5
auditd package to compile and install. It appears to be working.
Auditd 1.2.5 doesn't quite do what I need, but I'm getting close.
It has the framework, but it seems to take a little work to get the
answers I really want, and to handle the requirements for record
maintenance.
1) Auditing and reporting
I've copied the SYSCALL rules from the capp.rules sample, and I
think that covers what DSS will need audited. (Still checking and
confirming that I haven't missed anything obvious.)
To get the answers I wanted a bit more easily, I've made a GUI based
search tool that lets me specify reports with a bit more precision and
build customized reports. It's functional code, but is not pretty, and
gets pretty ugly when the data is way outside what I expected.
2) Maintaining records
The traditional log-rotate with N logs makes it difficult to keep X
days of logs. When the system is busy, I can rotate the logs every 10
minutes.
I've put together a small cron job that looks for audit.log.1,
filters out some data I know I won't want, and zips it into a file with
a name based on the timestamp.
My current report generator builds an SQLite database on the fly from
the flat ASCII logs. I'm thinking that the next rev of the file
rotation code will move the data to an SQLite database instead of
gzipped flat files and save that step.
I'm using SQLite instead of mySQL or Postgres because it it's fast,
mature and robust and doesn't require any database server (or dbadmin)
to run it.
I put together a small audisp test application to read from stdin and
save data in a timestamped file. When I run this, I get nothing but
empty reads, and finally an EOF from auditd. I'm expecting to see
plain ASCII input.
Is this not what is sent to the audisp target?
I just tried the sample.c application, compiled it to a.out and put
that into the auditd.conf file. When I restart audispd, I see no
output in /var/log/messages, and a.out does not show in the process
stack. If I just run /tmp/a.out and type something, output appears
in /var/log/messages.
If any of this is of interest or use, let me know, and I'll make it
available to the community.
Thanks,
Clif
--
.... Clif Flynt ... http://www.cflynt.com ... clif(a)cflynt.com ...
.. Tcl/Tk: A Developer's Guide (2nd edition) - Morgan Kauffman ..
..13th Annual Tcl/Tk Conference: Oct 9-13, 2006, Chicago, IL ..
............. http://www.tcl.tk/community/tcl2006/ ............
18 years, 5 months
type=SYSCALL, key= field?
by Michael C Thompson
Hey all,
I'm looking though the audit logs, and I'm wondering what exactly this
key field is in the SYSCALL audit record. I've always seen its value be
(null).
I'm not sure what this is meant to be related to, any clues?
Thanks,
Mike
18 years, 5 months
DAEMON_END message subj field
by Michael C Thompson
Hey Steve,
In the DAEMON_END message, it seems like the subj context is cut short:
type=DAEMON_END msg=audit(1153997923.281:9429) auditd normal halt,
sending auid=0 pid=3218 subj=root:staff_r:staff, auditd pid=3209
vs
type=CONFIG_CHANGE msg=audit(1153997824.379:314): audit_enabled=1 old=1
by auid=0 subj=root:staff_r:staff_t:s0-s15:c0.c255
CONFIG_CHANGE and others include the MLS label, but DAEMON_END does
not... is this by design or an oversight?
Thanks,
Mike
18 years, 5 months
Audit Software
by Kaushal Shriyan
Hi ALL
How do i use this audit software, can any cite me with examples
Thanks and Regards
Kaushal
18 years, 5 months
File Monitoring
by Steve
I am monitoring open syscalls on /etc/shadow and am receiving alerts
that I would like to suppress. Is it possible to exclude alerts for
files opened with particular commands? For example, xlock opening the
shadow file? I didn't see an option like this in the auditctl man page,
but I know those pages may be outdated.
Thanks,
Steve
18 years, 5 months
auid bug
by Steve
I am receiving audit events with an odd auid... I am not sure if this
is something wrong in the kernel or in audit. The auid I am receiving
is 4294967295 (the max value for an unsigned long). The other uid/gid
information is normal.
I have seen this on all audit versions since audit-1.2.3, and noticed it
using the following kernels:
2.6.17-1.2293.2.2_FC6.lspp.38.i686
2.6.17-1.2293.2.2_FC6.lspp.44.i686
The first time I noticed this was after the filter_key patch I applied
to audit-1.2.3, but it may have nothing to do with that patch. I
mentioned it then:
https://www.redhat.com/archives/linux-audit/2006-June/msg00086.html
There is an example record from the audit dispatcher there.
These events are coming straight from the real-time audit dispatcher.
Steve
18 years, 5 months
lspp.rules and time changes
by Steve
I know updating contrib/lspp.rules isn't a priority, but if anyone is
trying to catch changes to the system time, you may find this useful...
I tried out the rule in lspp.rules that should catch changes in the
system time and discovered that it doesn't catch changes made by the
date command. date uses the clock_settime syscall instead of adjtimex
or settimeofday.
Steve
18 years, 5 months
Using the Audit Failure Action Query functionality
by Lisa Smith
Starting with audit 1.2.4, the new audit failure action functionality is
available for applications and services.
The 1.2.5 audit package contains a man page for the new API,
get_auditfail_action(), which includes the following example that can be
used as a starting point for application developers:
/* Sample code */
auditfail_t failmode;
if ((fd = audit_open() ) < 0 ) {
fprintf (stderr, "Cannot open netlink audit socket");
/* Get the failure_action */
if ((rc = get_auditfail_action(&failmode)) == 0) {
if (failmode == FAIL_LOG)
fprintf (stderr, "Audit subsystem unavailable");
else if (failmode == FAIL_TERMINATE)
exit (1);
/* If failmode == FAIL_IGNORE, do nothing */
}
}
I'm happy to provide help to anyone who would like to incorporate the
new functionality into an application they are maintaining. If there
are any applications people would like me to go ahead and modify, please
let me know.
Lisa
18 years, 5 months