CVE-2017-6507: apparmor service restarts and package upgrades unload privately managed profiles

Bug #1668892 reported by Stéphane Graber on 2017-03-01
268
This bug affects 1 person
Affects Status Importance Assigned to Milestone
AppArmor
Critical
Tyler Hicks
2.10
Undecided
Unassigned
2.11
Undecided
Unassigned
2.9
Undecided
Unassigned
apparmor (Ubuntu)
Critical
Tyler Hicks

Bug Description

Restarting the apparmor init script, upstart job, or systemd service has historically removed all loaded profiles unknown to the well-known profile locations. In upstream AppArmor terms, this is /etc/apparmor.d/ but Ubuntu also adds additional locations.

This behavior has previously caused a problem where libvirt-managed profiles would be unloaded upon "restarting AppArmor":

  https://launchpad.net/bugs/702774

Stéphane Graber created this bug report after he noticed that the same behavior was causing similar problems with lxd-manager profiles.

In addition, AppArmor distro packaging may trigger an "AppArmor restart" when installing a new version of AppArmor, resulting in the same profile removal problem. This is true for the Debian/Ubuntu packaging.

The upstream AppArmor team has decided to remove this functionality from the AppArmor restart logic to prevent a similar issue happening with the next external project that needs to privately manage their own set of AppArmor profiles.

=== Original Bug Report ===

Apparmor package upgrades unloads all LXD apparmor profiles, making all LXD containers unconfined.

Example:

# Create an unprivileged and a privileged container
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ lxc launch ubuntu:16.04 c1
Creating c1
Starting c1
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ lxc launch ubuntu:16.04 c2 -c security.privileged=true
Creating c2
Starting c2

# Look at their apparmor profiles (expected values)
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ cat /proc/$(lxc info c1 | grep Pid | sed "s/Pid: //g")/attr/current
lxd-c1_</var/lib/lxd>//&:lxd-c1_<var-lib-lxd>://unconfined (enforce)

stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ cat /proc/$(lxc info c2 | grep Pid | sed "s/Pid: //g")/attr/current
lxd-c2_</var/lib/lxd>//&:lxd-c2_<var-lib-lxd>://unconfined (enforce)

# Apply an apparmor upgrade
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ sudo apt upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
  apparmor
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 493 kB of archives.
After this operation, 8,192 B of additional disk space will be used.
Do you want to continue? [Y/n]
Get:1 http://us.archive.ubuntu.com/ubuntu zesty/main amd64 apparmor amd64 2.11.0-2ubuntu1 [493 kB]
Fetched 493 kB in 0s (34.9 MB/s)
Preconfiguring packages ...
(Reading database ... 221457 files and directories currently installed.)
Preparing to unpack .../apparmor_2.11.0-2ubuntu1_amd64.deb ...
Unpacking apparmor (2.11.0-2ubuntu1) over (2.10.95-4ubuntu5.1) ...
Processing triggers for ureadahead (0.100.0-19) ...
Setting up apparmor (2.11.0-2ubuntu1) ...
Installing new version of config file /etc/apparmor.d/abstractions/X ...
Installing new version of config file /etc/apparmor.d/abstractions/authentication ...
Installing new version of config file /etc/apparmor.d/abstractions/base ...
Installing new version of config file /etc/apparmor.d/abstractions/dbus-session-strict ...
Installing new version of config file /etc/apparmor.d/abstractions/gnome ...
Installing new version of config file /etc/apparmor.d/abstractions/nameservice ...
Installing new version of config file /etc/apparmor.d/abstractions/php5 ...
Installing new version of config file /etc/apparmor.d/abstractions/samba ...
Installing new version of config file /etc/apparmor.d/abstractions/ssl_certs ...
Installing new version of config file /etc/apparmor.d/abstractions/ssl_keys ...
Installing new version of config file /etc/apparmor.d/abstractions/ubuntu-browsers ...
Installing new version of config file /etc/apparmor.d/abstractions/ubuntu-helpers ...
Installing new version of config file /etc/apparmor.d/abstractions/user-mail ...
update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults
Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
Skipping profile in /etc/apparmor.d/disable: usr.sbin.sssd
Processing triggers for systemd (232-18ubuntu1) ...
Processing triggers for man-db (2.7.6.1-1) ...

# And look at the now unconfined containers
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ cat /proc/$(lxc info c1 | grep Pid | sed "s/Pid: //g")/attr/current
unconfined//&:lxd-c1_<var-lib-lxd>://unconfined
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ cat /proc/$(lxc info c2 | grep Pid | sed "s/Pid: //g")/attr/current
unconfined//&:lxd-c2_<var-lib-lxd>://unconfined

# The LXD profiles are also entirely gone
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ ls /sys/kernel/security/apparmor/policy/profiles/ | grep lxd
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$

# And to confirm that apparmor is in fact gone
stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ lxc exec c2 bash
root@c2:~# mount -t proc proc /mnt
root@c2:~# echo "|/usr/bin/touch /pwned" > /mnt/sys/kernel/core_pattern
root@c2:~# sleep 30&
[1] 468
root@c2:~# kill -SIGSEGV $!
root@c2:~#
[1]+ Segmentation fault (core dumped) sleep 30
root@c2:~# exit

stgraber@dakara:~/data/code/lxc/lxd (stgraber/master)$ ls -lh /pwned
-rw-rw-rw- 1 root root 0 Mar 1 03:37 /pwned

This was originally reported (though not as a security issue) here: https://github.com/lxc/lxd/issues/2981

Stéphane Graber (stgraber) wrote :

Subscribed the LXC security team, mostly for awareness if we get more such reports from users.

Stéphane Graber (stgraber) wrote :

The LXD profiles are still available on disk in /var/lib/lxd/security/apparmor but I'm not sure we'll be able to easily fix all those processes that now got relabeled...

It may be simpler for the advisory to recommend all LXD users restart all their containers which will get LXD to regenerate and load the apparmor profile.

Something like "sudo lxd shutdown && sudo lxd activateifneeded" should do the trick, though note that having a maintainer script do so isn't a good idea as it'd be equivalent to having a maintainer script issuing random "reboot" commands to remote hosts.

Tyler Hicks (tyhicks) wrote :

The way that I plan to address this is by removing the calls to unload_obsolete_profiles() in the apparmor postinst and init script/upstart job/systemd unit.

I've prepared untested security updates for all releases and will test them early next week.

Changed in apparmor (Ubuntu):
status: New → In Progress
assignee: nobody → Tyler Hicks (tyhicks)
Tyler Hicks (tyhicks) wrote :

This is CVE-2017-6507

Tyler Hicks (tyhicks) wrote :

This patch is the actual CVE fix. It simply removes the functionality. A followup patch will be posted that adds a small utility that contains the old functionality for administrators that depend on it.

Changed in apparmor:
status: New → In Progress
importance: Undecided → Critical
assignee: nobody → Tyler Hicks (tyhicks)
Tyler Hicks (tyhicks) wrote :

This patch adds the helper utility.

Christian Boltz (cboltz) wrote :

aa-remove-unknown:
...
+ else
+ echo "Removing '${profile}'"
+ echo -n "$profile" > "${REMOVE}"
+ fi
+ done
+
+# will not catch all errors, but still better than nothing
+exit $?

I slightly disagree with the "better than nothing" part ;-)

If I didn't miss something, the only thing that could go wrong is
+ echo -n "$profile" > "${REMOVE}"

It would be much better to use something like
+ echo -n "$profile" > "${REMOVE}" || failure=1
...
exit $failure

(obviously, also initialize failure=0 before the loop)

On 03/12/2017 09:22 AM, Christian Boltz wrote:
> aa-remove-unknown:
> ...
> + else
> + echo "Removing '${profile}'"
> + echo -n "$profile" > "${REMOVE}"
> + fi
> + done
> +
> +# will not catch all errors, but still better than nothing
> +exit $?
>
> I slightly disagree with the "better than nothing" part ;-)
>
> If I didn't miss something, the only thing that could go wrong is
> + echo -n "$profile" > "${REMOVE}"

There's much more that could go wrong. To name a few:

1) Things could go wrong in the profiles_names_list() function
2) Things could go wrong while executing the awk and/or sort binaries
3) Things could go wrong in the awk script itself

Since all of that goop is piped together, none of those errors would be
caught. IMO, It is some pretty bad code that needs to be improved
outside of this security bug.

The reason I don't feel like it needs to be fixed at the same time as
this security bug is because it should fail safely. In other words,
failing would mean that processes are left confined rather than unconfined.

> It would be much better to use something like
> + echo -n "$profile" > "${REMOVE}" || failure=1
> ...
> exit $failure
>
> (obviously, also initialize failure=0 before the loop)

I agree that it would be better. I'll include an updated patch. Thanks
for the review!

> Since all of that goop is piped together,

... you should "set -o pipefail" ;-)

On 03/14/2017 01:14 PM, Christian Boltz wrote:
>> Since all of that goop is piped together,
>
> ... you should "set -o pipefail" ;-)

Not possible with POSIX shell. We can save all of these enhancements for
after these CVE fixes land and before the next upstream release.

I'd argue that requiring /bin/bash shouldn't be a real problem, but I'm aware that you try to use /bin/sh whenever possible.

Completely different question: does this bug only affect Ubuntu, or is a similar fix needed in rc.apparmor.functions? (__apparmor_restart() has code to unload unknown profiles)

On 03/15/2017 01:26 PM, Christian Boltz wrote:
> I'd argue that requiring /bin/bash shouldn't be a real problem, but I'm
> aware that you try to use /bin/sh whenever possible.

It shouldn't but I don't feel comfortable switching between the two
shells when this is supposed to be a minimal change.

> Completely different question: does this bug only affect Ubuntu, or is a
> similar fix needed in rc.apparmor.functions? (__apparmor_restart() has
> code to unload unknown profiles)

Upstream is affected. The only patches that I've attached so far are for
the upstream project.

The Ubuntu/Debian-specific init code is also affected and I'm working on
patches for that now.

Can you tell me if openSUSE is affected by this bug? A quick test is to do

$ echo "profile test {}" | sudo apparmor_parser -qr
$ sudo grep "test (enforce)" /sys/kernel/security/apparmor/profiles
test (enforce)
$ # do whateveris required to restart the apparmor init script/upstart
$ # job/systemd unit that your distro uses
$ sudo grep "test (enforce)" /sys/kernel/security/apparmor/profiles
test (enforce)

If the test profile is still loaded, you're not affected. If it was
unloaded, you're affected.

Testing confirmed what I expected from reading rc.apparmor.functions __apparmor_restart() - the test profile gets unloaded on "rcapparmor reload".

Tyler Hicks (tyhicks) on 2017-03-23
summary: - apparmor package upgrades unload all LXD profiles
+ apparmor package upgrades unload privately managed profiles
summary: - apparmor package upgrades unload privately managed profiles
+ CVE-2017-6507: apparmor package upgrades unload privately managed
+ profiles

I'm making this bug public since this behavior is not attacker-controlled. It is controlled by the system administrator and the distro package maintainer(s) for AppArmor.

description: updated
information type: Private Security → Public Security
Tyler Hicks (tyhicks) on 2017-03-23
summary: - CVE-2017-6507: apparmor package upgrades unload privately managed
- profiles
+ CVE-2017-6507: apparmor service restarts and package upgrades unload
+ privately managed profiles
tags: added: patch
Tyler Hicks (tyhicks) wrote :
Changed in apparmor:
status: In Progress → Fix Committed
milestone: none → 2.12
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package apparmor - 2.11.0-2ubuntu3

---------------
apparmor (2.11.0-2ubuntu3) zesty; urgency=medium

  * SECURITY UPDATE: Don't unload unknown profiles during package
    configuration or when restarting the apparmor init script, upstart job, or
    systemd unit as this could leave processes unconfined (LP: #1668892)
    - debian/apparmor.postinst, debian/apparmor.init, debian/apparmor.upstart:
      Remove calls to unload_obsolete_profiles()
    - debian/patches/utils-add-aa-remove-unknown.patch,
      debian/apparmor.install debian/apparmor.manpages: Include a new utility,
      aa-remove-unknown, which can be used to unload unknown profiles. Based
      on an upstream patch but adjusted to source the /lib/apparmor/functions
      shipped in Debian/Ubuntu.
    - CVE-2017-6507
  * debian/patches/r3645-profiles-update-nvidia-abstraction.patch: Update
    nvidia abstraction for newer nvidia drivers (LP: #1590561)

 -- Tyler Hicks <email address hidden> Fri, 24 Mar 2017 05:26:28 +0000

Changed in apparmor (Ubuntu):
status: In Progress → Fix Released
Changed in apparmor:
status: Fix Committed → Won't Fix
status: Won't Fix → Fix Committed
Christian Boltz (cboltz) on 2018-04-22
Changed in apparmor:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public Security information  Edit
Everyone can see this security related information.

Other bug subscribers