Loading libunwindstack/ElfInterface.cpp +37 −14 Original line number Diff line number Diff line Loading @@ -78,10 +78,31 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { CrcGenerateTable(); Crc64GenerateTable(); std::vector<uint8_t> src(gnu_debugdata_size_); if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) { gnu_debugdata_offset_ = 0; gnu_debugdata_size_ = static_cast<uint64_t>(-1); // Verify the request is not larger than the max size_t value. if (gnu_debugdata_size_ > SIZE_MAX) { return nullptr; } size_t initial_buffer_size; if (__builtin_mul_overflow(5, gnu_debugdata_size_, &initial_buffer_size)) { return nullptr; } size_t buffer_increment; if (__builtin_mul_overflow(2, gnu_debugdata_size_, &buffer_increment)) { return nullptr; } std::unique_ptr<uint8_t[]> src(new (std::nothrow) uint8_t[gnu_debugdata_size_]); if (src.get() == nullptr) { return nullptr; } std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer); if (!dst->Resize(initial_buffer_size)) { return nullptr; } if (!memory_->ReadFully(gnu_debugdata_offset_, src.get(), gnu_debugdata_size_)) { return nullptr; } Loading @@ -89,21 +110,23 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { CXzUnpacker state; alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); }; alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); }; XzUnpacker_Construct(&state, &alloc); std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer); int return_val; size_t src_offset = 0; size_t dst_offset = 0; ECoderStatus status; dst->Resize(5 * gnu_debugdata_size_); do { size_t src_remaining = src.size() - src_offset; size_t src_remaining = gnu_debugdata_size_ - src_offset; size_t dst_remaining = dst->Size() - dst_offset; if (dst_remaining < 2 * gnu_debugdata_size_) { dst->Resize(dst->Size() + 2 * gnu_debugdata_size_); dst_remaining += 2 * gnu_debugdata_size_; if (dst_remaining < buffer_increment) { size_t new_size; if (__builtin_add_overflow(dst->Size(), buffer_increment, &new_size) || !dst->Resize(new_size)) { XzUnpacker_Free(&state); return nullptr; } dst_remaining += buffer_increment; } return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset], &src_remaining, true, CODER_FINISH_ANY, &status); Loading @@ -112,13 +135,13 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED); XzUnpacker_Free(&state); if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) { gnu_debugdata_offset_ = 0; gnu_debugdata_size_ = static_cast<uint64_t>(-1); return nullptr; } // Shrink back down to the exact size. dst->Resize(dst_offset); if (!dst->Resize(dst_offset)) { return nullptr; } return dst.release(); } Loading libunwindstack/Memory.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -206,12 +206,12 @@ std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_ } size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { if (addr >= raw_.size()) { if (addr >= size_) { return 0; } size_t bytes_left = raw_.size() - static_cast<size_t>(addr); const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr; size_t bytes_left = size_ - static_cast<size_t>(addr); const unsigned char* actual_base = static_cast<const unsigned char*>(raw_) + addr; size_t actual_len = std::min(bytes_left, size); memcpy(dst, actual_base, actual_len); Loading @@ -219,7 +219,7 @@ size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { } uint8_t* MemoryBuffer::GetPtr(size_t offset) { if (offset < raw_.size()) { if (offset < size_) { return &raw_[offset]; } return nullptr; Loading libunwindstack/MemoryBuffer.h +13 −4 Original line number Diff line number Diff line Loading @@ -29,18 +29,27 @@ namespace unwindstack { class MemoryBuffer : public Memory { public: MemoryBuffer() = default; virtual ~MemoryBuffer() = default; virtual ~MemoryBuffer() { free(raw_); } size_t Read(uint64_t addr, void* dst, size_t size) override; uint8_t* GetPtr(size_t offset); void Resize(size_t size) { raw_.resize(size); } bool Resize(size_t size) { raw_ = reinterpret_cast<uint8_t*>(realloc(raw_, size)); if (raw_ == nullptr) { size_ = 0; return false; } size_ = size; return true; } uint64_t Size() { return raw_.size(); } uint64_t Size() { return size_; } private: std::vector<uint8_t> raw_; uint8_t* raw_ = nullptr; size_t size_ = 0; }; } // namespace unwindstack Loading libunwindstack/tests/ElfFake.h +3 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ class ElfInterfaceFake : public ElfInterface { void FakeSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; } void FakeSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; } void FakeSetGnuDebugdataOffset(uint64_t offset) { gnu_debugdata_offset_ = offset; } void FakeSetGnuDebugdataSize(uint64_t size) { gnu_debugdata_size_ = size; } private: std::unordered_map<std::string, uint64_t> globals_; std::string fake_build_id_; Loading libunwindstack/tests/ElfInterfaceTest.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -1944,4 +1944,23 @@ TEST_F(ElfInterfaceTest, get_load_bias_exec_negative_64) { CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, -0x4000); } TEST_F(ElfInterfaceTest, huge_gnu_debugdata_size) { ElfInterfaceFake interface(nullptr); interface.FakeSetGnuDebugdataOffset(0x1000); interface.FakeSetGnuDebugdataSize(0xffffffffffffffffUL); ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr); interface.FakeSetGnuDebugdataSize(0x4000000000000UL); ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr); // This should exceed the size_t value of the first allocation. #if defined(__LP64__) interface.FakeSetGnuDebugdataSize(0x3333333333333334ULL); #else interface.FakeSetGnuDebugdataSize(0x33333334); #endif ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr); } } // namespace unwindstack Loading
libunwindstack/ElfInterface.cpp +37 −14 Original line number Diff line number Diff line Loading @@ -78,10 +78,31 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { CrcGenerateTable(); Crc64GenerateTable(); std::vector<uint8_t> src(gnu_debugdata_size_); if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) { gnu_debugdata_offset_ = 0; gnu_debugdata_size_ = static_cast<uint64_t>(-1); // Verify the request is not larger than the max size_t value. if (gnu_debugdata_size_ > SIZE_MAX) { return nullptr; } size_t initial_buffer_size; if (__builtin_mul_overflow(5, gnu_debugdata_size_, &initial_buffer_size)) { return nullptr; } size_t buffer_increment; if (__builtin_mul_overflow(2, gnu_debugdata_size_, &buffer_increment)) { return nullptr; } std::unique_ptr<uint8_t[]> src(new (std::nothrow) uint8_t[gnu_debugdata_size_]); if (src.get() == nullptr) { return nullptr; } std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer); if (!dst->Resize(initial_buffer_size)) { return nullptr; } if (!memory_->ReadFully(gnu_debugdata_offset_, src.get(), gnu_debugdata_size_)) { return nullptr; } Loading @@ -89,21 +110,23 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { CXzUnpacker state; alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); }; alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); }; XzUnpacker_Construct(&state, &alloc); std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer); int return_val; size_t src_offset = 0; size_t dst_offset = 0; ECoderStatus status; dst->Resize(5 * gnu_debugdata_size_); do { size_t src_remaining = src.size() - src_offset; size_t src_remaining = gnu_debugdata_size_ - src_offset; size_t dst_remaining = dst->Size() - dst_offset; if (dst_remaining < 2 * gnu_debugdata_size_) { dst->Resize(dst->Size() + 2 * gnu_debugdata_size_); dst_remaining += 2 * gnu_debugdata_size_; if (dst_remaining < buffer_increment) { size_t new_size; if (__builtin_add_overflow(dst->Size(), buffer_increment, &new_size) || !dst->Resize(new_size)) { XzUnpacker_Free(&state); return nullptr; } dst_remaining += buffer_increment; } return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset], &src_remaining, true, CODER_FINISH_ANY, &status); Loading @@ -112,13 +135,13 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() { } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED); XzUnpacker_Free(&state); if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) { gnu_debugdata_offset_ = 0; gnu_debugdata_size_ = static_cast<uint64_t>(-1); return nullptr; } // Shrink back down to the exact size. dst->Resize(dst_offset); if (!dst->Resize(dst_offset)) { return nullptr; } return dst.release(); } Loading
libunwindstack/Memory.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -206,12 +206,12 @@ std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_ } size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { if (addr >= raw_.size()) { if (addr >= size_) { return 0; } size_t bytes_left = raw_.size() - static_cast<size_t>(addr); const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr; size_t bytes_left = size_ - static_cast<size_t>(addr); const unsigned char* actual_base = static_cast<const unsigned char*>(raw_) + addr; size_t actual_len = std::min(bytes_left, size); memcpy(dst, actual_base, actual_len); Loading @@ -219,7 +219,7 @@ size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { } uint8_t* MemoryBuffer::GetPtr(size_t offset) { if (offset < raw_.size()) { if (offset < size_) { return &raw_[offset]; } return nullptr; Loading
libunwindstack/MemoryBuffer.h +13 −4 Original line number Diff line number Diff line Loading @@ -29,18 +29,27 @@ namespace unwindstack { class MemoryBuffer : public Memory { public: MemoryBuffer() = default; virtual ~MemoryBuffer() = default; virtual ~MemoryBuffer() { free(raw_); } size_t Read(uint64_t addr, void* dst, size_t size) override; uint8_t* GetPtr(size_t offset); void Resize(size_t size) { raw_.resize(size); } bool Resize(size_t size) { raw_ = reinterpret_cast<uint8_t*>(realloc(raw_, size)); if (raw_ == nullptr) { size_ = 0; return false; } size_ = size; return true; } uint64_t Size() { return raw_.size(); } uint64_t Size() { return size_; } private: std::vector<uint8_t> raw_; uint8_t* raw_ = nullptr; size_t size_ = 0; }; } // namespace unwindstack Loading
libunwindstack/tests/ElfFake.h +3 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ class ElfInterfaceFake : public ElfInterface { void FakeSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; } void FakeSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; } void FakeSetGnuDebugdataOffset(uint64_t offset) { gnu_debugdata_offset_ = offset; } void FakeSetGnuDebugdataSize(uint64_t size) { gnu_debugdata_size_ = size; } private: std::unordered_map<std::string, uint64_t> globals_; std::string fake_build_id_; Loading
libunwindstack/tests/ElfInterfaceTest.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -1944,4 +1944,23 @@ TEST_F(ElfInterfaceTest, get_load_bias_exec_negative_64) { CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, -0x4000); } TEST_F(ElfInterfaceTest, huge_gnu_debugdata_size) { ElfInterfaceFake interface(nullptr); interface.FakeSetGnuDebugdataOffset(0x1000); interface.FakeSetGnuDebugdataSize(0xffffffffffffffffUL); ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr); interface.FakeSetGnuDebugdataSize(0x4000000000000UL); ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr); // This should exceed the size_t value of the first allocation. #if defined(__LP64__) interface.FakeSetGnuDebugdataSize(0x3333333333333334ULL); #else interface.FakeSetGnuDebugdataSize(0x33333334); #endif ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr); } } // namespace unwindstack