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/

iQIcBAEBCgAGBQJSKh1/AAoJEFHb3FjMVZVzwfIQAIqO2wQSH2Nr7Qo3qg4FLsCZ
Eyol9/2Fbt60i5LW9n137yjGRTQ8rFGb7SOnPGqjv3xIFIG1sc3tioh0Z60AqS/k
G0bOsBfaXIIKRMJifevHUZpT5PVg2We71wpIg7uuAYomp1ocR7DS0SUFJkmGuFYG
nvlyk1GV0k4nxgmamJfa38u+kQ/XTUfeOt0KSUV0rVdb/ZY+dAgRDmYiLOO5A72e
xupHZrePb5KogTMWE6KcV6UruKxmtf0wdqrroxGxnplZWUouNp2eG1tW6cOQK3ye
LSpAqUWUFkcWfdTbOF3F9sJIWvzxNI7MpXlRlpkRXH/KXcrvwxOH1NGegjREDDfT
M0SzvwDmJ8PY6w3pJUZpQKYJLg17hfcJb91uvcbsChBBcs7jNACBtFKzKuFqgHoF
X+g/RRCCklIAAvhsMnib68sHbOQy922jGdN898mhc+qKY5s083Gja1kgnXCyjClv
kf+MuWWqOFPzI14KmdNPrYd/5ste0rTRelF9VO6CBFu+RWrABdjAMxlfF7CQGT/d
ejiqv9JMSuAAlJ/3aoBVWML4rYV6eUkiDWwYgcM/p0Eav6Pb6V9qXG1T0QXj4bkV
LDKmS5ProtpeFrXutzz8YFaztfc9ZmQsBDBWQQz8HU03t0AEbeGENgA70QV+9scL
FXw9TBSAHyTU3WqUnF6Y
=2iOE
-----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/