summaryrefslogtreecommitdiffstats
path: root/security/apparmor/domain.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-11-18 19:43:13 -0800
committerJohn Johansen <john.johansen@canonical.com>2018-02-09 11:30:02 -0800
commit21f606610502ef56f9180b1529fc7e02957564c8 (patch)
treec9907b4423f352fbbb878fd4bc598a5b0ad032e9 /security/apparmor/domain.c
parent73f488cd903938e78979d50e081a0314ad142351 (diff)
downloadlinux-stable-21f606610502ef56f9180b1529fc7e02957564c8.tar.gz
linux-stable-21f606610502ef56f9180b1529fc7e02957564c8.tar.bz2
linux-stable-21f606610502ef56f9180b1529fc7e02957564c8.zip
apparmor: improve overlapping domain attachment resolution
Overlapping domain attachments using the current longest left exact match fail in some simple cases, and with the fix to ensure consistent behavior by failing unresolvable attachments it becomes important to do a better job. eg. under the current match the following are unresolvable where the alternation is clearly a better match under the most specific left match rule. /** /{bin/,}usr/ Use a counting match that detects when a loop in the state machine is enter, and return the match count to provide a better specific left match resolution. Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/domain.c')
-rw-r--r--security/apparmor/domain.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 6a1279f11fcc..57cc892e05a2 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -385,10 +385,13 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
struct list_head *head,
const char **info)
{
- int len = 0, xattrs = 0;
+ int candidate_len = 0, candidate_xattrs = 0;
bool conflict = false;
struct aa_profile *profile, *candidate = NULL;
+ AA_BUG(!name);
+ AA_BUG(!head);
+
list_for_each_entry_rcu(profile, head, base.list) {
if (profile->label.flags & FLAG_NULL &&
&profile->label == ns_unconfined(profile->ns))
@@ -406,19 +409,20 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
* match.
*/
if (profile->xmatch) {
- unsigned int state;
+ unsigned int state, count;
u32 perm;
- if (profile->xmatch_len < len)
- continue;
-
- state = aa_dfa_match(profile->xmatch,
- DFA_START, name);
+ state = aa_dfa_leftmatch(profile->xmatch, DFA_START,
+ name, &count);
perm = dfa_user_allow(profile->xmatch, state);
/* any accepting state means a valid match. */
if (perm & MAY_EXEC) {
- int ret = aa_xattrs_match(bprm, profile, state);
+ int ret;
+
+ if (count < candidate_len)
+ continue;
+ ret = aa_xattrs_match(bprm, profile, state);
/* Fail matching if the xattrs don't match */
if (ret < 0)
continue;
@@ -429,10 +433,10 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
* The new match isn't more specific
* than the current best match
*/
- if (profile->xmatch_len == len &&
- ret <= xattrs) {
+ if (count == candidate_len &&
+ ret <= candidate_xattrs) {
/* Match is equivalent, so conflict */
- if (ret == xattrs)
+ if (ret == candidate_xattrs)
conflict = true;
continue;
}
@@ -441,8 +445,8 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
* xattrs, or a longer match
*/
candidate = profile;
- len = profile->xmatch_len;
- xattrs = ret;
+ candidate_len = profile->xmatch_len;
+ candidate_xattrs = ret;
conflict = false;
}
} else if (!strcmp(profile->base.name, name))