Protect your applications with AppArmor


Author: Chris Brown

AppArmor is a product that Novell acquired when they bought the company Immunix in May 2005. It provides an interesting alternative to traditional security measures. AppArmor works by profiling the applications that it is protecting. A profile records the files that an application needs to access, and the capabilities it needs to exercise, during normal, “good” operation. Subsequently, a profile can be “enforced”; that is, attempts by the application to access resources not explicitly permitted by the profile are denied. Properly configured, AppArmor ensures that each profiled application is allowed to do what it is supposed to do, and nothing else.

This article is excerpted from the newly published bookSUSE LinuxCopyright © 2006 O’Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O’Reilly Media.

The documentation uses the metaphor of “immunizing” the applications, but the product does not actually prevent an application from being infected or compromised. Rather, it limits the damage that an application can do if this should happen.

If we must have a medical metaphor, “quarantine” might be better, or you might think of it as offering the program a large white handkerchief to sneeze into to prevent it from spreading germs.

AppArmor was originally a closed-source product, but became open source in January 2006. It is included with SUSE Linux 10.1 and with SLES9 SP3. It was also included with SUSE Linux 10.0, but the profiling tool was deliberately restricted in scope and required the purchase of a license file to become fully functional.

How Do I Do That?

To give you a feel for how AppArmor works, in this lab I’ll use it to profile and contain a very simple C program. Whilst this example is undeniably simplistic, it does help to show how AppArmor actually works.

Here’s the program that you will profile. It’s called scribble, because it scribbles on files:

#include <stdio.h>

int main(int argc, char *argv[]) { int i; FILE *fd; for (i=1; i<argc; i++) { fd = fopen(argv[i], "w"); if (fd == NULL) { fprintf(stderr, "fopen failed for %sn", argv[i]); return 1; } fprintf(fd, "scribbled on file %sn", argv[i]); fclose(fd); } }

If you can’t read C, don’t worry, it doesn’t really matter. The program loops over its command-line arguments, treating each as a filename. For each one, it tries to open the file for writing, writes a line of text to it, then closes the file. If it can’t open the file, it prints an error message. I created the source file scribble.c in my home directory and compiled it with:

$ cc scribble.c -o scribble

Before proceeding further, you must ensure that the apparmor module is loaded into the kernel. To do this, run the following command as root:

# rcapparmor start

To build a profile for this application, you can use YaST. From YaST’s main screen, select Novell AppArmor from the panel on the left, then Add Profile Wizard from the panel on the right. On the wizard’s first screen, you’re invited to enter the name of the application you want to profile. Since I built scribble in my home directory, I entered the name /home/chris/scribble then clicked Create. On the next screen, you’re invited to “start the application to be profiled in another window and exercise its functionality now”. The idea is to run the program and make it do the full range of things that it is “supposed to do”. In this case, I simply ran my little program with the command:

$ ./scribble apple orange /tmp/banana

causing it to open and write to three files. As the program runs, AppArmor records each resource that is accessed in the system log, /var/log/messages. You can run the program as many times as you want to get a complete, representative profile. When you’re done profiling, click the button labeled “Scan system log for AppArmor events.” Now we’re taken one by one through the events that AppArmor logged. For each one, AppArmor makes suggestions about what should be added to the profile. An example is shown in the figure.

Adding a rule to an AppArmor profile

In this figure, the program’s action of writing to the file /home/chris/apple has been noted and you’re offered a number of choices of what should be added to the profile to allow this. This is where you need to put your thinking cap on. One of the options is to allow access just to that one file: /home/chris/apple. Another option proposed by AppArmor is a generalization — namely, to allow writing to a file called apple in any user’s home directory (/home/*/apple). Clicking the Glob button will suggest a still broader rule to add to the profile; in this case /home/*/*. (“Glob” is short for “globbing,” a slang Unix expression relating to the use of filename wildcards.) The button labeled “Glob w/Ext” will broaden the pattern using a * wildcard, but retain the filename extension. For example, /home/chris/testimage.png would be broadened to /home/chris/*.png. Obviously, you need to make your own judgment here about what makes sense for the application. Having selected an appropriate rule, click Allow to add it to the profile, or click Deny if you don’t want it added to the profile. You’ll need to proceed event by event through the activities that AppArmor has logged in order to complete the profile.

Once the profile is built, AppArmor will automatically begin to enforce it. If I now try to use scribble to write to a file that’s within the profile, all is well, but if I try to access a file that’s not in the profile, it fails:

$ ./scribble apple
$ ./scribble mango

fopen failed for mango

The restrictions imposed by AppArmor are, of course, in addition to those imposed by the underlying filesystem. For example,

$ ./scribble /etc/passwd

will fail regardless of AppArmor, because I don’t have write permission on the file.

Profiling needs to be done with care. Too tight a profile means that the application can’t do its job. For example, one version of AppArmor I tested shipped with a profile for the PDF viewer acroread, which, if enforced, prevented Adobe Acrobat Reader from viewing the AppArmor documentation!

How It Works

AppArmor installs a module into the Linux kernel that monitors resource usage of programs according to their profiles. A profile can be interpreted in one of two modes: enforce mode, and complain (or learning) mode. In complain mode (used by the create profile wizard), AppArmor logs a line to /var/log/audit/audit.log through the kernel logging daemon klogd for each resource that the application accesses. Here’s a typical entry:

type=APPARMOR msg=audit(1144091465.305:6): PERMITTING w access to /home/chris/apple
(scribble(26781) profile /home/chris/scribble active /home/chris/scribble)

In the second stage of profile generation, the profile wizard works its way through these lines, prompting you for the rules to be added. Behind the scenes, the utility logprof does the work here. (logprof can also be used to build the profile from the command line instead of using the YaST wizard.)

In enforce mode, system calls made by the process for resources not explicitly allowed by the profile will fail (and a message will be logged to /var/log/messages).

The profiles are stored in the directory /etc/apparmor.d. They are loaded into the kernel by the program apparmor_parser. The profile for my little /home/chris/scribble application is written to the file home.chris.scribble. The profile I generated looks like this. The line numbers are for reference; they are not part of the file.

1 # Last Modified: Wed Dec  7 15:13:39 2005
2 /home/chris/scribble {
3   #include <abstractions/base>
5   /home/chris/orange w,
6   /home/chris/scribble r,
7   /tmp/banana w,
8 }

Line 2 (along with the matching bracket on line 8) defines the application that this profile applies to. Line 3 includes the contents of the file /etc/apparmor.d/abstractions/base. AppArmor uses a lot of #include files to factor out common sets of access requirements into separate files. For example there are #include files for access to audio devices, for authentication, and for access to name servers. The abstractions/base file referenced here is largely to do with allowing access to shared libraries. Lines 5 – 7 are the rules for this specific application.

To profile an application in complain mode, add the notation flags=(complain) to line 2 of the profile, so that it reads:

/home/chris/scribble flags=(complain) {

You can also do this from the command line using:

# complain

and you can set the profile back to enforce mode with:

# enforce

Using complain and enforce also loads the new profile into the kernel.

AppArmor refers to the type of profiling I just performed as standalone profiling. It also supports systemic profiling, which puts all the profiles into complain mode and allows you to run them over many hours or days (even across reboots) to collect as complete a profile as possible.

The range of resource requests that AppArmor can allow or deny is broader than the simple file access checks used in this example. For example, it’s also capable of restricting program execution (via the exec system call).

Table 8-4. Example profile rules



/etc/ r,

The file can be read.

/var/run/ rw,

The file can be read and written.

/etc/apache2/* r,

All files in /etc/apache2 can be read.

/srv/www/htdocs/** r,

All files in (and below) htdocs can be read.

/tmp/myprog.* l,

The program can create and remove links with this name.

/bin/mount ux

The program can execute /bin/mount which will run unconstrained; that is, without an AppArmor profile.

/usr/bin/procmail px

The program can execute procmail, which will run under constraint of its own profile.

/usr/bin/sendmail ix

The program can execute sendmail, which will inherit the profile of the current program.

Earlier versions of AppArmor included rules that restricted the establishment of UDP and TCP connections. These rules have been removed from the current version of the product, but may be restored in a future version.

What About…

…deciding what to profile? AppArmor is not intended to provide protection against execution of ordinary tools run by ordinary users. You already have the classic Linux security model in place to constrain the activities of such programs. AppArmor is intended for use on servers which typically have few or no regular user accounts. Indeed, there is no way to define user-specific profiles in AppArmor, and there is no concept of a role.

AppArmor should be used to constrain programs that (quoting the user guide) “mediate privilege”; that is, programs that have access to resources that the person using the program does not have. Examples of such programs include:

  • Programs that run setuid or setgid (i.e., which run with the identity of the program’s owner or group). You can find programs that run setuid to root with the command:

    # find / -user root -perm -4000

  • Programs run as cron jobs. You can find these by ferreting around in the crontab files in directories such as /etc/cron.d, /etc/cron.daily, /etc/cron.weekly, and so on.

  • Web applications; for example, CGI scripts or PHP pages invoked by a web server.

  • Network applications that have open ports. AppArmor provides a little utility called unconfined that uses the output from netstat -nlp to identify programs that are currently running with open network ports, but which currently have no profile.

Where to Learn More

For a brief but more technical overview, read the apparmor manpage. For full details of the syntax of the profile files, read the apparmor.d manpage.

There’s an interesting comparison of containment technologies such as chroot, Xen, selinux, and AppArmor at

SUSE Linux 10.0 contains a detailed user guide for AppArmor in PDF format. Although it’s thorough, it is rather labored and has a decidedly non-open-source feel; it even contains the immortal line “contact your sales representative for more information.” This guide has been removed in SUSE Linux 10.1, but documentation is available by following the the links here.