With the help of Magnus Runesson, Jesse Michael, Martin Pitt, and many others, I’ve got AppArmor packaged and uploaded into Feisty universe. Prior to this, admins interested in a Mandatory Access Control system in Ubuntu only had SELinux available; now we have more of a choice. For anyone wanting to try out AppArmor, you will need to compile the modules, and install the base packages:
sudo apt-get install apparmor-modules-source dpatch
sudo m-a -v -t prepare
sudo m-a -v -t build apparmor-modules
sudo m-a -v -t install apparmor-modules
sudo apt-get install apparmor apparmor-utils apparmor-profiles libterm-readline-gnu-perl
With the default profiles, you can see one quick example of a confined process. Try doing this:
ping localhost >/dev/null &
sudo ps aZ | grep ping
In the first column, you should see what profile is being used to confine the process:
/bin/ping 14351 pts/14 S 0:00 ping localhost
unconstrained 15381 pts/14 S+ 0:00 grep ping
The list of active profiles can be seen as root in /sys/kernel/security/apparmor/profiles
, which are loaded from /etc/apparmor.d/
.
To confine a process, use aa-autodep
and aa-logprof
. For example, I wanted to confine my PDF document browser to only use /tmp (since I tend to only use it when browsing PDFs online):
- First, I create an empty profile in “complain” mode:
sudo aa-autodep evince
- Next, I run evince like I normally would, including as many actions as I can think of (printing, preferences, help, etc). Watching the output of
dmesg
you can follow the trail of all the actions evince is taking. When I’m finished, I quit evince. - Next, I run
aa-logprof
, which runs through all the kernel audit output and offers suggestions on what to allow from evince. Where appropriate, I select “abstrations” for things like Gnome, DNS, fonts, tmp dir usage, etc. When a whole directory tree should be allowed, I double-glob the path (/usr/share/evince/**
). Once all the items from the log have been processed, the profile is saved. - Finally, I enable the profile with
aa-enforce evince
. Any disallowed actions will show up in the kernel logs.
Check out the resulting profile for evince.
Now if I end up reading a malicious PDF that takes advantage of some currently-unknown vulnerability in evince, it will be confined to the above AppArmor profile, unable to exec new processes, and only able to write to the Gnome preferences for evince. (It’s also unable to read files out of /home, so that the above profile may be way too strict for common usage. And to even get caught by AppArmor, the imaginary exploit would have to avoid the randomized stack, randomized heap, stack protector, and, since I’m running 64bit, the NX processor bit.)
Be aware, this is still a new bit of packaging for Ubuntu, so you may run into sneaky gotchas. If that happens, please open a bug.
© 2007, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 License.
Is there some way for malicious code to execute DBus (or other IPC) methods that would circumvent all of this?
Comment by Alex Jones — April 2, 2007 @ 11:16 am
I haven’t tried it myself yet, but I’d suspect that any unix-socket based communication would need “write” access to the files. AppArmor does not confine unprivileged network calls, so exploits that try to become a network zombie or perform internal network port-scans could, in theory, still happen. It’s not a cure-all by any means, but it is yet another layer of protections that admins can choose to use.
Comment by kees — April 2, 2007 @ 11:25 am
Note that apparmor security can be bypassed due to it’s reliance on path names. It’s somewhat assuming the user is a ‘good guy’ which totally doesn’t make sense.
In your example, if I do “cp /usr/bin/evince /tmp/evince” and then run evince, your policy doesn’t apply anymore.
If there is any directory where there are write and execute permissions (or getting any other process to write there, so any directory with execute permissions is very dangerous!), apparmor security can be bypassed, too.
And last but not least:
– you rely on being able to trigger all functionality you need during the training phase.
– you still have to choose the right ‘abstractions’; in your case it looks like you are either missing some abstraction or have some duplication; the .Xauthority access for example should be in the Gnome abstraction, shouldn’t it?
– this approach is okay as long as you are dealing with simple applications. But abstractions will quickly be unsatisfying once you are dealing with the *interaction* of multiple services.
AppArmor is seriously hyped. Novell is totally behind it, sure, but I havn’t seen real scientific support for it yet. That it’s a tight security system and such.
Comment by Erich Schubert — April 2, 2007 @ 4:46 pm
Of course! These are known issues with AppArmor. I was simply giving a quick overview for people who have been interested in using AppArmor on Ubuntu. Making it available for use is my primary goal, so that people can research its effectiveness, develop profiles, and generally get some discussion going. Which seems to be working! :)
Comment by kees — April 2, 2007 @ 5:19 pm
Erich, I read your blog on this topic.. and am an SElinux fan myself, but … I don’t think your comment about “cp /usr/bin/evince /tmp/evince” is really relevant, as what Kees is trying to protect against is malicious pdf executed from *his* /usr/bin/evince usage. How will copying /usr/bin/evince to /tmp give you (the attacker) any extra privileges you didn’t already have ?
(BTW: I’m assuming the evince process isn’t allowed to put code into /tmp and execute it!)
A counter example for how to develop a module for confining /usr/bin/evince using selinux would be interesting!
Comment by Jan-Frode Myklebust — April 3, 2007 @ 1:01 am
Erich has completely misunderstood AppArmor’s security model.
Under AppArmor, a system administrator must confine untrusted applications. If the system administrator does not trust Erich, then Erich must not have an unconfined shell. If the system administrator does trust Erich, then Erich may have an unconfined shell.
Any attack that starts with “using an unconfined shell..” is outside the AppArmor threat model. AppArmor is designed first-and-foremost to allow a system administrator to confine services that the admin must run, without requiring the admin to develop policy for the entire rest of the system. AppArmor can also be used in desktop environments to confine applications that the user does not trust with all their data.
But any process that is a threat is supposed to be confined.
Moving on to your other complaints:
It is true that our learning mode can only assist users write policy for things their application has done. Sites with good test suites can do this without trouble. (Prominent online retailers have profiled their entire application suite in under four hours. Most of this time was spent drinking coffee, because their test suite was very comprehensive. :)
Installations without good test suites must rely on placing their applications into learning mode “long enough” to catch a representative sample of what their applications must do, and then make good choices when being prompted about accesses to allow. Since our policy is simple text files, system administrators are free to hand-edit policy to add rules they know should be added, but weren’t captured during training — as well as remove rules added too hastily.
The abstractions are there entirely as an aid to profiling. Feel free to not use them if you don’t like my choices. Feel free to make your own abstractions. (Most of our users do. :) We decided to try to keep the abstractions orthogonal and minimal, so abstractions/gnome doesn’t automatically include abstractions/X — in this specific case, an access to both ~/.Xauthority and ~/.gtkrc-2.0 will prompt the user for including both abstractions/gnome and abstractions/X.
There are times when abstractions make good sense (read access to a bunch of libraries, fonts, data files, write access to e.g. nscd pipes, audit logs, etc) and there are times when abstractions aren’t the right answer (data pumps — one process must write only, one process must read only). In this case, there are two simple approaches: (a) either put the required rights in profiles directly, without abstractions (b) create ‘read’ and ‘write’ versions of abstractions. (b) is usually only worth the hassle if there are multiple kinds of readers and writers…
AppArmor isn’t for everyone — e.g., the DoD and so forth would probably be better served by labelled data schemes such as SELinux that can provide MLS policies that confine the entire computer. AppArmor is designed to make confining specific applications easy.
Users have a choice of mandatory access control systems, and I definitely think every user should give each system an afternoon’s test to decide which is a better match for their needs.
Thanks for your comments.
Comment by Seth Arnold — April 3, 2007 @ 9:08 am
Seth Arnold,
Can you provide a real-life example of AppArmor with a restricted shell that is still useful?
Because evince is like the simplest example. It’s a monolithic, binary application that doesn’t interact with others much (though I’m not sure if above policy would allow printing!)
Now if you look at some application written in Python, Perl or SH, things become really different. Shell scripts especially rely on being able to execute *tons* of other commands. And the next obvious question is: how about virtual machines? Can I really confine applications written in Mono or Java?
I’m totally with you that users should have a choice in MAC systems. However these systems *need* to be technically sound, and I’m not convinced of that point with AppArmor. I still have the impression that AppArmor can control 90%-95% of common accesses, however the remaining 5% may easily leave enough room open for a privilege escalation. And this is very dangerous.
You suggested that “each admin should give each system an afternoon’s test to decide which is a better match for their needs”. I seriously doubt that a typical admin will be able to judge if the system covers *any* attack vector relevant to him. An ‘admin’ is not a securit experct, he can’t be expected to judge a system for it’s security on a day; so this suggestion of yours is actually *suggesting that an admin should pick his security solution by how easy it is to use*!
What the admin needs instead is *honest* information about the available systems, which threats they can prevent and which they can not.
And all the marketing speak surrounding AppArmor is something I can not call “honest”.
AppArmor seems to like avoiding this discussion by claiming that certain things are not in their “threat model”. Of course you can make every non-trivial situation not part of your threat model, but it can seriously limit the overall usefulness of the protection. But how much security do you really gain by only covering certain situations? Sure, you can prevent certain common attack vectors from being easy to exploit, such as the evince example, but it should be made clear to the users, that this is all AppArmor does: when used right (e.g. by not using a custom copy of evince) it should prevent certain common attack vectors. Just to give you some example on unnecessary privileges granted by AppArmors default profiles: evolution and gaim (and probably many others) can read /proc/*/cmdline; which might for some badly written applications even contain passwords, and which definitely allows an attacker to gather some information on running services in the system. However, path-based access control can’t differentiate here. Just the example I found quickly, experts can probably find more.
To do an _entirely unfair_ comparison: by enforcing a password length of 9 characters and a username length of 8, I can effectively prevent users from picking ‘password’ or their username as password. Given the current attacks profile on the net, this does significantly reduce the risk of being hacked. However, it doesn’t prevent users from using ‘password1’ as password. But if I’m assuming the users are smart enough to not use ‘password’ or ‘password1’, then I wouldn’t have needed this policy in first place; and allowing shorter passwords as well in fact increases the search space.
Yes, this is very unfair, since AppArmor can actually confine applications. No user will be able to start an httpd on port 80 anyway, and the admin should be smart enough to make sure his httpd is running in the confinement. But the path-based confinement model of AppArmor is very limited, and so I’m not convinced it can actually cover complex real world cases. For example, my httpd needs to be able to execute various CGI scripts and helper applications (e.g. for URL rewriting, fastCGIs and so on), these in turn need to be able to write to some cache files and so on.
SELinux on the other hand has a very powerful toolchain, that can – for example – calculate if there is any way to migrate from the httpd_t domain to sysadm_t. All reachability can be calculated, and thus it’s showable that no CGI ever could give an attacker full control over the system. Yes, it can be calculated that the policy doesn’t allow the httpd or any of it’s children (!) ever to write to /etc/shadow, for example.
Comment by Erich Schubert — April 3, 2007 @ 2:57 pm
Shell scripts are remarkably easy to confine under AppArmor: simply select ‘inherit this profile’ in the profile development tools, or use ‘ix’ when writing profiles by hand, on all your little utilities such as grep and cat and so forth. All the filters will then run in the same profile as their parent, with no more rights than any of the rest of the system.
Python, Perl, etc., are identical.
Talking about confined shells intended for users realistically requires knowing what you intend to allow your users to do. It’d be simple to give them all access to mutt, pine, vim, slrn, wget, etc., but forbid them from mucking around with anything important on the system. Simpler still to give them execute access to nearly everything on the system but only write access under /home/*/**.
Mono and Java are similarly trivial.
(However, application containers such as Apache, Tomcat or Websphere are slightly more difficult. You options for running multiple applications in such a container are: (1) run all applications in a single security domain (2) run all applications in multiple security domains by starting an entire new tomcat or websphere process per application, or eschewing mod_perl, mod_php, etc., in Apache (3) a hybrid model that uses our change_hat() functionality to run multiple applications in different security domains in the same process. This does not provide full memory seperation, but it can help mitigate against applications running amok on their own.)
And, in fact, we have customers deployed with confined mono, confined websphere, confined jakarta, confined ruby, python, etc.
Users have happily deployed AppArmor in mixed Apache+lighttpd+fastcgi environments. In some cases, AppArmor’s mod_changehat module for Apache is “good enough” for them, in other cases, they have configured their systems to run different applications in different profiles and processes.
You raise a good point about the usability of the system not being a particularly good indicator of the security of the system. However, the counter point is that a complex security system can give a false sense of security by not making clear what privileges are being granted. (The quality of the SELinux profile inspection tools are hands-down fantastic. It’s been one of my goals to write an apol-style tool for AppArmor for several years. However, since AppArmor security policies are easily read and understood without more sophisticated tools, our need for tools is less severe.)
And ask yourself: how many SELinux users _really_ know what restorecond is doing? An obvious concession to usability that clearly trades many of SELinux’s strong points to try to emulate AppArmor’s path-based access controls. One might as well use the vfs_mnt, dentry pairs in the kernel to provide names at the time of use rather than rely on a secondary process to relabel files after they are created.
Perhaps there is a usecase for restorecond in SELinux deployments, that still makes good use of the rest of SELinux’s benefits, but it is difficult for me to see it.
Comment by Seth Arnold — April 3, 2007 @ 3:56 pm
Here is the white paper on how to use AppArmor to create a confined shell https://secure-support.novell.com/KanisaPlatform/Publishing/201/3768203_f.SAL_Public.html
Is it useful? Well, that depends on what you mean by “useful”:
-It is not useful if what you meant was “fully powered general-purpose user shell that gets to do anything, but not mess up the system.” No, it was not designed for that.
-Sophisticated multi-user interaction control. It wasn’t designed for that either.
What it is good for is creating strictly-limited confined shells that are purpose-specific. The linked white paper shows how to create a “syslog analyst” role so that a user can have root privilege to be able to read syslog, but still cannot hurt the system because they have very limited exec permission and extremely limited write permission.
Crispin
Comment by Crispin Cowan — April 4, 2007 @ 11:41 pm
Responding to my own challenge of how hard it would be to perform a similar confinement using SELinux.. I just went trough the process of creating an SELinux domain for google-earth on RHEL5, and it really wasn’t that difficult. Please see my notes at http://tanso.net/selinux/ under “Building googleearth policy”.
I’ll clean up the notes later.. and maybe even do an “evince” confinement just to get a more apples-to-apples comparison to this blog entry. I think googleearth is a bit more complex than evince, but for evince we would also have to not allow accesses to f.ex. /home.
Comment by Jan-Frode Myklebust — April 7, 2007 @ 6:41 am
I did the same thing using AppArmor. It took 5 minutes, had 3 steps, and zero editing of any configuration files.
1. As root, run “genprof /usr/local/bin/googleearth”.
2. In another shell, or from your desktop launcher, run googleearth. Visit some stuff. Exit googleearth.
3. Back in the first shell, answer genprof’s questions.
Done. No “make the module and reload it”, genprof did the policy reload for you. You don’t even really have to exit googleearth the first time, AppArmor can change the policy out from under the running process. The only real reason to exit googleearth the first time was so AppArmor can learn what an exit looks like.
Produced these two policy files:
# vim:syntax=apparmor
# Last Modified: Mon Apr 16 17:13:13 2007
#include
/opt/google-earth/googleearth flags=(complain) {
#include
#include
#include
#include
/bin/bash ixr,
/bin/grep ixr,
/bin/ls ixmr,
/bin/sed ixr,
/opt/google-earth/googleearth mr,
/opt/google-earth/googleearth-bin px,
/usr/bin/dirname ixr,
}
# vim:syntax=apparmor
# Last Modified: Mon Apr 16 17:13:13 2007
#include
/opt/google-earth/googleearth-bin {
#include
#include
#include
#include
#include
/dev/dri/* rw,
/home/*/.ICEauthority r,
/home/*/.Xauthority r,
/home/*/.fontconfig/* r,
/home/*/.googleearth/** rw,
/opt/google-earth r,
/opt/google-earth/** mr,
/proc/sys/kernel/osrelease r,
/usr/lib/dri/*.so mr,
/usr/lib/qt3/lib/lib*so* mr,
/usr/share/X11/XKeysymDB r,
/usr/share/X11/locale/** r,
}
Similar to Jan-Frode’s work, these policies are fairly loose, and in particular allow full read/write access to the .googleearth/** directory tree.
Comment by Crispin Cowan — April 16, 2007 @ 4:53 pm