CVE-2020-16120: unprivileged overlayfs permission checking
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
linux (Ubuntu) |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
Opening this as a tracking bug for CVE-2020-16120
Hi,
while playing with shiftfs I've noticed a strange interaction with
overlay and that seems to allow reading files under an accessible
directory, even if they are not readable to the user who created the
user namespace.
While overlay would not accept a FUSE file system as upper layer, it
seems the check doesn't work when it goes through a shiftfs layer.
For the exploit purpose, I've used fuse-overlayfs only because I am
familiar with it but I'd expect any FUSE file system to behave
in the same way. The additional drop_unlink.patch patch is used only to
inhibit deleting temporary files in fuse-overlayfs.
The steps required are:
1) create a user namespace with an unprivileged user.
2) mount a FUSE file system where we have full control at M1. In
the exploit fuse-overlayfs with a custom patch is used.
3) mount shiftfs from the FUSE mount M1 to a mountpoint M2.
4) mount overlay using /etc as lowerdir and M2 for the upperdir (and
workdir).
5) attempt a "mv M2/shadow M2/something-else".
The shadow file that is coming from the lower layer (/etc/shadow), is
copied to the shiftfs and ultimately to the FUSE file system. The copy
would fail but that happens too late, after the FUSE file system already
received the file content. Since we have full control on the FUSE file
system, we can access the content of /etc/shadow.
For running the exploit, you need to have the fuse-overlayfs
dependencies installed (libc6-dev gcc g++ make automake autoconf pkgconf
libfuse3-dev).
It is enough to run "make" as unprivileged user and if the exploit
succeeds you get the content of the /etc/shadow file under the result/
directory.
Tested on Ubuntu 20.04 with Linux 5.4.0-42-generic.
Thanks,
Giuseppe
CVE References
Changed in linux (Ubuntu): | |
status: | New → Confirmed |
Changed in linux (Ubuntu): | |
status: | Confirmed → Fix Released |
information type: | Private Security → Public Security |
Afaict, the bug is due to permission checking for copying up files in overlayfs that we are susceptible too because we allow unpriv overlayfs mounts.
When overlayfs does not support metacopy only copy up then overlayfs will copy up the whole file, i.e. including its contents, to the upper filesystem.
To this end overlayfs will call dentry_open() on any file from the lower filesystem in ovl_copy_ up_flags( ). But dentry_open() doesn't perform any permission checks and will always succeed.
After that overlayfs will copy the lower file contents into the upper filesystem and finally call ovl_set_attr() on it to change the mode and ids of the copied up file. Should ovl_set_attr() fail then the created file will have been improperly copied up, i.e. it will not accurately reflect the ownership the lower file had in the lower filesystem. An attacker can abuse this to get read access to a file on the system.
Getting ovl_set_attr() to fail can e.g. be triggered by mounting fuse-overlayfs in a new user and mount namespaces, then mounting shiftfs on top of it. Finally an overlayfs mount can be created on top of shiftfs that uses a directory or filesystem with invalid ids in the current user namespace as lower filesystem. Then a copy needs to be triggered in the overlayfs mount by e.g. renaming or moving a file in the merged directory. The initial copy up of the data of the file will succeed while the ovl_set_attr() will fail since the ids of the lower filesystem are not valid in the current user namespace. With some trickery, this can be used to leave a copied-up file with the caller's permissions lying in the workdir of the overlayfs mount. This file can now be read by the attacker.
Fixing this involves backporting
commit 56230d956739b9c b1cbde439d76227 d77979a04d
Author: Miklos Szeredi <email address hidden>
Date: Tue Jun 2 22:20:26 2020 +0200
ovl: verify permissions in ovl_path_open()
Check permission before opening a real file.
ovl_path_open() is used by readdir and copy-up routines.
ovl_ permission( ) theoretically already checked copy up permissions, but it
doesn't hurt to re-do these checks during the actual copy-up.
For directory reading ovl_permission() only checks access to topmost
underlying layer. Readdir on a merged directory accesses layers below the
topmost one as well. Permission wasn't checked for these layers.
Note: modifying ovl_permission() to perform this check would be far more
complex and hence more bug prone. The result is less precise permissions
returned in access(2). If this turns out to be an issue, we can revisit
this bug.
Signed-off-by: Miklos Szeredi <email address hidden>
and a small number of preliminary patches since this issue has been fixed upstream.