[ubuntu-hardened] AppArmor for Ubuntu (braindump/overview)

Crispin Cowan crispin at novell.com
Fri Mar 3 06:32:25 GMT 2006

Paul Sladen wrote:
> On Wed, 22 Feb 2006, Crispin Cowan wrote:
>> would like to help port it to Ubuntu. Since Ubuntu has a very strong
>> ease-of-use theme, AppArmor for Ubuntu should be a very strong fit.
> I had a good talk with Crispin this evening in London and I hopefully have a
> reason overview handle on AppArmour.  Crispin, please correct any of the
> following if I've got the wrong idea.
> Example policy:
>   $ cat /etc/apparmour/usr.bin.foo
>   /usr/bin/foo {
>     #include <another.base.policy>
>     /etc/foo/* r
>     /proc/[0-9]*/cmdline r
>     /tmp/ rw
>     /var/lib/foo/foo-helper-* rx
>   }
There should be a comma at the end of each rule line to make the
parser's life easier.

>   Permissions are standard Read, Write, eXecute.

    * Execute permissions come in 3 flavors:
          o ix means that the child executes with the same profile as
            the parent
          o px means that the child executes in its own profile, and
            that profile must exist in the set of profiles loaded into
            the kernel. If it does not exist, then the exec() call fails
            with EPERM
          o ux means that the child executes with no AppArmor
            confinement at all. Use sparingly :)

>   Globs are *, [x-y], ?.

    * Single * means anything but slash, i.e. matches files in a directory
    * Double ** matches slash characters too, i.e. recursively descend
      directory trees
    * We also support {}

> AppArmour approach:
>   LSM module (Linux Security Module), uses existing LSM hooks.
>   Class-based policy.  This means that policies are applied to all programs
>   named '/usr/sbin/sshd', rather than particular process IDs (instances).

>   Can only restrict existing permissions (by causing syscall failures/
>   permissions denial), cannot grant new privileges.

>   Has a training/learning mode that records file/syscall-access and 
>   bootstraps policy creation based on this log.

>   The syscall is 'chhat()', this changes the 'Hat' that the program is
>   using.  Processes either wear a hat, or they _don't_ wear a hat.
Well, the API is called change_hat() and is not really implemented as a
syscall. You need to link to libimmunix to get the change_hat API, and
the library takes care of it from there. As a result, you need to care
about stuff like whether the binary library you have is 32-bit or 64-bit.

>   Use sys_chhat($random_cookie) to wear a hat.  The hat (restriction
>   policy) can be removed by calling chhat() again with the _same_
>   random cookie;  calling with a incorrect value gets your process
>   terminated, immediately.  Using 'chhat(0)' means that the hat can never be
>   removed;  this one-way trapdoor is used for things like PAM setup.

> Current implementation:
>   LSM module loaded into the kernel at runtime.
Properly configured, it loads at boot time.

Much of the effort of porting AppArmor to Ubuntu is init script hacking
so that AppArmor comes up as early in the boot sequence as possible, so
that everything that starts after AppArmor can be confined. Things that
start before AppArmor cannot be confined unless they are restarted.

>   One tiny kernel patch to re-export a symbol that used to be exported but
>   isn't any longer---this should disappear when AppArmour goes for mainline
>   kernel integration.  This is to do with converting an inode number into a
>   filepath. 
>   Module contains the PCRE regex-parser for filepath matching and loads this
>   into the kernel, amongst other things, this is non-deterministic.
Not sure what you mean by 'non-deterministic'. The PCRE engine is
recursive, and so you could feed it a pathological regexp that causes
the kernel to run out of stack. However, to do that to AppArmor, you
would have to have write permission to the AppArmor policy directory and
enough privilege to ask AppArmor to reload the policies. If you have
that much privilege already, then you have the power to completely
rootkit the machine, and being able to DoS it by pushing strange
regexp's is not much of a threat.

> Possible first-glance improvements:
>   Remove all the Novell Proprietary Copyrights from the examples and make
>   them public domain/BSD.  They currently can't be distributed.
That has already been done in the open source releases on
http://opensuse.org/Apparmor just not on the version riding around on my
laptop that Paul saw :)

>   Switch filepath matcher from regex to glob-based.  Audit this and try to
>   ensure it is deterministic;  or, better still:
Improving the globber is on our TODO list.

>   Move filepath matcher to user-space, so that all matching is done
>   safely;  the kernel can then keep a cache table of previous
>   hits/misses.  Is removes all globing *completely* from the kernel and
>   seems the safest/cleanest.  Communication via netlink socket or similar.
That would impose a substantial performance penalty. In terms of safety,
I would trust a globber much more than an elaborate caching mechanism
that swaps data with userspace asynchronously. It is part of the SELinux
design, and I don't like it.

>   Mount the helper filesystem somewhere that is *not* '/security/'.  This is
>   non FHS.  Something like '/sys/kernel/security/' if that's what it is
>   designed for. 
The problem with this suggestion is that there are varying opinions, all
of them conflicting and emphatic :)

>   Processes have a 'label' (displayed by "ps Z"), this should probably point
>   to a something more useful than the name of the executable---eg. point to
>   the policy file '/etc/apparmour/usr.some.thing' or the helperfs).
The 'label' is the name of the profile wrapped around the process. It
uniquely identifies the profile. To translate it into a path name, just
pipe the output of 'ps Z' through a trivial sed script :)

>   The Yast GUI tool needs breaking-out/replacing with some nice Python/Gtk+.
What for? The YaST GUI tool is just a gloss over the real engine, which
is a library and a bunch of PERL code.

> My hunches/observations:
>   This is more useful^W usable to our users than SELinux.
That is what it was designed for.

>   Both use the same kernel LSM hooks;  so can be loaded either/or.

>   Looks like I could actually configure this without a rocket-scientist's
>   University degree.
Pretty much. We have marketing people that can do it :)

>   By default, Apparmour is off for a class of process.  Nobody's machine is
>   going to become unusable.

>   Combined with the existing 'sudo' infrastructure, we can give a user
>   temporary permissions and then immediate restrict them down to what is
>   required.  Eg.  "sudo gedit " but then immediately restricting that
>   process to only being able to read/write the file passed to it.
>   This can be wrapped up in the 'gksudo/ksudo' call from the GUI shell.

> Wish-list:
>   Be able to freeze the process when it does something naughty so that a
>   call to userspace can be made and a "firewall" dialogue pop up asking the
>   currently disallowed action should be allowed.  Looking at the freezer/
>   suspend code to work out how this might be possible immediately before
>   return to userspace.
This turns out to be very difficult because of the LSM architecture vs.
kernel architecture. At any given LSM hook, you may or may not be
holding some number of semaphores. Unless you can know that, you cannot
pop to user space from an LSM hook.

Crispin Cowan, Ph.D.                      http://crispincowan.com/~crispin/
Director of Software Engineering, Novell  http://novell.com
	Olympic Games: The Bi-Annual Festival of Corruption

More information about the ubuntu-hardened mailing list