summaryrefslogtreecommitdiff
path: root/security/apparmor/label.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/label.c')
-rw-r--r--security/apparmor/label.c183
1 files changed, 79 insertions, 104 deletions
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index e68bcedca976..913678f199c3 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -154,13 +154,14 @@ static int profile_cmp(struct aa_profile *a, struct aa_profile *b)
/**
* vec_cmp - label comparison for set ordering
- * @a: label to compare (NOT NULL)
- * @vec: vector of profiles to compare (NOT NULL)
- * @n: length of @vec
- *
- * Returns: <0 if a < vec
- * ==0 if a == vec
- * >0 if a > vec
+ * @a: aa_profile to compare (NOT NULL)
+ * @an: length of @a
+ * @b: aa_profile to compare (NOT NULL)
+ * @bn: length of @b
+ *
+ * Returns: <0 if @a < @b
+ * ==0 if @a == @b
+ * >0 if @a > @b
*/
static int vec_cmp(struct aa_profile **a, int an, struct aa_profile **b, int bn)
{
@@ -197,18 +198,25 @@ static bool vec_is_stale(struct aa_profile **vec, int n)
return false;
}
-static bool vec_unconfined(struct aa_profile **vec, int n)
+static void accum_label_info(struct aa_label *new)
{
+ long u = FLAG_UNCONFINED;
int i;
- AA_BUG(!vec);
+ AA_BUG(!new);
- for (i = 0; i < n; i++) {
- if (!profile_unconfined(vec[i]))
- return false;
- }
+ /* size == 1 is a profile and flags must be set as part of creation */
+ if (new->size == 1)
+ return;
- return true;
+ for (i = 0; i < new->size; i++) {
+ u |= new->vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 |
+ FLAG_STALE);
+ if (!(u & new->vec[i]->label.flags & FLAG_UNCONFINED))
+ u &= ~FLAG_UNCONFINED;
+ new->mediates |= new->vec[i]->label.mediates;
+ }
+ new->flags |= u;
}
static int sort_cmp(const void *a, const void *b)
@@ -253,6 +261,7 @@ static inline int unique(struct aa_profile **vec, int n)
* aa_vec_unique - canonical sort and unique a list of profiles
* @n: number of refcounted profiles in the list (@n > 0)
* @vec: list of profiles to sort and merge
+ * @flags: null terminator flags of @vec
*
* Returns: the number of duplicates eliminated == references put
*
@@ -425,9 +434,8 @@ struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp)
AA_BUG(size < 1);
/* + 1 for null terminator entry on vec */
- new = kzalloc(sizeof(*new) + sizeof(struct aa_profile *) * (size + 1),
- gfp);
- AA_DEBUG("%s (%p)\n", __func__, new);
+ new = kzalloc(struct_size(new, vec, size + 1), gfp);
+ AA_DEBUG(DEBUG_LABEL, "%s (%p)\n", __func__, new);
if (!new)
goto fail;
@@ -486,7 +494,7 @@ int aa_label_next_confined(struct aa_label *label, int i)
}
/**
- * aa_label_next_not_in_set - return the next profile of @sub not in @set
+ * __aa_label_next_not_in_set - return the next profile of @sub not in @set
* @I: label iterator
* @set: label to test against
* @sub: label to if is subset of @set
@@ -582,7 +590,7 @@ bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub)
/**
* __label_remove - remove @label from the label set
- * @l: label to remove
+ * @label: label to remove
* @new: label to redirect to
*
* Requires: labels_set(@label)->lock write_lock
@@ -641,6 +649,7 @@ static bool __label_replace(struct aa_label *old, struct aa_label *new)
rb_replace_node(&old->node, &new->node, &ls->root);
old->flags &= ~FLAG_IN_TREE;
new->flags |= FLAG_IN_TREE;
+ accum_label_info(new);
return true;
}
@@ -701,6 +710,7 @@ static struct aa_label *__label_insert(struct aa_labelset *ls,
rb_link_node(&label->node, parent, new);
rb_insert_color(&label->node, &ls->root);
label->flags |= FLAG_IN_TREE;
+ accum_label_info(label);
return aa_get_label(label);
}
@@ -895,28 +905,11 @@ struct aa_label *aa_vec_find_or_create_label(struct aa_profile **vec, int len,
return vec_create_and_insert_label(vec, len, gfp);
}
-/**
- * aa_label_find - find label @label in label set
- * @label: label to find (NOT NULL)
- *
- * Requires: caller to hold a valid ref on l
- *
- * Returns: refcounted @label if @label is in tree
- * refcounted label that is equiv to @label in tree
- * else NULL if @label or equiv is not in tree
- */
-struct aa_label *aa_label_find(struct aa_label *label)
-{
- AA_BUG(!label);
-
- return vec_find(label->vec, label->size);
-}
-
/**
* aa_label_insert - insert label @label into @ls or return existing label
- * @ls - labelset to insert @label into
- * @label - label to insert
+ * @ls: labelset to insert @label into
+ * @label: label to insert
*
* Requires: caller to hold a valid ref on @label
*
@@ -1098,8 +1091,6 @@ static struct aa_label *label_merge_insert(struct aa_label *new,
else if (k == b->size)
return aa_get_label(b);
}
- if (vec_unconfined(new->vec, new->size))
- new->flags |= FLAG_UNCONFINED;
ls = labels_set(new);
write_lock_irqsave(&ls->lock, flags);
label = __label_insert(labels_set(new), new, false);
@@ -1203,7 +1194,6 @@ struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b)
/**
* aa_label_merge - attempt to insert new merged label of @a and @b
- * @ls: set of labels to insert label into (NOT NULL)
* @a: label to merge with @b (NOT NULL)
* @b: label to merge with @a (NOT NULL)
* @gfp: memory allocation type
@@ -1255,39 +1245,35 @@ out:
return label;
}
-static inline bool label_is_visible(struct aa_profile *profile,
- struct aa_label *label)
-{
- return aa_ns_visible(profile->ns, labels_ns(label), true);
-}
-
/* match a profile and its associated ns component if needed
* Assumes visibility test has already been done.
* If a subns profile is not to be matched should be prescreened with
* visibility test.
*/
-static inline unsigned int match_component(struct aa_profile *profile,
- struct aa_profile *tp,
- unsigned int state)
+static inline aa_state_t match_component(struct aa_profile *profile,
+ struct aa_ruleset *rules,
+ struct aa_profile *tp,
+ aa_state_t state)
{
const char *ns_name;
if (profile->ns == tp->ns)
- return aa_dfa_match(profile->policy.dfa, state, tp->base.hname);
+ return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
/* try matching with namespace name and then profile */
ns_name = aa_ns_name(profile->ns, tp->ns, true);
- state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1);
- state = aa_dfa_match(profile->policy.dfa, state, ns_name);
- state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1);
- return aa_dfa_match(profile->policy.dfa, state, tp->base.hname);
+ state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
+ state = aa_dfa_match(rules->policy->dfa, state, ns_name);
+ state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
+ return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
}
/**
* label_compound_match - find perms for full compound label
* @profile: profile to find perms for
+ * @rules: ruleset to search
* @label: label to check access permissions for
- * @start: state to start match in
+ * @state: state to start match in
* @subns: whether to do permission checks on components in a subns
* @request: permissions to request
* @perms: perms struct to set
@@ -1299,8 +1285,9 @@ static inline unsigned int match_component(struct aa_profile *profile,
* check to be stacked.
*/
static int label_compound_match(struct aa_profile *profile,
+ struct aa_ruleset *rules,
struct aa_label *label,
- unsigned int state, bool subns, u32 request,
+ aa_state_t state, bool subns, u32 request,
struct aa_perms *perms)
{
struct aa_profile *tp;
@@ -1310,7 +1297,7 @@ static int label_compound_match(struct aa_profile *profile,
label_for_each(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue;
- state = match_component(profile, tp, state);
+ state = match_component(profile, rules, tp, state);
if (!state)
goto fail;
goto next;
@@ -1324,12 +1311,12 @@ next:
label_for_each_cont(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue;
- state = aa_dfa_match(profile->policy.dfa, state, "//&");
- state = match_component(profile, tp, state);
+ state = aa_dfa_match(rules->policy->dfa, state, "//&");
+ state = match_component(profile, rules, tp, state);
if (!state)
goto fail;
}
- aa_compute_perms(profile->policy.dfa, state, perms);
+ *perms = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, perms);
if ((perms->allow & request) != request)
return -EACCES;
@@ -1344,6 +1331,7 @@ fail:
/**
* label_components_match - find perms for all subcomponents of a label
* @profile: profile to find perms for
+ * @rules: ruleset to search
* @label: label to check access permissions for
* @start: state to start match in
* @subns: whether to do permission checks on components in a subns
@@ -1357,20 +1345,21 @@ fail:
* check to be stacked.
*/
static int label_components_match(struct aa_profile *profile,
- struct aa_label *label, unsigned int start,
+ struct aa_ruleset *rules,
+ struct aa_label *label, aa_state_t start,
bool subns, u32 request,
struct aa_perms *perms)
{
struct aa_profile *tp;
struct label_it i;
struct aa_perms tmp;
- unsigned int state = 0;
+ aa_state_t state = 0;
/* find first subcomponent to test */
label_for_each(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue;
- state = match_component(profile, tp, start);
+ state = match_component(profile, rules, tp, start);
if (!state)
goto fail;
goto next;
@@ -1380,16 +1369,16 @@ static int label_components_match(struct aa_profile *profile,
return 0;
next:
- aa_compute_perms(profile->policy.dfa, state, &tmp);
+ tmp = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
if (!aa_ns_visible(profile->ns, tp->ns, subns))
continue;
- state = match_component(profile, tp, start);
+ state = match_component(profile, rules, tp, start);
if (!state)
goto fail;
- aa_compute_perms(profile->policy.dfa, state, &tmp);
+ tmp = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
}
@@ -1407,6 +1396,7 @@ fail:
/**
* aa_label_match - do a multi-component label match
* @profile: profile to match against (NOT NULL)
+ * @rules: ruleset to search
* @label: label to match (NOT NULL)
* @state: state to start in
* @subns: whether to match subns components
@@ -1415,18 +1405,18 @@ fail:
*
* Returns: the state the match finished in, may be the none matching state
*/
-int aa_label_match(struct aa_profile *profile, struct aa_label *label,
- unsigned int state, bool subns, u32 request,
- struct aa_perms *perms)
+int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
+ struct aa_label *label, aa_state_t state, bool subns,
+ u32 request, struct aa_perms *perms)
{
- int error = label_compound_match(profile, label, state, subns, request,
- perms);
+ int error = label_compound_match(profile, rules, label, state, subns,
+ request, perms);
if (!error)
return error;
*perms = allperms;
- return label_components_match(profile, label, state, subns, request,
- perms);
+ return label_components_match(profile, rules, label, state, subns,
+ request, perms);
}
@@ -1454,7 +1444,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
if (label->hname || labels_ns(label) != ns)
return res;
- if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) == -1)
+ if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0)
return res;
ls = labels_set(label);
@@ -1471,7 +1461,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
/*
* cached label name is present and visible
- * @label->hname only exists if label is namespace hierachical
+ * @label->hname only exists if label is namespace hierarchical
*/
static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
int flags)
@@ -1632,9 +1622,9 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
AA_BUG(!str && size != 0);
AA_BUG(!label);
- if (flags & FLAG_ABS_ROOT) {
+ if (DEBUG_ABS_ROOT && (flags & FLAG_ABS_ROOT)) {
ns = root_ns;
- len = snprintf(str, size, "=");
+ len = snprintf(str, size, "_");
update_for_len(total, len, size, str);
} else if (!ns) {
ns = labels_ns(label);
@@ -1704,7 +1694,7 @@ int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
/**
* aa_label_acntsxprint - allocate a __counted string buffer and print label
- * @strp: buffer to write to. (MAY BE NULL if @size == 0)
+ * @strp: buffer to write to.
* @ns: namespace profile is being viewed from
* @label: label to view (NOT NULL)
* @flags: flags controlling what label info is printed
@@ -1745,8 +1735,8 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
if (!use_label_hname(ns, label, flags) ||
display_mode(ns, label, flags)) {
len = aa_label_asxprint(&name, ns, label, flags, gfp);
- if (len == -1) {
- AA_DEBUG("label print error");
+ if (len < 0) {
+ AA_DEBUG(DEBUG_LABEL, "label print error");
return;
}
str = name;
@@ -1773,8 +1763,8 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
int len;
len = aa_label_asxprint(&str, ns, label, flags, gfp);
- if (len == -1) {
- AA_DEBUG("label print error");
+ if (len < 0) {
+ AA_DEBUG(DEBUG_LABEL, "label print error");
return;
}
seq_puts(f, str);
@@ -1796,8 +1786,8 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
int len;
len = aa_label_asxprint(&str, ns, label, flags, gfp);
- if (len == -1) {
- AA_DEBUG("label print error");
+ if (len < 0) {
+ AA_DEBUG(DEBUG_LABEL, "label print error");
return;
}
pr_info("%s", str);
@@ -1809,22 +1799,6 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
pr_info("%s", label->hname);
}
-void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp)
-{
- struct aa_ns *ns = aa_get_current_ns();
-
- aa_label_xaudit(ab, ns, label, FLAG_VIEW_SUBNS, gfp);
- aa_put_ns(ns);
-}
-
-void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp)
-{
- struct aa_ns *ns = aa_get_current_ns();
-
- aa_label_seq_xprint(f, ns, label, FLAG_VIEW_SUBNS, gfp);
- aa_put_ns(ns);
-}
-
void aa_label_printk(struct aa_label *label, gfp_t gfp)
{
struct aa_ns *ns = aa_get_current_ns();
@@ -1896,7 +1870,8 @@ struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
AA_BUG(!str);
str = skipn_spaces(str, n);
- if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label))
+ if (str == NULL || (DEBUG_ABS_ROOT && *str == '_' &&
+ base != &root_ns->unconfined->label))
return ERR_PTR(-EINVAL);
len = label_count_strn_entries(str, end - str);
@@ -2036,7 +2011,7 @@ out:
/**
* __label_update - insert updated version of @label into labelset
- * @label - the label to update/replace
+ * @label: the label to update/replace
*
* Returns: new label that is up to date
* else NULL on failure
@@ -2137,7 +2112,7 @@ static void __labelset_update(struct aa_ns *ns)
}
/**
- * __aa_labelset_udate_subtree - update all labels with a stale component
+ * __aa_labelset_update_subtree - update all labels with a stale component
* @ns: ns to start update at (NOT NULL)
*
* Requires: @ns lock be held