fix(relinker): validate scan ranges before narrowing memory offsets
This commit is contained in:
parent
3e658db4b6
commit
e1ef33047c
|
|
@ -296,10 +296,10 @@ void Amd64OnlyConverter::_convertSegment(
|
|||
std::uint64_t completed,
|
||||
std::uint64_t total
|
||||
) const {
|
||||
if (ph.Offset > fileBytes.size() || ph.FileSize > fileBytes.size() - ph.Offset)
|
||||
throw CodegenException("Code segment exceeds the file", ph.Offset);
|
||||
const auto segOffset = static_cast<std::size_t>(ph.Offset);
|
||||
const auto segSize = static_cast<std::size_t>(ph.FileSize);
|
||||
if (segOffset > fileBytes.size() || segSize > fileBytes.size() - segOffset)
|
||||
throw CodegenException("Code segment exceeds the file", ph.Offset);
|
||||
|
||||
std::vector<std::uint8_t> seg(
|
||||
fileBytes.begin() + static_cast<std::ptrdiff_t>(segOffset),
|
||||
|
|
@ -318,9 +318,9 @@ void Amd64OnlyConverter::_convertSegment(
|
|||
if (substitution.has_value())
|
||||
pending.push_back({index, match, std::move(*substitution)});
|
||||
}
|
||||
if (progress) progress(completed + 2 * segSize, total);
|
||||
if (progress) progress(completed + std::uint64_t{2} * segSize, total);
|
||||
if (pending.empty()) {
|
||||
if (progress) progress(completed + 3 * segSize, total);
|
||||
if (progress) progress(completed + std::uint64_t{3} * segSize, total);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ void Amd64OnlyConverter::_convertSegment(
|
|||
|
||||
std::size_t processed = 0;
|
||||
for (const auto& item : pending) {
|
||||
if (progress && processed != 0 && processed % 256 == 0) progress(completed + 2 * segSize + item.Instruction.Offset, total);
|
||||
if (progress && processed != 0 && processed % 256 == 0) progress(completed + std::uint64_t{2} * segSize + item.Instruction.Offset, total);
|
||||
++processed;
|
||||
if (consumed.contains(item.Index))
|
||||
continue;
|
||||
|
|
@ -439,7 +439,7 @@ void Amd64OnlyConverter::_convertSegment(
|
|||
if (seg.size() != segSize)
|
||||
throw CodegenException("Code segment size changed during Intel conversion", ph.Offset);
|
||||
std::copy(seg.begin(), seg.end(), fileBytes.begin() + static_cast<std::ptrdiff_t>(segOffset));
|
||||
if (progress) progress(completed + 3 * segSize, total);
|
||||
if (progress) progress(completed + std::uint64_t{3} * segSize, total);
|
||||
}
|
||||
|
||||
ConvertResult Amd64OnlyConverter::Convert(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <codegen/x86/X64InstructionDecoder.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
namespace Codegen {
|
||||
|
|
@ -17,14 +18,16 @@ private:
|
|||
};
|
||||
|
||||
std::vector<InstructionMatch> InstructionScanner::ScanCodeSection(const std::vector<std::uint8_t>& codeSection, const Domain::FileByteOffset codeSectionOffset, const Domain::FileByteOffset codeSectionSize) const {
|
||||
const std::size_t limit = std::min(codeSection.size(), static_cast<std::size_t>(codeSectionSize));
|
||||
if (codeSectionSize > codeSection.size()) throw CodegenException("Code section exceeds the input buffer", codeSectionOffset);
|
||||
if (codeSectionSize > std::numeric_limits<Domain::FileByteOffset>::max() - codeSectionOffset) throw CodegenException("Code section offset overflow", codeSectionOffset);
|
||||
const auto limit = static_cast<std::size_t>(codeSectionSize);
|
||||
|
||||
const X64InstructionDecoder decoder;
|
||||
std::vector<InstructionMatch> matches;
|
||||
std::size_t i = 0;
|
||||
|
||||
if (progress) progress(0, limit);
|
||||
std::size_t nextReport = 65536;
|
||||
std::size_t lastReport = 0;
|
||||
while (i < limit) {
|
||||
const std::uint8_t* cursor = codeSection.data() + i;
|
||||
const std::size_t available = limit - i;
|
||||
|
|
@ -40,9 +43,9 @@ std::vector<InstructionMatch> InstructionScanner::ScanCodeSection(const std::vec
|
|||
matches.push_back({codeSectionOffset + i, length});
|
||||
|
||||
i += length;
|
||||
if (progress && i >= nextReport) {
|
||||
if (progress && i - lastReport >= 65536) {
|
||||
progress(i, limit);
|
||||
nextReport = i + 65536;
|
||||
lastReport = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,8 @@ private:
|
|||
};
|
||||
|
||||
std::vector<std::size_t> SyscallScanner::ScanCodeSectionForSyscalls(const std::vector<std::uint8_t>& codeSection, const FileByteOffset codeSectionOffset, const FileByteOffset codeSectionSize, std::string_view input) {
|
||||
const std::size_t limit = std::min(codeSection.size(), static_cast<std::size_t>(codeSectionSize));
|
||||
if (codeSectionSize > codeSection.size()) throw RelinkerException("Code section exceeds the input buffer", codeSectionOffset);
|
||||
const auto limit = static_cast<std::size_t>(codeSectionSize);
|
||||
|
||||
const auto scanner = Codegen::MakeInstructionScanner([&](auto completed, auto total) { progress.Report({Domain::ProgressStage::Decode, std::string(input), completed, total}); });
|
||||
const auto matches = scanner->ScanCodeSection(codeSection, codeSectionOffset, codeSectionSize);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ void scanning() {
|
|||
previous = event.Completed;
|
||||
}
|
||||
require(previous == progress.Events.back().Total, "Instruction conversion progress did not finish");
|
||||
reject([&] { scanner->ScanCodeSectionForSyscalls(code, 0, (std::uint64_t{1} << 32) + code.size()); });
|
||||
code[70000] = 0x0f;
|
||||
code[70001] = 0x05;
|
||||
progress.Events.clear();
|
||||
|
|
|
|||
Loading…
Reference in New Issue