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@gmail.com Replies to: oss-security@lists.openwall.com To: oss-security@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=v... * 4.14.178 (current longterm release), see commit https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v... * 4.9.221 (current longterm release), see commit https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v... * 4.4.221 (current longterm release), see commit https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v...
# 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@kernel.org and via a private bug report with Ubuntu.
# Discoverer
Piotr Krysiuk piotras@gmail.com
# References
CVE-2020-12114 (reserved via https://cveform.mitre.org/)