* [PATCH 01/26] audit: make filetype matching consistent with other filters
@ 2011-11-17 22:02 Eric Paris
2011-11-17 22:02 ` [PATCH 02/26] audit: dynamically allocate audit_names when not enough space is in the names array Eric Paris
` (24 more replies)
0 siblings, 25 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:02 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Every other filter that matches part of the inodes list collected by audit
will match against any of the inodes on that list. The filetype matching
however had a strange way of doing things. It allowed userspace to
indicated if it should match on the first of the second name collected by
the kernel. Name collection ordering seems like a kernel internal and
making userspace rules get that right just seems like a bad idea. As it
turns out the userspace audit writers had no idea it was doing this and
thus never overloaded the value field. The kernel always checked the first
name collected which for the tested rules was always correct.
This patch just makes the filetype matching like the major, minor, inode,
and LSM rules in that it will match against any of the names collected. It
also changes the rule validation to reject the old unused rule types.
Noone new it was there. Noone used it. Why keep around the extra code?
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditfilter.c | 4 ++--
kernel/auditsc.c | 19 +++++++++----------
2 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index f8277c8..d94dde8 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -385,7 +385,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
goto exit_free;
break;
case AUDIT_FILETYPE:
- if ((f->val & ~S_IFMT) > S_IFMT)
+ if (f->val & ~S_IFMT)
goto exit_free;
break;
case AUDIT_INODE:
@@ -536,7 +536,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
goto exit_free;
break;
case AUDIT_FILETYPE:
- if ((f->val & ~S_IFMT) > S_IFMT)
+ if (f->val & ~S_IFMT)
goto exit_free;
break;
default:
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 47b7fc1..dc8e5f0 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -305,21 +305,20 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
}
}
-static int audit_match_filetype(struct audit_context *ctx, int which)
+static int audit_match_filetype(struct audit_context *ctx, int val)
{
- unsigned index = which & ~S_IFMT;
- mode_t mode = which & S_IFMT;
+ int index;
+ mode_t mode = (mode_t)val;
if (unlikely(!ctx))
return 0;
- if (index >= ctx->name_count)
- return 0;
- if (ctx->names[index].ino == -1)
- return 0;
- if ((ctx->names[index].mode ^ mode) & S_IFMT)
- return 0;
- return 1;
+ for (index = 0; index < ctx->name_count; index++) {
+ if ((ctx->names[index].ino != -1) &&
+ ((ctx->names[index].mode & S_IFMT) == mode))
+ return 1;
+ }
+ return 0;
}
/*
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 02/26] audit: dynamically allocate audit_names when not enough space is in the names array
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
@ 2011-11-17 22:02 ` Eric Paris
2011-11-17 22:02 ` [PATCH 03/26] audit: drop the meaningless and format breaking word 'user' Eric Paris
` (23 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:02 UTC (permalink / raw)
To: linux-audit; +Cc: viro
This patch does 2 things. First it reduces the number of audit_names
allocated in every audit context from 20 to 5. 5 should be enough for all
'normal' syscalls (rename being the worst). Some syscalls can still touch
more the 5 inodes such as mount. When rpc filesystem is mounted it will
create inodes and those can exceed 5. To handle that problem this patch will
dynamically allocate audit_names if it needs more than 5. This should
decrease the typicall memory usage while still supporting all the possible
kernel operations.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditsc.c | 403 +++++++++++++++++++++++++++++-------------------------
1 files changed, 215 insertions(+), 188 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index dc8e5f0..59d58e7 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -71,8 +71,9 @@
#include "audit.h"
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
- * for saving names from getname(). */
-#define AUDIT_NAMES 20
+ * for saving names from getname(). If we get more names we will allocate
+ * a name dynamically and also add those to the list anchored by names_list. */
+#define AUDIT_NAMES 5
/* Indicates that audit should log the full pathname. */
#define AUDIT_NAME_FULL -1
@@ -101,9 +102,8 @@ struct audit_cap_data {
*
* Further, in fs/namei.c:path_lookup() we store the inode and device. */
struct audit_names {
+ struct list_head list; /* audit_context->names_list */
const char *name;
- int name_len; /* number of name's characters to log */
- unsigned name_put; /* call __putname() for this name */
unsigned long ino;
dev_t dev;
umode_t mode;
@@ -113,6 +113,14 @@ struct audit_names {
u32 osid;
struct audit_cap_data fcap;
unsigned int fcap_ver;
+ int name_len; /* number of name's characters to log */
+ bool name_put; /* call __putname() for this name */
+ /*
+ * This was an allocated audit_names and not from the array of
+ * names allocated in the task audit context. Thus this name
+ * should be freed on syscall exit
+ */
+ bool should_free;
};
struct audit_aux_data {
@@ -174,8 +182,17 @@ struct audit_context {
long return_code;/* syscall return code */
u64 prio;
int return_valid; /* return code is valid */
- int name_count;
- struct audit_names names[AUDIT_NAMES];
+ /*
+ * The names_list is the list of all audit_names collected during this
+ * syscall. The first AUDIT_NAMES entries in the names_list will
+ * actually be from the preallocated_names array for performance
+ * reasons. Except during allocation they should never be referenced
+ * through the preallocated_names array and should only be found/used
+ * by running the names_list.
+ */
+ struct audit_names preallocated_names[AUDIT_NAMES];
+ int name_count; /* total records in names_list */
+ struct list_head names_list; /* anchor for struct audit_names->list */
char * filterkey; /* key for rule that triggered record */
struct path pwd;
struct audit_context *previous; /* For nested syscalls */
@@ -307,17 +324,18 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
static int audit_match_filetype(struct audit_context *ctx, int val)
{
- int index;
+ struct audit_names *n;
mode_t mode = (mode_t)val;
if (unlikely(!ctx))
return 0;
- for (index = 0; index < ctx->name_count; index++) {
- if ((ctx->names[index].ino != -1) &&
- ((ctx->names[index].mode & S_IFMT) == mode))
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if ((n->ino != -1) &&
+ ((n->mode & S_IFMT) == mode))
return 1;
}
+
return 0;
}
@@ -456,13 +474,14 @@ static int audit_filter_rules(struct task_struct *tsk,
bool task_creation)
{
const struct cred *cred;
- int i, j, need_sid = 1;
+ int i, need_sid = 1;
u32 sid;
cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
for (i = 0; i < rule->field_count; i++) {
struct audit_field *f = &rule->fields[i];
+ struct audit_names *n;
int result = 0;
switch (f->type) {
@@ -525,8 +544,8 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_comparator(MAJOR(name->dev),
f->op, f->val);
else if (ctx) {
- for (j = 0; j < ctx->name_count; j++) {
- if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_comparator(MAJOR(n->dev), f->op, f->val)) {
++result;
break;
}
@@ -538,8 +557,8 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_comparator(MINOR(name->dev),
f->op, f->val);
else if (ctx) {
- for (j = 0; j < ctx->name_count; j++) {
- if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_comparator(MINOR(n->dev), f->op, f->val)) {
++result;
break;
}
@@ -550,8 +569,8 @@ static int audit_filter_rules(struct task_struct *tsk,
if (name)
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)) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_comparator(n->ino, f->op, f->val)) {
++result;
break;
}
@@ -606,11 +625,10 @@ static int audit_filter_rules(struct task_struct *tsk,
name->osid, f->type, f->op,
f->lsm_rule, ctx);
} else if (ctx) {
- for (j = 0; j < ctx->name_count; j++) {
- if (security_audit_rule_match(
- ctx->names[j].osid,
- f->type, f->op,
- f->lsm_rule, ctx)) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (security_audit_rule_match(n->osid, f->type,
+ f->op, f->lsm_rule,
+ ctx)) {
++result;
break;
}
@@ -721,40 +739,53 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
return AUDIT_BUILD_CONTEXT;
}
-/* At syscall exit time, this filter is called if any audit_names[] have been
+/*
+ * Given an audit_name check the inode hash table to see if they match.
+ * Called holding the rcu read lock to protect the use of audit_inode_hash
+ */
+static int audit_filter_inode_name(struct task_struct *tsk,
+ struct audit_names *n,
+ struct audit_context *ctx) {
+ int word, bit;
+ int h = audit_hash_ino((u32)n->ino);
+ struct list_head *list = &audit_inode_hash[h];
+ struct audit_entry *e;
+ enum audit_state state;
+
+ word = AUDIT_WORD(ctx->major);
+ bit = AUDIT_BIT(ctx->major);
+
+ if (list_empty(list))
+ return 0;
+
+ list_for_each_entry_rcu(e, list, list) {
+ if ((e->rule.mask[word] & bit) == bit &&
+ audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
+ ctx->current_state = state;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* At syscall exit time, this filter is called if any audit_names have been
* collected during syscall processing. We only check rules in sublists at hash
- * buckets applicable to the inode numbers in audit_names[].
+ * buckets applicable to the inode numbers in audit_names.
* Regarding audit_state, same rules apply as for audit_filter_syscall().
*/
void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
{
- int i;
- struct audit_entry *e;
- enum audit_state state;
+ struct audit_names *n;
if (audit_pid && tsk->tgid == audit_pid)
return;
rcu_read_lock();
- for (i = 0; i < ctx->name_count; i++) {
- int word = AUDIT_WORD(ctx->major);
- int bit = AUDIT_BIT(ctx->major);
- struct audit_names *n = &ctx->names[i];
- int h = audit_hash_ino((u32)n->ino);
- struct list_head *list = &audit_inode_hash[h];
- if (list_empty(list))
- continue;
-
- list_for_each_entry_rcu(e, list, list) {
- if ((e->rule.mask[word] & bit) == bit &&
- audit_filter_rules(tsk, &e->rule, ctx, n,
- &state, false)) {
- rcu_read_unlock();
- ctx->current_state = state;
- return;
- }
- }
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_filter_inode_name(tsk, n, ctx))
+ break;
}
rcu_read_unlock();
}
@@ -798,7 +829,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
static inline void audit_free_names(struct audit_context *context)
{
- int i;
+ struct audit_names *n, *next;
#if AUDIT_DEBUG == 2
if (context->put_count + context->ino_count != context->name_count) {
@@ -809,10 +840,9 @@ static inline void audit_free_names(struct audit_context *context)
context->serial, context->major, context->in_syscall,
context->name_count, context->put_count,
context->ino_count);
- for (i = 0; i < context->name_count; i++) {
+ list_for_each_entry(n, &context->names_list, list) {
printk(KERN_ERR "names[%d] = %p = %s\n", i,
- context->names[i].name,
- context->names[i].name ?: "(null)");
+ n->name, n->name ?: "(null)");
}
dump_stack();
return;
@@ -823,9 +853,12 @@ static inline void audit_free_names(struct audit_context *context)
context->ino_count = 0;
#endif
- for (i = 0; i < context->name_count; i++) {
- if (context->names[i].name && context->names[i].name_put)
- __putname(context->names[i].name);
+ list_for_each_entry_safe(n, next, &context->names_list, list) {
+ list_del(&n->list);
+ if (n->name && n->name_put)
+ __putname(n->name);
+ if (n->should_free)
+ kfree(n);
}
context->name_count = 0;
path_put(&context->pwd);
@@ -863,6 +896,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
return NULL;
audit_zero_context(context, state);
INIT_LIST_HEAD(&context->killed_trees);
+ INIT_LIST_HEAD(&context->names_list);
return context;
}
@@ -1323,6 +1357,68 @@ static void show_special(struct audit_context *context, int *call_panic)
audit_log_end(ab);
}
+static void audit_log_name(struct audit_context *context, struct audit_names *n,
+ int record_num, int *call_panic)
+{
+ struct audit_buffer *ab;
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
+ if (!ab)
+ return; /* audit_panic has been called */
+
+ audit_log_format(ab, "item=%d", record_num);
+
+ 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);
+ break;
+ default:
+ /* log the name's directory component */
+ audit_log_format(ab, " name=");
+ audit_log_n_untrustedstring(ab, n->name,
+ n->name_len);
+ }
+ } 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 (security_secid_to_secctx(
+ n->osid, &ctx, &len)) {
+ audit_log_format(ab, " osid=%u", n->osid);
+ *call_panic = 2;
+ } else {
+ audit_log_format(ab, " obj=%s", ctx);
+ security_release_secctx(ctx, len);
+ }
+ }
+
+ audit_log_fcaps(ab, n);
+
+ audit_log_end(ab);
+}
+
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
const struct cred *cred;
@@ -1330,6 +1426,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
struct audit_buffer *ab;
struct audit_aux_data *aux;
const char *tty;
+ struct audit_names *n;
/* tsk == current */
context->pid = tsk->pid;
@@ -1469,66 +1566,10 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_end(ab);
}
}
- for (i = 0; i < context->name_count; i++) {
- struct audit_names *n = &context->names[i];
-
- ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
- if (!ab)
- continue; /* audit_panic has been called */
-
- audit_log_format(ab, "item=%d", i);
-
- 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);
- break;
- default:
- /* log the name's directory component */
- audit_log_format(ab, " name=");
- audit_log_n_untrustedstring(ab, n->name,
- n->name_len);
- }
- } 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 (security_secid_to_secctx(
- n->osid, &ctx, &len)) {
- audit_log_format(ab, " osid=%u", n->osid);
- call_panic = 2;
- } else {
- audit_log_format(ab, " obj=%s", ctx);
- security_release_secctx(ctx, len);
- }
- }
-
- audit_log_fcaps(ab, n);
- audit_log_end(ab);
- }
+ i = 0;
+ list_for_each_entry(n, &context->names_list, list)
+ audit_log_name(context, n, i++, &call_panic);
/* Send end of event record to help user space know we are finished */
ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
@@ -1820,6 +1861,30 @@ retry:
#endif
}
+static struct audit_names *audit_alloc_name(struct audit_context *context)
+{
+ struct audit_names *aname;
+
+ if (context->name_count < AUDIT_NAMES) {
+ aname = &context->preallocated_names[context->name_count];
+ memset(aname, 0, sizeof(*aname));
+ } else {
+ aname = kzalloc(sizeof(*aname), GFP_NOFS);
+ if (!aname)
+ return NULL;
+ aname->should_free = true;
+ }
+
+ aname->ino = (unsigned long)-1;
+ list_add_tail(&aname->list, &context->names_list);
+
+ context->name_count++;
+#if AUDIT_DEBUG
+ context->ino_count++;
+#endif
+ return aname;
+}
+
/**
* audit_getname - add a name to the list
* @name: name to add
@@ -1830,6 +1895,7 @@ retry:
void __audit_getname(const char *name)
{
struct audit_context *context = current->audit_context;
+ struct audit_names *n;
if (IS_ERR(name) || !name)
return;
@@ -1842,13 +1908,15 @@ void __audit_getname(const char *name)
#endif
return;
}
- 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->names[context->name_count].osid = 0;
- ++context->name_count;
+
+ n = audit_alloc_name(context);
+ if (!n)
+ return;
+
+ n->name = name;
+ n->name_len = AUDIT_NAME_FULL;
+ n->name_put = true;
+
if (!context->pwd.dentry)
get_fs_pwd(current->fs, &context->pwd);
}
@@ -1870,12 +1938,13 @@ void audit_putname(const char *name)
printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n",
__FILE__, __LINE__, context->serial, name);
if (context->name_count) {
+ struct audit_names *n;
int i;
- for (i = 0; i < context->name_count; i++)
+
+ list_for_each_entry(n, &context->names_list, list)
printk(KERN_ERR "name[%d] = %p = %s\n", i,
- context->names[i].name,
- context->names[i].name ?: "(null)");
- }
+ n->name, n->name ?: "(null)");
+ }
#endif
__putname(name);
}
@@ -1896,39 +1965,11 @@ void audit_putname(const char *name)
#endif
}
-static int audit_inc_name_count(struct audit_context *context,
- const struct inode *inode)
-{
- if (context->name_count >= AUDIT_NAMES) {
- if (inode)
- printk(KERN_DEBUG "audit: name_count maxed, losing inode data: "
- "dev=%02x:%02x, inode=%lu\n",
- MAJOR(inode->i_sb->s_dev),
- MINOR(inode->i_sb->s_dev),
- inode->i_ino);
-
- else
- printk(KERN_DEBUG "name_count maxed, losing inode data\n");
- return 1;
- }
- context->name_count++;
-#if AUDIT_DEBUG
- context->ino_count++;
-#endif
- return 0;
-}
-
-
static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
{
struct cpu_vfs_cap_data caps;
int rc;
- memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t));
- memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t));
- name->fcap.fE = 0;
- name->fcap_ver = 0;
-
if (!dentry)
return 0;
@@ -1968,30 +2009,25 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
*/
void __audit_inode(const char *name, const struct dentry *dentry)
{
- int idx;
struct audit_context *context = current->audit_context;
const struct inode *inode = dentry->d_inode;
+ struct audit_names *n;
if (!context->in_syscall)
return;
- if (context->name_count
- && context->names[context->name_count-1].name
- && context->names[context->name_count-1].name == name)
- idx = context->name_count - 1;
- else if (context->name_count > 1
- && context->names[context->name_count-2].name
- && context->names[context->name_count-2].name == name)
- idx = context->name_count - 2;
- else {
- /* FIXME: how much do we care about inodes that have no
- * associated name? */
- if (audit_inc_name_count(context, inode))
- return;
- idx = context->name_count - 1;
- context->names[idx].name = NULL;
+
+ list_for_each_entry_reverse(n, &context->names_list, list) {
+ if (n->name && (n->name == name))
+ goto out;
}
+
+ /* unable to find the name from a previous getname() */
+ n = audit_alloc_name(context);
+ if (!n)
+ return;
+out:
handle_path(dentry);
- audit_copy_inode(&context->names[idx], dentry, inode);
+ audit_copy_inode(n, dentry, inode);
}
/**
@@ -2010,11 +2046,11 @@ void __audit_inode(const char *name, const struct dentry *dentry)
void __audit_inode_child(const struct dentry *dentry,
const struct inode *parent)
{
- int idx;
struct audit_context *context = current->audit_context;
const char *found_parent = NULL, *found_child = NULL;
const struct inode *inode = dentry->d_inode;
const char *dname = dentry->d_name.name;
+ struct audit_names *n;
int dirlen = 0;
if (!context->in_syscall)
@@ -2024,9 +2060,7 @@ void __audit_inode_child(const struct dentry *dentry,
handle_one(inode);
/* parent is more likely, look for it first */
- for (idx = 0; idx < context->name_count; idx++) {
- struct audit_names *n = &context->names[idx];
-
+ list_for_each_entry(n, &context->names_list, list) {
if (!n->name)
continue;
@@ -2039,9 +2073,7 @@ void __audit_inode_child(const struct dentry *dentry,
}
/* no matching parent, look for matching child */
- for (idx = 0; idx < context->name_count; idx++) {
- struct audit_names *n = &context->names[idx];
-
+ list_for_each_entry(n, &context->names_list, list) {
if (!n->name)
continue;
@@ -2059,34 +2091,29 @@ void __audit_inode_child(const struct dentry *dentry,
add_names:
if (!found_parent) {
- if (audit_inc_name_count(context, parent))
+ n = audit_alloc_name(context);
+ if (!n)
return;
- idx = context->name_count - 1;
- context->names[idx].name = NULL;
- audit_copy_inode(&context->names[idx], NULL, parent);
+ audit_copy_inode(n, NULL, parent);
}
if (!found_child) {
- if (audit_inc_name_count(context, inode))
+ n = audit_alloc_name(context);
+ if (!n)
return;
- idx = context->name_count - 1;
/* Re-use the name belonging to the slot for a matching parent
* directory. All names for this context are relinquished in
* audit_free_names() */
if (found_parent) {
- context->names[idx].name = found_parent;
- context->names[idx].name_len = AUDIT_NAME_FULL;
+ n->name = found_parent;
+ n->name_len = AUDIT_NAME_FULL;
/* don't call __putname() */
- context->names[idx].name_put = 0;
- } else {
- context->names[idx].name = NULL;
+ n->name_put = false;
}
if (inode)
- audit_copy_inode(&context->names[idx], NULL, inode);
- else
- context->names[idx].ino = (unsigned long)-1;
+ audit_copy_inode(n, NULL, inode);
}
}
EXPORT_SYMBOL_GPL(__audit_inode_child);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 03/26] audit: drop the meaningless and format breaking word 'user'
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
2011-11-17 22:02 ` [PATCH 02/26] audit: dynamically allocate audit_names when not enough space is in the names array Eric Paris
@ 2011-11-17 22:02 ` Eric Paris
2011-11-17 22:03 ` [PATCH 04/26] audit: check current inode and containing object when filtering on major and minor Eric Paris
` (22 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:02 UTC (permalink / raw)
To: linux-audit; +Cc: viro
userspace audit messages look like so:
type=USER msg=audit(1271170549.415:24710): user pid=14722 uid=0 auid=500 ses=1 subj=unconfined_u:unconfined_r:auditctl_t:s0-s0:c0.c1023 msg=''
That third field just says 'user'. That's useless and doesn't follow the
key=value pair we are trying to enforce. We already know it came from the
user based on the record type. Kill that word. Die.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/audit.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/kernel/audit.c b/kernel/audit.c
index 2c1d6ab..00efe47 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -631,7 +631,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
}
*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
- audit_log_format(*ab, "user pid=%d uid=%u auid=%u ses=%u",
+ audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u",
pid, uid, auid, ses);
if (sid) {
rc = security_secid_to_secctx(sid, &ctx, &len);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 04/26] audit: check current inode and containing object when filtering on major and minor
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
2011-11-17 22:02 ` [PATCH 02/26] audit: dynamically allocate audit_names when not enough space is in the names array Eric Paris
2011-11-17 22:02 ` [PATCH 03/26] audit: drop the meaningless and format breaking word 'user' Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 05/26] seccomp: audit abnormal end to a process due to seccomp Eric Paris
` (21 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
The audit system has the ability to filter on the major and minor number of
the device containing the inode being operated upon. Lets say that
/dev/sda1 has major,minor 8,1 and that we mount /dev/sda1 on /boot. Now lets
say we add a watch with a filter on 8,1. If we proceed to open an inode
inside /boot, such as /vboot/vmlinuz, we will match the major,minor filter.
Lets instead assume that one were to use a tool like debugfs and were to
open /dev/sda1 directly and to modify it's contents. We might hope that
this would also be logged, but it isn't. The rules will check the
major,minor of the device containing /dev/sda1. In other words the rule
would match on the major/minor of the tmpfs mounted at /dev.
I believe these rules should trigger on either device. The man page is
devoid of useful information about the intended semantics. It only seems
logical that if you want to know everything that happened on a major,minor
that would include things that happened to the device itself...
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditsc.c | 24 ++++++++++++++----------
1 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 59d58e7..1a0604e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -540,12 +540,14 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_DEVMAJOR:
- if (name)
- result = audit_comparator(MAJOR(name->dev),
- f->op, f->val);
- else if (ctx) {
+ if (name) {
+ if (audit_comparator(MAJOR(name->dev), f->op, f->val) ||
+ audit_comparator(MAJOR(name->rdev), f->op, f->val))
+ ++result;
+ } else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- if (audit_comparator(MAJOR(n->dev), f->op, f->val)) {
+ if (audit_comparator(MAJOR(n->dev), f->op, f->val) ||
+ audit_comparator(MAJOR(n->rdev), f->op, f->val)) {
++result;
break;
}
@@ -553,12 +555,14 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_DEVMINOR:
- if (name)
- result = audit_comparator(MINOR(name->dev),
- f->op, f->val);
- else if (ctx) {
+ if (name) {
+ if (audit_comparator(MINOR(name->dev), f->op, f->val) ||
+ audit_comparator(MINOR(name->rdev), f->op, f->val))
+ ++result;
+ } else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- if (audit_comparator(MINOR(n->dev), f->op, f->val)) {
+ if (audit_comparator(MINOR(n->dev), f->op, f->val) ||
+ audit_comparator(MINOR(n->rdev), f->op, f->val)) {
++result;
break;
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 05/26] seccomp: audit abnormal end to a process due to seccomp
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (2 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 04/26] audit: check current inode and containing object when filtering on major and minor Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 06/26] Audit: push audit success and retcode into arch ptrace.h Eric Paris
` (20 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
The audit system likes to collect information about processes that end
abnormally (SIGSEGV) as this may me useful intrusion detection information.
This patch adds audit support to collect information when seccomp forces a
task to exit because of misbehavior in a similar way.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 8 ++++++++
kernel/auditsc.c | 50 ++++++++++++++++++++++++++++---------------------
kernel/seccomp.c | 2 ++
3 files changed, 39 insertions(+), 21 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 2f81c6f..24851b5 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -430,6 +430,7 @@ extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct dentry *dentry);
extern void __audit_inode_child(const struct dentry *dentry,
const struct inode *parent);
+extern void __audit_seccomp(unsigned long syscall);
extern void __audit_ptrace(struct task_struct *t);
static inline int audit_dummy_context(void)
@@ -453,6 +454,12 @@ static inline void audit_inode_child(const struct dentry *dentry,
}
void audit_core_dumps(long signr);
+static inline void audit_seccomp(unsigned long syscall)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_seccomp(syscall);
+}
+
static inline void audit_ptrace(struct task_struct *t)
{
if (unlikely(!audit_dummy_context()))
@@ -558,6 +565,7 @@ extern int audit_signals;
#define audit_inode(n,d) do { (void)(d); } while (0)
#define audit_inode_child(i,p) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0)
+#define audit_seccomp(i) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) (0)
#define audit_get_loginuid(t) (-1)
#define audit_get_sessionid(t) (-1)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 1a0604e..a0785cf 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2529,6 +2529,25 @@ void __audit_mmap_fd(int fd, int flags)
context->type = AUDIT_MMAP;
}
+static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
+{
+ uid_t auid, uid;
+ gid_t gid;
+ unsigned int sessionid;
+
+ auid = audit_get_loginuid(current);
+ sessionid = audit_get_sessionid(current);
+ current_uid_gid(&uid, &gid);
+
+ audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
+ auid, uid, gid, sessionid);
+ audit_log_task_context(ab);
+ audit_log_format(ab, " pid=%d comm=", current->pid);
+ audit_log_untrustedstring(ab, current->comm);
+ audit_log_format(ab, " reason=");
+ audit_log_string(ab, reason);
+ audit_log_format(ab, " sig=%ld", signr);
+}
/**
* audit_core_dumps - record information about processes that end abnormally
* @signr: signal value
@@ -2539,10 +2558,6 @@ void __audit_mmap_fd(int fd, int flags)
void audit_core_dumps(long signr)
{
struct audit_buffer *ab;
- u32 sid;
- uid_t auid = audit_get_loginuid(current), uid;
- gid_t gid;
- unsigned int sessionid = audit_get_sessionid(current);
if (!audit_enabled)
return;
@@ -2551,24 +2566,17 @@ void audit_core_dumps(long signr)
return;
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
- current_uid_gid(&uid, &gid);
- audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
- auid, uid, gid, sessionid);
- security_task_getsecid(current, &sid);
- if (sid) {
- char *ctx = NULL;
- u32 len;
+ audit_log_abend(ab, "memory violation", signr);
+ audit_log_end(ab);
+}
- if (security_secid_to_secctx(sid, &ctx, &len))
- audit_log_format(ab, " ssid=%u", sid);
- else {
- audit_log_format(ab, " subj=%s", ctx);
- security_release_secctx(ctx, len);
- }
- }
- audit_log_format(ab, " pid=%d comm=", current->pid);
- audit_log_untrustedstring(ab, current->comm);
- audit_log_format(ab, " sig=%ld", signr);
+void __audit_seccomp(unsigned long syscall)
+{
+ struct audit_buffer *ab;
+
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+ audit_log_abend(ab, "seccomp", SIGKILL);
+ audit_log_format(ab, " syscall=%ld", syscall);
audit_log_end(ab);
}
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 57d4b13..e8d76c5 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -6,6 +6,7 @@
* This defines a simple but solid secure-computing mode.
*/
+#include <linux/audit.h>
#include <linux/seccomp.h>
#include <linux/sched.h>
#include <linux/compat.h>
@@ -54,6 +55,7 @@ void __secure_computing(int this_syscall)
#ifdef SECCOMP_DEBUG
dump_stack();
#endif
+ audit_seccomp(this_syscall);
do_exit(SIGKILL);
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 06/26] Audit: push audit success and retcode into arch ptrace.h
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (3 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 05/26] seccomp: audit abnormal end to a process due to seccomp Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 07/26] audit: ia32entry.S sign extend error codes when calling 64 bit code Eric Paris
` (19 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
The audit system previously expected arches calling to audit_syscall_exit to
supply as arguments if the syscall was a success and what the return code was.
Audit also provides a helper AUDITSC_RESULT which was supposed to simplify things
by converting from negative retcodes to an audit internal magic value stating
success or failure. This helper was wrong and could indicate that a valid
pointer returned to userspace was a failed syscall. The fix is to fix the
layering foolishness. We now pass audit_syscall_exit a struct pt_reg and it
in turns calls back into arch code to collect the return value and to
determine if the syscall was a success or failure. We also define a generic
is_syscall_success() macro which determines success/failure based on if the
value is < -MAX_ERRNO. This works for arches like x86 which do not use a
separate mechanism to indicate syscall failure.
We make both the is_syscall_success() and regs_return_value() static inlines
instead of macros. The reason is because the audit function must take a void*
for the regs. (uml calls theirs struct uml_pt_regs instead of just struct
pt_regs so audit_syscall_exit can't take a struct pt_regs). Since the audit
function takes a void* we need to use static inlines to cast it back to the
arch correct structure to dereference it.
The other major change is that on some arches, like ia64, MIPS and ppc, we
change regs_return_value() to give us the negative value on syscall failure.
THE only other user of this macro, kretprobe_example.c, won't notice and it
makes the value signed consistently for the audit functions across all archs.
In arch/sh/kernel/ptrace_64.c I see that we were using regs[9] in the old
audit code as the return value. But the ptrace_64.h code defined the macro
regs_return_value() as regs[3]. I have no idea which one is correct, but this
patch now uses the regs_return_value() function, so it now uses regs[3].
For powerpc we previously used regs->result but now use the
regs_return_value() function which uses regs->gprs[3]. regs->gprs[3] is
always positive so the regs_return_value(), much like ia64 makes it negative
before calling the audit code when appropriate.
Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: H. Peter Anvin <hpa@zytor.com> [for x86 portion]
Acked-by: Tony Luck <tony.luck@intel.com> [for ia64]
Acked-by: Richard Weinberger <richard@nod.at> [for uml]
Acked-by: David S. Miller <davem@davemloft.net> [for sparc]
Acked-by: Ralf Baechle <ralf@linux-mips.org> [for mips]
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> [for ppc]
---
arch/ia64/include/asm/ptrace.h | 13 ++++++++++++-
arch/ia64/kernel/ptrace.c | 9 +--------
arch/microblaze/include/asm/ptrace.h | 5 +++++
arch/microblaze/kernel/ptrace.c | 3 +--
arch/mips/include/asm/ptrace.h | 14 +++++++++++++-
arch/mips/kernel/ptrace.c | 4 +---
arch/powerpc/include/asm/ptrace.h | 13 ++++++++++++-
arch/powerpc/kernel/ptrace.c | 4 +---
arch/s390/include/asm/ptrace.h | 6 +++++-
arch/s390/kernel/ptrace.c | 4 +---
arch/sh/include/asm/ptrace_32.h | 5 ++++-
arch/sh/include/asm/ptrace_64.h | 5 ++++-
arch/sh/kernel/ptrace_32.c | 4 +---
arch/sh/kernel/ptrace_64.c | 4 +---
arch/sparc/include/asm/ptrace.h | 10 +++++++++-
arch/sparc/kernel/ptrace_64.c | 11 +----------
arch/um/kernel/ptrace.c | 4 ++--
arch/x86/ia32/ia32entry.S | 10 +++++-----
arch/x86/kernel/entry_32.S | 8 ++++----
arch/x86/kernel/entry_64.S | 10 +++++-----
arch/x86/kernel/ptrace.c | 3 +--
arch/x86/kernel/vm86_32.c | 4 ++--
arch/x86/um/shared/sysdep/ptrace_32.h | 5 +++++
arch/x86/um/shared/sysdep/ptrace_64.h | 5 +++++
include/linux/audit.h | 22 ++++++++++++++--------
include/linux/ptrace.h | 10 ++++++++++
kernel/auditsc.c | 16 ++++++++++++----
27 files changed, 137 insertions(+), 74 deletions(-)
diff --git a/arch/ia64/include/asm/ptrace.h b/arch/ia64/include/asm/ptrace.h
index f5cb276..68c98f5 100644
--- a/arch/ia64/include/asm/ptrace.h
+++ b/arch/ia64/include/asm/ptrace.h
@@ -246,7 +246,18 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
return regs->ar_bspstore;
}
-#define regs_return_value(regs) ((regs)->r8)
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+ return regs->r10 != -1;
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ if (is_syscall_success(regs))
+ return regs->r8;
+ else
+ return -regs->r8;
+}
/* Conserve space in histogram by encoding slot bits in address
* bits 2 and 3 rather than bits 0 and 1.
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 8848f43..2c15408 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1268,14 +1268,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
{
int step;
- if (unlikely(current->audit_context)) {
- int success = AUDITSC_RESULT(regs.r10);
- long result = regs.r8;
-
- if (success != AUDITSC_SUCCESS)
- result = -result;
- audit_syscall_exit(success, result);
- }
+ audit_syscall_exit(®s);
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include/asm/ptrace.h
index 816bee6..94e92c8 100644
--- a/arch/microblaze/include/asm/ptrace.h
+++ b/arch/microblaze/include/asm/ptrace.h
@@ -61,6 +61,11 @@ struct pt_regs {
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ return regs->r3;
+}
+
#else /* __KERNEL__ */
/* pt_regs offsets used by gdbserver etc in ptrace syscalls */
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index 043cb58..f564b1b 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -159,8 +159,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
- if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);
+ audit_syscall_exit(regs);
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 7b99c67..4b7f525 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -137,7 +137,19 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
*/
#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
-#define regs_return_value(_regs) ((_regs)->regs[2])
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+ return !regs->regs[7];
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ if (is_syscall_success(regs))
+ return regs->regs[2];
+ else
+ return -regs->regs[2];
+}
+
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 4e6ea1f..ab0f196 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -572,9 +572,7 @@ out:
*/
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{
- if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]),
- -regs->regs[2]);
+ audit_syscall_exit(regs);
if (!(current->ptrace & PT_PTRACED))
return;
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 48223f9..78a2051 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -86,7 +86,18 @@ struct pt_regs {
#define instruction_pointer(regs) ((regs)->nip)
#define user_stack_pointer(regs) ((regs)->gpr[1])
#define kernel_stack_pointer(regs) ((regs)->gpr[1])
-#define regs_return_value(regs) ((regs)->gpr[3])
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+ return !(regs->ccr & 0x10000000);
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ if (is_syscall_success(regs))
+ return regs->gpr[3];
+ else
+ return -regs->gpr[3];
+}
#ifdef CONFIG_SMP
extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 5de73db..09d31c1 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1748,9 +1748,7 @@ void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
- if (unlikely(current->audit_context))
- audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
- regs->result);
+ audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->result);
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index a658463..0310d0d 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -540,9 +540,13 @@ struct user_regs_struct
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
#define user_stack_pointer(regs)((regs)->gprs[15])
-#define regs_return_value(regs)((regs)->gprs[2])
#define profile_pc(regs) instruction_pointer(regs)
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ return regs->gprs[2];
+}
+
int regs_query_register_offset(const char *name);
const char *regs_query_register_name(unsigned int offset);
unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 450931a..0045a30 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -763,9 +763,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
{
- if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
- regs->gprs[2]);
+ audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->gprs[2]);
diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h
index 6c2239c..2d3e906 100644
--- a/arch/sh/include/asm/ptrace_32.h
+++ b/arch/sh/include/asm/ptrace_32.h
@@ -76,7 +76,10 @@ struct pt_dspregs {
#ifdef __KERNEL__
#define MAX_REG_OFFSET offsetof(struct pt_regs, tra)
-#define regs_return_value(_regs) ((_regs)->regs[0])
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ return regs->regs[0];
+}
#endif /* __KERNEL__ */
diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h
index bf9be77..eb3fcce 100644
--- a/arch/sh/include/asm/ptrace_64.h
+++ b/arch/sh/include/asm/ptrace_64.h
@@ -13,7 +13,10 @@ struct pt_regs {
#ifdef __KERNEL__
#define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7])
-#define regs_return_value(_regs) ((_regs)->regs[3])
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ return regs->regs[3];
+}
#endif /* __KERNEL__ */
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 92b3c27..c0b5c17 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -530,9 +530,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
- if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
- regs->regs[0]);
+ audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->regs[0]);
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index c8f9764..ba720d6 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -548,9 +548,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
- if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
- regs->regs[9]);
+ audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->regs[9]);
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index a0e1bcf..c00c3b5 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -207,7 +207,15 @@ do { current_thread_info()->syscall_noerror = 1; \
#define instruction_pointer(regs) ((regs)->tpc)
#define instruction_pointer_set(regs, val) ((regs)->tpc = (val))
#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
-#define regs_return_value(regs) ((regs)->u_regs[UREG_I0])
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+ return !(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY));
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ return regs->u_regs[UREG_I0];
+}
#ifdef CONFIG_SMP
extern unsigned long profile_pc(struct pt_regs *);
#else
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index 96ee50a..c73c8c5 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -1086,17 +1086,8 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{
-#ifdef CONFIG_AUDITSYSCALL
- if (unlikely(current->audit_context)) {
- unsigned long tstate = regs->tstate;
- int result = AUDITSC_SUCCESS;
+ audit_syscall_exit(regs);
- if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
- result = AUDITSC_FAILURE;
-
- audit_syscall_exit(result, regs->u_regs[UREG_I0]);
- }
-#endif
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->u_regs[UREG_G1]);
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index c9da32b..2ccf25c 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -175,8 +175,8 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit)
UPT_SYSCALL_ARG2(regs),
UPT_SYSCALL_ARG3(regs),
UPT_SYSCALL_ARG4(regs));
- else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
- UPT_SYSCALL_RET(regs));
+ else
+ audit_syscall_exit(regs);
}
/* Fake a debug trap */
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index a6253ec..1c03202 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -14,6 +14,7 @@
#include <asm/segment.h>
#include <asm/irqflags.h>
#include <linux/linkage.h>
+#include <linux/err.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
#include <linux/elf-em.h>
@@ -210,13 +211,12 @@ sysexit_from_sys_call:
TRACE_IRQS_ON
sti
movl %eax,%esi /* second arg, syscall return value */
- cmpl $0,%eax /* is it < 0? */
- setl %al /* 1 if so, 0 if not */
+ cmpl $-MAX_ERRNO,%eax /* is it an error ? */
+ setbe %al /* 1 if so, 0 if not */
movzbl %al,%edi /* zero-extend that into %edi */
- inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
- call audit_syscall_exit
+ call __audit_syscall_exit
GET_THREAD_INFO(%r10)
- movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall return value */
+ movq RAX-ARGOFFSET(%rsp),%rax /* reload syscall return value */
movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
cli
TRACE_IRQS_OFF
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index f3f6f53..f09c334 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -42,6 +42,7 @@
*/
#include <linux/linkage.h>
+#include <linux/err.h>
#include <asm/thread_info.h>
#include <asm/irqflags.h>
#include <asm/errno.h>
@@ -466,11 +467,10 @@ sysexit_audit:
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_ANY)
movl %eax,%edx /* second arg, syscall return value */
- cmpl $0,%eax /* is it < 0? */
- setl %al /* 1 if so, 0 if not */
+ cmpl $-MAX_ERRNO,%eax /* is it an error ? */
+ setbe %al /* 1 if so, 0 if not */
movzbl %al,%eax /* zero-extend that */
- inc %eax /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
- call audit_syscall_exit
+ call __audit_syscall_exit
DISABLE_INTERRUPTS(CLBR_ANY)
TRACE_IRQS_OFF
movl TI_flags(%ebp), %ecx
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index faf8d5e..e3c399f 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -55,6 +55,7 @@
#include <asm/paravirt.h>
#include <asm/ftrace.h>
#include <asm/percpu.h>
+#include <linux/err.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
#include <linux/elf-em.h>
@@ -565,17 +566,16 @@ auditsys:
jmp system_call_fastpath
/*
- * Return fast path for syscall audit. Call audit_syscall_exit()
+ * Return fast path for syscall audit. Call __audit_syscall_exit()
* directly and then jump back to the fast path with TIF_SYSCALL_AUDIT
* masked off.
*/
sysret_audit:
movq RAX-ARGOFFSET(%rsp),%rsi /* second arg, syscall return value */
- cmpq $0,%rsi /* is it < 0? */
- setl %al /* 1 if so, 0 if not */
+ cmpq $-MAX_ERRNO,%rsi /* is it < -MAX_ERRNO? */
+ setbe %al /* 1 if so, 0 if not */
movzbl %al,%edi /* zero-extend that into %edi */
- inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
- call audit_syscall_exit
+ call __audit_syscall_exit
movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
jmp sysret_check
#endif /* CONFIG_AUDITSYSCALL */
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 89a04c7..8b02187 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1414,8 +1414,7 @@ void syscall_trace_leave(struct pt_regs *regs)
{
bool step;
- if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
+ audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->ax);
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 863f875..af17e1c 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -335,9 +335,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
if (info->flags & VM86_SCREEN_BITMAP)
mark_screen_rdonly(tsk->mm);
- /*call audit_syscall_exit since we do not exit via the normal paths */
+ /*call __audit_syscall_exit since we do not exit via the normal paths */
if (unlikely(current->audit_context))
- audit_syscall_exit(AUDITSC_RESULT(0), 0);
+ __audit_syscall_exit(1, 0);
__asm__ __volatile__(
"movl %0,%%esp\n\t"
diff --git a/arch/x86/um/shared/sysdep/ptrace_32.h b/arch/x86/um/shared/sysdep/ptrace_32.h
index befd1df..0ee4005 100644
--- a/arch/x86/um/shared/sysdep/ptrace_32.h
+++ b/arch/x86/um/shared/sysdep/ptrace_32.h
@@ -109,6 +109,11 @@ struct syscall_args {
#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+static inline long regs_return_value(struct uml_pt_regs *regs)
+{
+ return UPT_SYSCALL_RET(regs);
+}
+
extern void arch_init_registers(int pid);
#endif
diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h
index 031edc5..5682cad 100644
--- a/arch/x86/um/shared/sysdep/ptrace_64.h
+++ b/arch/x86/um/shared/sysdep/ptrace_64.h
@@ -150,6 +150,11 @@ struct syscall_args {
#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+static inline long regs_return_value(struct uml_pt_regs *regs)
+{
+ return UPT_SYSCALL_RET(regs);
+}
+
static inline void arch_init_registers(int pid)
{
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 24851b5..8c77764 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -26,6 +26,7 @@
#include <linux/types.h>
#include <linux/elf-em.h>
+#include <linux/ptrace.h>
/* The netlink messages for the audit system is divided into blocks:
* 1000 - 1099 are for commanding the audit system
@@ -408,10 +409,6 @@ struct audit_field {
void *lsm_rule;
};
-#define AUDITSC_INVALID 0
-#define AUDITSC_SUCCESS 1
-#define AUDITSC_FAILURE 2
-#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
extern int __init audit_register_class(int class, unsigned *list);
extern int audit_classify_syscall(int abi, unsigned syscall);
extern int audit_classify_arch(int arch);
@@ -424,7 +421,7 @@ extern void audit_free(struct task_struct *task);
extern void audit_syscall_entry(int arch,
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
-extern void audit_syscall_exit(int failed, long return_code);
+extern void __audit_syscall_exit(int ret_success, long ret_value);
extern void __audit_getname(const char *name);
extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct dentry *dentry);
@@ -438,6 +435,15 @@ static inline int audit_dummy_context(void)
void *p = current->audit_context;
return !p || *(int *)p;
}
+static inline void audit_syscall_exit(void *pt_regs)
+{
+ if (unlikely(current->audit_context)) {
+ int success = is_syscall_success(pt_regs);
+ int return_code = regs_return_value(pt_regs);
+
+ __audit_syscall_exit(success, return_code);
+ }
+}
static inline void audit_getname(const char *name)
{
if (unlikely(!audit_dummy_context()))
@@ -551,12 +557,12 @@ static inline void audit_mmap_fd(int fd, int flags)
extern int audit_n_rules;
extern int audit_signals;
-#else
+#else /* CONFIG_AUDITSYSCALL */
#define audit_finish_fork(t)
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0)
-#define audit_syscall_exit(f,r) do { ; } while (0)
+#define audit_syscall_exit(r) do { ; } while (0)
#define audit_dummy_context() 1
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
@@ -587,7 +593,7 @@ extern int audit_signals;
#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
#define audit_signals 0
-#endif
+#endif /* CONFIG_AUDITSYSCALL */
#ifdef CONFIG_AUDIT
/* These are defined in audit.c */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 800f113..dd4cefa 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -112,6 +112,7 @@
#include <linux/compiler.h> /* For unlikely. */
#include <linux/sched.h> /* For struct task_struct. */
+#include <linux/err.h> /* for IS_ERR_VALUE */
extern long arch_ptrace(struct task_struct *child, long request,
@@ -265,6 +266,15 @@ static inline void ptrace_release_task(struct task_struct *task)
#define force_successful_syscall_return() do { } while (0)
#endif
+#ifndef is_syscall_success
+/*
+ * On most systems we can tell if a syscall is a success based on if the retval
+ * is an error value. On some systems like ia64 and powerpc they have different
+ * indicators of success/failure and must define their own.
+ */
+#define is_syscall_success(regs) (!IS_ERR_VALUE((unsigned long)(regs_return_value(regs))))
+#endif
+
/*
* <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__.
*
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index a0785cf..1cad28e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -70,6 +70,11 @@
#include "audit.h"
+/* flags stating the success for a syscall */
+#define AUDITSC_INVALID 0
+#define AUDITSC_SUCCESS 1
+#define AUDITSC_FAILURE 2
+
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
* for saving names from getname(). If we get more names we will allocate
* a name dynamically and also add those to the list anchored by names_list. */
@@ -1724,8 +1729,7 @@ void audit_finish_fork(struct task_struct *child)
/**
* audit_syscall_exit - deallocate audit context after a system call
- * @valid: success/failure flag
- * @return_code: syscall return value
+ * @pt_regs: syscall registers
*
* Tear down after system call. If the audit context has been marked as
* auditable (either because of the AUDIT_RECORD_CONTEXT state from
@@ -1733,13 +1737,17 @@ void audit_finish_fork(struct task_struct *child)
* message), then write out the syscall information. In call cases,
* free the names stored from getname().
*/
-void audit_syscall_exit(int valid, long return_code)
+void __audit_syscall_exit(int success, long return_code)
{
struct task_struct *tsk = current;
struct audit_context *context;
- context = audit_get_context(tsk, valid, return_code);
+ if (success)
+ success = AUDITSC_SUCCESS;
+ else
+ success = AUDITSC_FAILURE;
+ context = audit_get_context(tsk, success, return_code);
if (likely(!context))
return;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 07/26] audit: ia32entry.S sign extend error codes when calling 64 bit code
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (4 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 06/26] Audit: push audit success and retcode into arch ptrace.h Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 08/26] audit: inline audit_syscall_entry to reduce burdon on archs Eric Paris
` (18 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
In the ia32entry syscall exit audit fastpath we have assembly code which calls
__audit_syscall_exit directly. This code was, however, zeroes the upper 32
bits of the return code. It then proceeded to call code which expects longs
to be 64bits long. In order to handle code which expects longs to be 64bit we
sign extend the return code if that code is an error. Thus the
__audit_syscall_exit function can correctly handle using the values in
snprintf("%ld"). This fixes the regression introduced in 5cbf1565f29eb57a86a.
Old record:
type=SYSCALL msg=audit(1306197182.256:281): arch=40000003 syscall=192 success=no exit=4294967283
New record:
type=SYSCALL msg=audit(1306197182.256:281): arch=40000003 syscall=192 success=no exit=-13
Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: H. Peter Anvin <hpa@zytor.com>
---
arch/x86/ia32/ia32entry.S | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 1c03202..da8ac87 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -212,7 +212,9 @@ sysexit_from_sys_call:
sti
movl %eax,%esi /* second arg, syscall return value */
cmpl $-MAX_ERRNO,%eax /* is it an error ? */
- setbe %al /* 1 if so, 0 if not */
+ jbe 1f
+ movslq %eax, %rsi /* if error sign extend to 64 bits */
+1: setbe %al /* 1 if error, 0 if not */
movzbl %al,%edi /* zero-extend that into %edi */
call __audit_syscall_exit
GET_THREAD_INFO(%r10)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 08/26] audit: inline audit_syscall_entry to reduce burdon on archs
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (5 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 07/26] audit: ia32entry.S sign extend error codes when calling 64 bit code Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 09/26] audit: remove AUDIT_SETUP_CONTEXT as it isn't used Eric Paris
` (17 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Every arch calls:
if (unlikely(current->audit_context))
audit_syscall_entry()
which requires knowledge about audit (the existance of audit_context) in
the arch code. Just do it all in static inline in audit.h so that arch's
can remain blissfully ignorant.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
arch/ia64/kernel/ptrace.c | 9 +--------
arch/microblaze/kernel/ptrace.c | 6 ++----
arch/mips/kernel/ptrace.c | 7 +++----
arch/powerpc/kernel/ptrace.c | 26 ++++++++++++--------------
arch/s390/kernel/ptrace.c | 11 +++++------
arch/sh/kernel/ptrace_32.c | 7 +++----
arch/sh/kernel/ptrace_64.c | 7 +++----
arch/sparc/kernel/ptrace_64.c | 17 ++++++++---------
arch/um/kernel/ptrace.c | 20 +++++++++-----------
arch/x86/ia32/ia32entry.S | 2 +-
arch/x86/kernel/entry_32.S | 2 +-
arch/x86/kernel/entry_64.S | 4 ++--
arch/x86/kernel/ptrace.c | 22 ++++++++++------------
arch/xtensa/kernel/ptrace.c | 3 +--
include/linux/audit.h | 13 ++++++++++---
kernel/auditsc.c | 2 +-
16 files changed, 72 insertions(+), 86 deletions(-)
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 2c15408..dad9166 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1246,15 +1246,8 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
if (test_thread_flag(TIF_RESTORE_RSE))
ia64_sync_krbs();
- if (unlikely(current->audit_context)) {
- long syscall;
- int arch;
- syscall = regs.r15;
- arch = AUDIT_ARCH_IA64;
-
- audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3);
- }
+ audit_syscall_entry(AUDIT_ARCH_IA64, regs.r15, arg0, arg1, arg2, arg3);
return 0;
}
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index f564b1b..6eb2aa9 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -147,10 +147,8 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
*/
ret = -1L;
- if (unlikely(current->audit_context))
- audit_syscall_entry(EM_MICROBLAZE, regs->r12,
- regs->r5, regs->r6,
- regs->r7, regs->r8);
+ audit_syscall_entry(EM_MICROBLAZE, regs->r12, regs->r5, regs->r6,
+ regs->r7, regs->r8);
return ret ?: regs->r12;
}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index ab0f196..7786b60 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -560,10 +560,9 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
}
out:
- if (unlikely(current->audit_context))
- audit_syscall_entry(audit_arch(), regs->regs[2],
- regs->regs[4], regs->regs[5],
- regs->regs[6], regs->regs[7]);
+ audit_syscall_entry(audit_arch(), regs->regs[2],
+ regs->regs[4], regs->regs[5],
+ regs->regs[6], regs->regs[7]);
}
/*
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 09d31c1..5b43325 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1724,22 +1724,20 @@ long do_syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->gpr[0]);
- if (unlikely(current->audit_context)) {
#ifdef CONFIG_PPC64
- if (!is_32bit_task())
- audit_syscall_entry(AUDIT_ARCH_PPC64,
- regs->gpr[0],
- regs->gpr[3], regs->gpr[4],
- regs->gpr[5], regs->gpr[6]);
- else
+ if (!is_32bit_task())
+ audit_syscall_entry(AUDIT_ARCH_PPC64,
+ regs->gpr[0],
+ regs->gpr[3], regs->gpr[4],
+ regs->gpr[5], regs->gpr[6]);
+ else
#endif
- audit_syscall_entry(AUDIT_ARCH_PPC,
- regs->gpr[0],
- regs->gpr[3] & 0xffffffff,
- regs->gpr[4] & 0xffffffff,
- regs->gpr[5] & 0xffffffff,
- regs->gpr[6] & 0xffffffff);
- }
+ audit_syscall_entry(AUDIT_ARCH_PPC,
+ regs->gpr[0],
+ regs->gpr[3] & 0xffffffff,
+ regs->gpr[4] & 0xffffffff,
+ regs->gpr[5] & 0xffffffff,
+ regs->gpr[6] & 0xffffffff);
return ret ?: regs->gpr[0];
}
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 0045a30..0747c69 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -752,12 +752,11 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->gprs[2]);
- if (unlikely(current->audit_context))
- audit_syscall_entry(is_compat_task() ?
- AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
- regs->gprs[2], regs->orig_gpr2,
- regs->gprs[3], regs->gprs[4],
- regs->gprs[5]);
+ audit_syscall_entry(is_compat_task() ?
+ AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
+ regs->gprs[2], regs->orig_gpr2,
+ regs->gprs[3], regs->gprs[4],
+ regs->gprs[5]);
return ret ?: regs->gprs[2];
}
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index c0b5c17..a3e6515 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -518,10 +518,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->regs[0]);
- if (unlikely(current->audit_context))
- audit_syscall_entry(audit_arch(), regs->regs[3],
- regs->regs[4], regs->regs[5],
- regs->regs[6], regs->regs[7]);
+ audit_syscall_entry(audit_arch(), regs->regs[3],
+ regs->regs[4], regs->regs[5],
+ regs->regs[6], regs->regs[7]);
return ret ?: regs->regs[0];
}
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index ba720d6..3d0080b 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -536,10 +536,9 @@ asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->regs[9]);
- if (unlikely(current->audit_context))
- audit_syscall_entry(audit_arch(), regs->regs[1],
- regs->regs[2], regs->regs[3],
- regs->regs[4], regs->regs[5]);
+ audit_syscall_entry(audit_arch(), regs->regs[1],
+ regs->regs[2], regs->regs[3],
+ regs->regs[4], regs->regs[5]);
return ret ?: regs->regs[9];
}
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index c73c8c5..9388844 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -1071,15 +1071,14 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->u_regs[UREG_G1]);
- if (unlikely(current->audit_context) && !ret)
- audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
- AUDIT_ARCH_SPARC :
- AUDIT_ARCH_SPARC64),
- regs->u_regs[UREG_G1],
- regs->u_regs[UREG_I0],
- regs->u_regs[UREG_I1],
- regs->u_regs[UREG_I2],
- regs->u_regs[UREG_I3]);
+ audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
+ AUDIT_ARCH_SPARC :
+ AUDIT_ARCH_SPARC64),
+ regs->u_regs[UREG_G1],
+ regs->u_regs[UREG_I0],
+ regs->u_regs[UREG_I1],
+ regs->u_regs[UREG_I2],
+ regs->u_regs[UREG_I3]);
return ret;
}
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 2ccf25c..06b1903 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -167,17 +167,15 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit)
int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
int tracesysgood;
- if (unlikely(current->audit_context)) {
- if (!entryexit)
- audit_syscall_entry(HOST_AUDIT_ARCH,
- UPT_SYSCALL_NR(regs),
- UPT_SYSCALL_ARG1(regs),
- UPT_SYSCALL_ARG2(regs),
- UPT_SYSCALL_ARG3(regs),
- UPT_SYSCALL_ARG4(regs));
- else
- audit_syscall_exit(regs);
- }
+ if (!entryexit)
+ audit_syscall_entry(HOST_AUDIT_ARCH,
+ UPT_SYSCALL_NR(regs),
+ UPT_SYSCALL_ARG1(regs),
+ UPT_SYSCALL_ARG2(regs),
+ UPT_SYSCALL_ARG3(regs),
+ UPT_SYSCALL_ARG4(regs));
+ else
+ audit_syscall_exit(regs);
/* Fake a debug trap */
if (is_singlestep)
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index da8ac87..45d4530 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -194,7 +194,7 @@ sysexit_from_sys_call:
movl %ebx,%edx /* 3rd arg: 1st syscall arg */
movl %eax,%esi /* 2nd arg: syscall number */
movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */
- call audit_syscall_entry
+ call __audit_syscall_entry
movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */
cmpq $(IA32_NR_syscalls-1),%rax
ja ia32_badsys
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index f09c334..ae61075 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -456,7 +456,7 @@ sysenter_audit:
movl %ebx,%ecx /* 3rd arg: 1st syscall arg */
movl %eax,%edx /* 2nd arg: syscall number */
movl $AUDIT_ARCH_I386,%eax /* 1st arg: audit arch */
- call audit_syscall_entry
+ call __audit_syscall_entry
pushl_cfi %ebx
movl PT_EAX(%esp),%eax /* reload syscall number */
jmp sysenter_do_call
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index e3c399f..1b52df6 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -551,7 +551,7 @@ badsys:
#ifdef CONFIG_AUDITSYSCALL
/*
* Fast path for syscall audit without full syscall trace.
- * We just call audit_syscall_entry() directly, and then
+ * We just call __audit_syscall_entry() directly, and then
* jump back to the normal fast path.
*/
auditsys:
@@ -561,7 +561,7 @@ auditsys:
movq %rdi,%rdx /* 3rd arg: 1st syscall arg */
movq %rax,%rsi /* 2nd arg: syscall number */
movl $AUDIT_ARCH_X86_64,%edi /* 1st arg: audit arch */
- call audit_syscall_entry
+ call __audit_syscall_entry
LOAD_ARGS 0 /* reload call-clobbered registers */
jmp system_call_fastpath
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 8b02187..5026738 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1392,20 +1392,18 @@ long syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->orig_ax);
- if (unlikely(current->audit_context)) {
- if (IS_IA32)
- audit_syscall_entry(AUDIT_ARCH_I386,
- regs->orig_ax,
- regs->bx, regs->cx,
- regs->dx, regs->si);
+ if (IS_IA32)
+ audit_syscall_entry(AUDIT_ARCH_I386,
+ regs->orig_ax,
+ regs->bx, regs->cx,
+ regs->dx, regs->si);
#ifdef CONFIG_X86_64
- else
- audit_syscall_entry(AUDIT_ARCH_X86_64,
- regs->orig_ax,
- regs->di, regs->si,
- regs->dx, regs->r10);
+ else
+ audit_syscall_entry(AUDIT_ARCH_X86_64,
+ regs->orig_ax,
+ regs->di, regs->si,
+ regs->dx, regs->r10);
#endif
- }
return ret ?: regs->orig_ax;
}
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index a0d042a..2dff698 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -334,8 +334,7 @@ void do_syscall_trace_enter(struct pt_regs *regs)
do_syscall_trace();
#if 0
- if (unlikely(current->audit_context))
- audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
+ audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
#endif
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 8c77764..83e4c02 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -418,9 +418,9 @@ extern int audit_classify_arch(int arch);
extern void audit_finish_fork(struct task_struct *child);
extern int audit_alloc(struct task_struct *task);
extern void audit_free(struct task_struct *task);
-extern void audit_syscall_entry(int arch,
- int major, unsigned long a0, unsigned long a1,
- unsigned long a2, unsigned long a3);
+extern void __audit_syscall_entry(int arch,
+ int major, unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
extern void __audit_getname(const char *name);
extern void audit_putname(const char *name);
@@ -435,6 +435,13 @@ static inline int audit_dummy_context(void)
void *p = current->audit_context;
return !p || *(int *)p;
}
+static inline void audit_syscall_entry(int arch, int major, unsigned long a0,
+ unsigned long a1, unsigned long a2,
+ unsigned long a3)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_syscall_entry(arch, major, a0, a1, a2, a3);
+}
static inline void audit_syscall_exit(void *pt_regs)
{
if (unlikely(current->audit_context)) {
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 1cad28e..5e89b60 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1632,7 +1632,7 @@ void audit_free(struct task_struct *tsk)
* will only be written if another part of the kernel requests that it
* be written).
*/
-void audit_syscall_entry(int arch, int major,
+void __audit_syscall_entry(int arch, int major,
unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4)
{
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 09/26] audit: remove AUDIT_SETUP_CONTEXT as it isn't used
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (6 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 08/26] audit: inline audit_syscall_entry to reduce burdon on archs Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 10/26] audit: drop some potentially inadvisable likely notations Eric Paris
` (16 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Audit contexts have 3 states. Disabled, which doesn't collect anything,
build, which collects info but might not emit it, and record, which
collects and emits. There is a 4th state, setup, which isn't used. Get
rid of it.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/audit.h | 6 +-----
1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/kernel/audit.h b/kernel/audit.h
index 91e7071..8167668 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -36,12 +36,8 @@ enum audit_state {
AUDIT_DISABLED, /* Do not create per-task audit_context.
* No syscall-specific audit records can
* be generated. */
- AUDIT_SETUP_CONTEXT, /* Create the per-task audit_context,
- * but don't necessarily fill it in at
- * syscall entry time (i.e., filter
- * instead). */
AUDIT_BUILD_CONTEXT, /* Create the per-task audit_context,
- * and always fill it in at syscall
+ * and fill it in at syscall
* entry time. This makes a full
* syscall record available if some
* other part of the kernel decides it
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 10/26] audit: drop some potentially inadvisable likely notations
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (7 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 09/26] audit: remove AUDIT_SETUP_CONTEXT as it isn't used Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 11/26] audit: inline checks for not needing to collect aux records Eric Paris
` (15 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
The audit code makes heavy use of likely() and unlikely() macros, but they
don't always make sense. Drop any that seem questionable and let the
computer do it's thing.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditsc.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 5e89b60..e6f0e1e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -805,7 +805,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
{
struct audit_context *context = tsk->audit_context;
- if (likely(!context))
+ if (!context)
return NULL;
context->return_valid = return_valid;
@@ -928,7 +928,7 @@ int audit_alloc(struct task_struct *tsk)
return 0; /* Return if not auditing. */
state = audit_filter_task(tsk, &key);
- if (likely(state == AUDIT_DISABLED))
+ if (state == AUDIT_DISABLED)
return 0;
if (!(context = audit_alloc_context(state))) {
@@ -1599,7 +1599,7 @@ void audit_free(struct task_struct *tsk)
struct audit_context *context;
context = audit_get_context(tsk, 0, 0);
- if (likely(!context))
+ if (!context)
return;
/* Check for system calls that do not go through the exit
@@ -1640,7 +1640,7 @@ void __audit_syscall_entry(int arch, int major,
struct audit_context *context = tsk->audit_context;
enum audit_state state;
- if (unlikely(!context))
+ if (!context)
return;
/*
@@ -1697,7 +1697,7 @@ void __audit_syscall_entry(int arch, int major,
context->prio = 0;
state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
}
- if (likely(state == AUDIT_DISABLED))
+ if (state == AUDIT_DISABLED)
return;
context->serial = 0;
@@ -1748,7 +1748,7 @@ void __audit_syscall_exit(int success, long return_code)
success = AUDITSC_FAILURE;
context = audit_get_context(tsk, success, return_code);
- if (likely(!context))
+ if (!context)
return;
if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 11/26] audit: inline checks for not needing to collect aux records
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (8 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 10/26] audit: drop some potentially inadvisable likely notations Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 12/26] audit: drop audit_set_macxattr as it doesn't do anything Eric Paris
` (14 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
A number of audit hooks make function calls before they determine that
auxilary records do not need to be collected. Do those checks as static
inlines since the most common case is going to be that records are not
needed and we can skip the function call overhead.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 23 ++++++++++++++++++++---
kernel/auditsc.c | 15 +++------------
2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 83e4c02..68df4f4 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -489,9 +489,9 @@ extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern void audit_log_task_context(struct audit_buffer *ab);
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
-extern int audit_bprm(struct linux_binprm *bprm);
-extern void audit_socketcall(int nargs, unsigned long *args);
-extern int audit_sockaddr(int len, void *addr);
+extern int __audit_bprm(struct linux_binprm *bprm);
+extern void __audit_socketcall(int nargs, unsigned long *args);
+extern int __audit_sockaddr(int len, void *addr);
extern void __audit_fd_pair(int fd1, int fd2);
extern int audit_set_macxattr(const char *name);
extern void __audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr);
@@ -519,6 +519,23 @@ static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid
if (unlikely(!audit_dummy_context()))
__audit_ipc_set_perm(qbytes, uid, gid, mode);
}
+static inline int audit_bprm(struct linux_binprm *bprm)
+{
+ if (unlikely(!audit_dummy_context()))
+ return __audit_bprm(bprm);
+ return 0;
+}
+static inline void audit_socketcall(int nargs, unsigned long *args)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_socketcall(nargs, args);
+}
+static inline int audit_sockaddr(int len, void *addr)
+{
+ if (unlikely(!audit_dummy_context()))
+ return __audit_sockaddr(len, addr);
+ return 0;
+}
static inline void audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr)
{
if (unlikely(!audit_dummy_context()))
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e6f0e1e..d600146 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2309,14 +2309,11 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mod
context->ipc.has_perm = 1;
}
-int audit_bprm(struct linux_binprm *bprm)
+int __audit_bprm(struct linux_binprm *bprm)
{
struct audit_aux_data_execve *ax;
struct audit_context *context = current->audit_context;
- if (likely(!audit_enabled || !context || context->dummy))
- return 0;
-
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax)
return -ENOMEM;
@@ -2337,13 +2334,10 @@ int audit_bprm(struct linux_binprm *bprm)
* @args: args array
*
*/
-void audit_socketcall(int nargs, unsigned long *args)
+void __audit_socketcall(int nargs, unsigned long *args)
{
struct audit_context *context = current->audit_context;
- if (likely(!context || context->dummy))
- return;
-
context->type = AUDIT_SOCKETCALL;
context->socketcall.nargs = nargs;
memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long));
@@ -2369,13 +2363,10 @@ void __audit_fd_pair(int fd1, int fd2)
*
* Returns 0 for success or NULL context or < 0 on error.
*/
-int audit_sockaddr(int len, void *a)
+int __audit_sockaddr(int len, void *a)
{
struct audit_context *context = current->audit_context;
- if (likely(!context || context->dummy))
- return 0;
-
if (!context->sockaddr) {
void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);
if (!p)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 12/26] audit: drop audit_set_macxattr as it doesn't do anything
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (9 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 11/26] audit: inline checks for not needing to collect aux records Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:03 ` [PATCH 13/26] audit: inline audit_free to simplify the look of generic code Eric Paris
` (13 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
unused. deleted.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 68df4f4..d65d5ec 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -493,7 +493,6 @@ extern int __audit_bprm(struct linux_binprm *bprm);
extern void __audit_socketcall(int nargs, unsigned long *args);
extern int __audit_sockaddr(int len, void *addr);
extern void __audit_fd_pair(int fd1, int fd2);
-extern int audit_set_macxattr(const char *name);
extern void __audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr);
extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification);
@@ -606,7 +605,6 @@ extern int audit_signals;
#define audit_socketcall(n,a) ((void)0)
#define audit_fd_pair(n,a) ((void)0)
#define audit_sockaddr(len, addr) ({ 0; })
-#define audit_set_macxattr(n) do { ; } while (0)
#define audit_mq_open(o,m,a) ((void)0)
#define audit_mq_sendrecv(d,l,p,t) ((void)0)
#define audit_mq_notify(d,n) ((void)0)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 13/26] audit: inline audit_free to simplify the look of generic code
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (10 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 12/26] audit: drop audit_set_macxattr as it doesn't do anything Eric Paris
@ 2011-11-17 22:03 ` Eric Paris
2011-11-17 22:04 ` [PATCH 14/26] audit: reject entry,always rules Eric Paris
` (12 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:03 UTC (permalink / raw)
To: linux-audit; +Cc: viro
make the conditional a static inline instead of doing it in generic code.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 7 ++++++-
kernel/auditsc.c | 2 +-
kernel/exit.c | 3 +--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index d65d5ec..6bdd395 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -417,7 +417,7 @@ extern int audit_classify_arch(int arch);
/* Public API */
extern void audit_finish_fork(struct task_struct *child);
extern int audit_alloc(struct task_struct *task);
-extern void audit_free(struct task_struct *task);
+extern void __audit_free(struct task_struct *task);
extern void __audit_syscall_entry(int arch,
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
@@ -435,6 +435,11 @@ static inline int audit_dummy_context(void)
void *p = current->audit_context;
return !p || *(int *)p;
}
+static inline void audit_free(struct task_struct *task)
+{
+ if (unlikely(task->audit_context))
+ __audit_free(task);
+}
static inline void audit_syscall_entry(int arch, int major, unsigned long a0,
unsigned long a1, unsigned long a2,
unsigned long a3)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d600146..f13f3fe 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1594,7 +1594,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
*
* Called from copy_process and do_exit
*/
-void audit_free(struct task_struct *tsk)
+void __audit_free(struct task_struct *tsk)
{
struct audit_context *context;
diff --git a/kernel/exit.c b/kernel/exit.c
index 7136fa5..369a9f6 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -965,8 +965,7 @@ void do_exit(long code)
acct_collect(code, group_dead);
if (group_dead)
tty_audit_exit();
- if (unlikely(tsk->audit_context))
- audit_free(tsk);
+ audit_free(tsk);
tsk->exit_code = code;
taskstats_exit(tsk, group_dead);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 14/26] audit: reject entry,always rules
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (11 preceding siblings ...)
2011-11-17 22:03 ` [PATCH 13/26] audit: inline audit_free to simplify the look of generic code Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 15/26] audit: remove audit_finish_fork as it can't be called Eric Paris
` (11 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
We deprecated entry,always rules a long time ago. Reject those rules as
invalid.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditfilter.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index d94dde8..903caa2 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -235,13 +235,15 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
switch(listnr) {
default:
goto exit_err;
- case AUDIT_FILTER_USER:
- case AUDIT_FILTER_TYPE:
#ifdef CONFIG_AUDITSYSCALL
case AUDIT_FILTER_ENTRY:
+ if (rule->action == AUDIT_ALWAYS)
+ goto exit_err;
case AUDIT_FILTER_EXIT:
case AUDIT_FILTER_TASK:
#endif
+ case AUDIT_FILTER_USER:
+ case AUDIT_FILTER_TYPE:
;
}
if (unlikely(rule->action == AUDIT_POSSIBLE)) {
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 15/26] audit: remove audit_finish_fork as it can't be called
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (12 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 14/26] audit: reject entry,always rules Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 16/26] audit: allow matching on obj_uid Eric Paris
` (10 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Audit entry,always rules are not allowed and are automatically changed in
exit,always rules in userspace. The kernel refuses to load such rules.
Thus a task in the middle of a syscall (and thus in audit_finish_fork())
can only be in one of two states: AUDIT_BUILD_CONTEXT or AUDIT_DISABLED.
Since the current task cannot be in AUDIT_RECORD_CONTEXT we aren't every
going to actually use the code in audit_finish_fork() since it will
return without doing anything. Thus drop the code.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 2 --
kernel/auditsc.c | 20 --------------------
kernel/fork.c | 2 --
3 files changed, 0 insertions(+), 24 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 6bdd395..abff67f 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -415,7 +415,6 @@ extern int audit_classify_arch(int arch);
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
/* Public API */
-extern void audit_finish_fork(struct task_struct *child);
extern int audit_alloc(struct task_struct *task);
extern void __audit_free(struct task_struct *task);
extern void __audit_syscall_entry(int arch,
@@ -586,7 +585,6 @@ static inline void audit_mmap_fd(int fd, int flags)
extern int audit_n_rules;
extern int audit_signals;
#else /* CONFIG_AUDITSYSCALL */
-#define audit_finish_fork(t)
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f13f3fe..aa8588c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1707,26 +1707,6 @@ void __audit_syscall_entry(int arch, int major,
context->ppid = 0;
}
-void audit_finish_fork(struct task_struct *child)
-{
- struct audit_context *ctx = current->audit_context;
- struct audit_context *p = child->audit_context;
- if (!p || !ctx)
- return;
- if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT)
- return;
- p->arch = ctx->arch;
- p->major = ctx->major;
- memcpy(p->argv, ctx->argv, sizeof(ctx->argv));
- p->ctime = ctx->ctime;
- p->dummy = ctx->dummy;
- p->in_syscall = ctx->in_syscall;
- p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
- p->ppid = current->pid;
- p->prio = ctx->prio;
- p->current_state = ctx->current_state;
-}
-
/**
* audit_syscall_exit - deallocate audit context after a system call
* @pt_regs: syscall registers
diff --git a/kernel/fork.c b/kernel/fork.c
index 1c4b0e1..950518e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1528,8 +1528,6 @@ long do_fork(unsigned long clone_flags,
init_completion(&vfork);
}
- audit_finish_fork(p);
-
/*
* We set PF_STARTING at creation in case tracing wants to
* use this to distinguish a fully live task from one that
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 16/26] audit: allow matching on obj_uid
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (13 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 15/26] audit: remove audit_finish_fork as it can't be called Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 17/26] audit: allow audit matching on inode gid Eric Paris
` (9 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Allow syscall exit filter matching based on the uid of the owner of an
inode used in a syscall. aka:
auditctl -a always,exit -S open -F obj_uid=0 -F perm=wa
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 1 +
kernel/auditfilter.c | 1 +
kernel/auditsc.c | 12 ++++++++++++
3 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index abff67f..15a87f1 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -223,6 +223,7 @@
#define AUDIT_PERM 106
#define AUDIT_DIR 107
#define AUDIT_FILETYPE 108
+#define AUDIT_OBJ_UID 109
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 903caa2..13e9974 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -461,6 +461,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
case AUDIT_ARG1:
case AUDIT_ARG2:
case AUDIT_ARG3:
+ case AUDIT_OBJ_UID:
break;
case AUDIT_ARCH:
entry->rule.arch_f = f;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index aa8588c..4a231e8 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -586,6 +586,18 @@ static int audit_filter_rules(struct task_struct *tsk,
}
}
break;
+ case AUDIT_OBJ_UID:
+ if (name) {
+ result = audit_comparator(name->uid, f->op, f->val);
+ } else if (ctx) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_comparator(n->uid, f->op, f->val)) {
+ ++result;
+ break;
+ }
+ }
+ }
+ break;
case AUDIT_WATCH:
if (name)
result = audit_watch_compare(rule->watch, name->ino, name->dev);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 17/26] audit: allow audit matching on inode gid
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (14 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 16/26] audit: allow matching on obj_uid Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 18/26] audit: allow interfield comparison in audit rules Eric Paris
` (8 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Much like the ability to filter audit on the uid of an inode collected, we
should be able to filter on the gid of the inode.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 1 +
kernel/auditfilter.c | 1 +
kernel/auditsc.c | 12 ++++++++++++
3 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 15a87f1..49a19cc 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -224,6 +224,7 @@
#define AUDIT_DIR 107
#define AUDIT_FILETYPE 108
#define AUDIT_OBJ_UID 109
+#define AUDIT_OBJ_GID 110
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 13e9974..f10605c 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -462,6 +462,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
case AUDIT_ARG2:
case AUDIT_ARG3:
case AUDIT_OBJ_UID:
+ case AUDIT_OBJ_GID:
break;
case AUDIT_ARCH:
entry->rule.arch_f = f;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4a231e8..4cabcef 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -598,6 +598,18 @@ static int audit_filter_rules(struct task_struct *tsk,
}
}
break;
+ case AUDIT_OBJ_GID:
+ if (name) {
+ result = audit_comparator(name->gid, f->op, f->val);
+ } else if (ctx) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_comparator(n->gid, f->op, f->val)) {
+ ++result;
+ break;
+ }
+ }
+ }
+ break;
case AUDIT_WATCH:
if (name)
result = audit_watch_compare(rule->watch, name->ino, name->dev);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 18/26] audit: allow interfield comparison in audit rules
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (15 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 17/26] audit: allow audit matching on inode gid Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 19/26] audit: complex interfield comparison helper Eric Paris
` (7 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
We wish to be able to audit when a uid=500 task accesses a file which is
uid=0. Or vice versa. This patch introduces a new audit filter type
AUDIT_FIELD_COMPARE which takes as an 'enum' which indicates which fields
should be compared. At this point we only define the task->uid vs
inode->uid, but other comparisons can be added.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 4 ++++
kernel/auditfilter.c | 5 ++++-
kernel/auditsc.c | 29 ++++++++++++++++++++++++++++-
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 49a19cc..04295cb 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -182,7 +182,10 @@
* AUDIT_UNUSED_BITS is updated if need be. */
#define AUDIT_UNUSED_BITS 0x07FFFC00
+/* AUDIT_FIELD_COMPARE rule list */
+#define AUDIT_COMPARE_UID_TO_OBJ_UID 1
+#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_UID_TO_OBJ_UID
/* Rule fields */
/* These are useful when checking the
* task structure at task creation time
@@ -225,6 +228,7 @@
#define AUDIT_FILETYPE 108
#define AUDIT_OBJ_UID 109
#define AUDIT_OBJ_GID 110
+#define AUDIT_FIELD_COMPARE 111
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index f10605c..a6c3f1a 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -526,7 +526,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
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);
@@ -543,6 +542,10 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
if (f->val & ~S_IFMT)
goto exit_free;
break;
+ case AUDIT_FIELD_COMPARE:
+ if (f->val > AUDIT_MAX_FIELD_COMPARE)
+ goto exit_free;
+ break;
default:
goto exit_free;
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4cabcef..104967d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -463,6 +463,31 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
return 0;
}
+static int audit_field_compare(struct task_struct *tsk,
+ const struct cred *cred,
+ struct audit_field *f,
+ struct audit_context *ctx,
+ struct audit_names *name)
+{
+ struct audit_names *n;
+
+ switch (f->val) {
+ case AUDIT_COMPARE_UID_TO_OBJ_UID:
+ if (name) {
+ return audit_comparator(cred->uid, f->op, name->uid);
+ } else if (ctx) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ if (audit_comparator(cred->uid, f->op, n->uid))
+ return 1;
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+ 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.
@@ -693,8 +718,10 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_FILETYPE:
result = audit_match_filetype(ctx, f->val);
break;
+ case AUDIT_FIELD_COMPARE:
+ result = audit_field_compare(tsk, cred, f, ctx, name);
+ break;
}
-
if (!result)
return 0;
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 19/26] audit: complex interfield comparison helper
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (16 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 18/26] audit: allow interfield comparison in audit rules Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 20/26] audit: allow interfield comparison between gid and ogid Eric Paris
` (6 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Rather than code the same loop over and over implement a helper function which
uses some pointer magic to make it generic enough to be used numerous places
as we implement more audit interfield comparisons
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditsc.c | 51 ++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 104967d..848a84b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -463,25 +463,54 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
return 0;
}
+static int audit_compare_id(const struct cred *cred,
+ unsigned long cred_offset,
+ struct audit_names *name,
+ unsigned long name_offset,
+ struct audit_field *f,
+ struct audit_context *ctx)
+{
+ struct audit_names *n;
+ unsigned long addr;
+ uid_t cred_uid, name_uid;
+
+ addr = (unsigned long)cred;
+ addr += cred_offset;
+
+ cred_uid = *(uid_t *)addr;
+
+ if (name) {
+ addr = (unsigned long)name;
+ addr += name_offset;
+
+ name_uid = *(uid_t *)addr;
+ return audit_comparator(cred_uid, f->op, name_uid);
+ }
+
+ if (ctx) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ addr = (unsigned long)n;
+ addr += name_offset;
+
+ name_uid = *(uid_t *)addr;
+ if (audit_comparator(cred_uid, f->op, name_uid))
+ return 1;
+ }
+ }
+ return 0;
+}
+
static int audit_field_compare(struct task_struct *tsk,
const struct cred *cred,
struct audit_field *f,
struct audit_context *ctx,
struct audit_names *name)
{
- struct audit_names *n;
-
switch (f->val) {
case AUDIT_COMPARE_UID_TO_OBJ_UID:
- if (name) {
- return audit_comparator(cred->uid, f->op, name->uid);
- } else if (ctx) {
- list_for_each_entry(n, &ctx->names_list, list) {
- if (audit_comparator(cred->uid, f->op, n->uid))
- return 1;
- }
- }
- break;
+ return audit_compare_id(cred, offsetof(struct cred, uid),
+ name, offsetof(struct audit_names, uid),
+ f, ctx);
default:
return 0;
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 20/26] audit: allow interfield comparison between gid and ogid
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (17 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 19/26] audit: complex interfield comparison helper Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 21/26] audit: remove task argument to audit_set_loginuid Eric Paris
` (5 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Allow audit rules to compare the gid of the running task to the gid of the
inode in question.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/audit.h | 3 ++-
kernel/auditsc.c | 6 ++++++
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 04295cb..9734b1e 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -184,8 +184,9 @@
/* AUDIT_FIELD_COMPARE rule list */
#define AUDIT_COMPARE_UID_TO_OBJ_UID 1
+#define AUDIT_COMPARE_GID_TO_OBJ_GID 2
-#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_UID_TO_OBJ_UID
+#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_GID_TO_OBJ_GID
/* Rule fields */
/* These are useful when checking the
* task structure at task creation time
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 848a84b..d0b388c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -474,6 +474,8 @@ static int audit_compare_id(const struct cred *cred,
unsigned long addr;
uid_t cred_uid, name_uid;
+ BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
+
addr = (unsigned long)cred;
addr += cred_offset;
@@ -511,6 +513,10 @@ static int audit_field_compare(struct task_struct *tsk,
return audit_compare_id(cred, offsetof(struct cred, uid),
name, offsetof(struct audit_names, uid),
f, ctx);
+ case AUDIT_COMPARE_GID_TO_OBJ_GID:
+ return audit_compare_id(cred, offsetof(struct cred, gid),
+ name, offsetof(struct audit_names, gid),
+ f, ctx);
default:
return 0;
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 21/26] audit: remove task argument to audit_set_loginuid
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (18 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 20/26] audit: allow interfield comparison between gid and ogid Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 22/26] audit: only allow tasks to set their loginuid if it is -1 Eric Paris
` (4 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
The function always deals with current. Don't expose an option
pretending one can use it for something. You can't.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/proc/base.c | 2 +-
include/linux/audit.h | 2 +-
kernel/auditsc.c | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f200c72..be2b542 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1295,7 +1295,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
goto out_free_page;
}
- length = audit_set_loginuid(current, loginuid);
+ length = audit_set_loginuid(loginuid);
if (likely(length == 0))
length = count;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 9734b1e..1b4b109 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -494,7 +494,7 @@ static inline void audit_ptrace(struct task_struct *t)
extern unsigned int audit_serial(void);
extern int auditsc_get_stamp(struct audit_context *ctx,
struct timespec *t, unsigned int *serial);
-extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
+extern int audit_set_loginuid(uid_t loginuid);
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d0b388c..a3f6f3c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2225,16 +2225,16 @@ int auditsc_get_stamp(struct audit_context *ctx,
static atomic_t session_id = ATOMIC_INIT(0);
/**
- * audit_set_loginuid - set a task's audit_context loginuid
- * @task: task whose audit context is being modified
+ * audit_set_loginuid - set current task's audit_context loginuid
* @loginuid: loginuid value
*
* Returns 0.
*
* Called (set) from fs/proc/base.c::proc_loginuid_write().
*/
-int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
+int audit_set_loginuid(uid_t loginuid)
{
+ struct task_struct *task = current;
unsigned int sessionid = atomic_inc_return(&session_id);
struct audit_context *context = task->audit_context;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 22/26] audit: only allow tasks to set their loginuid if it is -1
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (19 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 21/26] audit: remove task argument to audit_set_loginuid Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 23/26] audit: do not call audit_getname on error Eric Paris
` (3 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
At the moment we allow tasks to set their loginuid if they have
CAP_AUDIT_CONTROL. In reality we want tasks to set the loginuid when they
log in and it be impossible to ever reset. We had to make it mutable even
after it was once set (with the CAP) because on update and admin might have
to restart sshd. Now sshd would get his loginuid and the next user which
logged in using ssh would not be able to set his loginuid.
Systemd has changed how userspace works and allowed us to make the kernel
work the way it should. With systemd users (even admins) are not supposed
to restart services directly. The system will restart the service for
them. Thus since systemd is going to loginuid==-1, sshd would get -1, and
sshd would be allowed to set a new loginuid without special permissions.
If an admin in this system were to manually start an sshd he is inserting
himself into the system chain of trust and thus, logically, it's his
loginuid that should be used! Since we have old systems I make this a
Kconfig option.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/proc/base.c | 3 ---
init/Kconfig | 14 ++++++++++++++
kernel/auditsc.c | 11 ++++++++++-
3 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index be2b542..c86996b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1264,9 +1264,6 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
ssize_t length;
uid_t loginuid;
- if (!capable(CAP_AUDIT_CONTROL))
- return -EPERM;
-
rcu_read_lock();
if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
rcu_read_unlock();
diff --git a/init/Kconfig b/init/Kconfig
index 6dfc8c3..a8a87e5 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -372,6 +372,20 @@ config AUDIT_TREE
depends on AUDITSYSCALL
select FSNOTIFY
+config AUDIT_LOGINUID_IMMUTABLE
+ bool "Make audit loginuid immutable"
+ depends on AUDIT
+ help
+ The config option toggles if a task setting it's loginuid requires
+ CAP_SYS_AUDITCONTROL or if that task should require no special permissions
+ but should instead only allow setting its loginuid if it was never
+ previously set. On systems which use systemd or a similar central
+ process to restart login services this should be set to true. On older
+ systems in which an admin would typically have to directly stop and
+ start processes this should be set to false. Setting this to true allows
+ one to drop potentially dangerous capabilites from the login tasks,
+ but may not be backwards compatible with older init systems.
+
source "kernel/irq/Kconfig"
menu "RCU Subsystem"
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index a3f6f3c..796dca6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2235,9 +2235,18 @@ static atomic_t session_id = ATOMIC_INIT(0);
int audit_set_loginuid(uid_t loginuid)
{
struct task_struct *task = current;
- unsigned int sessionid = atomic_inc_return(&session_id);
struct audit_context *context = task->audit_context;
+ unsigned int sessionid;
+
+#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
+ if (task->loginuid != -1)
+ return -EPERM;
+#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
+ if (!capable(CAP_AUDIT_CONTROL))
+ return -EPERM;
+#endif /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
+ sessionid = atomic_inc_return(&session_id);
if (context && context->in_syscall) {
struct audit_buffer *ab;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 23/26] audit: do not call audit_getname on error
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (20 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 22/26] audit: only allow tasks to set their loginuid if it is -1 Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:04 ` [PATCH 24/26] Kernel: Audit Support For The ARM Platform Eric Paris
` (2 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
Just a code cleanup really. We don't need to make a function call just for
it to return on error. This also makes the VFS function even easier to follow
and removes a conditional on a hot path.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/namei.c | 31 +++++++++++++++----------------
kernel/auditsc.c | 3 ---
2 files changed, 15 insertions(+), 19 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 0ba99d0..58c8d08 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -139,21 +139,20 @@ static int do_getname(const char __user *filename, char *page)
static char *getname_flags(const char __user *filename, int flags, int *empty)
{
- char *tmp, *result;
-
- result = ERR_PTR(-ENOMEM);
- tmp = __getname();
- if (tmp) {
- int retval = do_getname(filename, tmp);
-
- result = tmp;
- if (retval < 0) {
- if (retval == -ENOENT && empty)
- *empty = 1;
- if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
- __putname(tmp);
- result = ERR_PTR(retval);
- }
+ char *result;
+ int retval;
+
+ result = __getname();
+ if (!result)
+ return ERR_PTR(-ENOMEM);
+
+ retval = do_getname(filename, result);
+ if (retval < 0) {
+ if (retval == -ENOENT && empty)
+ *empty = 1;
+ if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
+ __putname(result);
+ return ERR_PTR(retval);
}
}
audit_getname(result);
@@ -162,7 +161,7 @@ static char *getname_flags(const char __user *filename, int flags, int *empty)
char *getname(const char __user * filename)
{
- return getname_flags(filename, 0, 0);
+ return getname_flags(filename, 0, NULL);
}
#ifdef CONFIG_AUDITSYSCALL
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 796dca6..fdcbc6b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1975,9 +1975,6 @@ void __audit_getname(const char *name)
struct audit_context *context = current->audit_context;
struct audit_names *n;
- if (IS_ERR(name) || !name)
- return;
-
if (!context->in_syscall) {
#if AUDIT_DEBUG == 2
printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n",
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 24/26] Kernel: Audit Support For The ARM Platform
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (21 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 23/26] audit: do not call audit_getname on error Eric Paris
@ 2011-11-17 22:04 ` Eric Paris
2011-11-17 22:05 ` [PATCH 25/26] audit: fix mark refcounting Eric Paris
2011-11-17 22:05 ` [PATCH 26/26] audit: collect path information when possible Eric Paris
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:04 UTC (permalink / raw)
To: linux-audit; +Cc: viro
From: Nathaniel Husted <nhusted@gmail.com>
This patch provides functionality to audit system call events on the
ARM platform. The implementation was based off the structure of the
MIPS platform and information in this
(http://lists.fedoraproject.org/pipermail/arm/2009-October/000382.html)
mailing list thread. The required audit_syscall_exit and
audit_syscall_entry checks were added to ptrace using the standard
registers for system call values (r0 through r3). A thread information
flag was added for auditing (TIF_SYSCALL_AUDIT) and a meta-flag was
added (_TIF_SYSCALL_WORK) to simplify modifications to the syscall
entry/exit. Now, if either the TRACE flag is set or the AUDIT flag is
set, the syscall_trace function will be executed. The prober changes
were made to Kconfig to allow CONFIG_AUDITSYSCALL to be enabled.
Due to platform availability limitations, this patch was only tested
on the Android platform running the modified "android-goldfish-2.6.29"
kernel. A test compile was performed using Code Sourcery's
cross-compilation toolset and the current linux-3.0 stable kernel. The
changes compile without error. I'm hoping, due to the simple modifications,
the patch is "obviously correct".
Signed-off-by: Nathaniel Husted <nhusted@gmail.com>
Signed-off-by: Eric Paris <eparis@redhat.com>
---
arch/arm/include/asm/kprobes.h | 1 -
arch/arm/include/asm/ptrace.h | 5 +++++
arch/arm/include/asm/thread_info.h | 6 ++++++
arch/arm/kernel/entry-common.S | 4 ++--
arch/arm/kernel/ptrace.c | 16 +++++++++++-----
init/Kconfig | 2 +-
6 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index feec867..f82ec22 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -24,7 +24,6 @@
#define MAX_INSN_SIZE 2
#define MAX_STACK_SIZE 64 /* 32 would probably be OK */
-#define regs_return_value(regs) ((regs)->ARM_r0)
#define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 96187ff..451808b 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -189,6 +189,11 @@ static inline int valid_user_regs(struct pt_regs *regs)
return 0;
}
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ return regs->ARM_r0;
+}
+
#define instruction_pointer(regs) (regs)->ARM_pc
#ifdef CONFIG_SMP
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 7b5cc8d..fd1d11f 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -129,6 +129,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
/*
* thread information flags:
* TIF_SYSCALL_TRACE - syscall trace active
+ * TIF_SYSCAL_AUDIT - syscall auditing active
* TIF_SIGPENDING - signal pending
* TIF_NEED_RESCHED - rescheduling necessary
* TIF_NOTIFY_RESUME - callback before returning to user
@@ -139,6 +140,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
#define TIF_NEED_RESCHED 1
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_SYSCALL_TRACE 8
+#define TIF_SYSCALL_AUDIT 9
#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -150,12 +152,16 @@ extern void vfp_flush_hwstate(struct thread_info *);
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#define _TIF_FREEZE (1 << TIF_FREEZE)
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+/* Checks for any syscall work in entry-common.S */
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+
/*
* Change these and you break ASM code in entry-common.S
*/
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index b2a27b6..520889c 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -87,7 +87,7 @@ ENTRY(ret_from_fork)
get_thread_info tsk
ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing
mov why, #1
- tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
+ tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
beq ret_slow_syscall
mov r1, sp
mov r0, #1 @ trace exit [IP = 1]
@@ -443,7 +443,7 @@ ENTRY(vector_swi)
1:
#endif
- tst r10, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
+ tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
bne __sys_trace
cmp scno, #NR_syscalls @ check upper syscall limit
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 483727a..e1d5e19 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -906,11 +906,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
{
unsigned long ip;
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return scno;
- if (!(current->ptrace & PT_PTRACED))
- return scno;
-
/*
* Save IP. IP is used to denote syscall entry/exit:
* IP = 0 -> entry, = 1 -> exit
@@ -918,6 +913,17 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
ip = regs->ARM_ip;
regs->ARM_ip = why;
+ if (!ip)
+ audit_syscall_exit(regs);
+ else
+ audit_syscall_entry(AUDIT_ARCH_ARMEB, scno, regs->ARM_r0,
+ regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return scno;
+ if (!(current->ptrace & PT_PTRACED))
+ return scno;
+
current_thread_info()->syscall = scno;
/* the 0x80 provides a way for the tracing parent to distinguish
diff --git a/init/Kconfig b/init/Kconfig
index a8a87e5..98ba757 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -355,7 +355,7 @@ config AUDIT
config AUDITSYSCALL
bool "Enable system-call auditing support"
- depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH)
+ depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || ARM)
default y if SECURITY_SELINUX
help
Enable low-overhead system-call auditing infrastructure that
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 25/26] audit: fix mark refcounting
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (22 preceding siblings ...)
2011-11-17 22:04 ` [PATCH 24/26] Kernel: Audit Support For The ARM Platform Eric Paris
@ 2011-11-17 22:05 ` Eric Paris
2011-11-17 22:05 ` [PATCH 26/26] audit: collect path information when possible Eric Paris
24 siblings, 0 replies; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:05 UTC (permalink / raw)
To: linux-audit; +Cc: viro
From: Miklos Szeredi <mszeredi@suse.cz>
Removing the parent of a watched file results in "kernel BUG at
fs/notify/mark.c:139".
To reproduce
add "-w /tmp/audit/dir/watched_file" to audit.rules
rm -rf /tmp/audit/dir
This is caused by fsnotify_destroy_mark() being called without an
extra reference taken by the caller.
Reported by Francesco Cosoleto here:
https://bugzilla.novell.com/show_bug.cgi?id=689860
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Al Viro <viro@zeniv.linux.org.uk>
CC: Eric Paris <eparis@redhat.com>
CC: stable@vger.kernel.org
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/audit_watch.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index e683869..4270d84 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -349,7 +349,9 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
}
mutex_unlock(&audit_filter_mutex);
+ audit_get_parent(parent);
fsnotify_destroy_mark(&parent->mark);
+ audit_put_parent(parent);
}
/* Get path information necessary for adding watches. */
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 26/26] audit: collect path information when possible
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
` (23 preceding siblings ...)
2011-11-17 22:05 ` [PATCH 25/26] audit: fix mark refcounting Eric Paris
@ 2011-11-17 22:05 ` Eric Paris
2011-11-17 22:47 ` Al Viro
24 siblings, 1 reply; 27+ messages in thread
From: Eric Paris @ 2011-11-17 22:05 UTC (permalink / raw)
To: linux-audit; +Cc: viro
For _at type syscalls (like openat) we do not collect any information about
the dfd. This patch grabs a reference to the path of all fd's passed to
the kernel. We free those on syscall exit. We will then output those paths
as inode records and use the path information to generate better pathnames if
possible.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/file_table.c | 12 ++++++
include/linux/audit.h | 12 ++++++
kernel/auditsc.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 109 insertions(+), 7 deletions(-)
diff --git a/fs/file_table.c b/fs/file_table.c
index 6f19cf5..2dceb76 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -287,6 +287,9 @@ struct file *fget(unsigned int fd)
}
rcu_read_unlock();
+ if (file)
+ audit_path(&file->f_path);
+
return file;
}
@@ -306,6 +309,9 @@ struct file *fget_raw(unsigned int fd)
}
rcu_read_unlock();
+ if (file)
+ audit_path(&file->f_path);
+
return file;
}
@@ -351,6 +357,9 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
rcu_read_unlock();
}
+ if (file)
+ audit_path(&file->f_path);
+
return file;
}
@@ -375,6 +384,9 @@ struct file *fget_raw_light(unsigned int fd, int *fput_needed)
rcu_read_unlock();
}
+ if (file)
+ audit_path(&file->f_path);
+
return file;
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 1b4b109..86f4108 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -433,6 +433,7 @@ extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct dentry *dentry);
extern void __audit_inode_child(const struct dentry *dentry,
const struct inode *parent);
+extern void __audit_path(struct path *path);
extern void __audit_seccomp(unsigned long syscall);
extern void __audit_ptrace(struct task_struct *t);
@@ -476,6 +477,13 @@ static inline void audit_inode_child(const struct dentry *dentry,
if (unlikely(!audit_dummy_context()))
__audit_inode_child(dentry, parent);
}
+
+static inline void audit_path(struct path *path)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_path(path);
+}
+
void audit_core_dumps(long signr);
static inline void audit_seccomp(unsigned long syscall)
@@ -599,10 +607,11 @@ extern int audit_signals;
#define audit_dummy_context() 1
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
-#define __audit_inode(n,d) do { ; } while (0)
+#define __audit_inode (n, d) do { ; } while (0)
#define __audit_inode_child(i,p) do { ; } while (0)
#define audit_inode(n,d) do { (void)(d); } while (0)
#define audit_inode_child(i,p) do { ; } while (0)
+#define audit_path(p) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0)
#define audit_seccomp(i) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) (0)
@@ -625,6 +634,7 @@ extern int audit_signals;
#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
#define audit_signals 0
+
#endif /* CONFIG_AUDITSYSCALL */
#ifdef CONFIG_AUDIT
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index fdcbc6b..f50c143 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -78,7 +78,7 @@
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
* for saving names from getname(). If we get more names we will allocate
* a name dynamically and also add those to the list anchored by names_list. */
-#define AUDIT_NAMES 5
+#define AUDIT_NAMES 6
/* Indicates that audit should log the full pathname. */
#define AUDIT_NAME_FULL -1
@@ -109,6 +109,7 @@ struct audit_cap_data {
struct audit_names {
struct list_head list; /* audit_context->names_list */
const char *name;
+ struct path *path;
unsigned long ino;
dev_t dev;
umode_t mode;
@@ -198,6 +199,8 @@ struct audit_context {
struct audit_names preallocated_names[AUDIT_NAMES];
int name_count; /* total records in names_list */
struct list_head names_list; /* anchor for struct audit_names->list */
+ int path_count; /* number of paths in paths[] */
+ struct path paths[AUDIT_NAMES]; /* paths held to be merged with names_list */
char * filterkey; /* key for rule that triggered record */
struct path pwd;
struct audit_context *previous; /* For nested syscalls */
@@ -961,6 +964,16 @@ static inline void audit_free_names(struct audit_context *context)
context->pwd.mnt = NULL;
}
+static inline void audit_free_paths(struct audit_context *context)
+{
+ int i;
+
+ for (i = 0; i < context->path_count; i++)
+ path_put(&context->paths[i]);
+
+ context->path_count = 0;
+}
+
static inline void audit_free_aux(struct audit_context *context)
{
struct audit_aux_data *aux;
@@ -1044,6 +1057,7 @@ static inline void audit_free_context(struct audit_context *context)
context->name_count, count);
}
audit_free_names(context);
+ audit_free_paths(context);
unroll_tree_refs(context, NULL, 0);
free_tree_refs(context);
audit_free_aux(context);
@@ -1452,6 +1466,35 @@ static void show_special(struct audit_context *context, int *call_panic)
audit_log_end(ab);
}
+static struct audit_names *____audit_inode(struct audit_context *, const char *, const struct dentry*);
+
+static void audit_merge_paths_and_names(struct audit_context *context)
+{
+ struct audit_names *n;
+ int i;
+
+ for (i = 0; i < context->path_count; i++) {
+ struct path *p;
+
+ p = &context->paths[i];
+
+ /* if this path happens to also be part of the normal name
+ * collection, why not make the full path available? */
+ list_for_each_entry(n, &context->names_list, list) {
+ if (p->dentry->d_inode->i_ino == n->ino &&
+ p->dentry->d_inode->i_sb->s_dev == n->dev) {
+ n->path = p;
+ break;
+ }
+ }
+
+ /* create a new name record with this path */
+ n = ____audit_inode(context, NULL, p->dentry);
+ if (n)
+ n->path = p;
+ }
+}
+
static void audit_log_name(struct audit_context *context, struct audit_names *n,
int record_num, int *call_panic)
{
@@ -1483,6 +1526,11 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
} else
audit_log_format(ab, " name=(null)");
+ if (n->path)
+ audit_log_d_path(ab, "path=", n->path);
+ else
+ audit_log_format(ab, " path=(null)");
+
if (n->ino != (unsigned long)-1) {
audit_log_format(ab, " inode=%lu"
" dev=%02x:%02x mode=%#o"
@@ -1662,6 +1710,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
}
}
+ audit_merge_paths_and_names(context);
+
i = 0;
list_for_each_entry(n, &context->names_list, list)
audit_log_name(context, n, i++, &call_panic);
@@ -1833,6 +1883,7 @@ void __audit_syscall_exit(int success, long return_code)
tsk->audit_context = new_context;
} else {
audit_free_names(context);
+ audit_free_paths(context);
unroll_tree_refs(context, NULL, 0);
audit_free_aux(context);
context->aux = NULL;
@@ -2082,14 +2133,14 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
*
* Called from fs/namei.c:path_lookup().
*/
-void __audit_inode(const char *name, const struct dentry *dentry)
+static struct audit_names *____audit_inode(struct audit_context *context, const char *name,
+ const struct dentry *dentry)
{
- struct audit_context *context = current->audit_context;
const struct inode *inode = dentry->d_inode;
struct audit_names *n;
if (!context->in_syscall)
- return;
+ return NULL;
list_for_each_entry_reverse(n, &context->names_list, list) {
if (n->name && (n->name == name))
@@ -2099,10 +2150,18 @@ void __audit_inode(const char *name, const struct dentry *dentry)
/* unable to find the name from a previous getname() */
n = audit_alloc_name(context);
if (!n)
- return;
+ return NULL;
out:
- handle_path(dentry);
audit_copy_inode(n, dentry, inode);
+ return n;
+}
+
+void __audit_inode(const char *name, const struct dentry *dentry)
+{
+ struct audit_context *context = current->audit_context;
+
+ ____audit_inode(context, name, dentry);
+ handle_path(dentry);
}
/**
@@ -2193,6 +2252,27 @@ add_names:
}
EXPORT_SYMBOL_GPL(__audit_inode_child);
+void __audit_path(struct path *path)
+{
+ struct audit_context *context = current->audit_context;
+ int i, path_count;
+
+ path_count = context->path_count;
+
+ if (path_count >= AUDIT_NAMES - 1)
+ return;
+
+ for (i = 0; i < path_count; i++) {
+ if (context->paths[i].dentry == path->dentry &&
+ context->paths[i].mnt == path->mnt)
+ return;
+ }
+
+ context->paths[path_count] = *path;
+ path_get(&context->paths[path_count]);
+ context->path_count++;
+}
+
/**
* auditsc_get_stamp - get local copies of audit_context values
* @ctx: audit_context for the task
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 26/26] audit: collect path information when possible
2011-11-17 22:05 ` [PATCH 26/26] audit: collect path information when possible Eric Paris
@ 2011-11-17 22:47 ` Al Viro
0 siblings, 0 replies; 27+ messages in thread
From: Al Viro @ 2011-11-17 22:47 UTC (permalink / raw)
To: Eric Paris; +Cc: linux-audit
On Thu, Nov 17, 2011 at 05:05:11PM -0500, Eric Paris wrote:
> For _at type syscalls (like openat) we do not collect any information about
> the dfd. This patch grabs a reference to the path of all fd's passed to
> the kernel. We free those on syscall exit. We will then output those paths
> as inode records and use the path information to generate better pathnames if
> possible.
I think this is bogus. If nothing else, if you want dfd, then by damn
collect that information *when* *you* *are* *starting* *a* *lookup*.
Not on every bleeding fget(), no matter why and by whom had it been called.
FWIW, hooking into getname() also had always looked wrong, for much the
same reasons...
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2011-11-17 22:47 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-17 22:02 [PATCH 01/26] audit: make filetype matching consistent with other filters Eric Paris
2011-11-17 22:02 ` [PATCH 02/26] audit: dynamically allocate audit_names when not enough space is in the names array Eric Paris
2011-11-17 22:02 ` [PATCH 03/26] audit: drop the meaningless and format breaking word 'user' Eric Paris
2011-11-17 22:03 ` [PATCH 04/26] audit: check current inode and containing object when filtering on major and minor Eric Paris
2011-11-17 22:03 ` [PATCH 05/26] seccomp: audit abnormal end to a process due to seccomp Eric Paris
2011-11-17 22:03 ` [PATCH 06/26] Audit: push audit success and retcode into arch ptrace.h Eric Paris
2011-11-17 22:03 ` [PATCH 07/26] audit: ia32entry.S sign extend error codes when calling 64 bit code Eric Paris
2011-11-17 22:03 ` [PATCH 08/26] audit: inline audit_syscall_entry to reduce burdon on archs Eric Paris
2011-11-17 22:03 ` [PATCH 09/26] audit: remove AUDIT_SETUP_CONTEXT as it isn't used Eric Paris
2011-11-17 22:03 ` [PATCH 10/26] audit: drop some potentially inadvisable likely notations Eric Paris
2011-11-17 22:03 ` [PATCH 11/26] audit: inline checks for not needing to collect aux records Eric Paris
2011-11-17 22:03 ` [PATCH 12/26] audit: drop audit_set_macxattr as it doesn't do anything Eric Paris
2011-11-17 22:03 ` [PATCH 13/26] audit: inline audit_free to simplify the look of generic code Eric Paris
2011-11-17 22:04 ` [PATCH 14/26] audit: reject entry,always rules Eric Paris
2011-11-17 22:04 ` [PATCH 15/26] audit: remove audit_finish_fork as it can't be called Eric Paris
2011-11-17 22:04 ` [PATCH 16/26] audit: allow matching on obj_uid Eric Paris
2011-11-17 22:04 ` [PATCH 17/26] audit: allow audit matching on inode gid Eric Paris
2011-11-17 22:04 ` [PATCH 18/26] audit: allow interfield comparison in audit rules Eric Paris
2011-11-17 22:04 ` [PATCH 19/26] audit: complex interfield comparison helper Eric Paris
2011-11-17 22:04 ` [PATCH 20/26] audit: allow interfield comparison between gid and ogid Eric Paris
2011-11-17 22:04 ` [PATCH 21/26] audit: remove task argument to audit_set_loginuid Eric Paris
2011-11-17 22:04 ` [PATCH 22/26] audit: only allow tasks to set their loginuid if it is -1 Eric Paris
2011-11-17 22:04 ` [PATCH 23/26] audit: do not call audit_getname on error Eric Paris
2011-11-17 22:04 ` [PATCH 24/26] Kernel: Audit Support For The ARM Platform Eric Paris
2011-11-17 22:05 ` [PATCH 25/26] audit: fix mark refcounting Eric Paris
2011-11-17 22:05 ` [PATCH 26/26] audit: collect path information when possible Eric Paris
2011-11-17 22:47 ` Al Viro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox