Apparmor - How to use it

By Rainer Wichmann rainer@nullla-samhna.de    (last update: Apr 29, 2013)

What is Apparmor

Apparmor is a Linux security mechanism that restricts what a process can do. E.g. if you are browsing the web using firefox, and firefox is restricted by an apparmor profile, then the firefox process can only do things that are allowed by this profile. As an example, one of these restrictions might be that within the user's home directory, firefox can only write to ~/Downloads (for downloaded files) and to the ~/.firefox directory tree (configuration data, cache, etc.). In reality, at least the Ubuntu apparmor profile for firefox allows much more, and its usefulness seems a little questionable.

An important property of apparmor is that apparmor profiles restrict processes based on the path of the executable. Thus apparmor does not provide any protection against a rogue local user who may copy an executable to another location and run it under a different path.

What it does protect against, however, is the scenario that a remote attacker may gain control over a network facing application and make it do bad things to the filesystem. E.g. when a malicious website exploits some flaw in firefox to take control of the browser, the apparmor profile could prevent firefox from doing things you may disapprove of.

How can I use Apparmor to protect a process?

On Ubuntu, you need to install the apparmor-utils package for working with apparmor:

apt-get install apparmor-utils

Say you are using application /usr/bin/foobar to offer a publicly available service on your machine (e.g. a mail server, or whatever). You want to restrict this process with an apparmor profile. How would you do that?

What you need is to stop the foobar process, and execute (as root) the following command:

aa-genprof /usr/bin/foobar

This will create an initial profile, set it to complain mode, write a start marker to the system log, and ask you to execute the application /usr/bin/foobar. Complain mode means that violations of the profile will be logged, rather than enforcing the profile.

If you use aa-genprof to refine a existing profile, you need to run the following command after starting aa-genprof and before starting your application. The reason is that aa-genprof is not smart enough to make apparmor reload the apparmor profiles:

service apparmor reload

Once you have exercised the functionality of the foobar program, you can then hit S, which will cause aa-genprof to scan the system logs and refine the profile based on the reported violations. Finally, you can hit F to finish profile generation and set the profile to enforce mode.

You can always switch back to complain mode with:

aa-complain /usr/bin/foobar

and there are also the corresponding commands aa-enforce and aa-disable, to switch back a profile to enforce mode or disable it.

Well, it isn't quite that easy...

Hitting the first bug

Following the instructions on screen, I hit 'S'. Nothing interesting happens, and the generated profile looks quite empty. Uh huh..

#include 

/usr/bin/foobar flags=(complain) {
  #include 
  #include 


  /bin/bash ix,

}

Ahem. A little search on google turns up a reference to /etc/apparmor/logprof.conf, where we have the line:

  logfiles = /var/log/audit/audit.log /var/log/messages /var/log/syslog

It turns out that on my system there is no /var/log/audit/audit.log, but /var/log/messages exists yet is empty (on Debian/Ubuntu, syslog logs most stuff to /var/log/syslog). So apparently aa-genprof uses the first existing file in the list, even if it provably contains nothing, not even the start marker logged by aa-genprof itself. At least this problem can easily be solved by removing the empty /var/log/messages file.

Ok, aa-genprof does something now

Obviously aa-genprof can't do magic, so you need to help it a little. What it does is, it will ask you questions about the rule violations it has detected. Most of the time, these will be about the execution of helper programs or access to files.

Execution of other programs (childs)
Profile:  /usr/bin/foobar
Execute:  /bin/uname
Severity: unknown


(I)nherit / (P)rofile / (C)hild / (N)ame / (U)nconfined / (X)ix / (D)eny / Abo(r)t / (F)inish

This means that the foobar program (parent) has invoked another program uname (child). You can now choose between several options. These options mean the following:

  • Inherit: The child will inherit the parent's profile and run with the same restrictions.
  • Profile: The child has its own profile (which must be loaded). Use this if the child is some system-wide service like DNS lookups
  • Child: The child will have it's own profile within the profile of the parent process.
  • Name: Use an (existing) profile that you have to specify.
  • Unconfined: The child runs without any restrictions. This may introduce a security risk.
  • Xix: The child may have its own profile but will use the parent's profile as fallback if no own profile exists.
  • Deny: Don't execute the requested program.
  • Abort: This aborts aa-genprof, and you will lose all rule changes enetred so far. The profile will not be modified.
  • Finish: This ends aa-genprof. Rule changes entered so far will be saved and the profile will be modified (takes effect after a reload of apparmor).

Access to files
Profile:  /usr/bin/foobar
Path:     /proc/4381/stat
Mode:     r
Severity: 6

  1 - /proc/4381/stat 
 [2 - /proc/*/stat]

[(A)llow] / (D)eny / (G)lob / Glob w/(E)xt / (N)ew / Abo(r)t / (F)inish / (O)pts

This means that the foobar program (parent) wants to access the file /proc/4381/stat for reading (Mode: r). You can now select one of the offered patterns for the path (square brackets indicate the currently selected one) and choose between several options. These options mean the following:

  • Allow: Allows access to this file or directory. In this particular example it makes no sense to choose the first option (1 - /proc/4381/stat) because the /proc directory holds informations about processes and the "4381" is the process id (PID) of some process. It is highly likely that next time, the number will be different, so apparmor suggests to use a wildcard (2 - /proc/*/stat).
  • Deny: Deny access to this file or directory.
  • New: This will prompt you to enter a new path that will be added to the list of offerings.
  • Glob: This will replace the last part with a wildcard, creating a new entry in the offered list. If you use this option again, an even broader wildcard expression will be created.
  • Glob w/Ext: As above, but the filename extension will be kept.
  • Abort: This aborts aa-genprof, and you will lose all rule changes enetred so far. The profile will not be modified.
  • Finish: This ends aa-genprof. Rule changes entered so far will be saved and the profile will be modified (takes effect after a reload of apparmor).

Refining the rules

The rules for an apparmor profile are stored in a file within /etc/apparmor.d/, named after the executable, with slashes in the path replaces by dots. So the apparmor profile for /usr/bin/foobar would be:

/etc/apparmor.d/usr.bin.foobar

After finishing with aa-genprof, you may want to have a look at the file. The syntax is pretty self-explanatory. Access rules for files or directories look like:

/path/to/file/or/directory  access_permissions,

For paths, the following shell style wildcard patterns are supported (see the manpage for apparmor.d). Note that noly rules that end with a trailing slash will match a directory.

*  Substitutes for any number of characters, except /.
   I.e., /tmp/* matches any file in /tmp. /tmp/*/ matches any
   directory in /tmp.

** Substitutes for any number of characters, including /.
    I.e., /tmp/** matches all files and directories underneath /tmp.
    /tmp/**/ matches all directories underneath /tmp.

?  Substitutes for any single character, except /. 

[abc] Substitutes for the single character a, b, or c.
      Note that this is a list.

[a-c] Substitutes for the single character a, b, or c.
      Note that this is a range. 

{ab,cd} Expand to one rule to match ab and another to match cd. 

[^a] Substitutes for any character except a.

Access permissions are a combination of letters like 'r' (read), 'w' (write), or 'rw' (read and write). The full list (again from the manpage for apparmor.d) is:

r    - read
w    - write -- conflicts with append
a    - append -- conflicts with write
ux   - unconfined execute
Ux   - unconfined execute -- scrub the environment
px   - discrete profile execute
Px   - discrete profile execute -- scrub the environment
cx   - transition to subprofile on execute
Cx   - transition to subprofile on execute -- scrub the environment
ix   - inherit execute
m    - allow PROT_EXEC with mmap(2) calls
l    - link
k    - lock
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.0 Germany License.