Ubuntu 26.04 Tutorial / Inspect AppArmor Profiles and Denial Logs
AppArmor adds per-program controls over files, execution, networking, and other operations. Investigate ordinary filesystem permissions alongside the active profile and denial logs rather than disabling AppArmor globally as the first fix.
Distinguish ordinary permissions from profiles
A program can be denied by AppArmor even when user, group, and file mode allow access. Conversely, no AppArmor message does not establish correct directory permissions, mount state, or service identity. Record the failing path and executing account first.
Inspect loaded profiles and modes
sudo aa-status
systemctl status apparmor --no-pager
Enforce and complain modes differ: enforce applies policy, while complain helps investigation but can reduce protection. Service status alone does not prove every process is confined; inspect loaded profiles and associated processes in aa-status.
Ubuntu’s security documentation explains AppArmor enforcement, modes, and confinement scope.
Correlate the failure with recent logs
sudo journalctl -k -b --since '10 minutes ago' --no-pager | grep 'apparmor="DENIED"'
Record the time of one controlled reproduction and correlate profile, operation, name, pid, requested_mask, and denied_mask. Use the actual output instead of presenting fabricated logs as a machine result. Share only necessary lines because paths and user details can be sensitive.
If no output appears, check boot, time range, collection path, and the actual profile. Explicit deny rules and other conditions may not produce the expected message, so absence of logs is not proof of permission.
Read denial fields using an illustrative example
The line below is an invented field-reading example, not a log collected from a particular Ubuntu machine. profile identifies the policy, operation the attempted action, and name the target path. The r in requested_mask and denied_mask represents requested and denied reading.
apparmor="DENIED" operation="open" profile="/usr/sbin/example-app" name="/srv/example-data/settings.ini" requested_mask="r" denied_mask="r"
In a real investigation, correlate failure time, process, identity, and path. This is not a prescription to grant access to the illustrative path. Restoring a supported data location may be the appropriate fix; do not allow every logged request.
Identify the profile and its owner
For ordinary profiles, identify the name and executable under /etc/apparmor.d. For generated policies such as Snap profiles, inspect interfaces and publisher settings rather than editing generated output. Do not invent a profile filename or copy another program’s policy blindly.
If an unsupported data-path change caused the issue, first consider restoring a supported location. A policy change needs a documented operation, exact path, access scope, and backups of the profile and local includes. Do not allow the whole disk through broad wildcards.
Check a profile without loading it into the kernel
Identify one ordinary profile’s actual source file and enter it below; exclude Snap-generated policies from this editing exercise. -Q skips kernel loading and -K disables caching. Successful compilation does not establish correct application allow/deny behavior.
(
set -eu
read -r -p 'Actual ordinary profile path under /etc/apparmor.d/: ' profile
case "$profile" in
/etc/apparmor.d/*) ;;
*) printf 'Choose the verified profile source.\n' >&2; exit 1 ;;
esac
sudo test -f "$profile"
sudo apparmor_parser -Q -K "$profile"
)
If a scoped policy edit is actually required, back up the source and local includes, pass this check, and reload that profile with sudo apparmor_parser -r ACTUAL_PROFILE_FILE. On failure, restore those backups, validate/reapply, and check aa-status and the original enforce state. Do not reload anything for inspection-only practice.
Check the official AppArmor 5.0 manual for compilation, cache, and kernel replacement behavior.
Define narrow changes, checks, and rollback
Validate an edited profile with official tools, reload only that profile, and test both the operation that should work and operations that should remain denied. Review diagnostic tools’ proposed rules rather than approving every logged request.
On failure, restore only the policy change and verify the original enforce state and application behavior. Do not make the test pass by disabling AppArmor or user-namespace protections globally. Record cause, profile, scope, allowed and denied tests, and rollback steps.




