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. Another
problem with this overloading interface is that the most interesting
event type where it might be needed, rename(), won't work. The first
two names collected are both the parent directory, not either of the
inodes actually being renamed.
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.
Signed-off-by: Eric Paris <eparis(a)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 f5e4cae..5ed85aa 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -384,7 +384,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:
@@ -535,7 +535,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 f286982..92212c4 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -300,21 +300,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;
}
/*