Paranoid Penguin - AppArmor in Ubuntu 9
The Future of AppArmor
AppArmor has been adopted as the default Mandatory Access Control solution for both the Ubuntu and Mandriva distributions. I've sung its praises before, and as evidenced by writing my now third column about it, clearly I'm still a fan.
But, you should know that AppArmor's future is uncertain. In late 2007, Novell laid off its full-time AppArmor developers, including project founder Crispin Cowan (who subsequently joined Microsoft).
Thus, Novell's commitment to AppArmor is open to question. It doesn't help that the AppArmor Development Roadmap on Novell's Web site hasn't been updated since 2006, or that Novell hasn't released a new version of AppArmor since 2.3 Beta 1 in July 2008, nearly a year ago at the time of this writing.
But, AppArmor's source code is GPL'd: with any luck, this apparent slack in AppArmor leadership soon will be taken up by some other concerned party—for example, Ubuntu and Mandriva developers. By incorporating AppArmor into their respective distributions, the Ubuntu and Mandriva teams have both committed to at least patching AppArmor against the inevitable bugs that come to light in any major software package.
Given this murky future, is it worth the trouble to use AppArmor? My answer is an emphatic yes, for a very simple reason: AppArmor is so easy to use—requiring no effort for packages already having distribution-provided profiles and minimal effort to create new profiles—that there's no reason not to take advantage of it for however long it remains an officially supported part of your SUSE, Ubuntu or Mandriva system.
At a high level, creating a new AppArmor profile involves creating a deny all policy and then running that profile in complain (log-only) mode; running your application in as typical a fashion as possible; using the resulting log messages to loosen up the profile enough (but only enough) for the application to work properly; and setting the finished, tuned profile to enforce mode.
AppArmor, through its genprof and logprof commands, walks you through this entire process interactively. I'm not going to cover the process for tweaking existing AppArmor profiles with logprof. logprof sessions are very similar to genprof sessions, so if you're comfortable creating new profiles, it's easy to tweak existing ones. (See Resources for more information on the latter.)
So, let's walk through the process of creating a new AppArmor profile. For this example scenario, let's start with a simple shell script, spaztacle.sh, that could use some protection. Listing 1 shows the script itself.
Listing 1. A Shell Script Needing AppArmor Protection
#!/bin/sh # # spaztacle.sh : archives /var/spaetzle to specified tar-file tar -cf $1 /var/spaetzle
As you can see, this script allows users to create a backup archive of the directory /var/spaetzle, using the archive filename specified in the command line (for example, spaztacle.sh mybackup.tar). To create an AppArmor profile for it, run the following command:
bash-$ sudo genprof spaztacle.sh
What follows is an interactive question-and-answer session in which:
genprof creates a new AppArmor profile for spaztacle.sh, containing a simple “deny all access” policy.
genprof loads the new policy in complain mode and prompts you to start the application in a separate window (this is your first opportunity to demonstrate normal application activity to genprof).
After you've demonstrated the application sufficiently, genprof analyzes the messages the new profile generated in /var/log/messages.
For each log message, genprof asks what sort of rule to add to your new AppArmor profile to account for the behavior that was logged.
After all log messages have been analyzed, genprof allows you to repeat the test/analyze cycle, which may or may not result in additional rules for the profile.
When you're done with the testing/log-analyzing cycle, genprof saves the profile and loads it in enforce mode. You're done!
A full genprof session is too lengthy to list and dissect here, but we can discuss some highlights from my sudo genprof spaztacle.sh session that illustrate how the process works.
First, I'm asked whether genprof should query the AppArmor profile repository at opensuse.org. I select d to disable repository access.
Next, I'm prompted to run my application. So I open another xterm window, and from my home directory, run the command spaztacle.sh arf.tar. That command results in the file arf.tar being written in my home directory, as expected.
Back in the genprof session, I type s to begin scanning the system log for AppArmor messages. genprof asks me whether and how to allow /bin/tar to be executed. This, of course, is the core function of spaztacle.sh, so I type i to cause tar to be allowed, “inheriting” the same profile as spaztacle.sh itself.
Next, I'm asked whether to allow /bin/dash to run. Because spaztacle.sh is a Bourne shell script, it needs to be interpreted by /bin/dash (on Ubuntu 9.04 /bin/sh actually is a symbolic link to /bin/dash). I type a to allow /bin/dash to run.
Then, I'm asked whether spaztacle.sh may read itself—that is, /usr/bin/spaztacle.sh. This is an expected part of the script-parsing process; I type a.
For now, there are no further log messages to process, so genprof prompts me to save the tweaked profile and asks whether to scan for more events. Before answering, I switch to my other xterm window, change my working directory to /home/mick/Public, and run the command spaztacle.sh anothertar.tar.
Sure enough, back in the genprof session after I type s again, there's a new set of “complaints” to process. The first concerns whether spaztacle.sh (actually tar) can read /etc/group. I'm given the option of allowing access only to /etc/group or of enabling the abstraction called nameservice.
Abstractions are groups of commonly accessed profile objects that constitute common system functions and services, such as checking file permissions, looking up hostnames and so forth. In this case, I select the nameservice abstraction and type a to allow it.
Next, genprof asks me whether to allow only write access to the (new) file anothertar.tar, or to use some sort of wild card (“glob” in AppArmor parlance). Because I want users to be able to create arbitrary tar archives in their respective home directories, I type n to specify a new glob, and specify /home/**.
In AppArmor profiles, ** is a wild card that means “any string, including /”. This is in contrast to *, which means “any string up to and excluding a / and anything after it”. Therefore, /home/** means “everything within /home/, including all subdirectories of its subdirectories”.
This implies that users might be able to write files to other users' home directories, but AppArmor controls augment normal Linux filesystem permissions; they don't replace them. In our example, therefore, users will be able to write to other other users' directories only if those directories' permissions are set accordingly.
In fact, our /home/** rule actually reduces the number of places spaztacle.sh can create tar archives. Without this rule, spaztacle.sh can write in any directory in which the user executing it has write privileges, not just subdirectories of /home/.
There are just two more log entries to account for. One concerns read access to /var/spaetzle. I type a to allow this access. You might be tempted to create a new glob instead, /var/spaetzle/**, but as it happens, tar handles the directory itself and its contents separately.
Therefore, only after creating the rule allowing access to /var/spaetzle and being prompted for a decision on allowing access to the file /var/spaetzle/arf.txt, will I type n, create the new glob /var/spaetzle/** and allow access to it.
Finally, we've reached the end of the new AppArmor events in /var/log/messages. When genprof asks me what to do after saving the changed profile, I finish the genprof session. genprof puts my new profile into enforce mode, reloads it and I'm done! Listing 2 shows the result, /etc/apparmor.d/usr.bin.spaztacle.sh.