2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-02 23:35:37 +00:00

parser: convert xmatch to use out of band transitions

xattrs can contain NULL characters in their values which means we can
not user regular NULL transitions to separate values. To fix this
use out of band transition instead.

Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen
2019-08-16 02:36:59 -07:00
parent 53dffc5304
commit 2992e6973f
5 changed files with 33 additions and 31 deletions

View File

@@ -140,13 +140,14 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
/* /*
* append_rule is like add_rule, but appends the rule to any existing rules * append_rule is like add_rule, but appends the rule to any existing rules
* with a null transition. The appended rule matches with the same permissions * with a separating transition. The appended rule matches with the same
* permissions
* as the rule it's appended to. * as the rule it's appended to.
* *
* This is used by xattrs matching where, after matching the path, the DFA is * This is used by xattrs matching where, after matching the path, the DFA is
* advanced by a null character for each xattr. * advanced by a null character for each xattr.
*/ */
bool aare_rules::append_rule(const char *rule, dfaflags_t flags) bool aare_rules::append_rule(const char *rule, bool oob, dfaflags_t flags)
{ {
Node *tree = NULL; Node *tree = NULL;
if (regex_parse(&tree, rule)) if (regex_parse(&tree, rule))
@@ -162,13 +163,13 @@ bool aare_rules::append_rule(const char *rule, dfaflags_t flags)
/* /*
* For each matching state, we want to create an optional path * For each matching state, we want to create an optional path
* separated by a null character. * separated by a separating character.
* *
* When matching xattrs, the DFA must end up in an accepting state for * When matching xattrs, the DFA must end up in an accepting state for
* the path, then each value of the xattrs. Using an optional node * the path, then each value of the xattrs. Using an optional node
* lets each rule end up in an accepting state. * lets each rule end up in an accepting state.
*/ */
tree = new OptionalNode(new CatNode(new CharNode(0), tree)); tree = new OptionalNode(new CatNode(oob ? new CharNode(transchar(-1, true)) : new CharNode(0), tree));
PermExprMap::iterator it; PermExprMap::iterator it;
for (it = expr_map.begin(); it != expr_map.end(); it++) { for (it = expr_map.begin(); it != expr_map.end(); it++) {
expr_map[it->first] = new CatNode(it->second, tree); expr_map[it->first] = new CatNode(it->second, tree);

View File

@@ -104,7 +104,7 @@ class aare_rules {
uint32_t audit, dfaflags_t flags); uint32_t audit, dfaflags_t flags);
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count, bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
const char **rulev, dfaflags_t flags, bool oob); const char **rulev, dfaflags_t flags, bool oob);
bool append_rule(const char *rule, dfaflags_t flags); bool append_rule(const char *rule, bool oob, dfaflags_t flags);
void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags); void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags);
}; };

View File

@@ -406,7 +406,7 @@ void CHFA::flex_table(ostream &os, const char *name)
} }
/* Write the actual flex parser table. */ /* Write the actual flex parser table. */
/* TODO: add max_oob */
size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 1); size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
th.th_magic = htonl(YYTH_REGEX_MAGIC); th.th_magic = htonl(YYTH_REGEX_MAGIC);
th.th_flags = htons(chfaflags); th.th_flags = htons(chfaflags);

View File

@@ -279,11 +279,11 @@ public:
*/ */
virtual int min_match_len() { return 0; } virtual int min_match_len() { return 0; }
/* /*
* contains_null returns if the expression tree contains a null character. * contains_oob returns if the expression tree contains a oob character.
* Null characters indicate that the rest of the DFA matches the xattrs and * oob characters indicate that the rest of the DFA matches has an
* not the path. This is used to compute min_match_len. * out of band transition. This is used to compute min_match_len.
*/ */
virtual bool contains_null() { return false; } virtual bool contains_oob() { return false; }
virtual int eq(Node *other) = 0; virtual int eq(Node *other) = 0;
virtual ostream &dump(ostream &os) = 0; virtual ostream &dump(ostream &os) = 0;
@@ -421,14 +421,17 @@ public:
int min_match_len() int min_match_len()
{ {
if (c == 0) { if (c < 0) {
// Null character indicates end of string. // oob characters indicates end of string.
// note: does NOT currently calc match len
// base on NULL char separator transitions
// which some match rules use.
return 0; return 0;
} }
return 1; return 1;
} }
bool contains_null() { return c == 0; } bool contains_oob() { return c < 0; }
transchar c; transchar c;
}; };
@@ -473,16 +476,16 @@ public:
int min_match_len() int min_match_len()
{ {
if (contains_null()) { if (contains_oob()) {
return 0; return 0;
} }
return 1; return 1;
} }
bool contains_null() bool contains_oob()
{ {
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) { for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
if (*i == 0) { if (*i < 0) {
return true; return true;
} }
} }
@@ -540,16 +543,16 @@ public:
int min_match_len() int min_match_len()
{ {
if (contains_null()) { if (contains_oob()) {
return 0; return 0;
} }
return 1; return 1;
} }
bool contains_null() bool contains_oob()
{ {
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) { for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
if (*i == 0) { if (*i < 0) {
return false; return false;
} }
} }
@@ -581,8 +584,6 @@ public:
return 0; return 0;
} }
ostream &dump(ostream &os) { return os << "."; } ostream &dump(ostream &os) { return os << "."; }
bool contains_null() { return true; }
}; };
/* Match a node zero or more times. (This is a unary operator.) */ /* Match a node zero or more times. (This is a unary operator.) */
@@ -611,7 +612,7 @@ public:
return os << ")*"; return os << ")*";
} }
bool contains_null() { return child[0]->contains_null(); } bool contains_oob() { return child[0]->contains_oob(); }
}; };
/* Match a node zero or one times. */ /* Match a node zero or one times. */
@@ -660,7 +661,7 @@ public:
return os << ")+"; return os << ")+";
} }
int min_match_len() { return child[0]->min_match_len(); } int min_match_len() { return child[0]->min_match_len(); }
bool contains_null() { return child[0]->contains_null(); } bool contains_oob() { return child[0]->contains_oob(); }
}; };
/* Match a pair of consecutive nodes. */ /* Match a pair of consecutive nodes. */
@@ -711,18 +712,18 @@ public:
int min_match_len() int min_match_len()
{ {
int len = child[0]->min_match_len(); int len = child[0]->min_match_len();
if (child[0]->contains_null()) { if (child[0]->contains_oob()) {
// Null characters are used to indicate when the DFA transitions // oob characters are used to indicate when the DFA transitions
// from matching the path to matching the xattrs. If the left child // from matching the path to matching the xattrs. If the left child
// contains a null character, the right side doesn't contribute to // contains an oob character, the right side doesn't contribute to
// the path match. // the path match.
return len; return len;
} }
return len + child[1]->min_match_len(); return len + child[1]->min_match_len();
} }
bool contains_null() bool contains_oob()
{ {
return child[0]->contains_null() || child[1]->contains_null(); return child[0]->contains_oob() || child[1]->contains_oob();
} }
}; };
@@ -771,9 +772,9 @@ public:
} }
return m2; return m2;
} }
bool contains_null() bool contains_oob()
{ {
return child[0]->contains_null() || child[1]->contains_null(); return child[0]->contains_oob() || child[1]->contains_oob();
} }
}; };

View File

@@ -512,7 +512,7 @@ static int process_profile_name_xmatch(Profile *prof)
convert_aaregex_to_pcre(xattr_value, 0, convert_aaregex_to_pcre(xattr_value, 0,
glob_default, tbuf, glob_default, tbuf,
&len); &len);
if (!rules->append_rule(tbuf.c_str(), dfaflags)) { if (!rules->append_rule(tbuf.c_str(), true, dfaflags)) {
delete rules; delete rules;
return FALSE; return FALSE;
} }