| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |