diff options
author | Mark Johnston <markj@FreeBSD.org> | 2021-03-15 20:02:17 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2021-04-06 19:18:49 +0000 |
commit | 724bc23da1a9c40768723a4796060c921dbaf224 (patch) | |
tree | 4a7732c2b7f80785b338d0f5a70af86a4fdaec53 | |
parent | f8a134d0ef1d430efb24b4e6bd6cd58a07ebc376 (diff) | |
download | src-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.c | 29 |
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); /* |