diff options
| author | Mark Johnston <markj@FreeBSD.org> | 2021-03-15 20:02:17 +0000 |
|---|---|---|
| committer | Mark Johnston <markj@FreeBSD.org> | 2021-04-06 18:50:46 +0000 |
| commit | 2e08308d62f381312b3da9dac8970dcdad4b3f2d (patch) | |
| tree | c2e393a752d19c0251fd03cc0416f4a3cae61ece | |
| parent | edda63ba979a8e39e935ed97e1c9049ee1ff4e0a (diff) | |
vm_fault: Shoot down multiply mapped COW source page mappings
Reviewed by: kib, rlibby
Discussed with: alc
Approved by: so
Security: CVE-2021-29626
Security: FreeBSD-SA-21:08.vm
(cherry picked from commit 982693bb729badac4e65ecd59772979f2849a2b2)
| -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 585e1544415d..0e8ff9b27ed1 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -896,6 +896,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 @@ -959,11 +962,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); /* |
