Author: Chris Brown
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> 4 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
/etc/subdomain.d/home.chris.scribble
and you can set the profile back to enforce mode with:
# enforce
/etc/subdomain.d/home.chris.scribble
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
Example |
Description |
---|---|
|
The file can be read. |
|
The file can be read and written. |
|
All files in /etc/apache2 can be read. |
|
All files in (and below) htdocs can be read. |
|
The program can create and remove links with this name. |
|
The program can execute /bin/mount which will run unconstrained; that is, without an AppArmor profile. |
|
The program can execute |
|
The program can execute |
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
orsetgid
(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 fromnetstat -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 http://crispincowan.com/~crispin/TUT304_final.sxi
.
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.