Merge pull request #1935 from Zinebyte/fix/prefixed-syscall-validation

fix(relinker): reject prefixed system-call instructions
This commit is contained in:
Dean 2026-10-10 17:42:59 +13:00 committed by GitHub
commit 300bd79439
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 5 deletions

View File

@ -1,5 +1,6 @@
#include <relinker/analysis/SyscallScanner.hpp>
#include <codegen/IInstructionScanner.hpp>
#include <codegen/x86/DecodedInstruction.hpp>
#include <memory>
#include <sstream>
@ -26,17 +27,16 @@ void SyscallScanner::ScanCodeSectionForSyscalls(
const std::vector<std::uint8_t>& codeSection,
const FileByteOffset codeSectionOffset,
const FileByteOffset codeSectionSize) {
const std::size_t limit = std::min(codeSection.size(), static_cast<std::size_t>(codeSectionSize));
const auto scanner = Codegen::MakeInstructionScanner();
const auto matches = scanner->ScanCodeSection(codeSection, codeSectionOffset, codeSectionSize);
for (const auto& [Offset, Length] : matches) {
const std::size_t i = Offset - codeSectionOffset;
const auto opcodeOffset = Codegen::DecodedInstruction{codeSection.data() + i, Length}.OpcodeOffset();
if (i + 1 < limit) {
const std::uint8_t b0 = codeSection[i];
const std::uint8_t b1 = codeSection[i + 1];
if (opcodeOffset + 1 < Length) {
const std::uint8_t b0 = codeSection[i + opcodeOffset];
const std::uint8_t b1 = codeSection[i + opcodeOffset + 1];
const bool isSyscall = (b0 == SYSCALL_BYTE0 && b1 == SYSCALL_BYTE1);
const bool isInt80 = (b0 == INT80_BYTE0 && b1 == INT80_BYTE1);

View File

@ -57,6 +57,28 @@ def main():
result, output = run_case(relinker, work, "syscall-filter", ["unused-filter=1"], b"\x0f\x05\xc3")
assert result.returncode == 2 and "Forbidden syscall instruction" in result.stderr and not output.exists(), result
forbidden = (
("rex-syscall", b"\x48\x0f\x05"),
("operand-syscall", b"\x66\x0f\x05"),
("address-sysenter", b"\x67\x0f\x34"),
("segment-sysenter", b"\x2e\x0f\x34"),
("rex-sysret", b"\x48\x0f\x07"),
("mixed-sysret", b"\x66\x67\x48\x0f\x07"),
("operand-int80", b"\x66\xcd\x80"),
("segment-int80", b"\x64\xcd\x80"),
)
for name, instruction in forbidden:
result, output = run_case(relinker, work, name, [], b"\x90" + instruction + b"\xc3")
assert result.returncode == 2 and not output.exists(), (name, result.stdout, result.stderr)
assert "Forbidden syscall instruction at code offset 0x1801" in result.stderr, (name, result.stderr)
result, output = run_case(relinker, work, "immediate-decoys", [],
b"\x48\xb8\x0f\x05\xcd\x80\x0f\x34\x0f\x07\xc3")
assert result.returncode == 0 and output.exists(), (result.stdout, result.stderr)
result, output = run_case(relinker, work, "skip-prefixed", ["--skip-syscall-check"], b"\x48\x0f\x05\xc3")
assert result.returncode == 0 and output.exists(), (result.stdout, result.stderr)
result, output = run_case(relinker, work, "skip", ["--skip-syscall-check"], b"\x0f\x05\xc3")
assert result.returncode == 0 and output.exists(), (result.stdout, result.stderr)
second_code = b"\x90" * 16 + b"\xb8\x2a\x00\x00\x00\xc3"