[apparmor] [PATCH] apparmor: synthesize ACCEPT_FLAG_OWNER bits in file pdb

Zygmunt Krynicki me at zygoon.pl
Tue Nov 25 07:12:19 UTC 2025


The file PDB implements "owner" checks by either encoding them in one of
two ways. The, historically, more common way was to use DFA accept{1,2}
tables - which are then picked up by the compatibility logic and work
correctly. The new way is to use the permissions table and index it with
a per-DFA-state index stored in the accept1 table. To indicate presence
of owner/non-owner distinction, the accept2 table contains, at each
index, the ACCEPT_FLAG_OWNER bit. This indicates that the permissions
table is twice as large as the number of states in the DFA, and that
each state corresponds with a pair of permissions, not just one. The
even index is used for owner permissions and the odd index is used for
non-owner permissions.

AppArmor parser 4.1.2 can emit a file PDB without the accept2 table
being defined in the binary blob. This causes the kernel to create a
zero-filled accept2 table for compatibility. The rest of the logic
remains intact and in the absence of the ACCEPT_FLAG_OWNER bits, the
kernel grants "owner" permissions to non-owners.

To remedy this problem, when loading the file PDB, if the accept2 table
is missing but the permission table exists and has size compatible with
the owner/non-owner encoding, set the ACCEPT_FLAG_OWNER bit at every
index of the place-holder table.

Signed-off-by: Zygmunt Krynicki <me at zygoon.pl>
---
 security/apparmor/policy_unpack.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 7523971e37d9c..bbd5ed805c00e 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -710,7 +710,7 @@ static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms)
 }
 
 static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
-		      bool required_dfa, bool required_trans,
+		      bool required_dfa, bool required_trans, bool uses_owner,
 		      const char **info)
 {
 	struct aa_policydb *pdb;
@@ -787,6 +787,14 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
 			*info = "failed to alloc dfa flags table";
 			goto out;
 		}
+		/* The accept1 table is clearly indexing perms table and is twice the
+		 * number of states (as indicated by the base table), so the user/other
+		 * split is in effect - the permissions table has two entries for each
+		 * state. Synthesize the missing owner flag all entries. */
+		if (uses_owner && pdb->size == 2 * pdb->dfa->tables[YYTD_ID_BASE]->td_lolen) {
+			for (u32 i=0; i<noents; i++)
+				pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_data[i] |= ACCEPT_FLAG_OWNER;
+		}
 		pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_lolen = noents;
 		pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_flags = tdflags;
 	}
@@ -895,7 +903,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
 	(void) aa_unpack_str(e, &profile->attach.xmatch_str, "attach");
 
 	/* xmatch is optional and may be NULL */
-	error = unpack_pdb(e, &profile->attach.xmatch, false, false, &info);
+	error = unpack_pdb(e, &profile->attach.xmatch, false, false, false, &info);
 	if (error) {
 		info = "bad xmatch";
 		goto fail;
@@ -1028,7 +1036,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
 	if (aa_unpack_nameX(e, AA_STRUCT, "policydb")) {
 		/* generic policy dfa - optional and may be NULL */
 		info = "failed to unpack policydb";
-		error = unpack_pdb(e, &rules->policy, true, false,
+		error = unpack_pdb(e, &rules->policy, true, false, false,
 				   &info);
 		if (error)
 			goto fail;
@@ -1053,7 +1061,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
 		rules->policy = aa_get_pdb(nullpdb);
 	}
 	/* get file rules */
-	error = unpack_pdb(e, &rules->file, false, true, &info);
+	error = unpack_pdb(e, &rules->file, false, true, true, &info);
 	if (error) {
 		goto fail;
 	} else if (rules->file->dfa) {
-- 
2.52.0




More information about the AppArmor mailing list