Hello Arne, hello * (cc'ed),
for your information.
Thanks, and best regards,
Peter Müller
-------- Forwarded Message --------
Subject: [oss-security] [CVE-2020-12114] Linux kernel denial of service by corrupting mountpoint reference counter
Date: Mon, 4 May 2020 00:24:19 +0100
From: Piotr Krysiuk <piotras(a)gmail.com>
Replies to: oss-security(a)lists.openwall.com
To: oss-security(a)lists.openwall.com
A race condition in fs/namespace.c in the Linux kernel allows unprivileged
local users to cause a denial of service by corrupting mountpoint reference
counter
# Affected Versions
The denial of service has been reproduced against the following Linux
kernel releases from kernel.org:
* 4.19.118 (longterm release)
* 4.14.177 (longterm release)
* 4.9.220 (longterm release)
* 4.4.220 (longterm release)
The denial of service has also been reproduced against the following
distribution kernel versions provided by current Ubuntu LTS releases:
* 5.0.0-1034-gcp (distribution kernel provided by package
"linux-image-5.0.0-1034-gcp" from Ubuntu 18.04.4 LTS)
* 4.15.0-1061-gcp (current distribution kernel provided by package
"linux-image-4.15.0-1061-gcp" from Ubuntu 16.04.6 LTS with all updates
installed)
Linux kernel releases 5.3 and newer from kernel.org are not affected.
# Root Cause
Unprivileged local user can cause kernel panic by triggering destruction of
a mountpoint that is still in use.
This is possible by exploiting a race condition to corrupt mountpoint
reference counter when simultaneously executing put_mountpoint() and
pivot_root():
* one thread increments m_count member of struct mountpoint
[under namespace_sem, but not holding mount_lock]
pivot_root()
* another thread simultaneously decrements the same m_count
[under mount_lock, but not holding namespace_sem]
put_mountpoint()
unhash_mnt()
umount_mnt()
mntput_no_expire()
# Bug Fix
To fix this race condition, grab mount_lock before updating m_count in
pivot_root().
This requires swapping two lines in fs/namespace.c:
```
@@ -3142,8 +3142,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *,
new_root,
/* make certain new is below the root */
if (!is_path_reachable(new_mnt, new.dentry, &root))
goto out4;
- root_mp->m_count++; /* pin it so it won't go away */
lock_mount_hash();
+ root_mp->m_count++; /* pin it so it won't go away */
detach_mnt(new_mnt, &parent_path);
detach_mnt(root_mnt, &root_parent);
if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
```
The above fix has been merged into all relevant longterm branches by
upstream Linux kernel.
The following Linux kernel releases from kernel.org incorporate the fix:
* 4.19.119 (longterm release), see commit
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=…
* 4.14.178 (current longterm release), see commit
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=…
* 4.9.221 (current longterm release), see commit
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=…
* 4.4.221 (current longterm release), see commit
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=…
# Proof Of Concept
I developed a PoC that allows unprivileged local users to reliably trigger
kernel panic inside VM instances on Compute Engine of Google Cloud Platform.
The PoC has been shared privately with <security(a)kernel.org> and via a
private bug report with Ubuntu.
# Discoverer
Piotr Krysiuk <piotras(a)gmail.com>
# References
CVE-2020-12114 (reserved via https://cveform.mitre.org/)