[apparmor] Questions about compat encoding in accept1 and accept2 tables
John Johansen
john.johansen at canonical.com
Sun Dec 7 08:44:09 UTC 2025
On 12/4/25 07:03, Zygmunt Krynicki wrote:
> Hello!
>
> I've been trying to document some of the bit-patterns and magic values present in the code. Looking at the macros dfa_{user,other}_{allow,xbits,audit,quiet,xindex} in security/apparmor/policy_compat.c, defined as follows:
>
> #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
> ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
> #define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f)
> #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
> #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
> #define dfa_user_xindex(dfa, state) \
> (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff))
>
> #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
> 0x7f) | \
> ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
> #define dfa_other_xbits(dfa, state) \
> ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f)
> #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
> #define dfa_other_quiet(dfa, state) \
> ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
> #define dfa_other_xindex(dfa, state) \
> dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
>
> I came up with a C type definition, ignoring undefined ordering of bitfield encoding, for a conceptual structure with the two accept fields:
>
> struct packed_perms {
> union {
> accept1 uint32_t;
> struct {
> union {
> struct {
> user_allow uint32_t : 7;
> user_xbits uint32_t : 7;
> };
> user_xindex uint32_t : 14;
> };
> union {
> struct {
> other_allow uint32_t : 7;
> other_xbits uint32_t : 7;
> };
> other_xindex uint32_t : 14;
> };
> _ uint32_t : 3;
> change_profile uint32_t : 1; // allow bit shared between user and other.
> };
> };
> union {
> accept2 uint32_t;
> struct {
> user_audit uint32_t : 7;
> user_quiet uint32_t : 7;
> other_audit uint32_t : 7;
> other_quiet uint32_t : 7;
> _ uint32_t : 4;
> };
> };
> };
>
> The following is true for kernel ABI v9+:
>
> What strikes me is the overlap of the user_{allow,xbits} with the user_xindex field. All seven bits of user_allow are meaningful - as they encode "exec", "write", "read", "append", "link", "lock" and "exec-map". The user_xbits field is only used by map_xbits which effectively bitwise-ands it with the mask 0xfc80, or in binary 0b1111_1100_1000_0000. This selects the highest bit (exec-map) and a the upper six bits of user_xbits itself. The result is interpreted as the full 32bit permission set bit-map so the bits correspond to "rename" (0x80), "set-creds" (0x400), "get-creds" (0x800), "chmod" (0x1000), "chown" (0x2000), "chgrp" (0x4000) and "lock" (0xx8000) - all granted to aa_perms.allow.
>
> How is this co-inhabited with xindex which uses the very same bits to derive, among other, an index into the transition table?
>
The file state machines accept1/2 mapping uses a different encoding than the newer policydb which uses a flatter mapping. The policydb originally skipped the "xbits" due to limitations in the compiler, but once that limitation was fixed those bits started to be used. Internally (and then externally via perms table 32) the kernel moved to mapping these to a permission table, with accept 1 becoming an index into the table. The kernel does a mapping for both the file and policydb accept table permissions to the permission table.
Originally the 7 xbits encoded the exec type + the xindex (up to 12 entries) but only if the xtable type was set in the xbits. With the new mapping moving permissions from the accept tables to an external wider permission table, the xbits get remapped to a 32 bit entry with 8 bits being used for type info, and up to 24 being used for xindex.
The bits previously used by the 7 xbits are used for other permissions in the 32 bit fields. We actually have the start of a doc around this
https://gitlab.com/apparmor/apparmor/-/blob/master/documentation/Permission%20Layout.pdf?ref_type=heads
More information about the AppArmor
mailing list