summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2025-12-25 01:21:23 -0800
committerJohn Johansen <john.johansen@canonical.com>2026-01-29 01:27:55 -0800
commit796c146fa6c8289afc9e18004c21bfe05c75a487 (patch)
treea8f69e3b815d23fc02d58ff735d05d7720f8562f /security
parenta4c9efa4dbad6dacad6e8b274e30e814c8353097 (diff)
apparmor: split xxx_in_ns into its two separate semantic use cases
This patch doesn't change current functionality, it switches the two uses of the in_ns fns and macros into the two semantically different cases they are used for. xxx_in_scope for checking mediation interaction between profiles xxx_in_view to determine which profiles are visible.The scope will always be a subset of the view as profiles that can not see each other can not interact. The split can not be completely done for label_match because it has to distinct uses matching permission against label in scope, and checking if a transition to a profile is allowed. The transition to a profile can include profiles that are in view but not in scope, so retain this distinction as a parameter. While at the moment the two uses are very similar, in the future there will be additional differences. So make sure the semantics differences are present in the code. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/af_unix.c2
-rw-r--r--security/apparmor/apparmorfs.c2
-rw-r--r--security/apparmor/domain.c58
-rw-r--r--security/apparmor/include/lib.h19
-rw-r--r--security/apparmor/label.c26
5 files changed, 61 insertions, 46 deletions
diff --git a/security/apparmor/af_unix.c b/security/apparmor/af_unix.c
index ac0f4be791ec..fdb4a9f212c3 100644
--- a/security/apparmor/af_unix.c
+++ b/security/apparmor/af_unix.c
@@ -416,7 +416,7 @@ static int profile_peer_perm(struct aa_profile *profile, u32 request,
unix_sk(sk),
peer_addr, peer_addrlen, &p, &ad->info);
- return fn_for_each_in_ns(peer_label, peerp,
+ return fn_for_each_in_scope(peer_label, peerp,
match_label(profile, rules, state, request,
peerp, p, ad));
}
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 91c1fcb78ac8..9b4f833e36cd 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -801,7 +801,7 @@ static ssize_t query_label(char *buf, size_t buf_len,
perms = allperms;
if (view_only) {
- label_for_each_in_ns(i, labels_ns(label), label, profile) {
+ label_for_each_in_scope(i, labels_ns(label), label, profile) {
profile_query_cb(profile, &perms, match_str, match_len);
}
} else {
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index ee2df25f355d..f02bf770f638 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -115,7 +115,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
* @label: label to check access permissions for
* @stack: whether this is a stacking request
* @state: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: perms struct to set
*
@@ -127,7 +127,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
*/
static int label_compound_match(struct aa_profile *profile,
struct aa_label *label, bool stack,
- aa_state_t state, bool subns, u32 request,
+ aa_state_t state, bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_ruleset *rules = profile->label.rules[0];
@@ -135,9 +135,9 @@ static int label_compound_match(struct aa_profile *profile,
struct label_it i;
struct path_cond cond = { };
- /* find first subcomponent that is visible */
+ /* find first subcomponent that is in view and going to be interated with */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, tp, stack, state);
if (!state)
@@ -151,7 +151,7 @@ static int label_compound_match(struct aa_profile *profile,
next:
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = aa_dfa_match(rules->file->dfa, state, "//&");
state = match_component(profile, tp, false, state);
@@ -177,7 +177,7 @@ fail:
* @label: label to check access permissions for
* @stack: whether this is a stacking request
* @start: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: an initialized perms struct to add accumulation to
*
@@ -189,7 +189,7 @@ fail:
*/
static int label_components_match(struct aa_profile *profile,
struct aa_label *label, bool stack,
- aa_state_t start, bool subns, u32 request,
+ aa_state_t start, bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_ruleset *rules = profile->label.rules[0];
@@ -201,7 +201,7 @@ static int label_components_match(struct aa_profile *profile,
/* find first subcomponent to test */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, tp, stack, start);
if (!state)
@@ -218,7 +218,7 @@ next:
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))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, tp, stack, start);
if (!state)
@@ -245,26 +245,26 @@ fail:
* @label: label to match (NOT NULL)
* @stack: whether this is a stacking request
* @state: state to start in
- * @subns: whether to match subns components
+ * @inview: whether to match labels in view or only in scope
* @request: permission request
* @perms: Returns computed perms (NOT NULL)
*
* Returns: the state the match finished in, may be the none matching state
*/
static int label_match(struct aa_profile *profile, struct aa_label *label,
- bool stack, aa_state_t state, bool subns, u32 request,
+ bool stack, aa_state_t state, bool inview, u32 request,
struct aa_perms *perms)
{
int error;
*perms = nullperms;
- error = label_compound_match(profile, label, stack, state, subns,
+ error = label_compound_match(profile, label, stack, state, inview,
request, perms);
if (!error)
return error;
*perms = allperms;
- return label_components_match(profile, label, stack, state, subns,
+ return label_components_match(profile, label, stack, state, inview,
request, perms);
}
@@ -880,14 +880,16 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
AA_BUG(!bprm);
AA_BUG(!buffer);
- /* TODO: determine how much we want to loosen this */
- error = fn_for_each_in_ns(label, profile,
+ /* TODO: determine how much we want to loosen this
+ * only check profiles in scope for permission to change at exec
+ */
+ error = fn_for_each_in_scope(label, profile,
profile_onexec(subj_cred, profile, onexec, stack,
bprm, buffer, cond, unsafe));
if (error)
return ERR_PTR(error);
- new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+ new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
stack ? aa_label_merge(&profile->label, onexec,
GFP_KERNEL)
: aa_get_newest_label(onexec),
@@ -897,7 +899,7 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
return new;
/* TODO: get rid of GLOBAL_ROOT_UID */
- error = fn_for_each_in_ns(label, profile,
+ error = fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred, profile, &nullperms,
OP_CHANGE_ONEXEC,
AA_MAY_ONEXEC, bprm->filename, NULL,
@@ -1123,7 +1125,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
/*find first matching hat */
for (i = 0; i < count && !hat; i++) {
name = hats[i];
- label_for_each_in_ns(it, labels_ns(label), label, profile) {
+ label_for_each_in_scope(it, labels_ns(label), label, profile) {
if (sibling && PROFILE_IS_HAT(profile)) {
root = aa_get_profile_rcu(&profile->parent);
} else if (!sibling && !PROFILE_IS_HAT(profile)) {
@@ -1159,7 +1161,7 @@ outer_continue:
* change_hat.
*/
name = NULL;
- label_for_each_in_ns(it, labels_ns(label), label, profile) {
+ label_for_each_in_scope(it, labels_ns(label), label, profile) {
if (!list_empty(&profile->base.profiles)) {
info = "hat not found";
error = -ENOENT;
@@ -1170,7 +1172,7 @@ outer_continue:
error = -ECHILD;
fail:
- label_for_each_in_ns(it, labels_ns(label), label, profile) {
+ label_for_each_in_scope(it, labels_ns(label), label, profile) {
/*
* no target as it has failed to be found or built
*
@@ -1188,7 +1190,7 @@ fail:
return ERR_PTR(error);
build:
- new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+ new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
build_change_hat(subj_cred, profile, name,
sibling),
aa_get_label(&profile->label));
@@ -1251,7 +1253,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
bool empty = true;
rcu_read_lock();
- label_for_each_in_ns(i, labels_ns(label), label, profile) {
+ label_for_each_in_scope(i, labels_ns(label), label, profile) {
empty &= list_empty(&profile->base.profiles);
}
rcu_read_unlock();
@@ -1338,7 +1340,7 @@ kill:
perms.kill = AA_MAY_CHANGEHAT;
fail:
- fn_for_each_in_ns(label, profile,
+ fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred, profile, &perms, OP_CHANGE_HAT,
AA_MAY_CHANGEHAT, NULL, NULL, target,
GLOBAL_ROOT_UID, info, error));
@@ -1446,7 +1448,7 @@ int aa_change_profile(const char *fqname, int flags)
*/
stack = true;
perms.audit = request;
- (void) fn_for_each_in_ns(label, profile,
+ (void) fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred, profile, &perms, op,
request, auditname, NULL, target,
GLOBAL_ROOT_UID, stack_msg, 0));
@@ -1492,7 +1494,7 @@ int aa_change_profile(const char *fqname, int flags)
*
* if (!stack) {
*/
- error = fn_for_each_in_ns(label, profile,
+ error = fn_for_each_in_scope(label, profile,
change_profile_perms_wrapper(op, auditname,
subj_cred,
profile, target, stack,
@@ -1506,7 +1508,7 @@ int aa_change_profile(const char *fqname, int flags)
check:
/* check if tracing task is allowed to trace target domain */
error = may_change_ptraced_domain(subj_cred, target, &info);
- if (error && !fn_for_each_in_ns(label, profile,
+ if (error && !fn_for_each_in_scope(label, profile,
COMPLAIN_MODE(profile)))
goto audit;
@@ -1522,7 +1524,7 @@ check:
/* stacking is always a subset, so only check the nonstack case */
if (!stack) {
- new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+ new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
aa_get_label(target),
aa_get_label(&profile->label));
/*
@@ -1565,7 +1567,7 @@ check:
}
audit:
- error = fn_for_each_in_ns(label, profile,
+ error = fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred,
profile, &perms, op, request, auditname,
NULL, new ? new : target,
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 73ec624fd8c4..1c5d1f60f6a7 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -80,6 +80,19 @@ int aa_print_debug_params(char *buffer);
/* Flag indicating whether initialization completed */
extern int apparmor_initialized;
+/* semantic split of scope and view */
+#define aa_in_scope(SUBJ, OBJ) \
+ aa_ns_visible(SUBJ, OBJ, false)
+
+#define aa_in_view(SUBJ, OBJ) \
+ aa_ns_visible(SUBJ, OBJ, true)
+
+#define label_for_each_in_scope(I, NS, L, P) \
+ label_for_each_in_ns(I, NS, L, P)
+
+#define fn_for_each_in_scope(L, P, FN) \
+ fn_for_each_in_ns(L, P, FN)
+
/* fn's in lib */
const char *skipn_spaces(const char *str, size_t n);
const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
@@ -316,7 +329,7 @@ __done: \
})
-#define __fn_build_in_ns(NS, P, NS_FN, OTHER_FN) \
+#define __fn_build_in_scope(NS, P, NS_FN, OTHER_FN) \
({ \
struct aa_label *__new; \
if ((P)->ns != (NS)) \
@@ -326,10 +339,10 @@ __done: \
(__new); \
})
-#define fn_label_build_in_ns(L, P, GFP, NS_FN, OTHER_FN) \
+#define fn_label_build_in_scope(L, P, GFP, NS_FN, OTHER_FN) \
({ \
fn_label_build((L), (P), (GFP), \
- __fn_build_in_ns(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
+ __fn_build_in_scope(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
})
#endif /* __AA_LIB_H */
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 1d3fa5c28d97..ef3448ecdf5f 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -1274,7 +1274,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
* @rules: ruleset to search
* @label: label to check access permissions for
* @state: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: perms struct to set
*
@@ -1287,7 +1287,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
static int label_compound_match(struct aa_profile *profile,
struct aa_ruleset *rules,
struct aa_label *label,
- aa_state_t state, bool subns, u32 request,
+ aa_state_t state, bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_profile *tp;
@@ -1295,7 +1295,7 @@ static int label_compound_match(struct aa_profile *profile,
/* find first subcomponent that is visible */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, rules, tp, state);
if (!state)
@@ -1309,7 +1309,7 @@ static int label_compound_match(struct aa_profile *profile,
next:
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = aa_dfa_match(rules->policy->dfa, state, "//&");
state = match_component(profile, rules, tp, state);
@@ -1330,7 +1330,7 @@ fail:
* @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
+ * @subns: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: an initialized perms struct to add accumulation to
*
@@ -1343,7 +1343,7 @@ fail:
static int label_components_match(struct aa_profile *profile,
struct aa_ruleset *rules,
struct aa_label *label, aa_state_t start,
- bool subns, u32 request,
+ bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_profile *tp;
@@ -1353,7 +1353,7 @@ static int label_components_match(struct aa_profile *profile,
/* find first subcomponent to test */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, rules, tp, start);
if (!state)
@@ -1368,7 +1368,7 @@ next:
tmp = *aa_lookup_perms(rules->policy, state);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, rules, tp, start);
if (!state)
@@ -1393,24 +1393,24 @@ fail:
* @rules: ruleset to search
* @label: label to match (NOT NULL)
* @state: state to start in
- * @subns: whether to match subns components
+ * @subns: whether to match labels in view or only in scope
* @request: permission request
* @perms: Returns computed perms (NOT NULL)
*
* Returns: the state the match finished in, may be the none matching state
*/
int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
- struct aa_label *label, aa_state_t state, bool subns,
+ struct aa_label *label, aa_state_t state, bool inview,
u32 request, struct aa_perms *perms)
{
- aa_state_t tmp = label_compound_match(profile, rules, label, state, subns,
- request, perms);
+ aa_state_t tmp = label_compound_match(profile, rules, label, state,
+ inview, request, perms);
if ((perms->allow & request) == request)
return 0;
/* failed compound_match try component matches */
*perms = allperms;
- return label_components_match(profile, rules, label, state, subns,
+ return label_components_match(profile, rules, label, state, inview,
request, perms);
}