Home / Alt manpages / aa-features-abi(1)

  • aa-features-abi(1)
  • User command
  • linux

Save an AppArmor Feature ABI with aa-features-abi

aa-features-abi grabs a snapshot of exactly what your running kernel's AppArmor build can do. Save it, compare it against another machine, or feed it straight into a different AppArmor tool. This walkthrough uses AppArmor 4.0.1, installed here as package version 4.0.1really4.0.1-0ubuntu0.24.04.7.

Give it about ten minutes. You need a shell, the AppArmor utilities package, and somewhere writable to save the result. Reading the kernel's feature set is normally unprivileged; writing the file just needs ordinary filesystem permission on the destination, not automatic sudo.

1. Check the command is actually there

Before you trust any output, confirm the binary and its package version. This step is read-only:

$ command -v aa-features-abi
/usr/bin/aa-features-abi
$ dpkg-query -W -f='${Package} ${Version}\n' apparmor
apparmor 4.0.1really4.0.1-0ubuntu0.24.04.7
$ aa-features-abi --help
USAGE: aa-features-abi [OPTIONS] <SOURCE> [OUTPUT OPTIONS]

The installed help text is the real contract for this release, not whatever you remember from a blog post. Every run needs a source, either --extract or --file. Output defaults to standard output unless you pick a destination with --write.

Checkpoint

If command -v comes back empty, stop and reinstall the AppArmor utilities through your normal package manager. Do not paste in a similarly named script and hope.

2. Extract the kernel's feature ABI to your terminal

Start with --extract plus --stdout, a safe first look that writes nothing:

$ aa-features-abi --extract --stdout
capability {0xffffff
}
caps {extended {yes
}
mask {chown dac_override ...
}
}
dbus {mask {acquire send receive
}

Your output will not match this one exactly. The feature list is specific to your running kernel and AppArmor configuration; the braces and names are data, not a sign the command changed anything. If you are calling this from a script, keep the exit status:

$ aa-features-abi --extract --stdout >/dev/null
$ printf 'exit status: %s\n' "$?"
exit status: 0

A quick peek with head is fine for a look, but do not mistake that truncated preview for the full ABI. Piping a large capture into something that exits early can also throw a broken-pipe error, so capture the whole stream if the file actually matters.

3. Save a complete ABI you can review later

Pick a path that is writable and not in use by a running service. The example below lands under /tmp, which is fine for a disposable test but nothing more. This step does touch the filesystem: it creates or overwrites the named file.

$ abi_file=$(mktemp /tmp/apparmor-features-abi.XXXXXX)
$ aa-features-abi --extract --write "$abi_file"
$ printf 'saved %s bytes to %s\n' "$(wc -c <"$abi_file")" "$abi_file"
saved 1234 bytes to /tmp/apparmor-features-abi.A1b2C3

The byte count and random suffix above are just examples from one run. Confirm the file actually landed and has content before you rely on it:

$ test -s "$abi_file" && echo 'feature ABI capture is non-empty'
feature ABI capture is non-empty

Keep this temporary file until the round-trip check in the next step is done. If you want a permanent copy, never overwrite a system-managed ABI or a file used by policy tooling without checking who owns it and how it is backed up. Worth saying plainly: a feature ABI describes what the kernel can do; it is not a policy file, and writing one here does not load anything into the kernel.

4. Read a saved ABI back and check it round-trips

--file swaps the source from the live kernel to a saved file. With no output flag, the data just prints:

$ aa-features-abi --file "$abi_file" --stdout
capability {0xffffff
}
caps {extended {yes
}

To check the file is valid as input without dumping the whole thing to your screen, write it to a second temporary file and compare the bytes:

$ copy_file=$(mktemp /tmp/apparmor-features-abi-copy.XXXXXX)
$ aa-features-abi --file "$abi_file" --write "$copy_file"
$ cmp -- "$abi_file" "$copy_file"
$ echo 'saved ABI round-trip matches'
saved ABI round-trip matches

"Validate" here only means the command accepted the file and reproduced it byte for byte. It does not mean the ABI suits a different kernel. Only compare captures when you actually know which kernel and AppArmor package produced each one.

5. Know the common failures before they confuse you

Every run needs a source option. Give it only an output option and you get an argument error, not an empty result:

$ aa-features-abi --stdout
USAGE: (null) [OPTIONS] <SOURCE> [OUTPUT OPTIONS]
Output AppArmor feature abi from SOURCE to OUTPUT
$ printf 'exit status: %s\n' "$?"
exit status: 1

This build prints its usage text when the source is missing, and the program name can show up as (null) in that message; that is a quirk of this release, not a sign something else broke. Script against the non-zero exit status, not the wording. A missing input file fails the same way, not with a silently empty ABI:

$ aa-features-abi --file /path/to/missing-features-abi --stdout
aa-features-abi: ERROR: failed to open file '/path/to/missing-features-abi' - No such file or directory
$ printf 'exit status: %s\n' "$?"
exit status: 1

If --write cannot create the destination, check the parent directory, ownership and free space first. Reach for sudo only when the destination genuinely needs it and you have thought through what that grants. Do not widen permissions on a whole directory just to make one capture succeed.

The short flags: -x for extraction, -f FILE for an input file, -w FILE for output. Stick to the long forms in anything you plan to maintain. --debug adds debug noise and --verbose prints statistics; neither one fixes a bad path or touches AppArmor policy.

Once you are done reviewing, clean up only the exact files you made:

$ rm -- "$abi_file" "$copy_file"
$ test ! -e "$abi_file" && test ! -e "$copy_file" && echo 'temporary captures removed'
temporary captures removed

Done means

  • You confirmed the version. The installed AppArmor package and command match what you expected.
  • You extracted a full ABI. You captured the whole feature set and checked its exit status, not just a truncated preview.
  • You saved it somewhere deliberate. The destination's ownership and purpose were something you actually checked first.
  • You proved the round-trip. Reading the saved file back with --file and comparing with cmp matched byte for byte.
  • You know its limits. The tool reads and writes ABI data; it never loads policy or changes the kernel itself.
  • You tidied up. Disposable captures were removed, and any permanent copy is under proper change control.