log ppid
by Alexander Viro
Signed-off-by: Al Viro <viro(a)zeniv.linux.org.uk>
---
kernel/auditsc.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
2a8fca72c08c197609918784c7ee5d13dfc77d90
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4ca913d..4fc3867 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -60,6 +60,7 @@
#include <linux/tty.h>
#include <linux/selinux.h>
#include <linux/binfmts.h>
+#include <linux/syscalls.h>
#include "audit.h"
@@ -156,7 +157,7 @@ struct audit_context {
struct audit_aux_data *aux;
/* Save things to print about task_struct */
- pid_t pid;
+ pid_t pid, ppid;
uid_t uid, euid, suid, fsuid;
gid_t gid, egid, sgid, fsgid;
unsigned long personality;
@@ -379,6 +380,7 @@ static inline struct audit_context *audi
}
context->pid = tsk->pid;
+ context->ppid = sys_getppid(); /* sic. tsk == current in all cases */
context->uid = tsk->uid;
context->gid = tsk->gid;
context->euid = tsk->euid;
@@ -614,7 +616,7 @@ static void audit_log_exit(struct audit_
tty = "(none)";
audit_log_format(ab,
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
- " pid=%d auid=%u uid=%u gid=%u"
+ " ppid=%d pid=%d auid=%u uid=%u gid=%u"
" euid=%u suid=%u fsuid=%u"
" egid=%u sgid=%u fsgid=%u tty=%s",
context->argv[0],
@@ -622,6 +624,7 @@ static void audit_log_exit(struct audit_
context->argv[2],
context->argv[3],
context->name_count,
+ context->ppid,
context->pid,
context->loginuid,
context->uid,
--
0.99.9.GIT
18 years, 7 months
issues with IPC_SET_PERM change
by Linda Knippers
I've been running portions of our audit test suite on the lspp.21 kernel
with the 1.2.1 user space tools and have noticed some problems with the
change from IPC to IPC_SET_PERM records.
What I'm seeing is this:
1. When an IPC_SET is done with semctl() or msgctl(), we only get an
IPC_SET_PERM record on the success case, not on the failure case.
For shmctl(), we get them for both cases. In RHEL4, we got the
information for both cases. I think we should get them for both
success and failure.
2. The IPC record used to include the information that is now in
IPC_SET_PERM and the original information was never captured.
Do we think anyone will be confused that the information in the
IPC record has a different meaning now? It doesn't seem very
backward compatible. If we want to be backward compatible with
the meaning of the IPC record, then I think IPC_SET_PERM should
become IPC again and we should create a new record type with the
information that's actually new.
3. The current IPC record includes a qbytes field but this field is
never initialized so I think it should be omitted if we keep the new
meaning of the IPC record, or we should change audit_ipc_obj()
so that we can pass it in. I don't think its available from the
information that audit_ipc_obj() has right now. If we really want
to capture everything that an IPC_SET can change, then we should
pass in the value.
4. The IPC_SET_PERM record includes the obj field, which I don't think
is changed as part of the IPC_SET call, so it seems redundant since
the same information is in the IPC record. If its not redundant
because the information can change, then its probably wrong in the
shmctl() case.
5. The IPC_SET_PERM record has field names with spaces in them.
I think we should replace the spaces with underscores.
I'm working on a patch that addresses 1, 3, 4, and 5. Anyone have
an opinion on 2?
If you're interested, the details of the audit records are below.
-- ljk
The RHEL4 records are from an ia64 box and the lspp.21 records are from
an x86_64 box.
With RHEL4, these are the audit records you get with
a successful semctl set:
type=SYSCALL msg=audit(1146770318.210:196): arch=c0000032 syscall=1108
success=yes exit=0 a0=0 a1=1 a2=1 a3=60000fffffff75b0 items=0 pid=4175
auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="syscalls" exe="/usr/local/eal3_testing/audit-test/syscalls/syscalls"
type=IPC msg=audit(1146770318.210:196): qbytes=0 iuid=502 igid=0 mode=0
and the failure case:
type=SYSCALL msg=audit(1146770318.900:206): arch=c0000032 syscall=1108
success=no exit=-1 a0=8000 a1=1 a2=1 a3=60000fffffff75c0 items=0
pid=4255 auid=500 uid=0 gid=0 euid=502 suid=0 fsuid=502 egid=0 sgid=0
fsgid=0 comm="syscalls"
exe="/usr/local/eal3_testing/audit-test/syscalls/syscalls"
type=IPC msg=audit(1146770318.900:206): qbytes=0 iuid=502 igid=0 mode=0
The IPC record includes the new values.
With the .21 kernel, this is what you get when running the same test
in the success case:
type=SYSCALL msg=audit(1146691872.791:94): arch=c000003e syscall=66
success=yes exit=0 a0=10000 a1=1 a2=1 a3=7fff328a7e70 items=0 pid=4327
auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
tty=pts2 comm="syscalls"
exe="/usr/local/eal3_testing/audit-test/syscalls/syscalls"
subj=user_u:system_r:unconfined_t:s0-s0:c0.c255
type=IPC_SET_PERM msg=audit(1146691872.791:94): new qbytes=0 new
iuid=501 new igid=0 new mode=0
obj=user_u:system_r:unconfined_t:s0-s0:c0.c255
type=IPC msg=audit(1146691872.791:94): qbytes=5a5a5a5a5a5a5a5a iuid=0
igid=0 mode=1c0 obj=user_u:system_r:unconfined_t:s0-s0:c0.c255
and the failure case:
type=SYSCALL msg=audit(1146691112.828:64): arch=c000003e syscall=66
success=no exit=-1 a0=8000 a1=1 a2=1 a3=7fff96610bd0 items=0 pid=3101
auid=500 uid=0 gid=0 euid=501 suid=0 fsuid=501 egid=0 sgid=0 fsgid=0
tty=pts2 comm="syscalls"
exe="/usr/local/eal3_testing/audit-test/syscalls/syscalls"
subj=user_u:system_r:unconfined_t:s0-s0:c0.c255
type=IPC msg=audit(1146691112.828:64): qbytes=5a5a5a5a5a5a5a5a iuid=0
igid=0 mode=1c0 obj=user_u:system_r:unconfined_t:s0-s0:c0.c255
The IPC record includes the original values, with qbytes not
initialized.
18 years, 7 months
[PATCH] improve performance with many inode rules
by Amy Griffis
The following patch improves audit syscall filtering performance when
the exit filter list contains many rules with an inode number field.
This implements Al Viro's idea from:
https://www.redhat.com/archives/linux-audit/2006-April/msg00087.html
Rules containing a single inode field are placed in one of 32 lists,
determined by hashing the inode number. Rules containing more than
one inode field, or using an operator other than equality, remain in
the exit filter list.
At syscall exit time, rules in the exit filter list are evaluated
first. The inode number hash is then checked for matching rules if
any audit_names[] have been collected during syscall processing.
Signed-off-by: Amy Griffis <amy.griffis(a)hp.com>
--
audit.c | 8 ++
audit.h | 11 +++
auditfilter.c | 168 +++++++++++++++++++++++++++++++++++++++++++++-------------
auditsc.c | 96 +++++++++++++++++++++++----------
4 files changed, 218 insertions(+), 65 deletions(-)
diff --git a/kernel/audit.c b/kernel/audit.c
index 7637410..40b3807 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -106,6 +106,9 @@ static struct sock *audit_sock;
/* Inotify handle. */
struct inotify_handle *audit_ih;
+/* Hash for inode-based rules */
+struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
+
/* The audit_freelist is a list of pre-allocated audit buffers (if more
* than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
* being placed on the freelist). */
@@ -669,6 +672,8 @@ static void audit_receive(struct sock *s
/* Initialize audit support at boot time. */
static int __init audit_init(void)
{
+ int i;
+
printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
audit_default ? "enabled" : "disabled");
audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
@@ -692,6 +697,9 @@ #ifdef CONFIG_AUDITSYSCALL
audit_ih = inotify_init(audit_handle_ievent);
if (IS_ERR(audit_ih))
audit_panic("cannot initialize inotify handle");
+
+ for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
+ INIT_LIST_HEAD(&audit_inode_hash[i]);
#endif
return 0;
diff --git a/kernel/audit.h b/kernel/audit.h
index 771833d..507998a 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -81,6 +81,7 @@ struct audit_krule {
u32 buflen; /* for data alloc on list rules */
u32 field_count;
struct audit_field *fields;
+ struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct list_head rlist; /* entry in audit_watch.rules list */
};
@@ -91,8 +92,16 @@ struct audit_entry {
struct audit_krule rule;
};
-
extern int audit_pid;
+
+#define AUDIT_INODE_BUCKETS 32
+extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
+
+static inline int audit_hash_ino(u32 ino)
+{
+ return (ino & (AUDIT_INODE_BUCKETS-1));
+}
+
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
extern int audit_compare_dname_path(const char *dname, const char *path);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4cc6406..e6c45fe 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -234,22 +234,40 @@ static char *audit_unpack_string(void **
return str;
}
+/* Translate an inode field to kernel respresentation. */
+static inline int audit_to_inode(struct audit_krule *krule,
+ struct audit_field *f)
+{
+ if (krule->listnr != AUDIT_FILTER_EXIT ||
+ krule->watch)
+ return -EINVAL;
+
+ /* if >1 inode field or op is not '=', rule goes on exit filter list,
+ * otherwise it goes in the inode hash table */
+ if (f->op & ~AUDIT_EQUAL ||
+ krule->inode_f)
+ krule->inode_f = NULL;
+ else
+ krule->inode_f = f;
+
+ return 0;
+}
+
/* Translate a watch string to kernel respresentation. */
static int audit_to_watch(struct audit_krule *krule, char *path, int len,
u32 op)
{
struct audit_watch *watch;
+ if (!audit_ih)
+ return -EOPNOTSUPP;
+
if (path[0] != '/' || path[len-1] == '/' ||
krule->listnr != AUDIT_FILTER_EXIT ||
op & ~AUDIT_EQUAL ||
- krule->watch) /* allow only 1 watch per rule */
+ krule->inode_f || krule->watch) /* 1 inode # per rule, for hash */
return -EINVAL;
- /* ensure inotify handle was initialized */
- if (!audit_ih)
- return -EOPNOTSUPP;
-
watch = audit_init_watch(path);
if (unlikely(IS_ERR(watch)))
return PTR_ERR(watch);
@@ -325,15 +343,23 @@ static struct audit_entry *audit_rule_to
f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
f->val = rule->values[i];
- if (f->type & AUDIT_UNUSED_BITS ||
- f->type == AUDIT_SE_USER ||
- f->type == AUDIT_SE_ROLE ||
- f->type == AUDIT_SE_TYPE ||
- f->type == AUDIT_SE_SEN ||
- f->type == AUDIT_SE_CLR ||
- f->type == AUDIT_WATCH) {
- err = -EINVAL;
+ err = -EINVAL;
+ if (f->type & AUDIT_UNUSED_BITS)
+ goto exit_free;
+
+ switch(f->type) {
+ case AUDIT_SE_USER:
+ case AUDIT_SE_ROLE:
+ case AUDIT_SE_TYPE:
+ case AUDIT_SE_SEN:
+ case AUDIT_SE_CLR:
+ case AUDIT_WATCH:
goto exit_free;
+ case AUDIT_INODE:
+ err = audit_to_inode(&entry->rule, f);
+ if (err)
+ goto exit_free;
+ break;
}
entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1;
@@ -426,6 +452,11 @@ static struct audit_entry *audit_data_to
goto exit_free;
}
break;
+ case AUDIT_INODE:
+ err = audit_to_inode(&entry->rule, f);
+ if (err)
+ goto exit_free;
+ break;
}
}
@@ -645,6 +676,7 @@ static struct audit_entry *audit_dupe_ru
for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
new->mask[i] = old->mask[i];
new->buflen = old->buflen;
+ new->inode_f = old->inode_f;
new->watch = NULL;
new->field_count = old->field_count;
memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
@@ -700,18 +732,20 @@ static inline void audit_update_watch(st
nwatch->ino = ino;
list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
+
oentry = container_of(r, struct audit_entry, rule);
+ list_del(&oentry->rule.rlist);
+ list_del_rcu(&oentry->list);
nentry = audit_dupe_rule(&oentry->rule, nwatch);
- if (unlikely(IS_ERR(nentry))) {
+ if (unlikely(IS_ERR(nentry)))
audit_panic("error updating watch, removing");
- list_del(&oentry->rule.rlist);
- list_del_rcu(&oentry->list);
- } else {
+ else {
+ int h = audit_hash_ino((u32)ino);
list_add(&nentry->rule.rlist, &nwatch->rules);
- list_del(&oentry->rule.rlist);
- list_replace_rcu(&oentry->list, &nentry->list);
+ list_add_rcu(&nentry->list, &audit_inode_hash[h]);
}
+
call_rcu(&oentry->rcu, audit_free_rule_rcu);
}
@@ -950,10 +984,11 @@ static inline int audit_add_rule(struct
struct list_head *list)
{
struct audit_entry *e;
+ struct audit_field *inode_f = entry->rule.inode_f;
struct audit_watch *watch = entry->rule.watch;
struct nameidata *ndp, *ndw;
LIST_HEAD(inotify_list);
- int err, putnd_needed = 0;
+ int h, err, putnd_needed = 0;
/* Taking audit_filter_mutex protects from stale rule data. */
mutex_lock(&audit_filter_mutex);
@@ -980,6 +1015,11 @@ static inline int audit_add_rule(struct
err = audit_add_watch(&entry->rule, ndp, ndw, &inotify_list);
if (err)
goto error;
+ h = audit_hash_ino((u32)watch->ino);
+ list = &audit_inode_hash[h];
+ } else if (inode_f) {
+ h = audit_hash_ino(inode_f->val);
+ list = &audit_inode_hash[h];
}
if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
@@ -1031,38 +1071,66 @@ static inline void audit_remove_watch(st
}
}
-/* Remove an existing rule from filterlist. */
-static inline int audit_del_rule(struct audit_entry *entry,
- struct list_head *list)
+/* Rule removal helper.
+ * Caller must hold audit_filter_mutex. */
+static inline int audit_do_del_rule(struct audit_entry *entry,
+ struct list_head *list,
+ struct list_head *inotify_list)
{
struct audit_entry *e;
- LIST_HEAD(inotify_list);
- mutex_lock(&audit_filter_mutex);
list_for_each_entry(e, list, list) {
if (audit_compare_rule(&entry->rule, &e->rule))
continue;
- if (e->rule.watch) {
- audit_remove_watch(&e->rule, &inotify_list);
- /* match initial get for tmp watch */
- audit_put_watch(entry->rule.watch);
- }
+ if (e->rule.watch)
+ audit_remove_watch(&e->rule, inotify_list);
list_del_rcu(&e->list);
call_rcu(&e->rcu, audit_free_rule_rcu);
+
+ return 0;
+ }
+ return -ENOENT; /* No matching rule */
+}
+
+/* Remove an existing rule from filterlist. */
+static inline int audit_del_rule(struct audit_entry *entry,
+ struct list_head *list)
+{
+ int h, ret;
+ struct audit_field *inode_f = entry->rule.inode_f;
+ struct audit_watch *watch = entry->rule.watch;
+ LIST_HEAD(inotify_list);
+
+ if (watch) {
+ mutex_lock(&audit_filter_mutex);
+ /* we don't know the inode number, so must walk entire hash */
+ for (h = 0; h < AUDIT_INODE_BUCKETS; h++) {
+ list = &audit_inode_hash[h];
+ ret = audit_do_del_rule(entry, list, &inotify_list);
+ if (!ret)
+ break;
+ }
mutex_unlock(&audit_filter_mutex);
if (!list_empty(&inotify_list))
audit_inotify_unregister(&inotify_list);
- return 0;
+ /* match initial get for tmp watch */
+ audit_put_watch(watch);
+
+ } else {
+ if (inode_f) {
+ h = audit_hash_ino(inode_f->val);
+ list = &audit_inode_hash[h];
+ }
+ mutex_lock(&audit_filter_mutex);
+ ret = audit_do_del_rule(entry, list, &inotify_list);
+ mutex_unlock(&audit_filter_mutex);
}
- mutex_unlock(&audit_filter_mutex);
- /* match initial get for tmp watch */
- if (entry->rule.watch)
- audit_put_watch(entry->rule.watch);
- return -ENOENT; /* No matching rule */
+
+ return ret;
}
/* List rules using struct audit_rule. Exists for backward
@@ -1089,6 +1157,20 @@ static void audit_list(int pid, int seq,
kfree(rule);
}
}
+ for (i = 0; i < AUDIT_INODE_BUCKETS; i++) {
+ list_for_each_entry(entry, &audit_inode_hash[i], list) {
+ struct audit_rule *rule;
+
+ rule = audit_krule_to_rule(&entry->rule);
+ if (unlikely(!rule))
+ break;
+ skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
+ rule, sizeof(*rule));
+ if (skb)
+ skb_queue_tail(q, skb);
+ kfree(rule);
+ }
+ }
skb = audit_make_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
if (skb)
skb_queue_tail(q, skb);
@@ -1117,6 +1199,20 @@ static void audit_list_rules(int pid, in
kfree(data);
}
}
+ for (i=0; i< AUDIT_INODE_BUCKETS; i++) {
+ list_for_each_entry(e, &audit_inode_hash[i], list) {
+ struct audit_rule_data *data;
+
+ data = audit_krule_to_data(&e->rule);
+ if (unlikely(!data))
+ break;
+ skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
+ data, sizeof(*data) + data->buflen);
+ if (skb)
+ skb_queue_tail(q, skb);
+ kfree(data);
+ }
+ }
skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
if (skb)
skb_queue_tail(q, skb);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 43512c1..ea7bafc 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -169,32 +169,12 @@ #endif
};
/* Determine if any context name data matches a rule's watch data */
-static inline int audit_match_watch(struct audit_context *ctx,
- struct audit_watch *watch)
-{
- int i;
-
- if (!ctx)
- return 0;
-
- if (watch->ino == (unsigned long)-1)
- return 0;
-
- for (i = 0; i < ctx->name_count; i++) {
- if (ctx->names[i].dev == watch->dev &&
- (ctx->names[i].ino == watch->ino ||
- ctx->names[i].pino == watch->ino))
- return 1;
- }
-
- return 0;
-}
-
/* Compare a task_struct with an audit_rule. Return 1 on match, 0
* otherwise. */
static int audit_filter_rules(struct task_struct *tsk,
struct audit_krule *rule,
struct audit_context *ctx,
+ struct audit_names *name,
enum audit_state *state)
{
int i, j, need_sid = 1;
@@ -253,7 +233,10 @@ static int audit_filter_rules(struct tas
}
break;
case AUDIT_DEVMAJOR:
- if (ctx) {
+ if (name)
+ result = audit_comparator(MAJOR(name->dev),
+ f->op, f->val);
+ else if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) {
++result;
@@ -263,7 +246,10 @@ static int audit_filter_rules(struct tas
}
break;
case AUDIT_DEVMINOR:
- if (ctx) {
+ if (name)
+ result = audit_comparator(MINOR(name->dev),
+ f->op, f->val);
+ else if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
++result;
@@ -273,7 +259,10 @@ static int audit_filter_rules(struct tas
}
break;
case AUDIT_INODE:
- if (ctx) {
+ if (name)
+ result = (name->ino == f->val ||
+ name->pino == f->val);
+ else if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
audit_comparator(ctx->names[j].pino, f->op, f->val)) {
@@ -284,7 +273,10 @@ static int audit_filter_rules(struct tas
}
break;
case AUDIT_WATCH:
- result = audit_match_watch(ctx, rule->watch);
+ if (name && rule->watch->ino != (unsigned long)-1)
+ result = (name->dev == rule->watch->dev &&
+ (name->ino == rule->watch->ino ||
+ name->pino == rule->watch->ino));
break;
case AUDIT_LOGINUID:
result = 0;
@@ -343,7 +335,7 @@ static enum audit_state audit_filter_tas
rcu_read_lock();
list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
- if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+ if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) {
rcu_read_unlock();
return state;
}
@@ -373,8 +365,47 @@ static enum audit_state audit_filter_sys
int bit = AUDIT_BIT(ctx->major);
list_for_each_entry_rcu(e, list, list) {
- if ((e->rule.mask[word] & bit) == bit
- && audit_filter_rules(tsk, &e->rule, ctx, &state)) {
+ if ((e->rule.mask[word] & bit) == bit &&
+ audit_filter_rules(tsk, &e->rule, ctx, NULL,
+ &state)) {
+ rcu_read_unlock();
+ return state;
+ }
+ }
+ }
+ rcu_read_unlock();
+ return AUDIT_BUILD_CONTEXT;
+}
+
+/* At syscall exit time, this filter is called if any audit_names[] have been
+ * collected during syscall processing. We only check rules in sublists at hash
+ * buckets applicable to the inode numbers in audit_names[].
+ * Regarding audit_state, same rules apply as for audit_filter_syscall().
+ */
+static enum audit_state audit_filter_inodes(struct task_struct *tsk,
+ struct audit_context *ctx)
+{
+ int i;
+ struct audit_entry *e;
+ enum audit_state state;
+
+ if (audit_pid && tsk->tgid == audit_pid)
+ return AUDIT_DISABLED;
+
+ rcu_read_lock();
+ for (i = 0; i < ctx->name_count; i++) {
+ int word = AUDIT_WORD(ctx->major);
+ int bit = AUDIT_BIT(ctx->major);
+ struct audit_names *n = &ctx->names[i];
+ int h = audit_hash_ino((u32)n->ino);
+ struct list_head *list = &audit_inode_hash[h];
+
+ if (list_empty(list))
+ continue;
+
+ list_for_each_entry_rcu(e, list, list) {
+ if ((e->rule.mask[word] & bit) == bit &&
+ audit_filter_rules(tsk, &e->rule, ctx, n, &state)) {
rcu_read_unlock();
return state;
}
@@ -397,11 +428,20 @@ static inline struct audit_context *audi
if (context->in_syscall && !context->auditable) {
enum audit_state state;
+
state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
+ if (state == AUDIT_RECORD_CONTEXT) {
+ context->auditable = 1;
+ goto get_context;
+ }
+
+ state = audit_filter_inodes(tsk, context);
if (state == AUDIT_RECORD_CONTEXT)
context->auditable = 1;
+
}
+get_context:
context->pid = tsk->pid;
context->uid = tsk->uid;
context->gid = tsk->gid;
18 years, 7 months
(no subject)
by Kirkwood, David A
I don't see any timestamps on audit events. How can I bracket events between
to dates /times?
18 years, 7 months
[PATCH 1/2] fix auditctl -D
by Joy Latten
The fix for the problem of auditctl -D not working
consists of two patches. One is the userspace patch
and the other is for the kernel.
Below is the userspace patch. I added AUDIT_DEL_ALL flag.
Regards,
Joy
diff -urpN audit-1.1.5.orig/lib/msg_typetab.h audit-1.1.5/lib/msg_typetab.h
--- audit-1.1.5.orig/lib/msg_typetab.h 2006-04-27 15:46:56.000000000 -0500
+++ audit-1.1.5/lib/msg_typetab.h 2006-04-28 09:53:13.000000000 -0500
@@ -31,6 +31,7 @@
//_S(AUDIT_LIST, "LIST" )
//_S(AUDIT_ADD, "ADD" )
//_S(AUDIT_DEL, "DEL" )
+//_S(AUDIT_DEL_ALL, "DEL_ALL" )
_S(AUDIT_USER, "USER" )
_S(AUDIT_LOGIN, "LOGIN" )
//_S(AUDIT_SIGNAL_INFO, "SIGNAL_INFO" )
diff -urpN audit-1.1.5.orig/src/auditctl.c audit-1.1.5/src/auditctl.c
--- audit-1.1.5.orig/src/auditctl.c 2006-04-27 15:46:56.000000000 -0500
+++ audit-1.1.5/src/auditctl.c 2006-04-28 09:51:06.000000000 -0500
@@ -1104,62 +1104,12 @@ static int audit_print_reply(struct audi
/* Returns 0 for success and -1 for failure */
static int delete_all_rules(void)
{
- int seq, i;
- int timeout = 40; /* tenths of seconds */
- struct audit_reply rep;
- fd_set read_mask;
+ int rc = 0;
- /* list the rules */
- seq = audit_request_rules_list(fd);
- if (seq <= 0)
+ rc = audit_send(fd, AUDIT_DEL_ALL, NULL, 0);
+ if (rc < 0) {
+ fprintf(stderr, "Error deleting rule (%s)\n", strerror(-rc));
return -1;
-
- FD_ZERO(&read_mask);
- FD_SET(fd, &read_mask);
-
- for (i = 0; i < timeout; i++) {
- struct timeval t;
- int rc;
-
- t.tv_sec = 0;
- t.tv_usec = 100000; /* .1 second */
- do {
- rc = select(fd+1, &read_mask, NULL, NULL, &t);
- } while (rc < 0 && errno == EINTR);
- // We'll try to read just in case
- rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
- if (rc > 0) {
- /* Reset timeout */
- i = 0;
-
- /* Don't make decisions based on wrong packet */
- if (rep.nlh->nlmsg_seq != seq)
- continue;
-
- /* If we get done or error, break out */
- if (rep.type == NLMSG_DONE)
- break;
-
- if (rep.type == NLMSG_ERROR && rep.error->error) {
- fprintf(stderr,
- "Error receiving rules list (%s)\n",
- strerror(-rep.error->error));
- return -1;
- }
-
- /* If its not what we are expecting, keep looping */
- if (rep.type != AUDIT_LIST)
- continue;
-
- /* Found it, bounce it right back with delete */
- rc = audit_send(fd, AUDIT_DEL, rep.rule,
- sizeof(struct audit_rule));
- if (rc < 0) {
- fprintf(stderr, "Error deleting rule (%s)\n",
- strerror(-rc));
- return -1;
- }
- }
}
return 0;
18 years, 7 months
[PATCH] fix audit_krule_to_{rule,data} return values
by Amy Griffis
Don't return -ENOMEM when callers of these functions are checking for
a NULL return. Bug noticed by Serge Hallyn.
Signed-off-by: Amy Griffis <amy.griffis(a)hp.com>
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 35dca7e..7647237 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -457,7 +457,7 @@ static struct audit_rule *audit_krule_to
rule = kmalloc(sizeof(*rule), GFP_KERNEL);
if (unlikely(!rule))
- return ERR_PTR(-ENOMEM);
+ return NULL;
memset(rule, 0, sizeof(*rule));
rule->flags = krule->flags | krule->listnr;
@@ -488,7 +488,7 @@ static struct audit_rule_data *audit_kru
data = kmalloc(sizeof(*data) + krule->buflen, GFP_KERNEL);
if (unlikely(!data))
- return ERR_PTR(-ENOMEM);
+ return NULL;
memset(data, 0, sizeof(*data));
data->flags = krule->flags | krule->listnr;
18 years, 7 months
[PATCH git] filesystem audit patch fixes
by Amy Griffis
A couple of fixes for the filesystem auditing patch:
- make audit_filter_mutex static
- always release nameidata
Please fold in with lspp.b9 dcdb3920a1393e88b65d086f6f3f42181ad02816.
Signed-off-by: Amy Griffis <amy.griffis(a)hp.com>
--
auditfilter.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 35dca7e..02039bb 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -91,7 +91,7 @@ #error Fix audit_filter_list initialiser
#endif
};
-DEFINE_MUTEX(audit_filter_mutex);
+static DEFINE_MUTEX(audit_filter_mutex);
/* Inotify handle */
extern struct inotify_handle *audit_ih;
@@ -953,7 +953,7 @@ static inline int audit_add_rule(struct
struct audit_watch *watch = entry->rule.watch;
struct nameidata *ndp, *ndw;
LIST_HEAD(inotify_list);
- int err;
+ int err, putnd_needed = 0;
/* Taking audit_filter_mutex protects from stale rule data. */
mutex_lock(&audit_filter_mutex);
@@ -971,16 +971,15 @@ static inline int audit_add_rule(struct
err = audit_get_nd(watch->path, &ndp, &ndw);
if (err)
goto error;
+ putnd_needed = 1;
}
mutex_lock(&audit_filter_mutex);
if (watch) {
/* audit_filter_mutex is dropped and re-taken during this call */
err = audit_add_watch(&entry->rule, ndp, ndw, &inotify_list);
- if (err) {
- audit_put_nd(ndp, ndw);
+ if (err)
goto error;
- }
}
if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
@@ -994,12 +993,15 @@ static inline int audit_add_rule(struct
err = audit_inotify_register(ndp, &inotify_list);
if (err)
goto error;
- audit_put_nd(ndp, ndw);
}
+ if (putnd_needed)
+ audit_put_nd(ndp, ndw);
return 0;
error:
+ if (putnd_needed)
+ audit_put_nd(ndp, ndw);
if (watch)
audit_put_watch(watch); /* tmp watch, matches initial get */
return err;
18 years, 7 months
Re: [redhat-lspp] Watch question
by Amy Griffis
Timothy R. Chavez wrote: [Fri Apr 28 2006, 11:29:27AM EDT]
> On Fri, 2006-04-28 at 08:50 -0400, Steve Grubb wrote:
> > I completely disagree with the current file system auditing approach requiring
> > explicit syscall coupling. I think it is a big problem for the security
> > community to have a tool for auditing files that requires knowledge of
> > syscalls.
This audit subsystem was designed around knowledge of syscalls, to the
point that it requires the user to know whether a particular rule
field is applicable at syscall entry or exit time. (!)
The filesystem auditing capability that is currently upstream
(inode-based) requires a knowledge of syscalls. The path-based
functionality I've been working on isn't supposed to be a replacement
for the current inode-based filtering. It is supposed to complement
it to provide a way to audit config files.
> > I personally want to be able to tell the kernel that I want notification of:
> > reads, writes, execution, or changes to attributes of a specific file or all
> > files in that directory and subdirectories. User space should not have to
> > know which syscalls implement each of the categories.
>
> This is really simple and intuitive. I like it. These abstractions
> should be easily expressed. I don't imagine that the majority of the
> users of audit are going to need the level of granularity that's been
> provided, which is why the above makes sense.
Agreed, I think this makes a lot of sense. As Al also mentioned in
another thread, having auditctl specify a special bit or flag that
tells the kernel to set the appropriate bits in the syscall mask would
solve the problem for userspace.
18 years, 7 months
[PATCH 2/2] fix auditctl -D
by Joy Latten
The fix for the problem of auditctl -D not working
consists of two patches. One is the userspace patch
and the other is for the kernel.
Below is the kernel patch. I added AUDIT_DEL_ALL flag.
Regards,
Joy
diff -urpN linux-2.6.orig/include/linux/audit.h linux-2.6.patch/include/linux/audit.h
--- linux-2.6.orig/include/linux/audit.h 2006-04-28 15:01:38.000000000 -0500
+++ linux-2.6.patch/include/linux/audit.h 2006-04-28 16:10:06.000000000 -0500
@@ -63,6 +63,7 @@
#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
+#define AUDIT_DEL_ALL 1014 /* Delete all syscall filtering rules */
#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
#define AUDIT_USER_AVC 1107 /* We filter this differently */
diff -urpN linux-2.6.orig/kernel/audit.c linux-2.6.patch/kernel/audit.c
--- linux-2.6.orig/kernel/audit.c 2006-04-28 15:01:37.000000000 -0500
+++ linux-2.6.patch/kernel/audit.c 2006-04-28 16:09:03.000000000 -0500
@@ -451,6 +451,7 @@ static int audit_netlink_ok(kernel_cap_t
case AUDIT_ADD_RULE:
case AUDIT_DEL:
case AUDIT_DEL_RULE:
+ case AUDIT_DEL_ALL:
case AUDIT_SIGNAL_INFO:
if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
err = -EPERM;
@@ -604,6 +605,7 @@ static int audit_receive_msg(struct sk_b
if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
return -EINVAL;
/* fallthrough */
+ case AUDIT_DEL_ALL:
case AUDIT_LIST_RULES:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, nlmsg_len(nlh),
diff -urpN linux-2.6.orig/kernel/auditfilter.c linux-2.6.patch/kernel/auditfilter.c
--- linux-2.6.orig/kernel/auditfilter.c 2006-04-28 15:01:37.000000000 -0500
+++ linux-2.6.patch/kernel/auditfilter.c 2006-04-28 16:09:13.000000000 -0500
@@ -1063,6 +1063,21 @@ static inline int audit_del_rule(struct
return -ENOENT; /* No matching rule */
}
+/* Remove all rules from all filterlists. Protected by
+ * audit_netlink_mutex. */
+static void audit_del_all_rules(void)
+{
+ struct audit_entry *e, *e2;
+ int i;
+
+ for (i=0; i<AUDIT_NR_FILTERS; i++) {
+ list_for_each_entry_safe(e, e2, &audit_filter_list[i], list) {
+ list_del_rcu(&e->list);
+ call_rcu(&e->rcu, audit_free_rule_rcu);
+ }
+ }
+}
+
/* List rules using struct audit_rule. Exists for backward
* compatibility with userspace. */
static void audit_list(int pid, int seq, struct sk_buff_head *q)
@@ -1233,6 +1248,12 @@ int audit_receive_filter(int type, int p
audit_free_rule(entry);
break;
+ case AUDIT_DEL_ALL:
+ audit_del_all_rules();
+ audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+ "auid=%u remove all rules res=%d\n",
+ loginuid, !err);
+ break;
default:
return -EINVAL;
}
diff -urpN linux-2.6.orig/security/selinux/nlmsgtab.c linux-2.6.patch/security/selinux/nlmsgtab.c
--- linux-2.6.orig/security/selinux/nlmsgtab.c 2006-04-28 15:02:20.000000000 -0500
+++ linux-2.6.patch/security/selinux/nlmsgtab.c 2006-04-28 16:08:23.000000000 -0500
@@ -109,6 +109,7 @@ static struct nlmsg_perm nlmsg_audit_per
{ AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
{ AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_DEL_ALL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
{ AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
};
18 years, 7 months