]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
apparmor: gate make fine grained unix mediation behind v9 abi
authorJohn Johansen <john.johansen@canonical.com>
Sat, 12 Oct 2024 11:43:34 +0000 (04:43 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Sat, 18 Jan 2025 14:47:13 +0000 (06:47 -0800)
Fine grained unix mediation in Ubuntu used ABI v7, and policy using
this has propogated onto systems where fine grained unix mediation was
not supported. The userspace policy compiler supports downgrading
policy so the policy could be shared without changes.

Unfortunately this had the side effect that policy was not updated for
the none Ubuntu systems and enabling fine grained unix mediation on
those systems means that a new kernel can break a system with existing
policy that worked with the previous kernel. With fine grained af_unix
mediation this regression can easily break the system causing boot to
fail, as it affect unix socket files, non-file based unix sockets, and
dbus communication.

To aoid this regression move fine grained af_unix mediation behind
a new abi. This means that the system's userspace and policy must
be updated to support the new policy before it takes affect and
dropping a new kernel on existing system will not result in a
regression.

The abi bump is done in such a way as existing policy can be activated
on the system by changing the policy abi declaration and existing unix
policy rules will apply. Policy then only needs to be incrementally
updated, can even be backported to existing Ubuntu policy.

Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/af_unix.c
security/apparmor/apparmorfs.c
security/apparmor/file.c
security/apparmor/include/policy.h

index ce7dc9d98fb1d8d15815faddda97f68d31406828..ed4b34b88e3889e51fc4892d9af2735e79746804 100644 (file)
@@ -197,7 +197,7 @@ static int profile_create_perm(struct aa_profile *profile, int family,
        AA_BUG(!profile);
        AA_BUG(profile_unconfined(profile));
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                state = aa_match_to_prot(rules->policy, state, AA_MAY_CREATE,
                                         PF_UNIX, type, protocol, NULL,
@@ -226,7 +226,7 @@ static int profile_sk_perm(struct aa_profile *profile,
        AA_BUG(is_unix_fs(sk));
        AA_BUG(profile_unconfined(profile));
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                state = match_to_sk(rules->policy, state, request, unix_sk(sk),
                                    &p, &ad->info);
@@ -251,7 +251,7 @@ static int profile_bind_perm(struct aa_profile *profile, struct sock *sk,
        AA_BUG(!ad);
        AA_BUG(profile_unconfined(profile));
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                /* bind for abstract socket */
                state = match_to_local(rules->policy, state, AA_MAY_BIND,
@@ -281,7 +281,7 @@ static int profile_listen_perm(struct aa_profile *profile, struct sock *sk,
        AA_BUG(!ad);
        AA_BUG(profile_unconfined(profile));
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                __be16 b = cpu_to_be16(backlog);
 
@@ -315,7 +315,7 @@ static int profile_accept_perm(struct aa_profile *profile,
        AA_BUG(!ad);
        AA_BUG(profile_unconfined(profile));
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                state = match_to_sk(rules->policy, state, AA_MAY_ACCEPT,
                                    unix_sk(sk), &p, &ad->info);
@@ -342,7 +342,7 @@ static int profile_opt_perm(struct aa_profile *profile, u32 request,
        AA_BUG(!ad);
        AA_BUG(profile_unconfined(profile));
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                __be16 b = cpu_to_be16(optname);
 
@@ -379,7 +379,7 @@ static int profile_peer_perm(struct aa_profile *profile, u32 request,
        AA_BUG(!ad);
        AA_BUG(is_unix_fs(peer_sk)); /* currently always calls unix_fs_perm */
 
-       state = RULE_MEDIATES_NET(rules);
+       state = RULE_MEDIATES_v9NET(rules);
        if (state) {
                struct aa_sk_ctx *peer_ctx = aa_sock(peer_sk);
                struct aa_profile *peerp;
index 45afd585b52bd3172fe740ae49f87173a459acdc..c5c756dda5cf9e5324a1c2d2d33110009dc6616f 100644 (file)
@@ -2414,7 +2414,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
        AA_SFS_DIR("domain",                    aa_sfs_entry_domain),
        AA_SFS_DIR("file",                      aa_sfs_entry_file),
        AA_SFS_DIR("network_v8",                aa_sfs_entry_network),
-       AA_SFS_DIR("network",           aa_sfs_entry_networkv9),
+       AA_SFS_DIR("network_v9",                aa_sfs_entry_networkv9),
        AA_SFS_DIR("mount",                     aa_sfs_entry_mount),
        AA_SFS_DIR("namespaces",                aa_sfs_entry_ns),
        AA_SFS_FILE_U64("capability",           VFS_CAP_FLAGS_MASK),
index d918b5dc6f59a6e21aed1c01c3e7ebfe3fcfcd35..85f89814af1e27101aeaa518fb3da4b85b44ed23 100644 (file)
@@ -228,7 +228,7 @@ int __aa_path_perm(const char *op, const struct cred *subj_cred,
        int e = 0;
 
        if (profile_unconfined(profile) ||
-           ((flags & PATH_SOCK_COND) && !RULE_MEDIATES_NET(rules)))
+           ((flags & PATH_SOCK_COND) && !RULE_MEDIATES_v9NET(rules)))
                return 0;
        aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
                     name, cond, perms);
index 5128c5414f04c28d702a9cabea7dcc3fa3d69204..a6ddf3b7478e2a5151520322f2a1d3cb42d65bea 100644 (file)
@@ -304,11 +304,27 @@ static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules,
                                        rules->policy->start[0], &class, 1);
 }
 
+static inline aa_state_t RULE_MEDIATES_v9NET(struct aa_ruleset *rules)
+{
+       return RULE_MEDIATES(rules, AA_CLASS_NETV9);
+}
+
 static inline aa_state_t RULE_MEDIATES_NET(struct aa_ruleset *rules)
 {
-       return RULE_MEDIATES(rules, AA_CLASS_NET);
+       /* can not use RULE_MEDIATE_v9AF here, because AF match fail
+        * can not be distiguished from class match fail, and we only
+        * fallback to checking older class on class match failure
+        */
+       aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NETV9);
+
+       /* fallback and check v7/8 if v9 is NOT mediated */
+       if (!state)
+               state = RULE_MEDIATES(rules, AA_CLASS_NET);
+
+       return state;
 }
 
+
 static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
                                           unsigned char class)
 {