Friday 6 September 2013

Dealing with AppArmor policy for hardware-specific access devices

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.14 (GNU/Linux)
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iQIcBAEBCgAGBQJSKh1cAAoJEFHb3FjMVZVzdS0P/2qk7PI82vfhksVOyOKBwOrl
h3XJZU+ogC6VXCxRvlUcVbQOh6wrCphsHKK2xGFGNcOhiFHwyIXQBX8IrXKw2L9d
UVqnXJHys6Cj7Mwvl5fGpq5+CoK74lUF4oL92L3Mb58wWYAVSy/iJGSPBhRYcDu1
WMBn/tlKchwb1kqOxzlUWM6n5zW8jr/ogALdXRd0Wjge3hW1Z7I1VydiAjj0L29Z
ephhWeYW+OndZhMXi0k94TZYDQalLY9dYzmIQWHKl0UgOGPsVPc8v/lAlzi3CGCS
6NfDiYjMzTmJ9FygQLvFrUBhMfxnrT77uxGjfPoc//aG2CRViU7JfV41WAUKRAtV
8hQzi2ld7z5JilCIvIU5USVlCgocarnuWQPTBNGGScZ5GaQ59x80kCrUjmxP3iJs
0OO/Veftrn44plY7+dFFhzZR8ZCYimuwDhEh1rDC2BBT2Hg2K/thqTq6kel/5Vt5
eewDpf6L2kYHt91bW3FoPzzAgUYrADM4IobRa3/IMJiufoEMfZbRC42HfYnGtLRz
MWY6HLy+HHYhefGFndUnQgixcqPhQpP8516WQvrKRGv3izKuXak/6qFiYP8TlcTh
H5eG8slA4jKtQB5Pnmeog0BF2sN8Phl6OO7fvWPHt8QP3ttMhT+WAi0UG3Pjlch6
kYrxnkLRS2lWJ3UhMq9U
=ecsB
-----END PGP SIGNATURE-----
Hi,

This is in reference to dealing with the short term solutions for
bug #1197133.

The basic problem is that AppArmor policy needs to specify device
access for things that don't use an out of process service, like
the graphics stack. Historically we've never dealt with this well
and we simply added rules like this (example from the X abstraction):
/usr/lib{,32,64}/dri/** mr,
/usr/lib/@{multiarch}/dri/** mr,
/usr/lib/fglrx/dri/** mr,
/dev/dri/** rw,

On Touch I've discovered that device names can be anything and
they usually live in the toplevel /dev/ directory (as opposed to
something like /dev/dri). Eg, we currently have policy like this:
# FIXME: Nexus7 (grouper)
/dev/nvmap rw,
/dev/nvhost-* rw,
/sys/module/nvhost/parameters/* r,
/sys/module/fuse/parameters/tegra* r,

# FIXME: Galaxy Nexus specific (maguro)
/dev/pvrsrvkm rw,

# FIXME: Nexus 4 (mako)
/dev/kgsl-3d0 rw,
/dev/ion rw,

# FIXME: Nexus 10 (manta)
/dev/mali[0-9] rw,
/dev/ion rw,

...

This is a maintenance nightmare, brittle, doesn't scale and doesn't
help porters of Touch at all. In thinking about this and discussions
on IRC, we have a few options:

1. Adjust udev rules to create all these devices under a specific
directory in /dev and then have udev create the symlinks from the
device file in this directory to what is expected to be in /dev.
Eg, for kgsl-3d0:
- adjust udev to create /dev/graphics-hardware/kgsl-3d0
- adjust udev to create the symlink:
ln -s /dev/graphics-hardware/kgsl-3d0 /dev/kgsl-3d0
- adjust apparmor policy for apps to have:
/dev/graphics-hardware/** rw,

Pros:
- simplifies apparmor policy
- porters only need to adjust udev rules
Cons:
- requires verifying all hardware to work by accessing a symlink
(shouldn't be an issue, but with binary blobs, who knows)
- apparmor policy is limited to only the specific device
- does not handle devices that don't use udev (ie, nvidia)


2. Use an apparmor include directory and adjust udev rules to drop
apparmor policy into it. Eg:
- create /etc/apparmor.d/abstractions/hardware/graphics.d
- adjust apparmor policy for apps to have:
#include <abstractions/hardware/graphics.d>
- adjust udev rules to add a RUN command for this device. Eg:
ACTION=="add", KERNEL=="kgsl-3d0", OWNER="system", GROUP="system", MODE="0666", RUN+="/usr/sbin/aa-udev-helper --type=graphics --name=%k --devpath=%p --access=rw"
This creates /etc/apparmor.d/abstractions/hardware/graphics.d/kgsl-3d0 with:
/dev/kgsl-3d0 rw,

Pros:
- simplifies apparmor policy
- only device specific policy is on the device
- porters only need to adjust udev rules
- devices are where they are expected to be, rather than redirected via
a symlink
- allows packages to drop files into the apparmor include directory if
they don't use udev (eg, nvidia)
Cons:
- assumes that udev devices are brought up before apparmor policy is loaded
- requires care with only updating apparmor policy if different from what is
on disk (ie, don't break caching by updating timestamps on every boot)
- apparmor policy is limited to only what aa-udev-helper exposes
- handling on read-only images needs to be considered


3. This is a variation on '2' except rather than using udev RUN to generate
the policy, the package that ships the udev rule for the device also ships
corresponding policy in the apparmor include directory. Eg:
- create /etc/apparmor.d/abstractions/hardware/graphics.d
- adjust apparmor policy for apps to have:
#include <abstractions/hardware/graphics.d>
- package shipping udev rule for kgsl-3d0 ships policy for the device in
/etc/apparmor.d/abstractions/hardware/graphics.d/kgsl-3d0 containing:
/dev/kgsl-3d0 rw,

Pros:
- simplifies apparmor policy
- only device specific policy is on the device
- porters only need to adjust udev rules and add an apparmor policy snippet
- devices are where they are expected to be, rather than redirected via
a symlink
- allows packages to drop files into the apparmor include directory if
they don't use udev (eg, nvidia)
- no upstart dependencies between udev and apparmor
- apparmor policy can be anything required (ie, we can handle rules like for
the Nexus 7 (see above)
- works fine on read-only images
Cons:
- porter is required to know AppArmor syntax


In discussing this with others, I prefer '3' over the others. It requires
slightly more work for the porter over '1' and '2', but it is loads better
than what we have now (nothing) and AppArmor syntax for file access is
straightforward and easily covered by documentation. '3' provides the
greatest flexibility and is robust. '2' and '3' allow for us to create
different categories for the devices too-- ie, for the sensor device or
gps we have /etc/apparmor.d/abstractions/hardware/sensors.d/ and
/etc/apparmor.d/abstractions/hardware/gps.d/ and the appropriate policy
groups simply include these directories as needed. In considering '3', we
can also move this outside of /etc completely, and instead ship the policy
in /usr/share/apparmor/hardware/*.

I'd like to move forward on '3' soon, are there any objections?

[1]https://launchpad.net/bugs/1197133

--
Jamie Strandboge http://www.ubuntu.com/