auditctl -a exit,always -F arch=b64 -C 'euid!=uid' -S execve -F 'euid!=0' -F 'success=1'
which would audit on someone executing a setuid binary if the binary isn't setuid root.
auditctl -a exit,always -F arch=b64 -C 'obj_uid!=uid' -F 'uid!=0' -F 'dir=/home/' -F 'success=1' -S open -F 'a2&=2'
One strange thing related to this patch: auditd seems to be reporting success for a normal user process (gklrellm) opening /proc/meminfo (mode 444) O_RDWR, and I don't see how this is possible. eg:
hopefully someone with more auditd internal knowledge can explain what's going on.
auditctl -l doesn't know how to report this yet; if this patch is generally acceptable, I can try to fix that and update the manpage, etc.
---
trunk/auparse/typetab.h | 1 +
trunk/lib/fieldtab.h | 1 +
trunk/lib/libaudit.c | 144 +++++++++++++++++++++++++++++++++++++++++++
trunk/lib/libaudit.h | 2 +
trunk/src/auditctl.c | 19 +++++-
trunk/src/ausearch-report.c | 1 +
6 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/trunk/auparse/typetab.h b/trunk/auparse/typetab.h
index 746573c..3e6c6d1 100644
--- a/trunk/auparse/typetab.h
+++ b/trunk/auparse/typetab.h
@@ -32,6 +32,7 @@ _S(AUPARSE_TYPE_UID, "iuid" )
_S(AUPARSE_TYPE_UID, "id" )
_S(AUPARSE_TYPE_UID, "inode_uid" )
_S(AUPARSE_TYPE_UID, "sauid" )
+_S(AUPARSE_TYPE_UID, "obj_uid" )
_S(AUPARSE_TYPE_GID, "gid" )
_S(AUPARSE_TYPE_GID, "egid" )
_S(AUPARSE_TYPE_GID, "sgid" )
diff --git a/trunk/lib/fieldtab.h b/trunk/lib/fieldtab.h
index ad95814..e053df6 100644
--- a/trunk/lib/fieldtab.h
+++ b/trunk/lib/fieldtab.h
@@ -55,6 +55,7 @@ _S(AUDIT_WATCH, "path" )
_S(AUDIT_PERM, "perm" )
_S(AUDIT_DIR, "dir" )
_S(AUDIT_FILETYPE, "filetype" )
+_S(AUDIT_OBJ_UID, "obj_uid" )
_S(AUDIT_ARG0, "a0" )
_S(AUDIT_ARG1, "a1" )
diff --git a/trunk/lib/libaudit.c b/trunk/lib/libaudit.c
index 9a5070c..b10f984 100644
--- a/trunk/lib/libaudit.c
+++ b/trunk/lib/libaudit.c
@@ -783,6 +783,148 @@ int audit_rule_syscallbyname_data(struct audit_rule_data *rule,
}
hidden_def(audit_rule_syscallbyname_data)
+int audit_rule_interfield_fieldpair_data(struct audit_rule_data **rulep,
+ const char *pair,
+ int flags) {
+ const char *f = pair;
+ char *v;
+ int op;
+ int field1, field2;
+ int vlen;
+ int offset;
+ struct audit_rule_data *rule = *rulep;
+
+ if (f == NULL)
+ return -1;
+
+ /* look for 2-char operators first
+ then look for 1-char operators afterwards
+ when found, null out the bytes under the operators to split
+ and set value pointer just past operator bytes
+ */
+ if ( (v = strstr(pair, "!=")) ) {
+ *v++ = '\0';
+ *v++ = '\0';
+ op = AUDIT_NOT_EQUAL;
+ } else if ( (v = strstr(pair, "=")) ) {
+ *v++ = '\0';
+ op = AUDIT_EQUAL;
+ } else {
+ fprintf(stderr, "only =, != comparisons are allowed in interfield\n");
+ return -1;
+ }
+
+ if (v == NULL)
+ return -1;
+
+ if (*f == 0)
+ return -22;
+
+ if (*v == 0)
+ return -20;
+
+ if ((field1 = audit_name_to_field(f)) < 0)
+ return -2;
+
+ if ((field2 = audit_name_to_field(v)) < 0)
+ return -2;
+
+ /* Exclude filter can be used only with MSGTYPE field */
+ if (flags == AUDIT_FILTER_EXCLUDE && field1 != AUDIT_MSGTYPE)
+ return -12;
+
+ // It should always be AUDIT_FIELD_COMPARE
+ rule->fields[rule->field_count] = AUDIT_FIELD_COMPARE;
+ rule->fieldflags[rule->field_count] = op;
+ switch (field1)
+ {
+ case AUDIT_UID:
+ switch(field2) {
+ case AUDIT_EUID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID;
+ break;
+ case AUDIT_OBJ_UID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_EUID:
+ switch(field2) {
+ case AUDIT_UID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_OBJ_UID:
+ switch(field2) {
+ case AUDIT_UID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_OBJ_GID:
+ switch(field2) {
+ case AUDIT_GID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_GID:
+ switch(field2) {
+ case AUDIT_EGID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID;
+ break;
+ case AUDIT_OBJ_GID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case AUDIT_EGID:
+ switch(field2) {
+ case AUDIT_OBJ_GID:
+ rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ /* fallthrough */
+ default:
+ if (field1 == AUDIT_INODE) {
+ if (!(op == AUDIT_NOT_EQUAL ||
+ op == AUDIT_EQUAL))
+ return -13;
+ }
+
+ if (field1 == AUDIT_PPID && !(flags == AUDIT_FILTER_EXIT
+ || flags == AUDIT_FILTER_ENTRY))
+ return -17;
+
+ if (!isdigit((char)*(v)))
+ return -21;
+
+ if (field1 == AUDIT_INODE)
+ rule->values[rule->field_count] =
+ strtoul(v, NULL, 0);
+ else
+ rule->values[rule->field_count] =
+ strtol(v, NULL, 0);
+ break;
+ }
+ rule->field_count++;
+ return 0;
+}
+
int audit_rule_fieldpair_data(struct audit_rule_data **rulep, const char *pair,
int flags)
{
@@ -857,6 +999,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data **rulep, const char *pair,
case AUDIT_SUID:
case AUDIT_FSUID:
case AUDIT_LOGINUID:
+ case AUDIT_OBJ_UID:
+ case AUDIT_OBJ_GID:
// Do positive & negative separate for 32 bit systems
vlen = strlen(v);
if (isdigit((char)*(v)))
diff --git a/trunk/lib/libaudit.h b/trunk/lib/libaudit.h
index 8feaa39..911bce4 100644
--- a/trunk/lib/libaudit.h
+++ b/trunk/lib/libaudit.h
@@ -428,6 +428,8 @@ extern int audit_rule_syscallbyname_data(struct audit_rule_data *rule,
* adding new fields */
extern int audit_rule_fieldpair_data(struct audit_rule_data **rulep,
const char *pair, int flags);
+extern int audit_rule_interfield_fieldpair_data(struct audit_rule_data **rulep,
+ const char *pair, int flags);
extern void audit_rule_free_data(struct audit_rule_data *rule);
#ifdef __cplusplus
diff --git a/trunk/src/auditctl.c b/trunk/src/auditctl.c
index 34b7935..d7ec998 100644
--- a/trunk/src/auditctl.c
+++ b/trunk/src/auditctl.c
@@ -482,7 +482,7 @@ static int setopt(int count, int lineno, char *vars[])
keylen = AUDIT_MAX_KEY_LEN;
while ((retval >= 0) && (c = getopt(count, vars,
- "hislDvte:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:")) != EOF) {
+ "hislDvtC:e:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:")) != EOF) {
int flags = AUDIT_FILTER_UNSET;
rc = 10; // Init to something impossible to see if unused.
switch (c) {
@@ -731,7 +731,6 @@ static int setopt(int count, int lineno, char *vars[])
retval = -1;
break;
}
-
rc = audit_rule_fieldpair_data(&rule_new,optarg,flags);
if (rc != 0) {
audit_number_to_errmsg(rc, optarg);
@@ -743,6 +742,22 @@ static int setopt(int count, int lineno, char *vars[])
}
break;
+ case 'C':
+ if (add != AUDIT_FILTER_UNSET)
+ flags = add & AUDIT_FILTER_MASK;
+ else if (del != AUDIT_FILTER_UNSET)
+ flags = del & AUDIT_FILTER_MASK;
+
+ rc = audit_rule_interfield_fieldpair_data(&rule_new, optarg, flags);
+ if (rc != 0) {
+ audit_number_to_errmsg(rc, optarg);
+ retval = -1;
+ } else {
+ if (rule_new->fields[rule_new->field_count - 1] ==
+ AUDIT_PERM)
+ audit_permadded = 1;
+ }
+ break;
case 'm':
if (count > 3) {
fprintf(stderr,
diff --git a/trunk/src/ausearch-report.c b/trunk/src/ausearch-report.c
index d50c732..62e1ae0 100644
--- a/trunk/src/ausearch-report.c
+++ b/trunk/src/ausearch-report.c
@@ -333,6 +333,7 @@ static struct nv_pair typetab[] = {
{T_UID, "id"},
{T_UID, "inode_uid"},
{T_UID, "sauid"},
+ {T_UID, "obj_uid"},
{T_GID, "gid"},
{T_GID, "egid"},
{T_GID, "sgid"},
--
1.7.3.1
--
Peter Moody Google 1.650.253.7306
Security Engineer pgp:0xC3410038