// Copyright 2018 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "snapshot/sanitized/memory_snapshot_sanitized.h" #include #include "util/linux/pac_helper.h" namespace crashpad { namespace internal { namespace { class MemorySanitizer : public MemorySnapshot::Delegate { public: MemorySanitizer(MemorySnapshot::Delegate* delegate, RangeSet* ranges, VMAddress address, bool is_64_bit) : delegate_(delegate), ranges_(ranges), address_(address), is_64_bit_(is_64_bit) {} MemorySanitizer(const MemorySanitizer&) = delete; MemorySanitizer& operator=(const MemorySanitizer&) = delete; ~MemorySanitizer() = default; bool MemorySnapshotDelegateRead(void* data, size_t size) override { if (is_64_bit_) { Sanitize(data, size); } else { Sanitize(data, size); } return delegate_->MemorySnapshotDelegateRead(data, size); } private: template void Sanitize(void* data, size_t size) { const Pointer defaced = static_cast(MemorySnapshotSanitized::kDefaced); // Sanitize up to a word-aligned address. const size_t aligned_offset = ((address_ + sizeof(Pointer) - 1) & ~(sizeof(Pointer) - 1)) - address_; memcpy(data, &defaced, aligned_offset); // Sanitize words that aren't small and don't look like pointers. size_t word_count = (size - aligned_offset) / sizeof(Pointer); auto words = reinterpret_cast(static_cast(data) + aligned_offset); for (size_t index = 0; index < word_count; ++index) { auto word = StripPACBits(words[index]); if (word > MemorySnapshotSanitized::kSmallWordMax && !ranges_->Contains(word)) { words[index] = defaced; } } // Sanitize trailing bytes beyond the word-sized items. const size_t sanitized_bytes = aligned_offset + word_count * sizeof(Pointer); memcpy(static_cast(data) + sanitized_bytes, &defaced, size - sanitized_bytes); } MemorySnapshot::Delegate* delegate_; RangeSet* ranges_; VMAddress address_; bool is_64_bit_; }; } // namespace MemorySnapshotSanitized::MemorySnapshotSanitized(const MemorySnapshot* snapshot, RangeSet* ranges, bool is_64_bit) : snapshot_(snapshot), ranges_(ranges), is_64_bit_(is_64_bit) {} MemorySnapshotSanitized::~MemorySnapshotSanitized() = default; uint64_t MemorySnapshotSanitized::Address() const { return snapshot_->Address(); } size_t MemorySnapshotSanitized::Size() const { return snapshot_->Size(); } bool MemorySnapshotSanitized::Read(Delegate* delegate) const { MemorySanitizer sanitizer(delegate, ranges_, Address(), is_64_bit_); return snapshot_->Read(&sanitizer); } } // namespace internal } // namespace crashpad