Linux permissions generally rely on Discretionary Access Control (DAC)—if a user has read/write permission to a file, they can do whatever they want with it. However, if a web server running as the www-data user gets compromised, the attacker inherits all the permissions of that user, potentially allowing them to modify sensitive system files. Ubuntu mitigates this using AppArmor, a Mandatory Access Control (MAC) system. AppArmor confines programs to a limited set of resources based on predefined profiles, regardless of the user’s traditional permissions.
Step 1: Check AppArmor Status
AppArmor is installed and enabled by default on all modern Ubuntu releases.
To verify its status and see which profiles are currently loaded, run:
sudo apparmor_status
You will see an output listing the number of profiles loaded. Pay attention to the terms Enforce (where AppArmor actively blocks violations) and Complain (where AppArmor allows the violation but logs it for debugging).
Step 2: Understand the Profile Location
AppArmor profiles are stored as plain text files in the /etc/apparmor.d/ directory. Let’s look at the profile for the Nginx web server (if installed).
cat /etc/apparmor.d/usr.sbin.nginx
Inside the profile, you will see rules defining exactly what the nginx binary is allowed to do. For example, you might see /var/www/html/** r, which grants read access to all files within the web root. If Nginx tries to read /etc/shadow (the password hash file), AppArmor will block it because there is no rule explicitly allowing it.
Step 3: Toggle Enforce and Complain Modes
If an application is crashing and you suspect AppArmor is blocking it, you should temporarily switch the profile to Complain mode.
First, install the AppArmor utilities package:
sudo apt install apparmor-utils
Now, put a specific profile (e.g., Nginx) into Complain mode:
sudo aa-complain /usr/sbin/nginx
Restart the application and test it. If it works perfectly now, you know AppArmor was the culprit. Once you have finished debugging and updating the profile, put it back into Enforce mode:
sudo aa-enforce /usr/sbin/nginx
Step 4: Generate a New Profile using aa-genprof
If you install a custom piece of software (e.g., a custom Python daemon located at /opt/myapp/daemon.py), it will not have an AppArmor profile. You can generate one automatically using aa-genprof.
- Run the profiler tool:
sudo aa-genprof /opt/myapp/daemon.py - The tool will create a blank profile and place it in Complain mode. It will then wait.
- In a separate terminal window, start your custom daemon and put it through its normal paces (read files, write to logs, open network ports).
- Return to the
aa-genprofwindow and press S to scan the system logs. - The tool will present you with every action your program attempted that was not explicitly allowed by the blank profile. It will ask you to Allow (A) or Deny (D) each action.
- Once you have answered the prompts, press F to finish.
Step 5: Applying Changes
If you manually edit a profile using nano, the changes do not take effect immediately. You must reload the specific profile into the kernel.
sudo apparmor_parser -r /etc/apparmor.d/opt.myapp.daemon
Alternatively, you can restart the entire AppArmor service:
sudo systemctl reload apparmor