This week Qualys dominate the week in security updates, disclosing details of 4 different SUID-root vulnerabilities, including Oh Snap! More Lemmings (Local Privilege Escalation in snap-confine), plus we look at updates for Firefox, cryptsetup and more.
23 unique CVEs addressed
/proc/self/mountinfo
to validate if is a FUSE fs(deleted)
to the name
of it in the mount tablemountinfo
to get the actual path(deleted)
in
the name - and then libumount will strip this off and umount the original
path - ie. could mount at /tmp/ (deleted)
then call umount /tmp
and this
will succeed(deleted)
suffix as this has not been used
by the kernel since December 2014https://www.qualys.com/2022/02/17/cve-2021-44731/oh-snap-more-lemmings.txt
Qualys appear to have been auditing various SUID-root binaries - recently
looked at snap-confine - low-level application, written in C, and used by
snapd to setup the execution environment for a snap application - as the
name suggests, it setups up the confinement for an application, creating
a separate mount namespace with own private /tmp
and /dev/pts
- as well
as any other mounts through content interfaces or layouts etc defined by
the snap, plus loading of seccomp syscall filters for the resulting snap
As such requires root privileges, hence is SUID-root - high value target
Very defensively programmed itself, plus is confined by seccomp and AppArmor itself
Nonetheless, even the most carefully programmed software can have issues
2 vulns:
Qualys liken these vulnerabilities (or the process to finding them) as like playing the original Lemmings game, due to the complex nature of steps required to thwart the defense-in-depth construction of snap-confine
Not the first time snap-confine has been audited - SuSE Security Team previously audited it in 2019 and found a couple issues, in particular in some of the same code sections as these
Back to these vulns:
When creating or deleting the mount namespace, snap-confine uses 2
helper programs written in Go - these are installed in the same
location as snap-confine, so it looks them up from the same directory
where it is running itself - however, since (when protected_hardlinks
is disabled) an unprivileged user could hardlink snap-confine into say
/tmp
they could also then place their own malicious binary in place of
these helpers and have that get executed by snap-confine instead
NOTE: protected_hardlinks
is enabled by default on almost all distros
so unless this has been changed by the system admin, this is unable to
be exploited in reality
Other vuln is a race condition when creating the private mount
namespace for the snap - snap-confine creates a per-snap private
directory under /tmp
- this is a known “dangerous” thing to do since
/tmp
is world writable so users could easily try and symlink their own
contents into it etc
snap-confine is very careful then to try and ensure this directory is owned by root and to then avoid following symlinks when traversing this hierarchy etc
However, when then doing the actual mount()
syscall to start setting up
the mount namespace inside this directory, the absolute path of this
directory is given to mount()
(since sadly there is no mountat()
or
similar syscall) - which then does follow symlinks allowing a user who
an race the creation of this directory with snap-confine to be able to
take control of the contents of it, and hence inject their own
libraries and configuration such that a malicious library can be
preloaded into a subsequent execution of snap-confine - and since
snap-confine will then still run as root, this allows to get root code
execution
In both cases, the use of AppArmor by default tries to isolate
snap-confine - and snap-confine is programmed defensively such that it
will refuse to execute if it is not confined by AppArmor - however, the
checks for this were not strict enough, and Qualys found they could use
aa-exec
to execute snap-confine under a separate, more permissive
AppArmor profile to escape these restrictions
Fixes for these issues were numerous - to both add additional hardening
to snap-confine so that it would validate the AppArmor profile it
executes under is the one that is expected - plus the actual fixes for
the vulnerabilities themselves, by checking snap-confine
is located where
it expects to be (so it doesn’t execute other arbitrary helpers), and to
also when setting up the mount namespace directory hierarchy, forcefully
try and move aside any existing parts that are not root owned so it can
create them afresh with known ownership/permissions so that unprivileged
users can’t trick it with their own contents
As mentioned, also includes fixes for 2 other issues identified by Canonical - open permissions on snap per-user HOME/private storage allows other users to potentially access private info stored by snaps
Plus a more sinister issue in the handling of AppArmor rules for snaps
A snap can define a content interface - way of making files available to other snaps - snaps can then connect to this to access that content - often used to implement plugins or other such concepts between snaps
When creating an AppArmor profile for a snap, adds additional rules then to allow access to these paths within the other snap
Included code to validate that a snap wasn’t trying to expose content it shouldn’t BUT didn’t validate that these were just paths and nothing else
Since AppArmor policy is human-readable text files, these get generated by snapd by adding the content interface paths into the policy
Content interface path could then contain additional AppArmor policy directives and these would get included in the generated profile
Since any snap can specify content interfaces, and they get auto-connected by snaps from the same publisher, would then just have to get a user to install 2 malicious snaps from the same publisher where one declares a malicious interface like this and then the snaps will be able to escape the usual strict confinement provided by AppArmor
Fixed in snapd to both validate paths more correctly, and to also quote all file-system paths in the generated AppArmor policies so that arbitrary rules cannot be specified
Shows that the defence-in-depth approach is still worthwhile - Qualys mentions they nearly gave up looking for vulns and then on trying to exploit them due to just how hard the task appeared given all the defensive measures they would have to overcome
Want to thank Qualys for all their efforts in disclosing vulns and in providing feedback on proposed fixes etc, and the snapd team for all their help on finding and remediating the vulnerability with content interface / layout paths, plus on preparing and delivering this update
Has been in the works for a while, glad it is finally out