[PATCH 06/11] Task watchers: Register audit task watcher
by Matt Helsley
Adapt audit to use task watchers.
Signed-off-by: Matt Helsley <matthltc(a)us.ibm.com>
Cc: David Woodhouse <dwmw2(a)infradead.org>
Cc: linux-audit(a)redhat.com
--
kernel/audit.c | 25 ++++++++++++++++++++++++-
kernel/exit.c | 3 ---
kernel/fork.c | 7 +------
3 files changed, 25 insertions(+), 10 deletions(-)
Index: linux-2.6.17-rc5-mm2/kernel/exit.c
===================================================================
--- linux-2.6.17-rc5-mm2.orig/kernel/exit.c
+++ linux-2.6.17-rc5-mm2/kernel/exit.c
@@ -35,11 +35,10 @@
#include <linux/posix-timers.h>
#include <linux/mutex.h>
#include <linux/futex.h>
#include <linux/compat.h>
#include <linux/pipe_fs_i.h>
-#include <linux/audit.h> /* for audit_free() */
#include <linux/resource.h>
#include <linux/notifier.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -914,12 +913,10 @@ fastcall NORET_TYPE void do_exit(long co
exit_robust_list(tsk);
#ifdef CONFIG_COMPAT
if (unlikely(tsk->compat_robust_list))
compat_exit_robust_list(tsk);
#endif
- if (unlikely(tsk->audit_context))
- audit_free(tsk);
tsk->exit_code = code;
taskstats_exit_send(tsk, tidstats, tgidstats);
taskstats_exit_free(tidstats, tgidstats);
delayacct_tsk_exit(tsk);
notify_result = notify_watchers(WATCH_TASK_FREE, tsk);
Index: linux-2.6.17-rc5-mm2/kernel/audit.c
===================================================================
--- linux-2.6.17-rc5-mm2.orig/kernel/audit.c
+++ linux-2.6.17-rc5-mm2/kernel/audit.c
@@ -46,10 +46,11 @@
#include <asm/atomic.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/kthread.h>
+#include <linux/notifier.h>
#include <linux/audit.h>
#include <net/sock.h>
#include <net/netlink.h>
@@ -64,10 +65,30 @@
static int audit_initialized;
/* No syscall auditing will take place unless audit_enabled != 0. */
int audit_enabled;
+static int audit_task(struct notifier_block *nb, unsigned long val, void *t)
+{
+ struct task_struct *tsk = t;
+
+ switch(get_watch_event(val)) {
+ case WATCH_TASK_INIT:
+ /* Hack: -EFOO sets NOTIFY_STOP_MASK */
+ return audit_alloc(tsk);
+ case WATCH_TASK_FREE:
+ if (unlikely(tsk->audit_context))
+ audit_free(tsk);
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static struct notifier_block __read_mostly audit_watch_tasks_nb = {
+ .notifier_call = audit_task,
+};
+
/* Default state when kernel boots without any parameters. */
static int audit_default;
/* If auditing cannot proceed, audit_failure selects what happens. */
static int audit_failure = AUDIT_FAIL_PRINTK;
@@ -707,12 +728,14 @@ static int __init audit_enable(char *str
{
audit_default = !!simple_strtol(str, NULL, 0);
printk(KERN_INFO "audit: %s%s\n",
audit_default ? "enabled" : "disabled",
audit_initialized ? "" : " (after initialization)");
- if (audit_initialized)
+ if (audit_initialized) {
audit_enabled = audit_default;
+ register_task_watcher(&audit_watch_tasks_nb);
+ }
return 1;
}
__setup("audit=", audit_enable);
Index: linux-2.6.17-rc5-mm2/kernel/fork.c
===================================================================
--- linux-2.6.17-rc5-mm2.orig/kernel/fork.c
+++ linux-2.6.17-rc5-mm2/kernel/fork.c
@@ -38,11 +38,10 @@
#include <linux/jiffies.h>
#include <linux/futex.h>
#include <linux/rcupdate.h>
#include <linux/ptrace.h>
#include <linux/mount.h>
-#include <linux/audit.h>
#include <linux/profile.h>
#include <linux/rmap.h>
#include <linux/acct.h>
#include <linux/delayacct.h>
#include <linux/notifier.h>
@@ -1088,15 +1087,13 @@ static task_t *copy_process(unsigned lon
p->softirq_context = 0;
#endif
if ((retval = security_task_alloc(p)))
goto bad_fork_cleanup_policy;
- if ((retval = audit_alloc(p)))
- goto bad_fork_cleanup_security;
/* copy all the process information */
if ((retval = copy_semundo(clone_flags, p)))
- goto bad_fork_cleanup_audit;
+ goto bad_fork_cleanup_security;
if ((retval = copy_files(clone_flags, p)))
goto bad_fork_cleanup_semundo;
if ((retval = copy_fs(clone_flags, p)))
goto bad_fork_cleanup_files;
if ((retval = copy_sighand(clone_flags, p)))
@@ -1270,12 +1267,10 @@ bad_fork_cleanup_fs:
exit_fs(p); /* blocking */
bad_fork_cleanup_files:
exit_files(p); /* blocking */
bad_fork_cleanup_semundo:
exit_sem(p);
-bad_fork_cleanup_audit:
- audit_free(p);
bad_fork_cleanup_security:
security_task_free(p);
notify_result = notify_watchers(WATCH_TASK_FREE, p);
WARN_ON(notify_result & NOTIFY_STOP_MASK);
bad_fork_cleanup_policy:
--
18 years, 6 months
[PATCH] add rule filterkey
by Amy Griffis
Add support for a rule key, which can be used to tie audit records to audit
rules. This is useful when a watched file is accessed through a link or
symlink, as well as for general audit log analysis.
Because this patch uses a string key instead of an integer key, there is a bit
of extra overhead to do the kstrdup() when a rule fires. However, we're also
allocating memory for the audit record buffer, so it's probably not that
significant. I went ahead with a string key because it seems more
user-friendly.
Note that the user must ensure that filterkeys are unique. The kernel only
checks for duplicate rules.
Signed-off-by: Amy Griffis <amy.griffis(a)hpd.com>
---
include/linux/audit.h | 3 ++
kernel/audit.h | 1 +
kernel/auditfilter.c | 95 ++++++++++++++++++++++++++++++-------------------
kernel/auditsc.c | 15 ++++++++
4 files changed, 78 insertions(+), 36 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index e1c1dbd..f7883ec 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -123,6 +123,7 @@ #define AUDIT_ALWAYS 2 /* Generate aud
/* Rule structure sizes -- if these change, different AUDIT_ADD and
* AUDIT_LIST commands must be implemented. */
#define AUDIT_MAX_FIELDS 64
+#define AUDIT_MAX_KEY_LEN 32
#define AUDIT_BITMASK_SIZE 64
#define AUDIT_WORD(nr) ((__u32)((nr)/32))
#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
@@ -172,6 +173,8 @@ #define AUDIT_ARG1 (AUDIT_ARG0+1)
#define AUDIT_ARG2 (AUDIT_ARG0+2)
#define AUDIT_ARG3 (AUDIT_ARG0+3)
+#define AUDIT_FILTERKEY 210
+
#define AUDIT_NEGATE 0x80000000
/* These are the supported operators.
diff --git a/kernel/audit.h b/kernel/audit.h
index 38e62b7..0381640 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -81,6 +81,7 @@ struct audit_krule {
u32 mask[AUDIT_BITMASK_SIZE];
u32 buflen; /* for data alloc on list rules */
u32 field_count;
+ char *filterkey; /* ties events to rules */
struct audit_field *fields;
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4c99d2c..e98db08 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -141,6 +141,7 @@ static inline void audit_free_rule(struc
selinux_audit_rule_free(f->se_rule);
}
kfree(e->rule.fields);
+ kfree(e->rule.filterkey);
kfree(e);
}
@@ -511,6 +512,16 @@ static struct audit_entry *audit_data_to
if (err)
goto exit_free;
break;
+ case AUDIT_FILTERKEY:
+ err = -EINVAL;
+ if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
+ goto exit_free;
+ str = audit_unpack_string(&bufp, &remain, f->val);
+ if (IS_ERR(str))
+ goto exit_free;
+ entry->rule.buflen += f->val;
+ entry->rule.filterkey = str;
+ break;
default:
goto exit_free;
}
@@ -612,6 +623,10 @@ static struct audit_rule_data *audit_kru
data->buflen += data->values[i] =
audit_pack_string(&bufp, krule->watch->path);
break;
+ case AUDIT_FILTERKEY:
+ data->buflen += data->values[i] =
+ audit_pack_string(&bufp, krule->filterkey);
+ break;
default:
data->values[i] = f->val;
}
@@ -651,6 +666,11 @@ static int audit_compare_rule(struct aud
if (strcmp(a->watch->path, b->watch->path))
return 1;
break;
+ case AUDIT_FILTERKEY:
+ /* both filterkeys exist based on above type compare */
+ if (strcmp(a->filterkey, b->filterkey))
+ return 1;
+ break;
default:
if (a->fields[i].val != b->fields[i].val)
return 1;
@@ -730,6 +750,7 @@ static struct audit_entry *audit_dupe_ru
u32 fcount = old->field_count;
struct audit_entry *entry;
struct audit_krule *new;
+ char *fk;
int i, err = 0;
entry = audit_init_entry(fcount);
@@ -760,6 +781,13 @@ static struct audit_entry *audit_dupe_ru
case AUDIT_SE_CLR:
err = audit_dupe_selinux_field(&new->fields[i],
&old->fields[i]);
+ break;
+ case AUDIT_FILTERKEY:
+ fk = kstrdup(old->filterkey, GFP_KERNEL);
+ if (unlikely(!fk))
+ err = -ENOMEM;
+ else
+ new->filterkey = fk;
}
if (err) {
audit_free_rule(entry);
@@ -1245,6 +1273,34 @@ static void audit_list_rules(int pid, in
skb_queue_tail(q, skb);
}
+/* Log rule additions and removals */
+static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
+ struct audit_krule *rule, int res)
+{
+ struct audit_buffer *ab;
+
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+ if (!ab)
+ return;
+ audit_log_format(ab, "auid=%u", loginuid);
+ if (sid) {
+ char *ctx = NULL;
+ u32 len;
+ if (selinux_ctxid_to_string(sid, &ctx, &len))
+ audit_log_format(ab, " ssid=%u", sid);
+ else
+ audit_log_format(ab, " subj=%s", ctx);
+ kfree(ctx);
+ }
+ audit_log_format(ab, " %s rule key=", action);
+ if (rule->filterkey)
+ audit_log_untrustedstring(ab, rule->filterkey);
+ else
+ audit_log_format(ab, "(null)");
+ audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
+ audit_log_end(ab);
+}
+
/**
* audit_receive_filter - apply all rules to the specified message type
* @type: audit message type
@@ -1304,24 +1360,7 @@ int audit_receive_filter(int type, int p
err = audit_add_rule(entry,
&audit_filter_list[entry->rule.listnr]);
-
- if (sid) {
- char *ctx = NULL;
- u32 len;
- if (selinux_ctxid_to_string(sid, &ctx, &len)) {
- /* Maybe call audit_panic? */
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "auid=%u ssid=%u add rule to list=%d res=%d",
- loginuid, sid, entry->rule.listnr, !err);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "auid=%u subj=%s add rule to list=%d res=%d",
- loginuid, ctx, entry->rule.listnr, !err);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "auid=%u add rule to list=%d res=%d",
- loginuid, entry->rule.listnr, !err);
+ audit_log_rule_change(loginuid, sid, "add", &entry->rule, !err);
if (err)
audit_free_rule(entry);
@@ -1337,24 +1376,8 @@ int audit_receive_filter(int type, int p
err = audit_del_rule(entry,
&audit_filter_list[entry->rule.listnr]);
-
- if (sid) {
- char *ctx = NULL;
- u32 len;
- if (selinux_ctxid_to_string(sid, &ctx, &len)) {
- /* Maybe call audit_panic? */
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "auid=%u ssid=%u remove rule from list=%d res=%d",
- loginuid, sid, entry->rule.listnr, !err);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "auid=%u subj=%s remove rule from list=%d res=%d",
- loginuid, ctx, entry->rule.listnr, !err);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "auid=%u remove rule from list=%d res=%d",
- loginuid, entry->rule.listnr, !err);
+ audit_log_rule_change(loginuid, sid, "remove", &entry->rule,
+ !err);
audit_free_rule(entry);
break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 1c43dba..b32ccfa 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -186,6 +186,7 @@ struct audit_context {
int auditable; /* 1 if record should be written */
int name_count;
struct audit_names names[AUDIT_NAMES];
+ char * filterkey; /* key for rule that triggered record */
struct dentry * pwd;
struct vfsmount * pwdmnt;
struct audit_context *previous; /* For nested syscalls */
@@ -348,11 +349,17 @@ static int audit_filter_rules(struct tas
if (ctx)
result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
break;
+ case AUDIT_FILTERKEY:
+ /* ignore this field for filtering */
+ result = 1;
+ break;
}
if (!result)
return 0;
}
+ if (rule->filterkey)
+ ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
switch (rule->action) {
case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
@@ -627,6 +634,7 @@ static inline void audit_free_context(st
}
audit_free_names(context);
audit_free_aux(context);
+ kfree(context->filterkey);
kfree(context);
context = previous;
} while (context);
@@ -736,6 +744,11 @@ static void audit_log_exit(struct audit_
context->euid, context->suid, context->fsuid,
context->egid, context->sgid, context->fsgid, tty);
audit_log_task_info(ab, tsk);
+ if (context->filterkey) {
+ audit_log_format(ab, " key=");
+ audit_log_untrustedstring(ab, context->filterkey);
+ } else
+ audit_log_format(ab, " key=(null)");
audit_log_end(ab);
for (aux = context->aux; aux; aux = aux->next) {
@@ -1061,6 +1074,8 @@ void audit_syscall_exit(int valid, long
} else {
audit_free_names(context);
audit_free_aux(context);
+ kfree(context->filterkey);
+ context->filterkey = NULL;
tsk->audit_context = context;
}
}
--
1.4.0
18 years, 6 months
[PATCH git] add key,value delimiter to PATH record
by Amy Griffis
Audit record key,value pairs must have a space delimiter.
This fix applies to lspp.b19 commit
3ee74f8797418a46e40976f1f1c2bcd23ded95bf
"log more info for directory entry change events"
Signed-off-by: Amy Griffis <amy.griffis(a)hpd.com>
---
kernel/auditsc.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index a2ad392..1c43dba 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -869,7 +869,7 @@ static void audit_log_exit(struct audit_
case 0:
/* name was specified as a relative path and the
* directory component is the cwd */
- audit_log_d_path(ab, "name=", context->pwd,
+ audit_log_d_path(ab, " name=", context->pwd,
context->pwdmnt);
break;
default:
@@ -879,7 +879,7 @@ static void audit_log_exit(struct audit_
n->name);
}
} else
- audit_log_format(ab, "name=(null)");
+ audit_log_format(ab, " name=(null)");
if (n->ino != (unsigned long)-1) {
audit_log_format(ab, " inode=%lu"
--
1.4.0
18 years, 6 months
Audit and file watching
by Steve
I have been using Audit's file watching ability to monitor when files
are opened. I decided to also try to monitor the deletion of files, so
I told audit to watch for all syscalls pertaining to a particular file.
I then tried opening the file, it worked as before. Then I tried to
delete the file using 'rm /tmp/test.c' the file was deleted from the
filesystem, but audit only showed two syscalls being performed: lstat64
and access. Audit also sent a message saying:
... audit updated rules specifying watch="/tmp/test.c" ...
lstat64 and access can not delete files on the filesystem, can they?
I expected to see unlink...
Any ideas?
Steve
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1300, payload size=279
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:679): arch=40000003 syscall=196 success=yes
exit=0 a0=bf8c7c49 a1=bf8c6fbc a2=8f1ff4 a3=bf8c7c49 items=1 ppid=7838
pid=8043 auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0
fsgid=0 tty=pts2 comm="rm" exe="/bin/rm"
subj=user_u:system_r:unconfined_t:s0"
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1307, payload size=43
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:679): cwd="/tmp/test""
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1302, payload size=143
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:679): item=0 name="/tmp/test.c" inode=5358237
dev=03:02 mode=0100644 ouid=0 ogid=0 rdev=00:00
obj=user_u:object_r:tmp_t:s0"
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1300, payload size=264
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:680): arch=40000003 syscall=33 success=yes
exit=0 a0=bf8c7c49 a1=2 a2=8f1ff4 a3=2 items=1 ppid=7838 pid=8043
auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
tty=pts2 comm="rm" exe="/bin/rm" subj=user_u:system_r:unconfined_t:s0"
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1307, payload size=43
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:680): cwd="/tmp/test""
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1302, payload size=143
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:680): item=0 name="/tmp/test.c" inode=5358237
dev=03:02 mode=0100644 ouid=0 ogid=0 rdev=00:00
obj=user_u:object_r:tmp_t:s0"
Jun 14 13:21:06 otslab11 user_actions[8035]: type=1305, payload size=113
Jun 14 13:21:06 otslab11 user_actions[8035]:
data="audit(1150305665.265:681): audit updated rules specifying
watch="/tmp/test.c" with dev=4294967295 ino=4294967295 "
18 years, 6 months
[RFC: PATCH] Audit Failure Query Functionality
by Lisa Smith
This is this initial patch for the audit failure query functionality.
Currently, each service and application is responsible for determining
the action to take when the audit subsystem is unavailable (stop the
action or service, continue on, log a message). Different
customers may want different actions taken, and this flexibility is
not possible if the action is hard-coded into the application.
This patch introduces a new query function,
audit_failure_action(), which can be called to determine what
action should be taken by the service after audit_open() fails.
The function will read the tunable "auditfailure" from the
new /etc/libaudit.conf file to determine what action should be
taken. audit_failure_action() can also be passed a filename
so that an application-specific action can be defined within its
own file.
The audit_open() man page will be updated to introduce
application developers to the new query function that should
be used when audit_open() returns failure. A new man page
will also be created for the audit_failure_action() function.
This patch is backed against audit version 1.2.3.
Lisa
----
libaudit.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++
libaudit.h | 25 ++++++++
2 files changed, 188 insertions(+)
diff -burN orig/libaudit.c src/libaudit.c
--- orig/libaudit.c 2006-05-25 17:39:52.000000000 -0400
+++ src/libaudit.c 2006-06-13 14:46:33.000000000 -0400
@@ -68,6 +68,169 @@
return rc;
}
+/*
+ * This function will retrieve the audit failure tunable value
+ * from the filename passed in. If no file is specified, the default
+ * /etc/libaudit.conf file will be used.
+ */
+auditfail_t audit_failure_action(char *file)
+{
+ int ret;
+ struct nv_pair nv;
+
+ if (file == NULL)
+ file = AUDIT_FAIL_CONFIG;
+
+ /* Find the audit failure action tunable in the config file */
+ ret = search_audituser_conf(file, AUDIT_FAIL_KEYWORD, &nv);
+
+ if (ret == -1) {
+ audit_msg(LOG_WARNING, "Error in %s", file);
+ return ERR;
+ } else if (ret == 1) {
+ /* Keyword not found, so do the default action */
+ return IGNORE;
+ }
+
+ /* Translate tunable string to valid enum */
+ if (strncmp(nv.value, AUDIT_FAIL_IGNORE,
+ strlen(AUDIT_FAIL_IGNORE)) == 0) {
+ free (nv.name);
+ free (nv.value);
+ return IGNORE;
+ }
+ else if (strncmp(nv.value, AUDIT_FAIL_LOG,
+ strlen(AUDIT_FAIL_LOG)) == 0) {
+ free (nv.name);
+ free (nv.value);
+ return LOG;
+ }
+ else if (strncmp(nv.value, AUDIT_FAIL_TERM,
+ strlen(AUDIT_FAIL_TERM)) == 0) {
+ free (nv.name);
+ free (nv.value);
+ return TERM;
+ }
+ else {
+ /* If we get this far, the failure action was not valid */
+ audit_msg(LOG_ERR, "Invalid %s keyword value in %s",
+ AUDIT_FAIL_KEYWORD, file);
+ free (nv.name);
+ free (nv.value);
+ return ERR;
+ }
+}
+
+/*
+ * This function searches for a keyword pair in the passed in filename.
+ * If the keyword pair is found, it is saved in the nv structure and zero
+ * is returned. If the file can not be opened, -1 is returned.
+ * If the keyword is not found in the file, 1 is returned.
+ *
+ * nv->name and nv->value must be freed if an error will be returned from this
+ * function after nv_split() is called. If this function returns success,
+ * the caller must free nv->name and nv->value when finished using the
+ * values.
+ */
+int search_audituser_conf(char *file, char *keyword, struct nv_pair *nv)
+{
+ int rc, lineno = 1;
+ size_t len = 0;
+ ssize_t bytesread;
+ FILE *fp;
+ char *buf = NULL;
+
+ /* Open the file for line by line reading*/
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ audit_msg(LOG_ERR, "Error - fdopen failed for %s (%s)",
+ file, strerror(errno));
+ return -1;
+ }
+
+ while ((bytesread = getline(&buf, &len, fp)) != -1) {
+
+ if (buf[0] == '#') {
+ lineno++;
+ continue; // Ignore comments
+ }
+
+ /* Convert line into name-value pair */
+ rc = nv_split(buf, nv);
+ if (rc == 1) {
+ audit_msg(LOG_ERR, "Error on line %d in %s", lineno,
+ file);
+ lineno++;
+ continue;
+ }
+
+ /* Find the name-value pair */
+ if (strcmp(nv->name, keyword) == 0)
+ {
+ fclose(fp);
+ if (buf)
+ free (buf);
+ return 0;
+ }
+
+ lineno++;
+ }
+
+ /* If we get here, the keyword was not found in the file */
+ audit_msg(LOG_ERR, "Keyword %s not found in %s", keyword, file);
+ fclose(fp);
+ if (buf)
+ free (buf);
+ if (nv->name)
+ free (nv->name);
+ if (nv->value)
+ free (nv->value);
+ return 1;
+}
+
+/*
+ * This function parses a line looking for a keyword = value pair
+ * and if found, returns it in the nv structure. If the function
+ * returns success, the calling function is expected to free
+ * nv->name and nv->value.
+ */
+int nv_split(char *buffer, struct nv_pair *nv)
+{
+ /* Get the name part */
+ char *saveptr, *ptr = NULL;
+ char *buf = strdup(buffer);
+
+ /* Look for = in buf */
+ nv->name = NULL;
+ nv->value = NULL;
+ ptr = strtok_r(buf, " =", &saveptr);
+ if ((ptr == NULL) || !(strcmp(ptr,"\n"))) {
+ return 0; // If there's nothing, go to next line
+ }
+ nv->name = strdup(ptr);
+
+ /* Get the keyword value */
+ ptr = strtok_r(NULL, " =", &saveptr);
+ if (ptr == NULL) {
+ free (nv->name);
+ return 1;
+ }
+ nv->value = strdup(ptr);
+
+ /* Make sure there's nothing else on the line */
+ ptr = strtok_r(NULL, " ", &saveptr);
+ if (ptr) {
+ free (nv->name);
+ free (nv->value);
+ return 1;
+ }
+
+ /* Everything is OK */
+ return 0;
+}
+
+
+
int audit_set_enabled(int fd, uint32_t enabled)
{
int rc;
diff -burN orig/libaudit.h src/libaudit.h
--- orig/libaudit.h 2006-05-25 17:38:21.000000000 -0400
+++ src/libaudit.h 2006-06-13 13:01:30.000000000 -0400
@@ -248,6 +248,28 @@
MACH_ALPHA
} machine_t;
+/* These are the valid audit failure tunable enum values */
+typedef enum {
+ ERR=-1,
+ IGNORE=0,
+ LOG,
+ TERM
+} auditfail_t;
+
+/* #defines for the audit failure query */
+#define AUDIT_FAIL_CONFIG "/etc/libaudit.conf"
+#define AUDIT_FAIL_KEYWORD "auditfailure"
+#define AUDIT_FAIL_IGNORE "ignore"
+#define AUDIT_FAIL_LOG "log"
+#define AUDIT_FAIL_TERM "terminate"
+
+/* Name-value pair */
+struct nv_pair
+{
+ char *name;
+ char *value;
+};
+
/*
* audit_rule_data supports filter rules with both integer and string
* fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
@@ -362,6 +384,9 @@
/* AUDIT_GET */
extern int audit_request_status(int fd);
extern int audit_is_enabled(int fd);
+extern auditfail_t audit_failure_action(char *file);
+static int search_audituser_conf(char *file, char *keyword, struct nv_pair *nv);
+static int nv_split(char *buf, struct nv_pair *nv);
/* AUDIT_SET */
typedef enum { WAIT_NO, WAIT_YES } rep_wait_t;
18 years, 6 months
Dispatching of events
by Steve
I have been testing the dispatch system by having auditd monitor when a
certain file is opened, I have always seen 3 messages per open event (a
1300, 1307, followed by a 1302). I would assume other syscall rule
violations may trigger fewer or more messages.
So, is there a way to tell when all messages for a particular event have
been dispatched? I am combining information from each of an event's
messages to create an entry in a queue (containing event structures that
I created). I am trying to determine when I can process the combined
event information (when there are no more messages) so it can be removed
from the queue.
Also, is it safe to assume a type 1300 message is always the first
message pertaining to a rule violation?
Thanks,
Steve
18 years, 6 months
[PATCH] make set_loginuid obey audit_enabled
by Steve Grubb
Hi,
I was doing some testing and noticed that when the audit system was disabled,
I was still getting messages about the loginuid being set. The following patch
makes audit_set_loginuid look at in_syscall to determine if it should create
an audit event. The loginuid will continue to be set as long as there is a context.
Signed-off-by: Steve Grubb <sgrubb(a)redhat.com>
diff -urp linux-2.6.16.x86_64.orig/kernel/auditsc.c linux-2.6.16.x86_64/kernel/auditsc.c
--- linux-2.6.16.x86_64.orig/kernel/auditsc.c 2006-06-10 14:01:20.000000000 -0400
+++ linux-2.6.16.x86_64/kernel/auditsc.c 2006-06-10 14:00:14.000000000 -0400
@@ -1275,18 +1275,23 @@ void auditsc_get_stamp(struct audit_cont
*/
int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
{
- if (task->audit_context) {
- struct audit_buffer *ab;
+ struct audit_context *context = task->audit_context;
- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
- if (ab) {
- audit_log_format(ab, "login pid=%d uid=%u "
- "old auid=%u new auid=%u",
- task->pid, task->uid,
- task->audit_context->loginuid, loginuid);
- audit_log_end(ab);
+ if (context) {
+ /* Only log if audit is enabled */
+ if (context->in_syscall) {
+ struct audit_buffer *ab;
+
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
+ if (ab) {
+ audit_log_format(ab, "login pid=%d uid=%u "
+ "old auid=%u new auid=%u",
+ task->pid, task->uid,
+ context->loginuid, loginuid);
+ audit_log_end(ab);
+ }
}
- task->audit_context->loginuid = loginuid;
+ context->loginuid = loginuid;
}
return 0;
}
18 years, 6 months
[PATCH git] remove inlines in auditfilter.c
by Amy Griffis
I updated gcc on my system and found that manually inlining these
functions was increasing the size of auditfilter.o. The exception is
audit_dupe_watch(), but that one has the potential for a second
callsite in the future.
This fix applies to lspp.b19 commit
bd5ea49f781e6984c1148fff4d3587eed6cb855e
"updated filesystem auditing patches..."
Signed-off-by: Amy Griffis <amy.griffis(a)hpd.com>
---
kernel/auditfilter.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
a0c2e4154a726af0824bdc462423b7f97c944435
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 30015fd..4c99d2c 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -109,7 +109,7 @@ static inline void audit_get_watch(struc
atomic_inc(&watch->count);
}
-static inline void audit_put_watch(struct audit_watch *watch)
+static void audit_put_watch(struct audit_watch *watch)
{
if (atomic_dec_and_test(&watch->count)) {
WARN_ON(watch->parent);
@@ -119,7 +119,7 @@ static inline void audit_put_watch(struc
}
}
-static inline void audit_remove_watch(struct audit_watch *watch)
+static void audit_remove_watch(struct audit_watch *watch)
{
list_del(&watch->wlist);
put_inotify_watch(&watch->parent->wdata);
@@ -151,7 +151,7 @@ static inline void audit_free_rule_rcu(s
}
/* Initialize a parent watch entry. */
-static inline struct audit_parent *audit_init_parent(struct nameidata *ndp)
+static struct audit_parent *audit_init_parent(struct nameidata *ndp)
{
struct audit_parent *parent;
s32 wd;
@@ -177,7 +177,7 @@ static inline struct audit_parent *audit
}
/* Initialize a watch entry. */
-static inline struct audit_watch *audit_init_watch(char *path)
+static struct audit_watch *audit_init_watch(char *path)
{
struct audit_watch *watch;
@@ -666,7 +666,7 @@ static int audit_compare_rule(struct aud
/* Duplicate the given audit watch. The new watch's rules list is initialized
* to an empty list and wlist is undefined. */
-static inline struct audit_watch *audit_dupe_watch(struct audit_watch *old)
+static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
{
char *path;
struct audit_watch *new;
@@ -776,9 +776,9 @@ static struct audit_entry *audit_dupe_ru
}
/* Update inode info in audit rules based on filesystem event. */
-static inline void audit_update_watch(struct audit_parent *parent,
- const char *dname, dev_t dev,
- unsigned long ino, unsigned invalidating)
+static void audit_update_watch(struct audit_parent *parent,
+ const char *dname, dev_t dev,
+ unsigned long ino, unsigned invalidating)
{
struct audit_watch *owatch, *nwatch, *nextw;
struct audit_krule *r, *nextr;
@@ -842,7 +842,7 @@ add_watch_to_parent:
}
/* Remove all watches & rules associated with a parent that is going away. */
-static inline void audit_remove_parent_watches(struct audit_parent *parent)
+static void audit_remove_parent_watches(struct audit_parent *parent)
{
struct audit_watch *w, *nextw;
struct audit_krule *r, *nextr;
@@ -948,7 +948,7 @@ static int audit_get_nd(char *path, stru
}
/* Release resources used for watch path information. */
-static inline void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
+static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
{
if (ndp) {
path_release(ndp);
--
1.3.0
18 years, 6 months
[PATCH] POSIX MQ audit memory leak fix
by George C. Wilson
This is an incremental patch that addresses a memory leak in the POSIX message
queue audit patch. It applies cleanly to Al Viro's lspp.b19 git branch. Many
thanks to Linda Knippers for pointing out the issue.
Please apply.
auditsc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Signed-off-by: George Wilson <ltcgcw(a)us.ibm.com>
--
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ba8520d..276bde6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1427,8 +1427,10 @@ int __audit_mq_timedreceive(mqd_t mqdes,
return -ENOMEM;
if (u_msg_prio != NULL) {
- if (get_user(ax->msg_prio, u_msg_prio))
+ if (get_user(ax->msg_prio, u_msg_prio)) {
+ kfree(ax);
return -EFAULT;
+ }
} else
ax->msg_prio = 0;
--
George Wilson <ltcgcw(a)us.ibm.com>
IBM Linux Technology Center
18 years, 6 months
[PATCH] log more info for directory entry change events
by Amy Griffis
When an audit event involves changes to a directory entry, include
a PATH record for the directory itself. A few other notable changes:
- fixed audit_inode_child() hooks in fsnotify_move()
- removed unused flags arg from audit_inode()
- added audit log routines for logging a portion of a string
Here's some sample output.
before patch:
type=SYSCALL msg=audit(1149821605.320:26): arch=40000003 syscall=39 success=yes exit=0 a0=bf8d3c7c a1=1ff a2=804e1b8 a3=bf8d3c7c items=1 ppid=739 pid=800 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 comm="mkdir" exe="/bin/mkdir" subj=root:system_r:unconfined_t:s0-s0:c0.c255
type=CWD msg=audit(1149821605.320:26): cwd="/root"
type=PATH msg=audit(1149821605.320:26): item=0 name="foo" parent=164068 inode=164010 dev=03:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=root:object_r:user_home_t:s0
after patch:
type=SYSCALL msg=audit(1149822032.332:24): arch=40000003 syscall=39 success=yes exit=0 a0=bfdd9c7c a1=1ff a2=804e1b8 a3=bfdd9c7c items=2 ppid=714 pid=777 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 comm="mkdir" exe="/bin/mkdir" subj=root:system_r:unconfined_t:s0-s0:c0.c255
type=CWD msg=audit(1149822032.332:24): cwd="/root"
type=PATH msg=audit(1149822032.332:24): item=0 name="/root" inode=164068 dev=03:00 mode=040750 ouid=0 ogid=0 rdev=00:00 obj=root:object_r:user_home_dir_t:s0
type=PATH msg=audit(1149822032.332:24): item=1 name="foo" inode=164010 dev=03:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=root:object_r:user_home_t:s0
Signed-off-by: Amy Griffis <amy.griffis(a)hp.com>
---
fs/namei.c | 2 -
fs/open.c | 4 +
fs/xattr.c | 4 +
include/linux/audit.h | 15 +++---
include/linux/fsnotify.h | 3 -
kernel/audit.c | 54 +++++++++++++++++++-
kernel/audit.h | 3 +
kernel/auditfilter.c | 8 ++-
kernel/auditsc.c | 123 ++++++++++++++++++++++++++--------------------
9 files changed, 142 insertions(+), 74 deletions(-)
4080b3bfb911fc9501a7256ed59da3c159ced915
diff --git a/fs/namei.c b/fs/namei.c
index 96723ae..6c5ae0d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1125,7 +1125,7 @@ out:
if (likely(retval == 0)) {
if (unlikely(current->audit_context && nd && nd->dentry &&
nd->dentry->d_inode))
- audit_inode(name, nd->dentry->d_inode, flags);
+ audit_inode(name, nd->dentry->d_inode);
}
return retval;
diff --git a/fs/open.c b/fs/open.c
index 317b7c7..4f178ac 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -633,7 +633,7 @@ asmlinkage long sys_fchmod(unsigned int
dentry = file->f_dentry;
inode = dentry->d_inode;
- audit_inode(NULL, inode, 0);
+ audit_inode(NULL, inode);
err = -EROFS;
if (IS_RDONLY(inode))
@@ -786,7 +786,7 @@ asmlinkage long sys_fchown(unsigned int
if (file) {
struct dentry * dentry;
dentry = file->f_dentry;
- audit_inode(NULL, dentry->d_inode, 0);
+ audit_inode(NULL, dentry->d_inode);
error = chown_common(dentry, user, group);
fput(file);
}
diff --git a/fs/xattr.c b/fs/xattr.c
index e416190..c32f15b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -242,7 +242,7 @@ sys_fsetxattr(int fd, char __user *name,
if (!f)
return error;
dentry = f->f_dentry;
- audit_inode(NULL, dentry->d_inode, 0);
+ audit_inode(NULL, dentry->d_inode);
error = setxattr(dentry, name, value, size, flags);
fput(f);
return error;
@@ -469,7 +469,7 @@ sys_fremovexattr(int fd, char __user *na
if (!f)
return error;
dentry = f->f_dentry;
- audit_inode(NULL, dentry->d_inode, 0);
+ audit_inode(NULL, dentry->d_inode);
error = removexattr(dentry, name);
fput(f);
return error;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index c783275..295defe 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -310,7 +310,7 @@ extern void audit_syscall_entry(int arch
extern void audit_syscall_exit(int failed, long return_code);
extern void __audit_getname(const char *name);
extern void audit_putname(const char *name);
-extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
+extern void __audit_inode(const char *name, const struct inode *inode);
extern void __audit_inode_child(const char *dname, const struct inode *inode,
unsigned long pino);
static inline void audit_getname(const char *name)
@@ -318,10 +318,9 @@ static inline void audit_getname(const c
if (unlikely(current->audit_context))
__audit_getname(name);
}
-static inline void audit_inode(const char *name, const struct inode *inode,
- unsigned flags) {
+static inline void audit_inode(const char *name, const struct inode *inode) {
if (unlikely(current->audit_context))
- __audit_inode(name, inode, flags);
+ __audit_inode(name, inode);
}
static inline void audit_inode_child(const char *dname,
const struct inode *inode,
@@ -398,9 +397,9 @@ #define audit_syscall_entry(ta,a,b,c,d,e
#define audit_syscall_exit(f,r) do { ; } while (0)
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
-#define __audit_inode(n,i,f) do { ; } while (0)
+#define __audit_inode(n,i) do { ; } while (0)
#define __audit_inode_child(d,i,p) do { ; } while (0)
-#define audit_inode(n,i,f) do { ; } while (0)
+#define audit_inode(n,i) do { ; } while (0)
#define audit_inode_child(d,i,p) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
#define audit_get_loginuid(c) ({ -1; })
@@ -435,6 +434,9 @@ extern void audit_log_hex(struct au
size_t len);
extern const char * audit_log_untrustedstring(struct audit_buffer *ab,
const char *string);
+extern const char * audit_log_n_untrustedstring(struct audit_buffer *ab,
+ unsigned n,
+ const char *string);
extern void audit_log_d_path(struct audit_buffer *ab,
const char *prefix,
struct dentry *dentry,
@@ -452,6 +454,7 @@ #define audit_log_format(b,f,...) do { ;
#define audit_log_end(b) do { ; } while (0)
#define audit_log_hex(a,b,l) do { ; } while (0)
#define audit_log_untrustedstring(a,s) do { ; } while (0)
+#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
#define audit_log_d_path(b,p,d,v) do { ; } while (0)
#endif
#endif
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index a9d3044..cc5dec7 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -67,8 +67,7 @@ static inline void fsnotify_move(struct
if (source) {
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
}
- audit_inode_child(old_name, source, old_dir->i_ino);
- audit_inode_child(new_name, target, new_dir->i_ino);
+ audit_inode_child(new_name, source, new_dir->i_ino);
}
/*
diff --git a/kernel/audit.c b/kernel/audit.c
index 0fbf1c1..7dfac70 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1051,20 +1051,53 @@ void audit_log_hex(struct audit_buffer *
skb_put(skb, len << 1); /* new string is twice the old string */
}
+/*
+ * Format a string of no more than slen characters into the audit buffer,
+ * enclosed in quote marks.
+ */
+static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
+ const char *string)
+{
+ int avail, new_len;
+ unsigned char *ptr;
+ struct sk_buff *skb;
+
+ BUG_ON(!ab->skb);
+ skb = ab->skb;
+ avail = skb_tailroom(skb);
+ new_len = slen + 3; /* enclosing quotes + null terminator */
+ if (new_len > avail) {
+ avail = audit_expand(ab, new_len);
+ if (!avail)
+ return;
+ }
+ ptr = skb->tail;
+ *ptr++ = '"';
+ memcpy(ptr, string, slen);
+ ptr += slen;
+ *ptr++ = '"';
+ *ptr = 0;
+ skb_put(skb, slen + 2); /* don't include null terminator */
+}
+
/**
- * audit_log_unstrustedstring - log a string that may contain random characters
+ * audit_log_n_unstrustedstring - log a string that may contain random characters
* @ab: audit_buffer
+ * @len: lenth of string (not including trailing null)
* @string: string to be logged
*
* This code will escape a string that is passed to it if the string
* contains a control character, unprintable character, double quote mark,
* or a space. Unescaped strings will start and end with a double quote mark.
* Strings that are escaped are printed in hex (2 digits per char).
+ *
+ * The caller specifies the number of characters in the string to log, which may
+ * or may not be the entire string.
*/
-const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
+const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
+ const char *string)
{
const unsigned char *p = string;
- size_t len = strlen(string);
while (*p) {
if (*p == '"' || *p < 0x21 || *p > 0x7f) {
@@ -1073,10 +1106,23 @@ const char *audit_log_untrustedstring(st
}
p++;
}
- audit_log_format(ab, "\"%s\"", string);
+ audit_log_n_string(ab, len, string);
return p + 1;
}
+/**
+ * audit_log_unstrustedstring - log a string that may contain random characters
+ * @ab: audit_buffer
+ * @string: string to be logged
+ *
+ * Same as audit_log_n_unstrustedstring(), except that strlen is used to
+ * determine string length.
+ */
+const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
+{
+ return audit_log_n_untrustedstring(ab, strlen(string), string);
+}
+
/* This is a helper-function to print the escaped d_path */
void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
struct dentry *dentry, struct vfsmount *vfsmnt)
diff --git a/kernel/audit.h b/kernel/audit.h
index 58fa44c..8323e41 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -104,7 +104,8 @@ static inline int audit_hash_ino(u32 ino
}
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 int audit_compare_dname_path(const char *dname, const char *path,
+ int *dirlen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
int done, int multi,
void *payload, int size);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 461f404..30015fd 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -787,7 +787,7 @@ static inline void audit_update_watch(st
mutex_lock(&audit_filter_mutex);
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
- if (audit_compare_dname_path(dname, owatch->path))
+ if (audit_compare_dname_path(dname, owatch->path, NULL))
continue;
/* If the update involves invalidating rules, do the inode-based
@@ -1387,7 +1387,8 @@ int audit_comparator(const u32 left, con
/* Compare given dentry name with last component in given path,
* return of 0 indicates a match. */
-int audit_compare_dname_path(const char *dname, const char *path)
+int audit_compare_dname_path(const char *dname, const char *path,
+ int *dirlen)
{
int dlen, plen;
const char *p;
@@ -1416,6 +1417,9 @@ int audit_compare_dname_path(const char
p++;
}
+ /* return length of path's directory component */
+ if (dirlen)
+ *dirlen = p - path;
return strncmp(p, dname, dlen);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 8503401..ba8520d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -82,6 +82,9 @@ #define AUDIT_NAMES 20
* path_lookup. */
#define AUDIT_NAMES_RESERVED 7
+/* Indicates that audit should log the full pathname. */
+#define AUDIT_NAME_FULL -1
+
/* When fs/namei.c:getname() is called, we store the pointer in name and
* we don't let putname() free it (instead we free all of the saved
* pointers at syscall exit time).
@@ -89,8 +92,9 @@ #define AUDIT_NAMES_RESERVED 7
* Further, in fs/namei.c:path_lookup() we store the inode and device. */
struct audit_names {
const char *name;
+ int name_len; /* number of name's characters to log */
+ unsigned name_put; /* call __putname() for this name */
unsigned long ino;
- unsigned long pino;
dev_t dev;
umode_t mode;
uid_t uid;
@@ -296,12 +300,10 @@ static int audit_filter_rules(struct tas
break;
case AUDIT_INODE:
if (name)
- result = (name->ino == f->val ||
- name->pino == f->val);
+ result = (name->ino == 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)) {
+ if (audit_comparator(ctx->names[j].ino, f->op, f->val)) {
++result;
break;
}
@@ -311,8 +313,7 @@ static int audit_filter_rules(struct tas
case AUDIT_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));
+ name->ino == rule->watch->ino);
break;
case AUDIT_LOGINUID:
result = 0;
@@ -526,7 +527,7 @@ #if AUDIT_DEBUG
#endif
for (i = 0; i < context->name_count; i++) {
- if (context->names[i].name)
+ if (context->names[i].name && context->names[i].name_put)
__putname(context->names[i].name);
}
context->name_count = 0;
@@ -850,8 +851,7 @@ static void audit_log_exit(struct audit_
}
}
for (i = 0; i < context->name_count; i++) {
- unsigned long ino = context->names[i].ino;
- unsigned long pino = context->names[i].pino;
+ struct audit_names *n = &context->names[i];
ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
if (!ab)
@@ -859,33 +859,47 @@ static void audit_log_exit(struct audit_
audit_log_format(ab, "item=%d", i);
- audit_log_format(ab, " name=");
- if (context->names[i].name)
- audit_log_untrustedstring(ab, context->names[i].name);
- else
- audit_log_format(ab, "(null)");
-
- if (pino != (unsigned long)-1)
- audit_log_format(ab, " parent=%lu", pino);
- if (ino != (unsigned long)-1)
- audit_log_format(ab, " inode=%lu", ino);
- if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1))
- audit_log_format(ab, " dev=%02x:%02x mode=%#o"
- " ouid=%u ogid=%u rdev=%02x:%02x",
- MAJOR(context->names[i].dev),
- MINOR(context->names[i].dev),
- context->names[i].mode,
- context->names[i].uid,
- context->names[i].gid,
- MAJOR(context->names[i].rdev),
- MINOR(context->names[i].rdev));
- if (context->names[i].osid != 0) {
+ if (n->name) {
+ switch(n->name_len) {
+ case AUDIT_NAME_FULL:
+ /* log the full path */
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, n->name);
+ break;
+ case 0:
+ /* name was specified as a relative path and the
+ * directory component is the cwd */
+ audit_log_d_path(ab, "name=", context->pwd,
+ context->pwdmnt);
+ break;
+ default:
+ /* log the name's directory component */
+ audit_log_format(ab, " name=");
+ audit_log_n_untrustedstring(ab, n->name_len,
+ n->name);
+ }
+ } else
+ audit_log_format(ab, "name=(null)");
+
+ if (n->ino != (unsigned long)-1) {
+ audit_log_format(ab, " inode=%lu"
+ " dev=%02x:%02x mode=%#o"
+ " ouid=%u ogid=%u rdev=%02x:%02x",
+ n->ino,
+ MAJOR(n->dev),
+ MINOR(n->dev),
+ n->mode,
+ n->uid,
+ n->gid,
+ MAJOR(n->rdev),
+ MINOR(n->rdev));
+ }
+ if (n->osid != 0) {
char *ctx = NULL;
u32 len;
if (selinux_ctxid_to_string(
- context->names[i].osid, &ctx, &len)) {
- audit_log_format(ab, " osid=%u",
- context->names[i].osid);
+ n->osid, &ctx, &len)) {
+ audit_log_format(ab, " osid=%u", n->osid);
call_panic = 2;
} else
audit_log_format(ab, " obj=%s", ctx);
@@ -1075,6 +1089,8 @@ #endif
}
BUG_ON(context->name_count >= AUDIT_NAMES);
context->names[context->name_count].name = name;
+ context->names[context->name_count].name_len = AUDIT_NAME_FULL;
+ context->names[context->name_count].name_put = 1;
context->names[context->name_count].ino = (unsigned long)-1;
++context->name_count;
if (!context->pwd) {
@@ -1141,11 +1157,10 @@ static void audit_inode_context(int idx,
* audit_inode - store the inode and device from a lookup
* @name: name being audited
* @inode: inode being audited
- * @flags: lookup flags (as used in path_lookup())
*
* Called from fs/namei.c:path_lookup().
*/
-void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
+void __audit_inode(const char *name, const struct inode *inode)
{
int idx;
struct audit_context *context = current->audit_context;
@@ -1171,20 +1186,13 @@ #if AUDIT_DEBUG
++context->ino_count;
#endif
}
+ context->names[idx].ino = inode->i_ino;
context->names[idx].dev = inode->i_sb->s_dev;
context->names[idx].mode = inode->i_mode;
context->names[idx].uid = inode->i_uid;
context->names[idx].gid = inode->i_gid;
context->names[idx].rdev = inode->i_rdev;
audit_inode_context(idx, inode);
- if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) &&
- (strcmp(name, ".") != 0)) {
- context->names[idx].ino = (unsigned long)-1;
- context->names[idx].pino = inode->i_ino;
- } else {
- context->names[idx].ino = inode->i_ino;
- context->names[idx].pino = (unsigned long)-1;
- }
}
/**
@@ -1206,34 +1214,40 @@ void __audit_inode_child(const char *dna
{
int idx;
struct audit_context *context = current->audit_context;
+ const char *found_name = NULL;
+ int dirlen = 0;
if (!context->in_syscall)
return;
/* determine matching parent */
if (!dname)
- goto no_match;
+ goto update_context;
for (idx = 0; idx < context->name_count; idx++)
- if (context->names[idx].pino == pino) {
+ if (context->names[idx].ino == pino) {
const char *name = context->names[idx].name;
if (!name)
continue;
- if (audit_compare_dname_path(dname, name) == 0)
- goto update_context;
+ if (audit_compare_dname_path(dname, name, &dirlen) == 0) {
+ context->names[idx].name_len = dirlen;
+ found_name = name;
+ break;
+ }
}
-no_match:
- /* catch-all in case match not found */
+update_context:
idx = context->name_count++;
- context->names[idx].name = NULL;
- context->names[idx].pino = pino;
#if AUDIT_DEBUG
context->ino_count++;
#endif
+ /* Re-use the name belonging to the slot for a matching parent directory.
+ * All names for this context are relinquished in audit_free_names() */
+ context->names[idx].name = found_name;
+ context->names[idx].name_len = AUDIT_NAME_FULL;
+ context->names[idx].name_put = 0; /* don't call __putname() */
-update_context:
if (inode) {
context->names[idx].ino = inode->i_ino;
context->names[idx].dev = inode->i_sb->s_dev;
@@ -1242,7 +1256,8 @@ update_context:
context->names[idx].gid = inode->i_gid;
context->names[idx].rdev = inode->i_rdev;
audit_inode_context(idx, inode);
- }
+ } else
+ context->names[idx].ino = (unsigned long)-1;
}
/**
--
1.3.0
18 years, 6 months