Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: syzygy/agent/asan/heap_managers/block_heap_manager.cc

Issue 2383793003: [SyzyAsan] More careful handling when freeing corrupt blocks. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 Google Inc. All Rights Reserved. 1 // Copyright 2014 Google Inc. All Rights Reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 return FreeCorruptBlock(block_info); 792 return FreeCorruptBlock(block_info);
793 } else { 793 } else {
794 return FreePristineBlock(block_info); 794 return FreePristineBlock(block_info);
795 } 795 }
796 } 796 }
797 797
798 bool BlockHeapManager::FreeCorruptBlock(BlockInfo* block_info) { 798 bool BlockHeapManager::FreeCorruptBlock(BlockInfo* block_info) {
799 DCHECK(initialized_); 799 DCHECK(initialized_);
800 DCHECK_NE(static_cast<BlockInfo*>(nullptr), block_info); 800 DCHECK_NE(static_cast<BlockInfo*>(nullptr), block_info);
801 ClearCorruptBlockMetadata(block_info); 801 ClearCorruptBlockMetadata(block_info);
802
803 // ClearCorruptBlockMetadata couldn't figure out which heap owns this block.
804 // Explode, as there's no way to safely move forward here. Note that the only
805 // way to get here is if ReportCorruptBlock decided it didn't want to report
806 // this block earlier, and decided to move forward in trying to free it.
807 // TODO(chrisha): Entertain the idea of keeping track of such blocks, and
808 // simply reporting them en masse when things finally do go south, or at
809 // process termination.
810 if (block_info->trailer->heap_id == 0)
811 ReportHeapError(block_info->body, CORRUPT_BLOCK);
812
813 // At this point there's very high confidence that the heap_id is valid so
814 // go ahead and try to free the block like normal.
802 return FreePristineBlock(block_info); 815 return FreePristineBlock(block_info);
803 } 816 }
804 817
805 bool BlockHeapManager::FreePristineBlock(BlockInfo* block_info) { 818 bool BlockHeapManager::FreePristineBlock(BlockInfo* block_info) {
806 DCHECK(initialized_); 819 DCHECK(initialized_);
807 DCHECK_NE(static_cast<BlockInfo*>(nullptr), block_info); 820 DCHECK_NE(static_cast<BlockInfo*>(nullptr), block_info);
808 BlockHeapInterface* heap = GetHeapFromId(block_info->trailer->heap_id); 821 BlockHeapInterface* heap = GetHeapFromId(block_info->trailer->heap_id);
809 822
810 if (enable_page_protections_) { 823 if (enable_page_protections_) {
811 // Remove block protections so the redzones may be modified. 824 // Remove block protections so the redzones may be modified.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 879
867 // Set the invalid stack captures to nullptr. 880 // Set the invalid stack captures to nullptr.
868 if (!stack_cache_->StackCapturePointerIsValid( 881 if (!stack_cache_->StackCapturePointerIsValid(
869 block_info->header->alloc_stack)) { 882 block_info->header->alloc_stack)) {
870 block_info->header->alloc_stack = nullptr; 883 block_info->header->alloc_stack = nullptr;
871 } 884 }
872 if (!stack_cache_->StackCapturePointerIsValid( 885 if (!stack_cache_->StackCapturePointerIsValid(
873 block_info->header->free_stack)) { 886 block_info->header->free_stack)) {
874 block_info->header->free_stack = nullptr; 887 block_info->header->free_stack = nullptr;
875 } 888 }
889
890 block_info->trailer->heap_id = GetCorruptBlockHeapId(block_info);
876 } 891 }
877 892
878 void BlockHeapManager::ReportHeapError(void* address, BadAccessKind kind) { 893 void BlockHeapManager::ReportHeapError(void* address, BadAccessKind kind) {
879 DCHECK(initialized_); 894 DCHECK(initialized_);
880 DCHECK_NE(static_cast<void*>(nullptr), address); 895 DCHECK_NE(static_cast<void*>(nullptr), address);
881 896
882 // Collect information about the error. 897 // Collect information about the error.
883 AsanErrorInfo error_info = {}; 898 AsanErrorInfo error_info = {};
884 ::RtlCaptureContext(&error_info.context); 899 ::RtlCaptureContext(&error_info.context);
885 error_info.access_mode = agent::asan::ASAN_UNKNOWN_ACCESS; 900 error_info.access_mode = agent::asan::ASAN_UNKNOWN_ACCESS;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
946 // Otherwise, allow everything through. 961 // Otherwise, allow everything through.
947 return true; 962 return true;
948 } 963 }
949 964
950 bool BlockHeapManager::ShouldReportCorruptBlock(const BlockInfo* block_info) { 965 bool BlockHeapManager::ShouldReportCorruptBlock(const BlockInfo* block_info) {
951 DCHECK_NE(static_cast<const BlockInfo*>(nullptr), block_info); 966 DCHECK_NE(static_cast<const BlockInfo*>(nullptr), block_info);
952 967
953 if (!parameters_.prevent_duplicate_corruption_crashes) 968 if (!parameters_.prevent_duplicate_corruption_crashes)
954 return true; 969 return true;
955 970
971 if (!corrupt_block_registry_cache_.get())
972 return true;
973
974 // At this point none of the block content can be trusted, so proceed with
975 // extreme caution.
956 const common::StackCapture* alloc_stack = block_info->header->alloc_stack; 976 const common::StackCapture* alloc_stack = block_info->header->alloc_stack;
977 if (!stack_cache_->StackCapturePointerIsValid(alloc_stack))
978 return true;
979
957 StackId relative_alloc_stack_id = alloc_stack->relative_stack_id(); 980 StackId relative_alloc_stack_id = alloc_stack->relative_stack_id();
958 981
959 // Look at the registry cache to see if an error has already been reported 982 // Look at the registry cache to see if an error has already been reported
960 // for this allocation stack trace, if so prevent from reporting another one. 983 // for this allocation stack trace, if so prevent from reporting another one.
961 if (corrupt_block_registry_cache_.get()) { 984 if (corrupt_block_registry_cache_->DoesIdExist(relative_alloc_stack_id))
962 if (corrupt_block_registry_cache_->DoesIdExist(relative_alloc_stack_id)) 985 return false;
963 return false;
964 986
965 // Update the corrupt block registry cache to prevent from crashing if we 987 // Update the corrupt block registry cache to prevent from crashing if we
966 // encounter a corrupt block that has the same allocation stack trace. 988 // encounter a corrupt block that has the same allocation stack trace.
967 corrupt_block_registry_cache_->AddOrUpdateStackId(relative_alloc_stack_id); 989 corrupt_block_registry_cache_->AddOrUpdateStackId(relative_alloc_stack_id);
968 }
969 990
970 return true; 991 return true;
971 } 992 }
972 993
973 void BlockHeapManager::TrimOrScheduleIfNecessary( 994 void BlockHeapManager::TrimOrScheduleIfNecessary(
974 TrimStatus trim_status, 995 TrimStatus trim_status,
975 BlockQuarantineInterface* quarantine) { 996 BlockQuarantineInterface* quarantine) {
976 // If no trimming is required, nothing to do. 997 // If no trimming is required, nothing to do.
977 if (trim_status == TRIM_NOT_REQUIRED) 998 if (trim_status == TRIM_NOT_REQUIRED)
978 return; 999 return;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 shared_quarantine_.SetOverbudgetSize( 1038 shared_quarantine_.SetOverbudgetSize(
1018 shared_quarantine_.max_quarantine_size() * kOverbudgetSizePercentage / 1039 shared_quarantine_.max_quarantine_size() * kOverbudgetSizePercentage /
1019 100); 1040 100);
1020 1041
1021 // Create the thread and wait for it to start. 1042 // Create the thread and wait for it to start.
1022 base::AutoLock lock(deferred_free_thread_lock_); 1043 base::AutoLock lock(deferred_free_thread_lock_);
1023 deferred_free_thread_.reset(new DeferredFreeThread(deferred_free_callback)); 1044 deferred_free_thread_.reset(new DeferredFreeThread(deferred_free_callback));
1024 deferred_free_thread_->Start(); 1045 deferred_free_thread_->Start();
1025 } 1046 }
1026 1047
1048 HeapId BlockHeapManager::GetCorruptBlockHeapId(const BlockInfo* block_info) {
1049 base::AutoLock lock(lock_);
1050
1051 // Check the heap specified in the trailer first.
1052 bool trailer_has_valid_heap_id = false;
1053 if (block_info->trailer->heap_id != 0) {
1054 for (auto hq = heaps_.begin(); hq != heaps_.end(); ++hq) {
1055 HeapId heap_id = GetHeapId(hq);
1056 if (heap_id == block_info->trailer->heap_id) {
1057 if ((hq->first->GetHeapFeatures() &
1058 BlockHeapInterface::kHeapSupportsIsAllocated) == 0) {
1059 // If the trailer heap id is valid but the heap doesn't support
1060 // IsAllocated then remember this as a backup answer for later.
1061 trailer_has_valid_heap_id = true;
1062 } else {
1063 // If the advertised heap can be confirmed to own this block then
1064 // return that heap id.
1065 if (hq->first->IsAllocated(block_info->header))
1066 return heap_id;
1067 }
1068
1069 break;
1070 }
1071 }
1072 }
1073
1074 // These keep track of heaps that don't support IsAllocated in the loop
1075 // below.
1076 HeapId unsupported_heap_id = 0;
1077 size_t unsupported_heap_count = 0;
1078
1079 // Check against every outstanding heap.
1080 for (auto hq = heaps_.begin(); hq != heaps_.end(); ++hq) {
1081 HeapId heap_id = GetHeapId(hq);
1082
1083 // Skip heaps that don't support IsAllocated.
1084 if ((hq->first->GetHeapFeatures() &
1085 BlockHeapInterface::kHeapSupportsIsAllocated) == 0) {
1086 unsupported_heap_id = heap_id;
1087 ++unsupported_heap_count;
1088 continue;
1089 }
1090
1091 if (hq->first->IsAllocated(block_info->header))
1092 return heap_id;
1093 }
1094
1095 // If no heap was found but only a single heap doesn't support
1096 // IsAllocated, then that's the heap by process of elimination.
1097 if (unsupported_heap_count == 1)
1098 return unsupported_heap_id;
1099
1100 // If the trailer contained a valid heap ID but it simply couldn't be
1101 // confirmed to be owner of the block then assume that's the heap.
1102 if (trailer_has_valid_heap_id)
1103 return block_info->trailer->heap_id;
1104
1105 // Unfortunately, there's no way to know which heap this block belongs to.
1106 return 0;
1107 }
1108
1027 } // namespace heap_managers 1109 } // namespace heap_managers
1028 } // namespace asan 1110 } // namespace asan
1029 } // namespace agent 1111 } // namespace agent
OLDNEW
« no previous file with comments | « syzygy/agent/asan/heap_managers/block_heap_manager.h ('k') | syzygy/agent/asan/heap_managers/block_heap_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698