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

Side by Side Diff: syzygy/agent/asan/shadow.cc

Issue 2379023002: [SyzyAsan] Fix overflow error in ShadowWalker for 4GB 32-bit processes. (Closed)
Patch Set: Fix comments. 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
« no previous file with comments | « syzygy/agent/asan/shadow.h ('k') | syzygy/agent/asan/shadow_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 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 1074 matching lines...) Expand 10 before | Expand all | Expand 10 after
1085 info->header_size = body - block; 1085 info->header_size = body - block;
1086 info->trailer_size = info->block_size - body_size - info->header_size; 1086 info->trailer_size = info->block_size - body_size - info->header_size;
1087 1087
1088 return true; 1088 return true;
1089 } 1089 }
1090 1090
1091 ShadowWalker::ShadowWalker(const Shadow* shadow, 1091 ShadowWalker::ShadowWalker(const Shadow* shadow,
1092 bool recursive, 1092 bool recursive,
1093 const void* lower_bound, 1093 const void* lower_bound,
1094 const void* upper_bound) 1094 const void* upper_bound)
1095 : shadow_(shadow), recursive_(recursive), lower_bound_(0), upper_bound_(0), 1095 : shadow_(shadow), recursive_(recursive), lower_index_(0), upper_index_(0),
1096 cursor_(nullptr), shadow_cursor_(nullptr), nesting_depth_(0) { 1096 shadow_cursor_(nullptr), nesting_depth_(0) {
1097 DCHECK_NE(static_cast<Shadow*>(nullptr), shadow); 1097 DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
1098 DCHECK_LE(Shadow::kAddressLowerBound, reinterpret_cast<size_t>(lower_bound)); 1098 DCHECK_LE(Shadow::kAddressLowerBound, reinterpret_cast<size_t>(lower_bound));
1099 DCHECK_GE(shadow->memory_size(), reinterpret_cast<size_t>(upper_bound));
1100 DCHECK_LE(lower_bound, upper_bound);
1101 1099
1102 lower_bound_ = ::common::AlignDown( 1100 // Get the bounds as shadow indices, being careful to deal with overflow
1103 reinterpret_cast<const uint8_t*>(lower_bound), kShadowRatio); 1101 // of |upper_bound|.
1104 upper_bound_ = ::common::AlignUp( 1102 lower_index_ = reinterpret_cast<uintptr_t>(lower_bound) >> kShadowRatioLog;
1105 reinterpret_cast<const uint8_t*>(upper_bound), kShadowRatio); 1103 upper_index_ = reinterpret_cast<size_t>(::common::AlignUp(
1104 reinterpret_cast<const uint8_t*>(upper_bound), kShadowRatio));
1105 upper_index_--;
1106 upper_index_ >>= kShadowRatioLog;
1107 upper_index_++;
1108
1109 DCHECK_LE(lower_index_, upper_index_);
1110 DCHECK_GE(shadow->length(), upper_index_);
1111
1106 Reset(); 1112 Reset();
1107 } 1113 }
1108 1114
1109 void ShadowWalker::Reset() { 1115 void ShadowWalker::Reset() {
1110 // Walk to the beginning of the first non-nested block, or to the end
1111 // of the range, whichever comes first.
1112 nesting_depth_ = -1; 1116 nesting_depth_ = -1;
1113 shadow_cursor_ = shadow_->GetShadowMemoryForAddress(lower_bound_); 1117 shadow_cursor_ = shadow_->shadow() + lower_index_;
1114 auto shadow_upper_bound = shadow_->GetShadowMemoryForAddress(upper_bound_);
1115 MEMORY_BASIC_INFORMATION memory_info = {};
1116 const uint8_t* next_shadow_cursor = shadow_cursor_;
1117
1118 while (shadow_cursor_ < shadow_upper_bound) {
1119 while (shadow_cursor_ < shadow_upper_bound) {
1120 size_t ret = ::VirtualQuery(shadow_cursor_, &memory_info,
1121 sizeof(memory_info));
1122 DCHECK_GT(ret, 0u);
1123 next_shadow_cursor = static_cast<uint8_t*>(memory_info.BaseAddress) +
1124 memory_info.RegionSize;
1125 if (memory_info.State == MEM_COMMIT)
1126 break;
1127 shadow_cursor_ = next_shadow_cursor;
1128 }
1129 next_shadow_cursor = std::min(next_shadow_cursor, shadow_upper_bound);
1130 for (; shadow_cursor_ != next_shadow_cursor; ++shadow_cursor_) {
1131 uint8_t marker = *shadow_cursor_;
1132 if (ShadowMarkerHelper::IsBlockStart(marker) &&
1133 !ShadowMarkerHelper::IsNestedBlockStart(marker)) {
1134 // Break both loops.
1135 shadow_upper_bound = shadow_cursor_;
1136 break;
1137 }
1138 }
1139 }
1140
1141 cursor_ = reinterpret_cast<uint8_t*>((shadow_cursor_ - shadow_->shadow()) *
1142 kShadowRatio);
1143 } 1118 }
1144 1119
1145 bool ShadowWalker::Next(BlockInfo* info) { 1120 bool ShadowWalker::Next(BlockInfo* info) {
1146 DCHECK_NE(static_cast<BlockInfo*>(NULL), info); 1121 DCHECK_NE(static_cast<BlockInfo*>(NULL), info);
1147 1122
1148 auto shadow_upper_bound = shadow_->GetShadowMemoryForAddress(upper_bound_); 1123 auto shadow_upper_bound = shadow_->shadow() + upper_index_;
1149 MEMORY_BASIC_INFORMATION memory_info = {};
1150 const uint8_t* next_shadow_cursor = shadow_cursor_;
1151 1124
1152 // Iterate until a reportable block is encountered, or the slab is exhausted. 1125 while (shadow_cursor_ < shadow_upper_bound) {
1153 while (cursor_ < upper_bound_) { 1126 // Skip uncommitted ranges of memory. This is possible when using a sparse
1154 // Find a range of commited pages in the shadow memory. 1127 // shadow that maps its pages in on demand.
1155 shadow_cursor_ = shadow_->GetShadowMemoryForAddress(cursor_); 1128 MEMORY_BASIC_INFORMATION memory_info = {};
1156 while (shadow_cursor_ != shadow_upper_bound) { 1129 size_t ret = ::VirtualQuery(shadow_cursor_, &memory_info,
1157 size_t ret = ::VirtualQuery(shadow_cursor_, &memory_info, 1130 sizeof(memory_info));
1158 sizeof(memory_info)); 1131 DCHECK_GT(ret, 0u);
chrisha 2016/09/29 14:12:10 Doing this at every step is quite wasteful. I've r
1159 DCHECK_GT(ret, 0u); 1132 auto start_of_region =
1160 next_shadow_cursor = static_cast<uint8_t*>(memory_info.BaseAddress) + 1133 static_cast<const uint8_t*>(memory_info.BaseAddress);
1161 memory_info.RegionSize; 1134 auto end_of_region = start_of_region + memory_info.RegionSize;
1162 if (memory_info.State == MEM_COMMIT) 1135
1163 break; 1136 // If the region isn't committed and readable memory then skip it.
1164 shadow_cursor_ = next_shadow_cursor; 1137 if (memory_info.State != MEM_COMMIT) {
1138 // If the next region is beyond the part of the shadow being scanned
1139 // then bail early (be careful to handle overflow here).
1140 if (end_of_region > shadow_upper_bound || end_of_region == nullptr)
1141 return false;
1142
1143 // Step to the beginning of the next region and try again.
1144 shadow_cursor_ = start_of_region;
1145 continue;
1165 } 1146 }
1166 1147
1167 cursor_ = reinterpret_cast<uint8_t*>((shadow_cursor_ - shadow_->shadow()) * 1148 // Getting here then |start_of_region| and |end_of_region| are a part of
1168 kShadowRatio); 1149 // the shadow that should be scanned. Calculate where to stop for this
1150 // region, taking care to handle overflow.
1151 if (!end_of_region) {
1152 end_of_region = shadow_upper_bound;
1153 } else {
1154 end_of_region = std::min(shadow_upper_bound, end_of_region);
1155 }
1169 1156
1170 if (cursor_ >= upper_bound_) 1157 // Scan this committed portion of the shadow.
1171 break; 1158 while (shadow_cursor_ < end_of_region) {
1172 1159 uint8_t marker = *shadow_cursor_;
1173 auto next_shadow_index = next_shadow_cursor - shadow_->shadow();
1174 auto next_cursor = std::min(upper_bound_,
1175 reinterpret_cast<const uint8_t*>(
1176 next_shadow_index * kShadowRatio));
1177
1178 for (; cursor_ != next_cursor; cursor_ += kShadowRatio) {
1179 uint8_t marker = shadow_->GetShadowMarkerForAddress(cursor_);
1180 1160
1181 // Update the nesting depth when block end markers are encountered. 1161 // Update the nesting depth when block end markers are encountered.
1182 if (ShadowMarkerHelper::IsBlockEnd(marker)) { 1162 if (ShadowMarkerHelper::IsBlockEnd(marker)) {
1183 DCHECK_LE(0, nesting_depth_); 1163 DCHECK_LE(0, nesting_depth_);
1184 --nesting_depth_; 1164 --nesting_depth_;
1165 ++shadow_cursor_;
1185 continue; 1166 continue;
1186 } 1167 }
1187 1168
1188 // Look for a block start marker. 1169 // Look for a block start marker.
1189 if (ShadowMarkerHelper::IsBlockStart(marker)) { 1170 if (ShadowMarkerHelper::IsBlockStart(marker)) {
1190 // Update the nesting depth when block start bytes are encountered. 1171 // Update the nesting depth when block start bytes are encountered.
1191 ++nesting_depth_; 1172 ++nesting_depth_;
1192 1173
1193 // Non-nested blocks should only be encountered at depth 0. 1174 // Non-nested blocks should only be encountered at depth 0.
1194 bool is_nested = ShadowMarkerHelper::IsNestedBlockStart(marker); 1175 bool is_nested = ShadowMarkerHelper::IsNestedBlockStart(marker);
1195 DCHECK(is_nested || nesting_depth_ == 0); 1176 DCHECK(is_nested || nesting_depth_ == 0);
1196 1177
1197 // Determine if the block is to be reported. 1178 // Determine if the block is to be reported.
1198 if (!is_nested || recursive_) { 1179 if (!is_nested || recursive_) {
1199 // This can only fail if the shadow memory is malformed. 1180 // This can only fail if the shadow memory is malformed.
1200 CHECK(shadow_->BlockInfoFromShadow(cursor_, info)); 1181 size_t block_index = shadow_cursor_ - shadow_->shadow();
1182 void* block_address = reinterpret_cast<void*>(
1183 block_index << kShadowRatioLog);
1184 CHECK(shadow_->BlockInfoFromShadow(block_address, info));
1201 1185
1202 // In a recursive descent we have to process body contents. 1186 // In a recursive descent we have to process body contents.
1203 if (recursive_) { 1187 if (recursive_) {
1204 cursor_ += kShadowRatio; 1188 // Jump straight to the body of the nested block.
1189 shadow_cursor_ = shadow_->GetShadowMemoryForAddress(
1190 info->body);
1205 } else { 1191 } else {
1206 // Otherwise we can skip the body of the block we just reported. 1192 // Otherwise we can skip the body of the block we just reported.
1207 // We skip directly to the end marker (but not past it so that depth 1193 // We skip directly to the end marker (but not past it so that depth
1208 // bookkeeping works properly). 1194 // bookkeeping works properly).
1209 cursor_ += info->block_size - kShadowRatio; 1195 auto block_end = reinterpret_cast<const uint8_t*>(info->header) +
1196 info->block_size;
1197 shadow_cursor_ = shadow_->GetShadowMemoryForAddress(block_end) - 1;
1210 } 1198 }
1211 1199
1212 shadow_cursor_ = shadow_->GetShadowMemoryForAddress(cursor_); 1200 // A block has been found and its |info| is parsed. Return to the
1201 // caller.
1213 return true; 1202 return true;
1214 } 1203 }
1215 continue;
1216 } 1204 }
1217 } 1205
1206 // Advance the shadow cursor.
1207 ++shadow_cursor_;
1208 } // while (shadow_cursor_ < end_of_region)
1218 } 1209 }
1219 1210
1220 return false; 1211 return false;
1221 } 1212 }
1222 1213
1223 } // namespace asan 1214 } // namespace asan
1224 } // namespace agent 1215 } // namespace agent
OLDNEW
« no previous file with comments | « syzygy/agent/asan/shadow.h ('k') | syzygy/agent/asan/shadow_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698