apparmor: ensure that undecidable profile attachments fail
Profiles that have an undecidable overlap in their attachments are
being incorrectly handled. Instead of failing to attach the first one
encountered is being used.
eg.
profile A /** { .. }
profile B /*foo { .. }
have an unresolvable longest left attachment, they both have an exact
match on / and then have an overlapping expression that has no clear
winner.
Currently the winner will be the profile that is loaded first which
can result in non-deterministic behavior. Instead in this situation
the exec should fail.
Fixes: 898127c34e
("AppArmor: functions for domain transitions")
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
4633307e5e
commit
844b8292b6
|
@ -305,6 +305,7 @@ static int change_profile_perms(struct aa_profile *profile,
|
||||||
* __attach_match_ - find an attachment match
|
* __attach_match_ - find an attachment match
|
||||||
* @name - to match against (NOT NULL)
|
* @name - to match against (NOT NULL)
|
||||||
* @head - profile list to walk (NOT NULL)
|
* @head - profile list to walk (NOT NULL)
|
||||||
|
* @info - info message if there was an error (NOT NULL)
|
||||||
*
|
*
|
||||||
* Do a linear search on the profiles in the list. There is a matching
|
* Do a linear search on the profiles in the list. There is a matching
|
||||||
* preference where an exact match is preferred over a name which uses
|
* preference where an exact match is preferred over a name which uses
|
||||||
|
@ -316,28 +317,44 @@ static int change_profile_perms(struct aa_profile *profile,
|
||||||
* Returns: profile or NULL if no match found
|
* Returns: profile or NULL if no match found
|
||||||
*/
|
*/
|
||||||
static struct aa_profile *__attach_match(const char *name,
|
static struct aa_profile *__attach_match(const char *name,
|
||||||
struct list_head *head)
|
struct list_head *head,
|
||||||
|
const char **info)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
bool conflict = false;
|
||||||
struct aa_profile *profile, *candidate = NULL;
|
struct aa_profile *profile, *candidate = NULL;
|
||||||
|
|
||||||
list_for_each_entry_rcu(profile, head, base.list) {
|
list_for_each_entry_rcu(profile, head, base.list) {
|
||||||
if (profile->label.flags & FLAG_NULL)
|
if (profile->label.flags & FLAG_NULL)
|
||||||
continue;
|
continue;
|
||||||
if (profile->xmatch && profile->xmatch_len > len) {
|
if (profile->xmatch) {
|
||||||
unsigned int state = aa_dfa_match(profile->xmatch,
|
if (profile->xmatch_len == len) {
|
||||||
DFA_START, name);
|
conflict = true;
|
||||||
u32 perm = dfa_user_allow(profile->xmatch, state);
|
continue;
|
||||||
/* any accepting state means a valid match. */
|
} else if (profile->xmatch_len > len) {
|
||||||
if (perm & MAY_EXEC) {
|
unsigned int state;
|
||||||
candidate = profile;
|
u32 perm;
|
||||||
len = profile->xmatch_len;
|
|
||||||
|
state = aa_dfa_match(profile->xmatch,
|
||||||
|
DFA_START, name);
|
||||||
|
perm = dfa_user_allow(profile->xmatch, state);
|
||||||
|
/* any accepting state means a valid match. */
|
||||||
|
if (perm & MAY_EXEC) {
|
||||||
|
candidate = profile;
|
||||||
|
len = profile->xmatch_len;
|
||||||
|
conflict = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (!strcmp(profile->base.name, name))
|
} else if (!strcmp(profile->base.name, name))
|
||||||
/* exact non-re match, no more searching required */
|
/* exact non-re match, no more searching required */
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
*info = "conflicting profile attachments";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,16 +363,17 @@ static struct aa_profile *__attach_match(const char *name,
|
||||||
* @ns: the current namespace (NOT NULL)
|
* @ns: the current namespace (NOT NULL)
|
||||||
* @list: list to search (NOT NULL)
|
* @list: list to search (NOT NULL)
|
||||||
* @name: the executable name to match against (NOT NULL)
|
* @name: the executable name to match against (NOT NULL)
|
||||||
|
* @info: info message if there was an error
|
||||||
*
|
*
|
||||||
* Returns: label or NULL if no match found
|
* Returns: label or NULL if no match found
|
||||||
*/
|
*/
|
||||||
static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list,
|
static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list,
|
||||||
const char *name)
|
const char *name, const char **info)
|
||||||
{
|
{
|
||||||
struct aa_profile *profile;
|
struct aa_profile *profile;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
profile = aa_get_profile(__attach_match(name, list));
|
profile = aa_get_profile(__attach_match(name, list, info));
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return profile ? &profile->label : NULL;
|
return profile ? &profile->label : NULL;
|
||||||
|
@ -448,11 +466,11 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
|
||||||
if (xindex & AA_X_CHILD)
|
if (xindex & AA_X_CHILD)
|
||||||
/* released by caller */
|
/* released by caller */
|
||||||
new = find_attach(ns, &profile->base.profiles,
|
new = find_attach(ns, &profile->base.profiles,
|
||||||
name);
|
name, info);
|
||||||
else
|
else
|
||||||
/* released by caller */
|
/* released by caller */
|
||||||
new = find_attach(ns, &ns->base.profiles,
|
new = find_attach(ns, &ns->base.profiles,
|
||||||
name);
|
name, info);
|
||||||
*lookupname = name;
|
*lookupname = name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -516,7 +534,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
|
||||||
|
|
||||||
if (profile_unconfined(profile)) {
|
if (profile_unconfined(profile)) {
|
||||||
new = find_attach(profile->ns, &profile->ns->base.profiles,
|
new = find_attach(profile->ns, &profile->ns->base.profiles,
|
||||||
name);
|
name, &info);
|
||||||
if (new) {
|
if (new) {
|
||||||
AA_DEBUG("unconfined attached to new label");
|
AA_DEBUG("unconfined attached to new label");
|
||||||
return new;
|
return new;
|
||||||
|
|
Loading…
Reference in New Issue