From b06275e65f012db0ea85c65bc4e30fb9b7197cf8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 16 Aug 2015 12:54:41 +0200 Subject: 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'. --- vm/vm_map.c | 55 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 16 deletions(-) (limited to 'vm/vm_map.c') diff --git a/vm/vm_map.c b/vm/vm_map.c index ae3ce21..9098dfd 100644 --- a/vm/vm_map.c +++ b/vm/vm_map.c @@ -1182,16 +1182,20 @@ kern_return_t vm_map_submap( if ((entry->vme_start == start) && (entry->vme_end == end) && (!entry->is_sub_map) && - ((object = entry->object.vm_object) == vm_submap_object) && - (object->resident_page_count == 0) && - (object->copy == VM_OBJECT_NULL) && - (object->shadow == VM_OBJECT_NULL) && - (!object->pager_created)) { - entry->object.vm_object = VM_OBJECT_NULL; - vm_object_deallocate(object); - entry->is_sub_map = TRUE; - vm_map_reference(entry->object.sub_map = submap); - result = KERN_SUCCESS; + ((object = entry->object.vm_object) == vm_submap_object)) { + vm_object_lock(object); + if ((object->resident_page_count == 0) && + (object->copy == VM_OBJECT_NULL) && + (object->shadow == VM_OBJECT_NULL) && + (!object->pager_created)) { + vm_object_unlock(object); + entry->object.vm_object = VM_OBJECT_NULL; + vm_object_deallocate(object); + entry->is_sub_map = TRUE; + vm_map_reference(entry->object.sub_map = submap); + result = KERN_SUCCESS; + } else + vm_object_unlock(object); } vm_map_unlock(map); @@ -2122,6 +2126,7 @@ start_pass_1: for (entry = tmp_entry;;) { vm_size_t sub_size = (entry->vme_end - entry->vme_start); vm_map_entry_t next = entry->vme_next; + vm_object_t object; if ( ! (entry->protection & VM_PROT_WRITE)) { vm_map_unlock(dst_map); @@ -2157,10 +2162,13 @@ start_pass_1: /* * Check for permanent objects in the destination. */ - - if ((entry->object.vm_object != VM_OBJECT_NULL) && - !entry->object.vm_object->temporary) - contains_permanent_objects = TRUE; + object = entry->object.vm_object; + if ((object != VM_OBJECT_NULL) + && ! contains_permanent_objects) { + vm_object_lock(object); + contains_permanent_objects = object->temporary; + vm_object_unlock(object); + } size -= sub_size; entry = next; @@ -2220,6 +2228,7 @@ start_pass_1: vm_map_entry_t copy_entry = vm_map_copy_first_entry(copy); vm_size_t copy_size = (copy_entry->vme_end - copy_entry->vme_start); vm_object_t object; + int temporary; entry = tmp_entry; size = (entry->vme_end - entry->vme_start); @@ -2275,8 +2284,15 @@ start_pass_1: */ object = entry->object.vm_object; + temporary = 0; + if (object != VM_OBJECT_NULL) { + vm_object_lock(object); + temporary = object->temporary; + vm_object_unlock(object); + } + if (!entry->is_shared && - ((object == VM_OBJECT_NULL) || object->temporary)) { + ((object == VM_OBJECT_NULL) || temporary)) { vm_object_t old_object = entry->object.vm_object; vm_offset_t old_offset = entry->offset; @@ -3219,11 +3235,15 @@ kern_return_t vm_map_copyin( /* * Attempt non-blocking copy-on-write optimizations. */ - + if (src_object) + vm_object_lock(src_object); if (src_destroy && (src_object == VM_OBJECT_NULL || (src_object->temporary && !src_object->use_shared_copy))) { + if (src_object) + vm_object_unlock(src_object); + /* * If we are destroying the source, and the object * is temporary, and not shared writable, @@ -3243,6 +3263,9 @@ kern_return_t vm_map_copyin( goto CopySuccessful; } + if (src_object) + vm_object_unlock(src_object); + if (!was_wired && vm_object_copy_temporary( &new_entry->object.vm_object, -- cgit v1.2.3