Snapd vs upstream kernel vs apparmor

The plan is to have everything upstream, but I don’t know what kernel Buster will use.

I just tested this in an up to date sid with 4.12 kernel. I did:

$ sudo apt-get install snapd
$ sudo snap install hello-world
$ /snap/bin/hello-world.evil
Hello Evil World!
This example demonstrates the app confinement
You should see a permission denied error next
If you see this line the confinement is not working correctly, please file a bug

That tested snapd with apparmor disabled. To enable apparmor, adjust /etc/default/grub to have:

GRUB_CMDLINE_LINUX_DEFAULT="quiet apparmor=1 security=apparmor"

then do:

$ sudo update-grub
$ sudo reboot
<login again>
$ sudo aa-status
$ sudo aa-status
apparmor module is loaded.
0 profiles are loaded.
0 profiles are in enforce mode.
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
$ snap --version
snap    2.27.1-1
snapd   2.27.1-1
series  16
debian  unknown
kernel  4.12.0-1-amd64
$ hello-world.evil 
Hello Evil World!
This example demonstrates the app confinement
You should see a permission denied error next
If you see this line the confinement is not working correctly, please file a bug

I found this curious-- the snap-confine profile was not loaded. I found that ‘apt-get install snapd’ installs an empty profile in /etc/apparmor.d/usr.lib.snapd.snap-confine.real

$ ls -l /etc/apparmor.d/usr.lib.snapd.snap-confine.real
-rw-r--r-- 1 root root 0 Aug 14 04:53 /etc/apparmor.d/usr.lib.snapd.snap-confine.real

If I generate the profile from git checkout release/2.27 (I used ./configure --prefix=/usr --libexecdir=/usr/lib/snapd --enable-nvidia-ubuntu --enable-static-libcap --enable-static-libapparmor --enable-static-libseccomp) and copy it over to the Debian machine:

$ sudo cp ./snap-confine.apparmor /etc/apparmor.d/usr.lib.snapd.snap-confine.real 
$ sudo apparmor_parser -r /etc/apparmor.d/usr.lib.snapd.snap-confine.real 
$ sudo aa-status
apparmor module is loaded.
2 profiles are loaded.
2 profiles are in enforce mode.
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
$ sudo snap install hello-world
...
$ /snap/bin/hello-world.evil
/usr/lib/snapd/snap-confine: error while loading shared libraries: libcap.so.2: cannot open shared object file: No such file or directory
$ grep DEN /var/log/syslog
Aug 16 07:22:48 debian-sid-amd64 kernel: audit: type=1400 audit(1502886168.383:7): apparmor="DENIED" operation="open" profile="/usr/lib/snapd/snap-confine" name="/lib/x86_64-linux-gnu/libcap.so.2.25" pid=2627 comm="snap-confine" requested_mask="r" denied_mask="r" fsuid=0 ouid=0

Ok, so snap-confine is confined, but it is missing a rule needed to run. Note that snapd didn’t load the hello-world profiles:

$ sudo aa-status
apparmor module is loaded.
2 profiles are loaded.
2 profiles are in enforce mode.
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.

If I add this rule to the snap-confine profile:

/lib/@{multiarch}/libcap.so* mr,

Then reload the profile and try hello-world.evil, I can reproduce the Debian bug:

$ sudo apparmor_parser -r /etc/apparmor.d/usr.lib.snapd.snap-confine.real
$ /snap/bin/hello-world.evil 
execv failed: Permission denied
$ sudo grep DEN /var/log/syslog | tail -1
Aug 16 07:25:17 debian-sid-amd64 kernel: [ 1351.246752] audit: type=1400 audit(1502886317.157:10): apparmor="DENIED" operation="exec" profile="/usr/lib/snapd/snap-confine" name="/usr/lib/snapd/snap-exec" pid=2665 comm="snap-confine" requested_mask="x" denied_mask="x" fsuid=1000 ouid=0

Ok, if I build 2.27 like we do on Ubuntu, and copy it all over to the sid machine, then snapd still won’t load the hello-world profiles:

$ sudo aa-status
apparmor module is loaded.
2 profiles are loaded.
2 profiles are in enforce mode.
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.

This is because snapd forces devmode (see requiredApparmorFeatures in release/release.go). If I booted a kernel with all the required features, I would expect things to start to work.

I believe there are several bugs:

  1. the snap-confine profile is empty
  2. the snap-confine profile is missing a rule for libcap (on Debian we aren’t using --enable-static-libcap like in Ubuntu)
  3. the snap-exec denial has to do with the fact that snapd is built with --disable-apparmor. snap-confine is not performing a profile transition to hello-world.evil, so snap-confine continues to stay in its profile where snap-exec is not allowed
  4. snapd-design: when booting a kernel without the required apparmor feature set, the system is put in devmode and apparmor profiles are not loaded

Detangling this would require:

  1. ship a proper apparmor profile for snap-confine
  2. use --enable-static-libcap
  3. conditionally add a rule to snap-confine’s profile: /usr/lib/snapd/snap-exec uxr,

With the above, one should be able to freely enable/disable apparmor via kernel command line, and when booting a kernel with the supported feature set, the profiles will be generated. Note that point ‘3’ needs a little design since snapd will be updating snap-confine’s profile dynamically.

Once all that is done, we could revisit the required apparmor feature set, but note this is an explicit snapd design decision that went through extensive review with @niemeyer, @mvo, @zyga-snapd and myself.

1 Like