Enable creation of rules to monitor for the execution of a future path.
This adds the ability to audit the actions of a not-yet-running process,
possibly not-yet-existing path, as well as the children of a process/path.
A path is supplied and stored with the rule, which is subsequently compared
with the path stored by sys_execve() when called.
Based-on-code-by: Peter Moody <pmoody(a)google.com>
Signed-off-by: Richard Guy Briggs <rgb(a)redhat.com>
---
include/linux/audit.h | 1 +
include/uapi/linux/audit.h | 2 ++
kernel/auditfilter.c | 35 +++++++++++++++++++++++++++++++++++
kernel/auditsc.c | 35 +++++++++++++++++++++++++++++++++++
4 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 7c42075..293759e 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -62,6 +62,7 @@ struct audit_krule {
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
struct list_head list; /* for AUDIT_LIST* purposes only */
u64 prio;
+ char *path; /* associated path */
};
struct audit_field {
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 573dc36..f4a72b9 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -266,6 +266,8 @@
#define AUDIT_OBJ_UID 109
#define AUDIT_OBJ_GID 110
#define AUDIT_FIELD_COMPARE 111
+#define AUDIT_EXE 112
+#define AUDIT_EXE_CHILDREN 113
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 6daea0a..3309943 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -87,6 +87,7 @@ static inline void audit_free_rule(struct audit_entry *e)
}
kfree(erule->fields);
kfree(erule->filterkey);
+ kfree(erule->path);
kfree(e);
}
@@ -390,6 +391,11 @@ 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:
+ case AUDIT_EXE_CHILDREN:
+ if (f->op != Audit_equal)
+ return -EINVAL;
+ break;
};
return 0;
}
@@ -539,6 +545,16 @@ 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:
+ case AUDIT_EXE_CHILDREN:
+ if (entry->rule.path || f->val > PATH_MAX)
+ 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.path = str;
+ break;
}
}
@@ -617,6 +633,11 @@ 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:
+ case AUDIT_EXE_CHILDREN:
+ data->buflen += data->values[i] =
+ audit_pack_string(&bufp, krule->path);
+ break;
default:
data->values[i] = f->val;
}
@@ -672,6 +693,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:
+ case AUDIT_EXE_CHILDREN:
+ /* both paths exist based on above type compare */
+ if (strcmp(a->path, b->path))
+ return 1;
+ break;
case AUDIT_UID:
case AUDIT_EUID:
case AUDIT_SUID:
@@ -742,6 +769,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
struct audit_entry *entry;
struct audit_krule *new;
char *fk;
+ char *path;
int i, err = 0;
entry = audit_init_entry(fcount);
@@ -793,6 +821,13 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
err = -ENOMEM;
else
new->filterkey = fk;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ path = kstrdup(old->path, GFP_KERNEL);
+ if (unlikely(!path))
+ err = -ENOMEM;
+ else
+ new->path = path;
}
if (err) {
audit_free_rule(entry);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f251a5e..6c6963d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -48,6 +48,7 @@
#include <asm/types.h>
#include <linux/atomic.h>
#include <linux/fs.h>
+#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/mm.h>
#include <linux/export.h>
@@ -70,6 +71,7 @@
#include <linux/capability.h>
#include <linux/fs_struct.h>
#include <linux/compat.h>
+#include <linux/sched.h>
#include <linux/ctype.h>
#include "audit.h"
@@ -432,6 +434,23 @@ static int audit_field_compare(struct task_struct *tsk,
return 0;
}
+int audit_match_exe(struct task_struct *tsk, struct audit_context *ctx, struct
audit_names *name, unsigned char *path)
+{
+ struct audit_names *n;
+
+ if ((!tsk || !tsk->audit_context) && !ctx && !name)
+ return 0;
+
+ if (name)
+ if (!strcmp(name->name->name, path))
+ return 1;
+
+ list_for_each_entry(n, &(ctx ?: tsk->audit_context)->names_list, list)
+ if (n->name && !strcmp(n->name->name, path))
+ return 1;
+ return 0;
+}
+
/* Determine if any context name data matches a rule's watch data */
/* Compare a task_struct with an audit_rule. Return 1 on match, 0
* otherwise.
@@ -471,6 +490,22 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_comparator(ctx->ppid, f->op, f->val);
}
break;
+ case AUDIT_EXE:
+ result = audit_match_exe(tsk, ctx, name, rule->path);
+ break;
+ case AUDIT_EXE_CHILDREN:
+ {
+ struct task_struct *ptsk;
+ for (ptsk = tsk;
+ ptsk->parent->pid > 0;
+ ptsk = find_task_by_vpid(ptsk->parent->pid)) {
+ if (audit_match_exe(ptsk, ctx, name, rule->path)) {
+ ++result;
+ break;
+ }
+ }
+ }
+ break;
case AUDIT_UID:
result = audit_uid_comparator(cred->uid, f->op, f->uid);
break;
--
1.7.1