|
@@ -252,7 +252,8 @@ static inline int audit_to_inode(struct audit_krule *krule,
|
|
|
struct audit_field *f)
|
|
|
{
|
|
|
if (krule->listnr != AUDIT_FILTER_EXIT ||
|
|
|
- krule->watch || krule->inode_f || krule->tree)
|
|
|
+ krule->watch || krule->inode_f || krule->tree ||
|
|
|
+ (f->op != Audit_equal && f->op != Audit_not_equal))
|
|
|
return -EINVAL;
|
|
|
|
|
|
krule->inode_f = f;
|
|
@@ -270,7 +271,7 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len,
|
|
|
|
|
|
if (path[0] != '/' || path[len-1] == '/' ||
|
|
|
krule->listnr != AUDIT_FILTER_EXIT ||
|
|
|
- op & ~AUDIT_EQUAL ||
|
|
|
+ op != Audit_equal ||
|
|
|
krule->inode_f || krule->watch || krule->tree)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -420,12 +421,32 @@ exit_err:
|
|
|
return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
|
+static u32 audit_ops[] =
|
|
|
+{
|
|
|
+ [Audit_equal] = AUDIT_EQUAL,
|
|
|
+ [Audit_not_equal] = AUDIT_NOT_EQUAL,
|
|
|
+ [Audit_bitmask] = AUDIT_BIT_MASK,
|
|
|
+ [Audit_bittest] = AUDIT_BIT_TEST,
|
|
|
+ [Audit_lt] = AUDIT_LESS_THAN,
|
|
|
+ [Audit_gt] = AUDIT_GREATER_THAN,
|
|
|
+ [Audit_le] = AUDIT_LESS_THAN_OR_EQUAL,
|
|
|
+ [Audit_ge] = AUDIT_GREATER_THAN_OR_EQUAL,
|
|
|
+};
|
|
|
+
|
|
|
+static u32 audit_to_op(u32 op)
|
|
|
+{
|
|
|
+ u32 n;
|
|
|
+ for (n = Audit_equal; n < Audit_bad && audit_ops[n] != op; n++)
|
|
|
+ ;
|
|
|
+ return n;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/* Translate struct audit_rule to kernel's rule respresentation.
|
|
|
* Exists for backward compatibility with userspace. */
|
|
|
static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
|
|
|
{
|
|
|
struct audit_entry *entry;
|
|
|
- struct audit_field *ino_f;
|
|
|
int err = 0;
|
|
|
int i;
|
|
|
|
|
@@ -435,12 +456,28 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
|
|
|
|
|
|
for (i = 0; i < rule->field_count; i++) {
|
|
|
struct audit_field *f = &entry->rule.fields[i];
|
|
|
+ u32 n;
|
|
|
+
|
|
|
+ n = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
|
|
|
+
|
|
|
+ /* Support for legacy operators where
|
|
|
+ * AUDIT_NEGATE bit signifies != and otherwise assumes == */
|
|
|
+ if (n & AUDIT_NEGATE)
|
|
|
+ f->op = Audit_not_equal;
|
|
|
+ else if (!n)
|
|
|
+ f->op = Audit_equal;
|
|
|
+ else
|
|
|
+ f->op = audit_to_op(n);
|
|
|
+
|
|
|
+ entry->rule.vers_ops = (n & AUDIT_OPERATORS) ? 2 : 1;
|
|
|
|
|
|
- f->op = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
|
|
|
f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
|
|
|
f->val = rule->values[i];
|
|
|
|
|
|
err = -EINVAL;
|
|
|
+ if (f->op == Audit_bad)
|
|
|
+ goto exit_free;
|
|
|
+
|
|
|
switch(f->type) {
|
|
|
default:
|
|
|
goto exit_free;
|
|
@@ -462,11 +499,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
|
|
|
case AUDIT_EXIT:
|
|
|
case AUDIT_SUCCESS:
|
|
|
/* bit ops are only useful on syscall args */
|
|
|
- if (f->op == AUDIT_BIT_MASK ||
|
|
|
- f->op == AUDIT_BIT_TEST) {
|
|
|
- err = -EINVAL;
|
|
|
+ if (f->op == Audit_bitmask || f->op == Audit_bittest)
|
|
|
goto exit_free;
|
|
|
- }
|
|
|
break;
|
|
|
case AUDIT_ARG0:
|
|
|
case AUDIT_ARG1:
|
|
@@ -475,11 +509,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
|
|
|
break;
|
|
|
/* arch is only allowed to be = or != */
|
|
|
case AUDIT_ARCH:
|
|
|
- if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL)
|
|
|
- && (f->op != AUDIT_NEGATE) && (f->op)) {
|
|
|
- err = -EINVAL;
|
|
|
+ if (f->op != Audit_not_equal && f->op != Audit_equal)
|
|
|
goto exit_free;
|
|
|
- }
|
|
|
entry->rule.arch_f = f;
|
|
|
break;
|
|
|
case AUDIT_PERM:
|
|
@@ -496,33 +527,10 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
|
|
|
goto exit_free;
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1;
|
|
|
-
|
|
|
- /* Support for legacy operators where
|
|
|
- * AUDIT_NEGATE bit signifies != and otherwise assumes == */
|
|
|
- if (f->op & AUDIT_NEGATE)
|
|
|
- f->op = AUDIT_NOT_EQUAL;
|
|
|
- else if (!f->op)
|
|
|
- f->op = AUDIT_EQUAL;
|
|
|
- else if (f->op == AUDIT_OPERATORS) {
|
|
|
- err = -EINVAL;
|
|
|
- goto exit_free;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- ino_f = entry->rule.inode_f;
|
|
|
- if (ino_f) {
|
|
|
- switch(ino_f->op) {
|
|
|
- case AUDIT_NOT_EQUAL:
|
|
|
- entry->rule.inode_f = NULL;
|
|
|
- case AUDIT_EQUAL:
|
|
|
- break;
|
|
|
- default:
|
|
|
- err = -EINVAL;
|
|
|
- goto exit_free;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
|
|
|
+ entry->rule.inode_f = NULL;
|
|
|
|
|
|
exit_nofree:
|
|
|
return entry;
|
|
@@ -538,7 +546,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
|
|
|
{
|
|
|
int err = 0;
|
|
|
struct audit_entry *entry;
|
|
|
- struct audit_field *ino_f;
|
|
|
void *bufp;
|
|
|
size_t remain = datasz - sizeof(struct audit_rule_data);
|
|
|
int i;
|
|
@@ -554,11 +561,11 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
|
|
|
struct audit_field *f = &entry->rule.fields[i];
|
|
|
|
|
|
err = -EINVAL;
|
|
|
- if (!(data->fieldflags[i] & AUDIT_OPERATORS) ||
|
|
|
- data->fieldflags[i] & ~AUDIT_OPERATORS)
|
|
|
+
|
|
|
+ f->op = audit_to_op(data->fieldflags[i]);
|
|
|
+ if (f->op == Audit_bad)
|
|
|
goto exit_free;
|
|
|
|
|
|
- f->op = data->fieldflags[i] & AUDIT_OPERATORS;
|
|
|
f->type = data->fields[i];
|
|
|
f->val = data->values[i];
|
|
|
f->lsm_str = NULL;
|
|
@@ -670,18 +677,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ino_f = entry->rule.inode_f;
|
|
|
- if (ino_f) {
|
|
|
- switch(ino_f->op) {
|
|
|
- case AUDIT_NOT_EQUAL:
|
|
|
- entry->rule.inode_f = NULL;
|
|
|
- case AUDIT_EQUAL:
|
|
|
- break;
|
|
|
- default:
|
|
|
- err = -EINVAL;
|
|
|
- goto exit_free;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
|
|
|
+ entry->rule.inode_f = NULL;
|
|
|
|
|
|
exit_nofree:
|
|
|
return entry;
|
|
@@ -721,10 +718,10 @@ static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule)
|
|
|
rule->fields[i] = krule->fields[i].type;
|
|
|
|
|
|
if (krule->vers_ops == 1) {
|
|
|
- if (krule->fields[i].op & AUDIT_NOT_EQUAL)
|
|
|
+ if (krule->fields[i].op == Audit_not_equal)
|
|
|
rule->fields[i] |= AUDIT_NEGATE;
|
|
|
} else {
|
|
|
- rule->fields[i] |= krule->fields[i].op;
|
|
|
+ rule->fields[i] |= audit_ops[krule->fields[i].op];
|
|
|
}
|
|
|
}
|
|
|
for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i];
|
|
@@ -752,7 +749,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
|
|
|
struct audit_field *f = &krule->fields[i];
|
|
|
|
|
|
data->fields[i] = f->type;
|
|
|
- data->fieldflags[i] = f->op;
|
|
|
+ data->fieldflags[i] = audit_ops[f->op];
|
|
|
switch(f->type) {
|
|
|
case AUDIT_SUBJ_USER:
|
|
|
case AUDIT_SUBJ_ROLE:
|
|
@@ -1626,28 +1623,29 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-int audit_comparator(const u32 left, const u32 op, const u32 right)
|
|
|
+int audit_comparator(u32 left, u32 op, u32 right)
|
|
|
{
|
|
|
switch (op) {
|
|
|
- case AUDIT_EQUAL:
|
|
|
+ case Audit_equal:
|
|
|
return (left == right);
|
|
|
- case AUDIT_NOT_EQUAL:
|
|
|
+ case Audit_not_equal:
|
|
|
return (left != right);
|
|
|
- case AUDIT_LESS_THAN:
|
|
|
+ case Audit_lt:
|
|
|
return (left < right);
|
|
|
- case AUDIT_LESS_THAN_OR_EQUAL:
|
|
|
+ case Audit_le:
|
|
|
return (left <= right);
|
|
|
- case AUDIT_GREATER_THAN:
|
|
|
+ case Audit_gt:
|
|
|
return (left > right);
|
|
|
- case AUDIT_GREATER_THAN_OR_EQUAL:
|
|
|
+ case Audit_ge:
|
|
|
return (left >= right);
|
|
|
- case AUDIT_BIT_MASK:
|
|
|
+ case Audit_bitmask:
|
|
|
return (left & right);
|
|
|
- case AUDIT_BIT_TEST:
|
|
|
+ case Audit_bittest:
|
|
|
return ((left & right) == right);
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ return 0;
|
|
|
}
|
|
|
- BUG();
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
/* Compare given dentry name with last component in given path,
|