aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-03-15 20:02:17 +0000
committerMark Johnston <markj@FreeBSD.org>2021-04-06 19:18:49 +0000
commit724bc23da1a9c40768723a4796060c921dbaf224 (patch)
tree4a7732c2b7f80785b338d0f5a70af86a4fdaec53
parentf8a134d0ef1d430efb24b4e6bd6cd58a07ebc376 (diff)
downloadsrc-724bc23da1a9c40768723a4796060c921dbaf224.tar.gz
src-724bc23da1a9c40768723a4796060c921dbaf224.zip
vm_fault: Shoot down multiply mapped COW source page mappings
Reviewed by: kib, rlibby Discussed with: alc Approved by: re (so, implicit) Approved by: so Security: CVE-2021-29626 Security: FreeBSD-SA-21:08.vm (cherry picked from commit 982693bb729badac4e65ecd59772979f2849a2b2) (cherry picked from commit 2e08308d62f381312b3da9dac8970dcdad4b3f2d)
-rw-r--r--sys/vm/vm_fault.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index da7b1f1d2d8e..8b212f3f84e5 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -894,6 +894,9 @@ vm_fault_cow(struct faultstate *fs)
{
bool is_first_object_locked;
+ KASSERT(fs->object != fs->first_object,
+ ("source and target COW objects are identical"));
+
/*
* This allows pages to be virtually copied from a backing_object
* into the first_object, where the backing object has no other
@@ -957,11 +960,29 @@ vm_fault_cow(struct faultstate *fs)
*/
fs->m_cow = fs->m;
fs->m = NULL;
+
+ /*
+ * Typically, the shadow object is either private to this
+ * address space (OBJ_ONEMAPPING) or its pages are read only.
+ * In the highly unusual case where the pages of a shadow object
+ * are read/write shared between this and other address spaces,
+ * we need to ensure that any pmap-level mappings to the
+ * original, copy-on-write page from the backing object are
+ * removed from those other address spaces.
+ *
+ * The flag check is racy, but this is tolerable: if
+ * OBJ_ONEMAPPING is cleared after the check, the busy state
+ * ensures that new mappings of m_cow can't be created.
+ * pmap_enter() will replace an existing mapping in the current
+ * address space. If OBJ_ONEMAPPING is set after the check,
+ * removing mappings will at worse trigger some unnecessary page
+ * faults.
+ */
+ vm_page_assert_xbusied(fs->m_cow);
+ if ((fs->first_object->flags & OBJ_ONEMAPPING) == 0)
+ pmap_remove_all(fs->m_cow);
}
- /*
- * fs->object != fs->first_object due to above
- * conditional
- */
+
vm_object_pip_wakeup(fs->object);
/*