diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-08-16 12:54:41 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-09-14 14:45:05 +0200 |
commit | 22778b589af94261c2d8d0665220770d0b56d1a8 (patch) | |
tree | 97bdb1c058f030d30dfe0d566630010572a4fb35 /vm/vm_fault.c | |
parent | 81747ac6d3e846d1955edaa94dee9065e541b7d8 (diff) |
vm: fix locking issues
Avoid accessing fields of `vm_object' objects without having it
locked. These problems have been found using a code transformation
done by Coccinelle that instrumented all accesses with a runtime
check, and manual inspection.
* vm/memory_object.c (memory_object_data_supply): Avoid accessing
fields without the lock.
* vm/vm_fault.c (vm_fault_page): Likewise.
* vm/vm_map.c (vm_map_submap): Properly lock `object'.
(vm_map_copy_overwrite): Avoid accessing fields without the lock.
(vm_map_copyin): Lock `src_object'.
* vm/vm_object.c (_vm_object_setup): Likewise.
(vm_object_allocate): Likewise.
(vm_object_terminate): Avoid accessing fields without the lock.
(vm_object_copy_slowly): Lock `new_object'.
(vm_object_copy_delayed): Lock `src_object' earlier, lock `new_copy'.
(vm_object_shadow): Lock `result'.
(vm_object_enter): Properly lock `object'. Avoid accessing fields
without the lock.
* vm/vm_pageout.c (vm_pageout_setup): Properly lock `old_object'.
Diffstat (limited to 'vm/vm_fault.c')
-rw-r--r-- | vm/vm_fault.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/vm/vm_fault.c b/vm/vm_fault.c index 46779f6..101ebce 100644 --- a/vm/vm_fault.c +++ b/vm/vm_fault.c @@ -229,6 +229,17 @@ vm_fault_return_t vm_fault_page( boolean_t look_for_page; vm_prot_t access_required; + /* We need to unlock an object before making requests to a + memory manager. We use this object to temporarily store + object attributes needed for the request to avoid accessing + the object while it is unlocked. */ + struct + { + struct ipc_port * pager; + pager_request_t pager_request; + vm_offset_t paging_offset; + } obj; + if (resume) { vm_fault_state_t *state = (vm_fault_state_t *) current_thread()->ith_other; @@ -510,11 +521,16 @@ vm_fault_return_t vm_fault_page( new_unlock_request = m->unlock_request = (access_required | m->unlock_request); + obj.pager = object->pager; + obj.pager_request = + object->pager_request; + obj.paging_offset = + object->paging_offset; vm_object_unlock(object); if ((rc = memory_object_data_unlock( - object->pager, - object->pager_request, - offset + object->paging_offset, + obj.pager, + obj.pager_request, + offset + obj.paging_offset, PAGE_SIZE, new_unlock_request)) != KERN_SUCCESS) { @@ -633,6 +649,11 @@ vm_fault_return_t vm_fault_page( m->absent = TRUE; object->absent_count++; + /* Save attributes for the request. */ + obj.pager = object->pager; + obj.pager_request = object->pager_request; + obj.paging_offset = object->paging_offset; + /* * We have a busy page, so we can * release the object lock. @@ -647,16 +668,16 @@ vm_fault_return_t vm_fault_page( vm_stat_sample(SAMPLED_PC_VM_PAGEIN_FAULTS); current_task()->pageins++; - if ((rc = memory_object_data_request(object->pager, - object->pager_request, - m->offset + object->paging_offset, + if ((rc = memory_object_data_request(obj.pager, + obj.pager_request, + m->offset + obj.paging_offset, PAGE_SIZE, access_required)) != KERN_SUCCESS) { if (rc != MACH_SEND_INTERRUPTED) printf("%s(0x%p, 0x%p, 0x%lx, 0x%x, 0x%x) failed, %x\n", "memory_object_data_request", - object->pager, - object->pager_request, - m->offset + object->paging_offset, + obj.pager, + obj.pager_request, + m->offset + obj.paging_offset, PAGE_SIZE, access_required, rc); /* * Don't want to leave a busy page around, |