Linux-audit Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V7 2/3] audit: implement audit by executable
From: Richard Guy Briggs @ 2015-08-01 19:48 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs
In-Reply-To: <cover.1438456536.git.rgb@redhat.com>

This adds the ability audit the actions of a not-yet-running process.

This patch implements the ability to filter on the executable path.  Instead of
just hard coding the ino and dev of the executable we care about at the moment
the rule is inserted into the kernel, use the new audit_fsnotify
infrastructure to manage this dynamically.  This means that if the filename
does not yet exist but the containing directory does, or if the inode in
question is unlinked and creat'd (aka updated) the rule will just continue to
work.  If the containing directory is moved or deleted or the filesystem is
unmounted, the rule is deleted automatically.  A future enhancement would be to
have the rule survive across directory disruptions.

This is a heavily modified version of a patch originally submitted by Eric
Paris with some ideas from Peter Moody.

Cc: Peter Moody <peter@hda3.com>
Cc: Eric Paris <eparis@redhat.com>
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 include/linux/audit.h      |    1 +
 include/uapi/linux/audit.h |    5 +++-
 kernel/audit.h             |    4 +++
 kernel/audit_tree.c        |    2 +
 kernel/audit_watch.c       |   31 +++++++++++++++++++++++++
 kernel/auditfilter.c       |   53 +++++++++++++++++++++++++++++++++++++++++++-
 kernel/auditsc.c           |    3 ++
 7 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index c2e7e3a..aee456f 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -59,6 +59,7 @@ struct audit_krule {
 	struct audit_field	*inode_f; /* quick access to an inode field */
 	struct audit_watch	*watch;	/* associated watch */
 	struct audit_tree	*tree;	/* associated watched tree */
+	struct audit_fsnotify_mark	*exe;
 	struct list_head	rlist;	/* entry in audit_{watch,tree}.rules list */
 	struct list_head	list;	/* for AUDIT_LIST* purposes only */
 	u64			prio;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 971df22..e2ca600 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -266,6 +266,7 @@
 #define AUDIT_OBJ_UID	109
 #define AUDIT_OBJ_GID	110
 #define AUDIT_FIELD_COMPARE	111
+#define AUDIT_EXE	112
 
 #define AUDIT_ARG0      200
 #define AUDIT_ARG1      (AUDIT_ARG0+1)
@@ -324,8 +325,10 @@ enum {
 
 #define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT	0x00000001
 #define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME	0x00000002
+#define AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH	0x00000004
 #define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \
-				  AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME)
+				  AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \
+				  AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH )
 
 /* deprecated: AUDIT_VERSION_* */
 #define AUDIT_VERSION_LATEST 		AUDIT_FEATURE_BITMAP_ALL
diff --git a/kernel/audit.h b/kernel/audit.h
index 46d10dd..dadf86a 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -277,6 +277,8 @@ extern char *audit_mark_path(struct audit_fsnotify_mark *mark);
 extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark);
 extern void audit_remove_mark_rule(struct audit_krule *krule);
 extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev);
+extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old);
+extern int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark);
 
 #else
 #define audit_put_watch(w) {}
@@ -292,6 +294,8 @@ extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long in
 #define audit_remove_mark(m)
 #define audit_remove_mark_rule(k)
 #define audit_mark_compare(m, i, d) 0
+#define audit_exe_compare(t, m) (-EINVAL)
+#define audit_dupe_exe(n, o) (-EINVAL)
 #endif /* CONFIG_AUDIT_WATCH */
 
 #ifdef CONFIG_AUDIT_TREE
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index b0f9877..94ecdab 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -479,6 +479,8 @@ static void kill_rules(struct audit_tree *tree)
 		if (rule->tree) {
 			/* not a half-baked one */
 			audit_tree_log_remove_rule(rule);
+			if (entry->rule.exe)
+				audit_remove_mark(entry->rule.exe);
 			rule->tree = NULL;
 			list_del_rcu(&entry->list);
 			list_del(&entry->rule.list);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index c668bfc..1255dbf 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -312,6 +312,8 @@ static void audit_update_watch(struct audit_parent *parent,
 				list_replace(&oentry->rule.list,
 					     &nentry->rule.list);
 			}
+			if (oentry->rule.exe)
+				audit_remove_mark(oentry->rule.exe);
 
 			audit_watch_log_rule_change(r, owatch, "updated_rules");
 
@@ -342,6 +344,8 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
 		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
 			e = container_of(r, struct audit_entry, rule);
 			audit_watch_log_rule_change(r, w, "remove_rule");
+			if (e->rule.exe)
+				audit_remove_mark(e->rule.exe);
 			list_del(&r->rlist);
 			list_del(&r->list);
 			list_del_rcu(&e->list);
@@ -514,3 +518,30 @@ static int __init audit_watch_init(void)
 	return 0;
 }
 device_initcall(audit_watch_init);
+
+int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
+{
+	struct audit_fsnotify_mark *audit_mark;
+	char *pathname;
+
+	pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
+	if (!pathname)
+		return -ENOMEM;
+
+	audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
+	if (IS_ERR(audit_mark)) {
+		kfree(pathname);
+		return PTR_ERR(audit_mark);
+	}
+	new->exe = audit_mark;
+
+	return 0;
+}
+
+int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
+{
+	unsigned long ino = tsk->mm->exe_file->f_inode->i_ino;
+	dev_t dev = tsk->mm->exe_file->f_inode->i_sb->s_dev;
+
+	return audit_mark_compare(mark, ino, dev);
+}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index dcfcac2..fa3672b 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -405,6 +405,12 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
 		if (f->val > AUDIT_MAX_FIELD_COMPARE)
 			return -EINVAL;
 		break;
+	case AUDIT_EXE:
+		if (f->op != Audit_equal)
+			return -EINVAL;
+		if (entry->rule.listnr != AUDIT_FILTER_EXIT)
+			return -EINVAL;
+		break;
 	};
 	return 0;
 }
@@ -419,6 +425,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 	size_t remain = datasz - sizeof(struct audit_rule_data);
 	int i;
 	char *str;
+	struct audit_fsnotify_mark *audit_mark;
 
 	entry = audit_to_entry_common(data);
 	if (IS_ERR(entry))
@@ -539,6 +546,24 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 			entry->rule.buflen += f->val;
 			entry->rule.filterkey = str;
 			break;
+		case AUDIT_EXE:
+			if (entry->rule.exe || f->val > PATH_MAX)
+				goto exit_free;
+			str = audit_unpack_string(&bufp, &remain, f->val);
+			if (IS_ERR(str)) {
+				err = PTR_ERR(str);
+				goto exit_free;
+			}
+			entry->rule.buflen += f->val;
+
+			audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
+			if (IS_ERR(audit_mark)) {
+				kfree(str);
+				err = PTR_ERR(audit_mark);
+				goto exit_free;
+			}
+			entry->rule.exe = audit_mark;
+			break;
 		}
 	}
 
@@ -551,6 +576,8 @@ exit_nofree:
 exit_free:
 	if (entry->rule.tree)
 		audit_put_tree(entry->rule.tree); /* that's the temporary one */
+	if (entry->rule.exe)
+		audit_remove_mark(entry->rule.exe); /* that's the template one */
 	audit_free_rule(entry);
 	return ERR_PTR(err);
 }
@@ -615,6 +642,10 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
 			data->buflen += data->values[i] =
 				audit_pack_string(&bufp, krule->filterkey);
 			break;
+		case AUDIT_EXE:
+			data->buflen += data->values[i] =
+				audit_pack_string(&bufp, audit_mark_path(krule->exe));
+			break;
 		case AUDIT_LOGINUID_SET:
 			if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
 				data->fields[i] = AUDIT_LOGINUID;
@@ -678,6 +709,12 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
 			if (strcmp(a->filterkey, b->filterkey))
 				return 1;
 			break;
+		case AUDIT_EXE:
+			/* both paths exist based on above type compare */
+			if (strcmp(audit_mark_path(a->exe),
+				   audit_mark_path(b->exe)))
+				return 1;
+			break;
 		case AUDIT_UID:
 		case AUDIT_EUID:
 		case AUDIT_SUID:
@@ -799,8 +836,14 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
 				err = -ENOMEM;
 			else
 				new->filterkey = fk;
+			break;
+		case AUDIT_EXE:
+			err = audit_dupe_exe(new, old);
+			break;
 		}
 		if (err) {
+			if (new->exe)
+				audit_remove_mark(new->exe);
 			audit_free_rule(entry);
 			return ERR_PTR(err);
 		}
@@ -965,6 +1008,9 @@ int audit_del_rule(struct audit_entry *entry)
 	if (e->rule.tree)
 		audit_remove_tree_rule(&e->rule);
 
+	if (e->rule.exe)
+		audit_remove_mark_rule(&e->rule);
+
 	list_del_rcu(&e->list);
 	list_del(&e->rule.list);
 	call_rcu(&e->rcu, audit_free_rule_rcu);
@@ -1068,8 +1114,11 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
 		WARN_ON(1);
 	}
 
-	if (err || type == AUDIT_DEL_RULE)
+	if (err || type == AUDIT_DEL_RULE) {
+		if (entry->rule.exe)
+			audit_remove_mark(entry->rule.exe);
 		audit_free_rule(entry);
+	}
 
 	return err;
 }
@@ -1361,6 +1410,8 @@ static int update_lsm_rule(struct audit_krule *r)
 		return 0;
 
 	nentry = audit_dupe_rule(r);
+	if (entry->rule.exe)
+		audit_remove_mark(entry->rule.exe);
 	if (IS_ERR(nentry)) {
 		/* save the first error encountered for the
 		 * return value */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 701ea5c..e9bac2b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -466,6 +466,9 @@ static int audit_filter_rules(struct task_struct *tsk,
 				result = audit_comparator(ctx->ppid, f->op, f->val);
 			}
 			break;
+		case AUDIT_EXE:
+			result = audit_exe_compare(tsk, rule->exe);
+			break;
 		case AUDIT_UID:
 			result = audit_uid_comparator(cred->uid, f->op, f->uid);
 			break;
-- 
1.7.1

^ permalink raw reply related

* [PATCH V7 1/3] audit: clean simple fsnotify implementation
From: Richard Guy Briggs @ 2015-08-01 19:48 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs
In-Reply-To: <cover.1438456536.git.rgb@redhat.com>

This is to be used to audit by executable path rules, but audit watches should
be able to share this code eventually.

At the moment the audit watch code is a lot more complex.  That code only
creates one fsnotify watch per parent directory.  That 'audit_parent' in
turn has a list of 'audit_watches' which contain the name, ino, dev of
the specific object we care about.  This just creates one fsnotify watch
per object we care about.  So if you watch 100 inodes in /etc this code
will create 100 fsnotify watches on /etc.  The audit_watch code will
instead create 1 fsnotify watch on /etc (the audit_parent) and then 100
individual watches chained from that fsnotify mark.

We should be able to convert the audit_watch code to do one fsnotify
mark per watch and simplify things/remove a whole lot of code.  After
that conversion we should be able to convert the audit_fsnotify code to
support that hierarchy if the optimization is necessary.

Move the access to the entry for audit_match_signal() to the beginning of
the audit_del_rule() function in case the entry found is the same one passed
in.  This will enable it to be used by audit_autoremove_mark_rule(),
kill_rules() and audit_remove_parent_watches().

This is a heavily modified and merged version of two patches originally
submitted by Eric Paris.

Cc: Peter Moody <peter@hda3.com>
Cc: Eric Paris <eparis@redhat.com>
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/Makefile         |    2 +-
 kernel/audit.h          |   14 +++
 kernel/audit_fsnotify.c |  215 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/auditfilter.c    |    2 +-
 4 files changed, 231 insertions(+), 2 deletions(-)
 create mode 100644 kernel/audit_fsnotify.c

diff --git a/kernel/Makefile b/kernel/Makefile
index 60c302c..58b5b52 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -64,7 +64,7 @@ obj-$(CONFIG_SMP) += stop_machine.o
 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
 obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
-obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
+obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o
 obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 obj-$(CONFIG_GCOV_KERNEL) += gcov/
 obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/kernel/audit.h b/kernel/audit.h
index d641f9b..46d10dd 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -50,6 +50,7 @@ enum audit_state {
 
 /* Rule lists */
 struct audit_watch;
+struct audit_fsnotify_mark;
 struct audit_tree;
 struct audit_chunk;
 
@@ -252,6 +253,7 @@ struct audit_net {
 extern int selinux_audit_rule_update(void);
 
 extern struct mutex audit_filter_mutex;
+extern int audit_del_rule(struct audit_entry *);
 extern void audit_free_rule_rcu(struct rcu_head *);
 extern struct list_head audit_filter_list[];
 
@@ -269,6 +271,13 @@ extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
 extern void audit_remove_watch_rule(struct audit_krule *krule);
 extern char *audit_watch_path(struct audit_watch *watch);
 extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
+
+extern struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len);
+extern char *audit_mark_path(struct audit_fsnotify_mark *mark);
+extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark);
+extern void audit_remove_mark_rule(struct audit_krule *krule);
+extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev);
+
 #else
 #define audit_put_watch(w) {}
 #define audit_get_watch(w) {}
@@ -278,6 +287,11 @@ extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev
 #define audit_watch_path(w) ""
 #define audit_watch_compare(w, i, d) 0
 
+#define audit_alloc_mark(k, p, l) (ERR_PTR(-EINVAL))
+#define audit_mark_path(m) ""
+#define audit_remove_mark(m)
+#define audit_remove_mark_rule(k)
+#define audit_mark_compare(m, i, d) 0
 #endif /* CONFIG_AUDIT_WATCH */
 
 #ifdef CONFIG_AUDIT_TREE
diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c
new file mode 100644
index 0000000..654c6c7
--- /dev/null
+++ b/kernel/audit_fsnotify.c
@@ -0,0 +1,215 @@
+/* audit_fsnotify.c -- tracking inodes
+ *
+ * Copyright 2003-2009,2014-2015 Red Hat, Inc.
+ * Copyright 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright 2005 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/audit.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/fsnotify_backend.h>
+#include <linux/namei.h>
+#include <linux/netlink.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+#include "audit.h"
+
+/*
+ * this mark lives on the parent directory of the inode in question.
+ * but dev, ino, and path are about the child
+ */
+struct audit_fsnotify_mark {
+	dev_t dev;		/* associated superblock device */
+	unsigned long ino;	/* associated inode number */
+	char *path;		/* insertion path */
+	struct fsnotify_mark mark; /* fsnotify mark on the inode */
+	struct audit_krule *rule;
+};
+
+/* fsnotify handle. */
+static struct fsnotify_group *audit_fsnotify_group;
+
+/* fsnotify events we care about. */
+#define AUDIT_FS_EVENTS (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
+			 FS_MOVE_SELF | FS_EVENT_ON_CHILD)
+
+static void audit_fsnotify_mark_free(struct audit_fsnotify_mark *audit_mark)
+{
+	kfree(audit_mark->path);
+	kfree(audit_mark);
+}
+
+static void audit_fsnotify_free_mark(struct fsnotify_mark *mark)
+{
+	struct audit_fsnotify_mark *audit_mark;
+
+	audit_mark = container_of(mark, struct audit_fsnotify_mark, mark);
+	audit_fsnotify_mark_free(audit_mark);
+}
+
+char *audit_mark_path(struct audit_fsnotify_mark *mark)
+{
+	return mark->path;
+}
+
+int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev)
+{
+	if (mark->ino == AUDIT_INO_UNSET)
+		return 0;
+	return (mark->ino == ino) && (mark->dev == dev);
+}
+
+static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
+			     struct inode *inode)
+{
+	audit_mark->dev = inode ? inode->i_sb->s_dev : AUDIT_DEV_UNSET;
+	audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
+}
+
+struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len)
+{
+	struct audit_fsnotify_mark *audit_mark;
+	struct path path;
+	struct dentry *dentry;
+	struct inode *inode;
+	int ret;
+
+	if (pathname[0] != '/' || pathname[len-1] == '/')
+		return ERR_PTR(-EINVAL);
+
+	dentry = kern_path_locked(pathname, &path);
+	if (IS_ERR(dentry))
+		return (void *)dentry; /* returning an error */
+	inode = path.dentry->d_inode;
+	mutex_unlock(&inode->i_mutex);
+
+	audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
+	if (unlikely(!audit_mark)) {
+		audit_mark = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	fsnotify_init_mark(&audit_mark->mark, audit_fsnotify_free_mark);
+	audit_mark->mark.mask = AUDIT_FS_EVENTS;
+	audit_mark->path = pathname;
+	audit_update_mark(audit_mark, dentry->d_inode);
+	audit_mark->rule = krule;
+
+	ret = fsnotify_add_mark(&audit_mark->mark, audit_fsnotify_group, inode, NULL, true);
+	if (ret < 0) {
+		audit_fsnotify_mark_free(audit_mark);
+		audit_mark = ERR_PTR(ret);
+	}
+out:
+	dput(dentry);
+	path_put(&path);
+	return audit_mark;
+}
+
+static void audit_mark_log_rule_change(struct audit_fsnotify_mark *audit_mark, char *op)
+{
+	struct audit_buffer *ab;
+	struct audit_krule *rule = audit_mark->rule;
+	if (!audit_enabled)
+		return;
+	ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
+	if (unlikely(!ab))
+		return;
+	audit_log_format(ab, "auid=%u ses=%u op=",
+			 from_kuid(&init_user_ns, audit_get_loginuid(current)),
+			 audit_get_sessionid(current));
+	audit_log_string(ab, op);
+	audit_log_format(ab, " path=");
+	audit_log_untrustedstring(ab, audit_mark->path);
+	audit_log_key(ab, rule->filterkey);
+	audit_log_format(ab, " list=%d res=1", rule->listnr);
+	audit_log_end(ab);
+}
+
+void audit_remove_mark(struct audit_fsnotify_mark *audit_mark)
+{
+	fsnotify_destroy_mark(&audit_mark->mark, audit_fsnotify_group);
+	fsnotify_put_mark(&audit_mark->mark);
+}
+
+void audit_remove_mark_rule(struct audit_krule *krule)
+{
+	struct audit_fsnotify_mark *mark = krule->exe;
+
+	audit_remove_mark(mark);
+}
+
+static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark)
+{
+	struct audit_krule *rule = audit_mark->rule;
+	struct audit_entry *entry = container_of(rule, struct audit_entry, rule);
+
+	audit_mark_log_rule_change(audit_mark, "autoremove_rule");
+	audit_del_rule(entry);
+}
+
+/* Update mark data in audit rules based on fsnotify events. */
+static int audit_mark_handle_event(struct fsnotify_group *group,
+				    struct inode *to_tell,
+				    struct fsnotify_mark *inode_mark,
+				    struct fsnotify_mark *vfsmount_mark,
+				    u32 mask, void *data, int data_type,
+				    const unsigned char *dname, u32 cookie)
+{
+	struct audit_fsnotify_mark *audit_mark;
+	struct inode *inode = NULL;
+
+	audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
+
+	BUG_ON(group != audit_fsnotify_group);
+
+	switch (data_type) {
+	case (FSNOTIFY_EVENT_PATH):
+		inode = ((struct path *)data)->dentry->d_inode;
+		break;
+	case (FSNOTIFY_EVENT_INODE):
+		inode = (struct inode *)data;
+		break;
+	default:
+		BUG();
+		return 0;
+	};
+
+	if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
+		if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
+			return 0;
+		audit_update_mark(audit_mark, inode);
+	} else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
+		audit_autoremove_mark_rule(audit_mark);
+
+	return 0;
+}
+
+static const struct fsnotify_ops audit_mark_fsnotify_ops = {
+	.handle_event =	audit_mark_handle_event,
+};
+
+static int __init audit_fsnotify_init(void)
+{
+	audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops);
+	if (IS_ERR(audit_fsnotify_group)) {
+		audit_fsnotify_group = NULL;
+		audit_panic("cannot create audit fsnotify group");
+	}
+	return 0;
+}
+device_initcall(audit_fsnotify_init);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index afb63b3..dcfcac2 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -935,7 +935,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
 }
 
 /* Remove an existing rule from filterlist. */
-static inline int audit_del_rule(struct audit_entry *entry)
+int audit_del_rule(struct audit_entry *entry)
 {
 	struct audit_entry  *e;
 	struct audit_tree *tree = entry->rule.tree;
-- 
1.7.1

^ permalink raw reply related

* [PATCH V7 0/3] audit by executable name
From: Richard Guy Briggs @ 2015-08-01 19:48 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs

Please see the accompanying userspace patchset:
	https://www.redhat.com/archives/linux-audit/2015-July/thread.html
	[[PATCH V2] 0/2] Log on the future execution of a path
The userspace interface is not expected to change appreciably unless something
important has been overlooked.  Setting and deleting rules works as expected.
	
If the path does not exist at rule creation time, it will be re-evaluated every
time there is a change to the parent directory at which point the change in
device and inode will be noted.


Here's a sample run:
Test for addition, trigger and deletion of tree executable rule:
# auditctl -a always,exit -S all -F dir=/tmp -F exe=/usr/bin/touch -F key=exetest_tree
----
time->Sat Jul 11 10:41:50 2015
type=CONFIG_CHANGE msg=audit(1436629310.720:44711): auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add_rule" key="exetest_tree" list=4 res=1
----

# /usr/bin/touch /tmp/test
----
time->Sat Jul 11 10:41:50 2015
type=PROCTITLE msg=audit(1436629310.757:44712): proctitle=2F7573722F62696E2F746F756368002F746D702F74657374
type=PATH msg=audit(1436629310.757:44712): item=1 name="/tmp/test" inode=166932 dev=00:24 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_tmp_t:s0 nametype=CREATE
type=PATH msg=audit(1436629310.757:44712): item=0 name="/tmp/" inode=11525 dev=00:24 mode=041777 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:tmp_t:s0 nametype=PARENT
type=CWD msg=audit(1436629310.757:44712):  cwd="/root"
type=SYSCALL msg=audit(1436629310.757:44712): arch=c000003e syscall=2 success=yes exit=3 a0=7ffdee2f9e27 a1=941 a2=1b6 a3=691 items=2 ppid=17655 pid=17762 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 ses=1 comm="touch" exe="/usr/bin/touch" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="exetest_tree"
----

# auditctl -d always,exit -S all -F dir=/tmp -F exe=/usr/bin/touch -F key=exetest_tree
----
time->Sat Jul 11 10:41:50 2015
type=CONFIG_CHANGE msg=audit(1436629310.839:44713): auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="remove_rule" key="exetest_tree" list=4 res=1
----


Revision history:
v7: Add Audit Feature Bitmap macro AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH to
      AUDIT_FEATURE_BITMAP_ALL.
    Split out new patch to use macros for unset inode and device values.
    Remove BUG() usage in stubs.
    Rename audit_mark_free() to audit_fsnotify_mark_free().
    Remove unused audit_get_mark() and audit_put_mark() functions.
    Rework ino and dev comparisons and assignments, using macros and existing
      funcs and eliminating temp variables.
    Move audit_update_mark() above its first usage.
    Move contents of kernel/audit_exe.c to kernel/audit_watch.c.
    Merge patch 3 with 1, merge patch 4 with 1 and 3 and rewrite the patch descriptions.
    Split out patch to audit by executable children.

v6: Explicitly declare prototypes as external.
    Rename audit_dup_exe() to audit_dupe_exe() consistent with rule, watch, lsm_field.
    Rebased on v4.1.
    Rename audit_remove_mark_rule() called from audit_mark_handle_event() to
      audit_autoremove_mark_rule() to avoid confusion with
      audit_remove_{watch,tree}_rule() usage.
    Add audit_remove_mark_rule() to provide similar interface as
      audit_remove_{watch,tree}_rule().
    Simplify stubs to defines.
    Rename audit_free_fsnotify_mark() to audit_fsnotify_free_mark() in keeping with
      the naming convention of inotify_free_mark(), dnotify_free_mark(),
      fanotify_free_mark(), audit_watch_free_mark().
    Return -ENOMEM rather than null in case of memory allocation failure for
      audit_mark in audit_alloc_mark().
    Rename audit_free_mark() to audit_mark_free() to avoid association with
      {i,d,fa}notify_free_mark() and audit_watch_free_mark().
    Clean up exe with similar interface as watch and tree.
    Clean up audit exe mark just before audit_free_rule() rather than in it to
      avoid mutex in software interrupt context.
    Fixed bug in audit_dupe_exe() that returned error rather than valid pointer.

v5: Revert patch "Let audit_free_rule() take care of calling
    audit_remove_mark()." since it caused a group mark deadlock.
    https://www.redhat.com/archives/linux-audit/2014-October/msg00024.html

v4: Re-order and squash down fixups
    Fix audit_dup_exe() to copy pathname string before calling audit_alloc_mark().
    https://www.redhat.com/archives/linux-audit/2014-August/msg00065.html

v3: Rationalize and rename some function names and clean up get/put and free code.
    Rename several "watch" references to "mark".
    Rename audit_remove_rule() to audit_remove_mark_rule().
    Let audit_free_rule() take care of calling audit_remove_mark().
    Put audit_alloc_mark() arguments in same order as watch, tree and inode.
    Move the access to the entry for audit_match_signal() to the beginning
     of the function in case the entry found is the same one passed in.
     This will enable it to be used by audit_remove_mark_rule().
    https://www.redhat.com/archives/linux-audit/2014-July/msg00000.html

v2: Misguided attempt to add in audit_exe similar to watches
    https://www.redhat.com/archives/linux-audit/2014-June/msg00066.html

v1.5: eparis' switch to fsnotify
    https://www.redhat.com/archives/linux-audit/2014-May/msg00046.html
    https://www.redhat.com/archives/linux-audit/2014-May/msg00066.html

v1: Change to path interface instead of inode
    https://www.redhat.com/archives/linux-audit/2014-May/msg00017.html

v0: Peter Moodie's original patches
    https://www.redhat.com/archives/linux-audit/2012-August/msg00033.html


Future step:
Get full-path notify working.


Richard Guy Briggs (3):
  audit: clean simple fsnotify implementation
  audit: implement audit by executable
  audit: add audit by children of executable path

 include/linux/audit.h      |    1 +
 include/uapi/linux/audit.h |    6 +-
 kernel/Makefile            |    2 +-
 kernel/audit.h             |   18 ++++
 kernel/audit_fsnotify.c    |  215 ++++++++++++++++++++++++++++++++++++++++++++
 kernel/audit_tree.c        |    2 +
 kernel/audit_watch.c       |   31 +++++++
 kernel/auditfilter.c       |   60 ++++++++++++-
 kernel/auditsc.c           |   14 +++
 9 files changed, 345 insertions(+), 4 deletions(-)
 create mode 100644 kernel/audit_fsnotify.c

^ permalink raw reply

* [PATCH V4 (was V6)] audit: save signal match info in case entry passed in is the one deleted
From: Richard Guy Briggs @ 2015-08-01 19:44 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs, sgrubb, pmoore, eparis
In-Reply-To: <cover.1438446636.git.rgb@redhat.com>

Move the access to the entry for audit_match_signal() to the beginning of the
function in case the entry found is the same one passed in.  This will enable
it to be used by audit_remove_mark_rule().

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/auditfilter.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4cb9b44..afb63b3 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -943,6 +943,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
 	int ret = 0;
 #ifdef CONFIG_AUDITSYSCALL
 	int dont_count = 0;
+	int match_signal = !audit_match_signal(entry);
 
 	/* If either of these, don't count towards total */
 	if (entry->rule.listnr == AUDIT_FILTER_USER ||
@@ -972,7 +973,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
 	if (!dont_count)
 		audit_n_rules--;
 
-	if (!audit_match_signal(entry))
+	if (match_signal)
 		audit_signals--;
 #endif
 	mutex_unlock(&audit_filter_mutex);
-- 
1.7.1

^ permalink raw reply related

* [PATCH V4 (was V6)] generalize audit_del_rule
From: Richard Guy Briggs @ 2015-08-01 19:44 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs, sgrubb, pmoore, eparis

This patch was split out from the audit by executable path patch set due to the
potential to use it elsewhere.

In particular, some questions came up while assessing the potential for code
reuse:

	Why does audit_remove_parent_watches() not call audit_del_rule() for
	each entry found?
                Is audit_signals not properly decremented?
                Is audit_n_rules not properly decremented?

        Why does kill_rules() not call audit_del_rule() for each entry found?
                Is audit_signals not properly decremented?
                Is audit_n_rules not properly decremented?


Richard Guy Briggs (1):
  audit: save signal match info in case entry passed in is the one
    deleted

 kernel/auditfilter.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

^ permalink raw reply

* [PATCH V4 (was V6)] audit: use macros for unset inode and device values
From: Richard Guy Briggs @ 2015-08-01 19:42 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs, sgrubb, pmoore, eparis
In-Reply-To: <cover.1438446565.git.rgb@redhat.com>

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 include/uapi/linux/audit.h |    2 ++
 kernel/audit.c             |    2 +-
 kernel/audit_watch.c       |    8 ++++----
 kernel/auditsc.c           |    6 +++---
 4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index d3475e1..971df22 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -440,6 +440,8 @@ struct audit_tty_status {
 };
 
 #define AUDIT_UID_UNSET (unsigned int)-1
+#define AUDIT_INO_UNSET (unsigned long)-1
+#define AUDIT_DEV_UNSET (unsigned)-1
 
 /* audit_rule_data supports filter rules with both integer and string
  * fields.  It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
diff --git a/kernel/audit.c b/kernel/audit.c
index 1c13e42..d546003 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1761,7 +1761,7 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
 	} else
 		audit_log_format(ab, " name=(null)");
 
-	if (n->ino != (unsigned long)-1)
+	if (n->ino != AUDIT_INO_UNSET)
 		audit_log_format(ab, " inode=%lu"
 				 " dev=%02x:%02x mode=%#ho"
 				 " ouid=%u ogid=%u rdev=%02x:%02x",
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 8f123d7..c668bfc 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -138,7 +138,7 @@ char *audit_watch_path(struct audit_watch *watch)
 
 int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
 {
-	return (watch->ino != (unsigned long)-1) &&
+	return (watch->ino != AUDIT_INO_UNSET) &&
 		(watch->ino == ino) &&
 		(watch->dev == dev);
 }
@@ -179,8 +179,8 @@ static struct audit_watch *audit_init_watch(char *path)
 	INIT_LIST_HEAD(&watch->rules);
 	atomic_set(&watch->count, 1);
 	watch->path = path;
-	watch->dev = (dev_t)-1;
-	watch->ino = (unsigned long)-1;
+	watch->dev = AUDIT_DEV_UNSET;
+	watch->ino = AUDIT_INO_UNSET;
 
 	return watch;
 }
@@ -493,7 +493,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
 	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
 		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
 	else if (mask & (FS_DELETE|FS_MOVED_FROM))
-		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
+		audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
 	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
 		audit_remove_parent_watches(parent);
 
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 9fb9d1c..701ea5c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -180,7 +180,7 @@ static int audit_match_filetype(struct audit_context *ctx, int val)
 		return 0;
 
 	list_for_each_entry(n, &ctx->names_list, list) {
-		if ((n->ino != -1) &&
+		if ((n->ino != AUDIT_INO_UNSET) &&
 		    ((n->mode & S_IFMT) == mode))
 			return 1;
 	}
@@ -1683,7 +1683,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
 		aname->should_free = true;
 	}
 
-	aname->ino = (unsigned long)-1;
+	aname->ino = AUDIT_INO_UNSET;
 	aname->type = type;
 	list_add_tail(&aname->list, &context->names_list);
 
@@ -1925,7 +1925,7 @@ void __audit_inode_child(const struct inode *parent,
 	if (inode)
 		audit_copy_inode(found_child, dentry, inode);
 	else
-		found_child->ino = (unsigned long)-1;
+		found_child->ino = AUDIT_INO_UNSET;
 }
 EXPORT_SYMBOL_GPL(__audit_inode_child);
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH V4 (was V6)] audit: macros to replace unset inode and device values
From: Richard Guy Briggs @ 2015-08-01 19:42 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs, sgrubb, pmoore, eparis

This is a patch to clean up a number of places were casted magic numbers are
used to represent unset inode and device numbers inpreparation for the audit by
executable path patch set.

Richard Guy Briggs (1):
  audit: use macros for unset inode and device values

 include/uapi/linux/audit.h |    2 ++
 kernel/audit.c             |    2 +-
 kernel/audit_watch.c       |    8 ++++----
 kernel/auditsc.c           |    6 +++---
 4 files changed, 10 insertions(+), 8 deletions(-)

^ permalink raw reply

* [PATCH V4 (was V6) 2/2] audit: eliminate unnecessary extra layer of watch parent references
From: Richard Guy Briggs @ 2015-08-01 19:41 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs, sgrubb, pmoore, eparis
In-Reply-To: <cover.1438446498.git.rgb@redhat.com>

The audit watch parent count was imbalanced, adding an unnecessary layer of
watch parent references.  Decrement the additional parent reference when a
watch is reused, already having a reference to the parent.

audit_find_parent() gets a reference to the parent, if the parent is
already known.  This additional parental reference is not needed if the
watch is subsequently found by audit_add_to_parent(), and consumed if
the watch does not already exist, so we need to put the parent if the
watch is found, and do nothing if this new watch is added to the parent.

If the parent wasn't already known, it is created with a refcount of 1
and added to the audit_watch_group, then incremented by one to be
subsequently consumed by the newly created watch in
audit_add_to_parent().

The rule points to the watch, not to the parent, so the rule's refcount
gets bumped, not the parent's.

See LKML, 2015-07-16

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/audit_watch.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index f33f54c..8f123d7 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -391,11 +391,12 @@ static void audit_add_to_parent(struct audit_krule *krule,
 
 		audit_get_watch(w);
 		krule->watch = watch = w;
+
+		audit_put_parent(parent);
 		break;
 	}
 
 	if (!watch_found) {
-		audit_get_parent(parent);
 		watch->parent = parent;
 
 		audit_get_watch(watch);
@@ -436,9 +437,6 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
 
 	audit_add_to_parent(krule, parent);
 
-	/* match get in audit_find_parent or audit_init_parent */
-	audit_put_parent(parent);
-
 	h = audit_hash_ino((u32)watch->ino);
 	*list = &audit_inode_hash[h];
 error:
-- 
1.7.1

^ permalink raw reply related

* [PATCH V4 (was V6) 1/2] audit: eliminate unnecessary extra layer of watch references
From: Richard Guy Briggs @ 2015-08-01 19:41 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs
In-Reply-To: <cover.1438446498.git.rgb@redhat.com>

The audit watch count was imbalanced, adding an unnecessary layer of watch
references.  Only add the second reference when it is added to a parent.

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/audit_watch.c |    5 ++---
 kernel/auditfilter.c |   16 +++-------------
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 6e30024..f33f54c 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -203,7 +203,6 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
 	if (IS_ERR(watch))
 		return PTR_ERR(watch);
 
-	audit_get_watch(watch);
 	krule->watch = watch;
 
 	return 0;
@@ -387,8 +386,7 @@ static void audit_add_to_parent(struct audit_krule *krule,
 
 		watch_found = 1;
 
-		/* put krule's and initial refs to temporary watch */
-		audit_put_watch(watch);
+		/* put krule's ref to temporary watch */
 		audit_put_watch(watch);
 
 		audit_get_watch(w);
@@ -400,6 +398,7 @@ static void audit_add_to_parent(struct audit_krule *krule,
 		audit_get_parent(parent);
 		watch->parent = parent;
 
+		audit_get_watch(watch);
 		list_add(&watch->wlist, &parent->watches);
 	}
 	list_add(&krule->rlist, &watch->rules);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 72e1660..4cb9b44 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -549,8 +549,6 @@ exit_nofree:
 	return entry;
 
 exit_free:
-	if (entry->rule.watch)
-		audit_put_watch(entry->rule.watch); /* matches initial get */
 	if (entry->rule.tree)
 		audit_put_tree(entry->rule.tree); /* that's the temporary one */
 	audit_free_rule(entry);
@@ -881,7 +879,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
 		/* normally audit_add_tree_rule() will free it on failure */
 		if (tree)
 			audit_put_tree(tree);
-		goto error;
+		return err;
 	}
 
 	if (watch) {
@@ -895,14 +893,14 @@ static inline int audit_add_rule(struct audit_entry *entry)
 			 */
 			if (tree)
 				audit_put_tree(tree);
-			goto error;
+			return err;
 		}
 	}
 	if (tree) {
 		err = audit_add_tree_rule(&entry->rule);
 		if (err) {
 			mutex_unlock(&audit_filter_mutex);
-			goto error;
+			return err;
 		}
 	}
 
@@ -933,11 +931,6 @@ static inline int audit_add_rule(struct audit_entry *entry)
 #endif
 	mutex_unlock(&audit_filter_mutex);
 
- 	return 0;
-
-error:
-	if (watch)
-		audit_put_watch(watch); /* tmp watch, matches initial get */
 	return err;
 }
 
@@ -945,7 +938,6 @@ error:
 static inline int audit_del_rule(struct audit_entry *entry)
 {
 	struct audit_entry  *e;
-	struct audit_watch *watch = entry->rule.watch;
 	struct audit_tree *tree = entry->rule.tree;
 	struct list_head *list;
 	int ret = 0;
@@ -986,8 +978,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
 	mutex_unlock(&audit_filter_mutex);
 
 out:
-	if (watch)
-		audit_put_watch(watch); /* match initial get */
 	if (tree)
 		audit_put_tree(tree);	/* that's the temporary one */
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH V4 (was V6) 0/2] audit: rebalance and remove extra layers of watch references
From: Richard Guy Briggs @ 2015-08-01 19:41 UTC (permalink / raw)
  To: linux-audit, linux-kernel; +Cc: Richard Guy Briggs

While working on the audit by executable path feature, it was discovered that
watches and parent references were slightly imbalanced and deeper than
necessary.

Only bump up references when they are actually used and decrease when removed.


v4: Eliminate unnecessary gotos and call return directly.
    Expand patch description with answer to mailing list query.


Richard Guy Briggs (2):
  audit: eliminate unnecessary extra layer of watch references
  audit: eliminate unnecessary extra layer of watch parent references

 kernel/audit_watch.c |   11 ++++-------
 kernel/auditfilter.c |   16 +++-------------
 2 files changed, 7 insertions(+), 20 deletions(-)

^ permalink raw reply

* Re: AUDIT_LOGIN vs AUDIT_USER_LOGIN
From: Satish Chandra Kilaru @ 2015-07-31 14:20 UTC (permalink / raw)
  To: Steve Grubb; +Cc: linux-audit@redhat.com
In-Reply-To: <13967055.4y2Q5z1Hcu@x2>


[-- Attachment #1.1: Type: text/plain, Size: 535 bytes --]

Thank you.

On Fri, Jul 31, 2015 at 10:19 AM, Steve Grubb <sgrubb@redhat.com> wrote:

> On Friday, July 31, 2015 09:59:13 AM Satish Chandra Kilaru wrote:
> > I see AUDIT_USER_LOGIN when I ssh to a linux machine.
>
> This means an interactive login session has been started by the user. This
> is
> in contract to a cron job which does not create this event.
>
> > What action will cause AUDIT_LOGIN  event?
>
> This means that the loginuid was set. Even a cron job will do this.
>
> -Steve
>
>


-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 1095 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: AUDIT_LOGIN vs AUDIT_USER_LOGIN
From: Steve Grubb @ 2015-07-31 14:19 UTC (permalink / raw)
  To: linux-audit
In-Reply-To: <CAAnai+X=6e43L7pJxsQRXP7dbb6nRsJFn-TmXsbN6D1Eaax1zg@mail.gmail.com>

On Friday, July 31, 2015 09:59:13 AM Satish Chandra Kilaru wrote:
> I see AUDIT_USER_LOGIN when I ssh to a linux machine. 

This means an interactive login session has been started by the user. This is 
in contract to a cron job which does not create this event.

> What action will cause AUDIT_LOGIN  event?

This means that the loginuid was set. Even a cron job will do this.

-Steve

^ permalink raw reply

* Re: AUDIT_LOGIN vs AUDIT_USER_LOGIN
From: Satish Chandra Kilaru @ 2015-07-31 14:12 UTC (permalink / raw)
  To: linux-audit@redhat.com
In-Reply-To: <CAAnai+X=6e43L7pJxsQRXP7dbb6nRsJFn-TmXsbN6D1Eaax1zg@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 423 bytes --]

It just means Audit Login Context is set...

http://lxr.free-electrons.com/source/kernel/auditsc.c#L1991

I actually see that event when I ssh.

On Fri, Jul 31, 2015 at 9:59 AM, Satish Chandra Kilaru <iam.kilaru@gmail.com
> wrote:

>
> I see AUDIT_USER_LOGIN when I ssh to a linux machine. What action will
> cause AUDIT_LOGIN  event?
>
> --
> Please Donate to www.wikipedia.org
>



-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 1105 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* AUDIT_LOGIN vs AUDIT_USER_LOGIN
From: Satish Chandra Kilaru @ 2015-07-31 13:59 UTC (permalink / raw)
  To: linux-audit@redhat.com


[-- Attachment #1.1: Type: text/plain, Size: 136 bytes --]

I see AUDIT_USER_LOGIN when I ssh to a linux machine. What action will
cause AUDIT_LOGIN  event?

--
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 313 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: auparse with AUSOURCE_DESCRIPTOR
From: Steve Grubb @ 2015-07-30 17:04 UTC (permalink / raw)
  To: Satish Chandra Kilaru; +Cc: linux-audit@redhat.com
In-Reply-To: <CAAnai+VpPa3+5AuUmWStMa_Upm1Pw0kt2QDTOkOHo=4vdX5xUg@mail.gmail.com>

On Thursday, July 30, 2015 12:34:26 PM Satish Chandra Kilaru wrote:
> Thank you. I went through the example code.

There is another example that does not use the feed interface here:
https://fedorahosted.org/audit/browser/trunk/tools/aulast/aulast.c#L531


> I do not see how FEED is better than using descriptor. Probably I am
> missing something.

It decouples processing from collecting events from the descriptor. This makes 
the event processing asynchronous relative to the socket. You just write a 
loop feeding events into the library and another that has the event handed to 
it. Typically, the part that collects the event only needs minor changes 
leaving the event handler as the only place you really need to worry about.

-Steve


> On Thu, Jul 30, 2015 at 12:12 PM, Steve Grubb <sgrubb@redhat.com> wrote:
> > On Thursday, July 30, 2015 10:16:53 AM Satish Chandra Kilaru wrote:
> > > Never mind... I found out why it was not working...
> > 
> > The auparse API expects string formatted events. The binary interface
> > exists
> > in case you completely understand how the audit events are formatted and
> > prefer to take events as they come out.
> > 
> > For anyone not completely familiar with the data structures, its better to
> > just use strings. In thsi way, you can extract portions of the log using
> > ausearch --raw > test.log  and then feed that to your program for
> > debugging.
> > 
> > > 1. auparse_next_event() does not call callback function. I have to call
> > > that function when auparse_next_event() returns.
> > 
> > The next event function is normally used when you are iterating through a
> > file.
> > If you are taking real-time events, its best to use the feed API and then
> > process the event in the call back. There is a sample program here that
> > should
> > make starting an analysis program very simple:
> > 
> > https://fedorahosted.org/audit/browser/trunk/contrib/plugin
> > 
> > > 2. it expects events in string format. I configured the plugin to send
> > > events in binary format. hence auparse_next_event() was not returning.
> > 
> > I'll update the man page to auparse_init to make sure this is clear.
> > 
> > > 3. auparse_next_event() returns only when the parser sees the beginning
> > 
> > of
> > 
> > > the next event.. i.e first event is returned after seeing the beginning
> > 
> > of
> > 
> > > the 2nd event. Is this expected?
> > 
> > Yes. For some types of events, we don't know when the event is complete
> > until
> > we see the next one. They can also be interlaced. Its on the TODO list to
> > fix
> > this second issue. But my suggestion is to look at a couple sample
> > programs
> > and follow how they do things.
> > 
> > -Steve
> > 
> > > On Wed, Jul 29, 2015 at 4:36 PM, Satish Chandra Kilaru <
> > 
> > iam.kilaru@gmail.com
> > 
> > > > wrote:
> > > > 
> > > > Has anyone tried AUSOURCE_DESCRIPTOR with a unix socket as fd?
> > > > 
> > > > I am doing the following.
> > > > 
> > > > int sd_u = socket(AF_UNIX, SOCK_STREAM, 0);
> > > > connect(sd_u, (struct sockaddr *) &sa, sizeof(sa))!=0)
> > > > auparse_state_t *au = auparse_init(AUSOURCE_DESCRIPTOR, (const void
> > > > *)sd_u);
> > > > auparse_add_callback(au, auparse_callback, event_cnt, free);
> > > > ausearch_next_event(au);
> > > > 
> > > > My auparse_callback() is not getting called. My program just blocks in
> > > > ausearch_next_event().
> > > > 
> > > > read(sd_u, buf, sizeof(buf)) gets me events... That means I am using
> > > > correct unix socket.
> > > > How do I make the callback function to get called for each event?
> > > > 
> > > > Am I missing something here?
> > > > 
> > > > Thanks in advance.
> > > > --Satish
> > > > --
> > > > Please Donate to www.wikipedia.org

^ permalink raw reply

* Re: auparse with AUSOURCE_DESCRIPTOR
From: Satish Chandra Kilaru @ 2015-07-30 16:34 UTC (permalink / raw)
  To: Steve Grubb; +Cc: linux-audit@redhat.com
In-Reply-To: <2051426.lyMsDP7mtV@x2>


[-- Attachment #1.1: Type: text/plain, Size: 2975 bytes --]

Thank you. I went through the example code.
I do not see how FEED is better than using descriptor. Probably I am
missing something.

--Satish

On Thu, Jul 30, 2015 at 12:12 PM, Steve Grubb <sgrubb@redhat.com> wrote:

> On Thursday, July 30, 2015 10:16:53 AM Satish Chandra Kilaru wrote:
> > Never mind... I found out why it was not working...
>
> The auparse API expects string formatted events. The binary interface
> exists
> in case you completely understand how the audit events are formatted and
> prefer to take events as they come out.
>
> For anyone not completely familiar with the data structures, its better to
> just use strings. In thsi way, you can extract portions of the log using
> ausearch --raw > test.log  and then feed that to your program for
> debugging.
>
>
> > 1. auparse_next_event() does not call callback function. I have to call
> > that function when auparse_next_event() returns.
>
> The next event function is normally used when you are iterating through a
> file.
> If you are taking real-time events, its best to use the feed API and then
> process the event in the call back. There is a sample program here that
> should
> make starting an analysis program very simple:
>
> https://fedorahosted.org/audit/browser/trunk/contrib/plugin
>
> > 2. it expects events in string format. I configured the plugin to send
> > events in binary format. hence auparse_next_event() was not returning.
>
> I'll update the man page to auparse_init to make sure this is clear.
>
> > 3. auparse_next_event() returns only when the parser sees the beginning
> of
> > the next event.. i.e first event is returned after seeing the beginning
> of
> > the 2nd event. Is this expected?
>
> Yes. For some types of events, we don't know when the event is complete
> until
> we see the next one. They can also be interlaced. Its on the TODO list to
> fix
> this second issue. But my suggestion is to look at a couple sample programs
> and follow how they do things.
>
> -Steve
>
>
> > On Wed, Jul 29, 2015 at 4:36 PM, Satish Chandra Kilaru <
> iam.kilaru@gmail.com
> > > wrote:
> > >
> > > Has anyone tried AUSOURCE_DESCRIPTOR with a unix socket as fd?
> > >
> > > I am doing the following.
> > >
> > > int sd_u = socket(AF_UNIX, SOCK_STREAM, 0);
> > > connect(sd_u, (struct sockaddr *) &sa, sizeof(sa))!=0)
> > > auparse_state_t *au = auparse_init(AUSOURCE_DESCRIPTOR, (const void
> > > *)sd_u);
> > > auparse_add_callback(au, auparse_callback, event_cnt, free);
> > > ausearch_next_event(au);
> > >
> > > My auparse_callback() is not getting called. My program just blocks in
> > > ausearch_next_event().
> > >
> > > read(sd_u, buf, sizeof(buf)) gets me events... That means I am using
> > > correct unix socket.
> > > How do I make the callback function to get called for each event?
> > >
> > > Am I missing something here?
> > >
> > > Thanks in advance.
> > > --Satish
> > > --
> > > Please Donate to www.wikipedia.org
>
>


-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 4151 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: auparse with AUSOURCE_DESCRIPTOR
From: Steve Grubb @ 2015-07-30 16:12 UTC (permalink / raw)
  To: linux-audit
In-Reply-To: <CAAnai+VtUtQ2MG+mYzq6sfKbRB6wP7UdWHtJhvZ3FNzNC_eU0g@mail.gmail.com>

On Thursday, July 30, 2015 10:16:53 AM Satish Chandra Kilaru wrote:
> Never mind... I found out why it was not working...

The auparse API expects string formatted events. The binary interface exists 
in case you completely understand how the audit events are formatted and 
prefer to take events as they come out.

For anyone not completely familiar with the data structures, its better to 
just use strings. In thsi way, you can extract portions of the log using 
ausearch --raw > test.log  and then feed that to your program for debugging.


> 1. auparse_next_event() does not call callback function. I have to call
> that function when auparse_next_event() returns.

The next event function is normally used when you are iterating through a file. 
If you are taking real-time events, its best to use the feed API and then 
process the event in the call back. There is a sample program here that should 
make starting an analysis program very simple:

https://fedorahosted.org/audit/browser/trunk/contrib/plugin

> 2. it expects events in string format. I configured the plugin to send
> events in binary format. hence auparse_next_event() was not returning.

I'll update the man page to auparse_init to make sure this is clear.

> 3. auparse_next_event() returns only when the parser sees the beginning of
> the next event.. i.e first event is returned after seeing the beginning of
> the 2nd event. Is this expected?

Yes. For some types of events, we don't know when the event is complete until 
we see the next one. They can also be interlaced. Its on the TODO list to fix 
this second issue. But my suggestion is to look at a couple sample programs 
and follow how they do things.

-Steve
 

> On Wed, Jul 29, 2015 at 4:36 PM, Satish Chandra Kilaru <iam.kilaru@gmail.com
> > wrote:
> > 
> > Has anyone tried AUSOURCE_DESCRIPTOR with a unix socket as fd?
> > 
> > I am doing the following.
> > 
> > int sd_u = socket(AF_UNIX, SOCK_STREAM, 0);
> > connect(sd_u, (struct sockaddr *) &sa, sizeof(sa))!=0)
> > auparse_state_t *au = auparse_init(AUSOURCE_DESCRIPTOR, (const void
> > *)sd_u);
> > auparse_add_callback(au, auparse_callback, event_cnt, free);
> > ausearch_next_event(au);
> > 
> > My auparse_callback() is not getting called. My program just blocks in
> > ausearch_next_event().
> > 
> > read(sd_u, buf, sizeof(buf)) gets me events... That means I am using
> > correct unix socket.
> > How do I make the callback function to get called for each event?
> > 
> > Am I missing something here?
> > 
> > Thanks in advance.
> > --Satish
> > --
> > Please Donate to www.wikipedia.org

^ permalink raw reply

* Re: Getting events on unix socket
From: Satish Chandra Kilaru @ 2015-07-30 15:58 UTC (permalink / raw)
  To: Steve Grubb; +Cc: linux-audit@redhat.com
In-Reply-To: <5598992.dAmjx71Ayh@x2>


[-- Attachment #1.1: Type: text/plain, Size: 1055 bytes --]

Thank you.
reading from stdin works. However, my program runs as a thread in a daemon
that does many other things. I cannot use stdin.

--Satish

On Thu, Jul 30, 2015 at 11:51 AM, Steve Grubb <sgrubb@redhat.com> wrote:

> On Wednesday, July 29, 2015 02:29:23 PM Satish Chandra Kilaru wrote:
> > I would like to receive events on unix socket in binary format.
> > There is already another program that is reading events from unix socket
> in
> > string format. I created another config file as below...
> >
> > active = yes
> > direction = out
> > path = builtin_af_unix
> > type = builtin
> > args = 0640 /var/run/satish_events
> > format = binary
> >
> > In my test program I am reading events from the socket
> > /var/run/satish_events
> > Surprisingly I see events in string format as well as binary format.
> >
> > Is it by design or a bug?
>
> I'd have to check. I don't think it was intended to run more than one
> instance. What is better, though, is to write the plugin to just read
> stdin.
>
> -Steve
>



-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 1700 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: Getting events on unix socket
From: Steve Grubb @ 2015-07-30 15:51 UTC (permalink / raw)
  To: linux-audit
In-Reply-To: <CAAnai+WP2i31j5Q=0=8oupN2v7ttX7-HzUD7xaTv5JRF-DOS9g@mail.gmail.com>

On Wednesday, July 29, 2015 02:29:23 PM Satish Chandra Kilaru wrote:
> I would like to receive events on unix socket in binary format.
> There is already another program that is reading events from unix socket in
> string format. I created another config file as below...
>
> active = yes
> direction = out
> path = builtin_af_unix
> type = builtin
> args = 0640 /var/run/satish_events
> format = binary
> 
> In my test program I am reading events from the socket
> /var/run/satish_events
> Surprisingly I see events in string format as well as binary format.
> 
> Is it by design or a bug?

I'd have to check. I don't think it was intended to run more than one 
instance. What is better, though, is to write the plugin to just read stdin. 

-Steve

^ permalink raw reply

* Re: auparse with AUSOURCE_DESCRIPTOR
From: Satish Chandra Kilaru @ 2015-07-30 14:16 UTC (permalink / raw)
  To: linux-audit@redhat.com
In-Reply-To: <CAAnai+Xti=KiAn_R3w0xwGKP0DZ596TY5ZuYHF3df9w3zBdsxg@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 1386 bytes --]

Never mind... I found out why it was not working...

1. auparse_next_event() does not call callback function. I have to call
that function when auparse_next_event() returns.
2. it expects events in string format. I configured the plugin to send
events in binary format. hence auparse_next_event() was not returning..
3. auparse_next_event() returns only when the parser sees the beginning of
the next event.. i.e first event is returned after seeing the beginning of
the 2nd event. Is this expected?

--Satish

On Wed, Jul 29, 2015 at 4:36 PM, Satish Chandra Kilaru <iam.kilaru@gmail.com
> wrote:

> Has anyone tried AUSOURCE_DESCRIPTOR with a unix socket as fd?
>
> I am doing the following.
>
> int sd_u = socket(AF_UNIX, SOCK_STREAM, 0);
> connect(sd_u, (struct sockaddr *) &sa, sizeof(sa))!=0)
> auparse_state_t *au = auparse_init(AUSOURCE_DESCRIPTOR, (const void
> *)sd_u);
> auparse_add_callback(au, auparse_callback, event_cnt, free);
> ausearch_next_event(au);
>
> My auparse_callback() is not getting called. My program just blocks in
> ausearch_next_event().
>
> read(sd_u, buf, sizeof(buf)) gets me events... That means I am using
> correct unix socket.
> How do I make the callback function to get called for each event?
>
> Am I missing something here?
>
> Thanks in advance.
> --Satish
> --
> Please Donate to www.wikipedia.org
>



-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 2215 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* auparse with AUSOURCE_DESCRIPTOR
From: Satish Chandra Kilaru @ 2015-07-29 20:36 UTC (permalink / raw)
  To: linux-audit@redhat.com


[-- Attachment #1.1: Type: text/plain, Size: 703 bytes --]

Has anyone tried AUSOURCE_DESCRIPTOR with a unix socket as fd?

I am doing the following.

int sd_u = socket(AF_UNIX, SOCK_STREAM, 0);
connect(sd_u, (struct sockaddr *) &sa, sizeof(sa))!=0)
auparse_state_t *au = auparse_init(AUSOURCE_DESCRIPTOR, (const void *)sd_u);
auparse_add_callback(au, auparse_callback, event_cnt, free);
ausearch_next_event(au);

My auparse_callback() is not getting called. My program just blocks in
ausearch_next_event().

read(sd_u, buf, sizeof(buf)) gets me events... That means I am using
correct unix socket.
How do I make the callback function to get called for each event?

Am I missing something here?

Thanks in advance.
--Satish
-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 1046 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Getting events on unix socket
From: Satish Chandra Kilaru @ 2015-07-29 18:29 UTC (permalink / raw)
  To: linux-audit@redhat.com


[-- Attachment #1.1: Type: text/plain, Size: 530 bytes --]

I would like to receive events on unix socket in binary format.
There is already another program that is reading events from unix socket in
string format.
I created another config file as below...

active = yes
direction = out
path = builtin_af_unix
type = builtin
args = 0640 /var/run/satish_events
format = binary

In my test program I am reading events from the socket
/var/run/satish_events
Surprisingly I see events in string format as well as binary format.

Is it by design or a bug?
-- 
Please Donate to www.wikipedia.org

[-- Attachment #1.2: Type: text/html, Size: 810 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: audit releases in recent RHEL releases (eg 6 and 7)
From: Burn Alting @ 2015-07-29 12:16 UTC (permalink / raw)
  To: Steve Grubb; +Cc: linux-audit
In-Reply-To: <12729657.YWHmqzP4VJ@x2>

Thanks.

On Wed, 2015-07-29 at 08:09 -0400, Steve Grubb wrote:
> On Wednesday, July 29, 2015 05:43:59 PM Burn Alting wrote:
> > I know this more a question for Red Hat, but before I approach my local
> > Red Hat rep, does anyone on the list know why RHEL6 only implements up
> > to a version of 2.3.7 yet RHEL7 goes up to a version of 2.4.1.
> 
> Sure. The issue is that if I pushed 2.4.2 into rhel6 and you start using 
> features in it, then what happens when you upgrade to RHEL7? RHEL6 is ahead 
> and there will be feature regressions.
>  
> > Basically, I want to know if RHEL6 can accept some elements from the
> > 2.4[.0] release if I ask really really reeeeeeeeeally nicely.
> 
> File a rebase RFE request through your support channel and that would be a 
> good start. Technically there is no reason why RHEL6 can't use 2.4, the ABI is 
> the same.
> 
> -Steve

^ permalink raw reply

* Re: audit releases in recent RHEL releases (eg 6 and 7)
From: Steve Grubb @ 2015-07-29 12:09 UTC (permalink / raw)
  To: linux-audit, burn
In-Reply-To: <1438155839.26354.125.camel@swtf.swtf.dyndns.org>

On Wednesday, July 29, 2015 05:43:59 PM Burn Alting wrote:
> I know this more a question for Red Hat, but before I approach my local
> Red Hat rep, does anyone on the list know why RHEL6 only implements up
> to a version of 2.3.7 yet RHEL7 goes up to a version of 2.4.1.

Sure. The issue is that if I pushed 2.4.2 into rhel6 and you start using 
features in it, then what happens when you upgrade to RHEL7? RHEL6 is ahead 
and there will be feature regressions.
 
> Basically, I want to know if RHEL6 can accept some elements from the
> 2.4[.0] release if I ask really really reeeeeeeeeally nicely.

File a rebase RFE request through your support channel and that would be a 
good start. Technically there is no reason why RHEL6 can't use 2.4, the ABI is 
the same.

-Steve

^ permalink raw reply

* audit releases in recent RHEL releases (eg 6 and 7)
From: Burn Alting @ 2015-07-29  7:43 UTC (permalink / raw)
  To: linux-audit

All,

I know this more a question for Red Hat, but before I approach my local
Red Hat rep, does anyone on the list know why RHEL6 only implements up
to a version of 2.3.7 yet RHEL7 goes up to a version of 2.4.1.

Basically, I want to know if RHEL6 can accept some elements from the
2.4[.0] release if I ask really really reeeeeeeeeally nicely.

Rgds

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox