pluginAPI/hooks: Remove dependency on cc from the hooksystem (#5801)

* Remove dependency on cc from the hooksystem

* Nix: remove cc from wrapper

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
Vaxry 2024-04-30 02:54:43 +01:00 committed by GitHub
parent 5edc32930d
commit 62ae2b3f40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 77 deletions

View file

@ -148,7 +148,6 @@ in
${lib.optionalString wrapRuntimeDeps '' ${lib.optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \ wrapProgram $out/bin/Hyprland \
--suffix PATH : ${lib.makeBinPath [ --suffix PATH : ${lib.makeBinPath [
stdenv.cc
binutils binutils
pciutils pciutils
pkgconf pkgconf

View file

@ -77,29 +77,28 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
size_t lastAsmNewline = 0; size_t lastAsmNewline = 0;
// needle for destination binary // needle for destination binary
size_t currentDestinationOffset = 0; size_t currentDestinationOffset = 0;
std::string assemblyBuilder;
std::vector<char> finalBytes;
finalBytes.resize(probe.len);
for (auto& len : probe.insSizes) { for (auto& len : probe.insSizes) {
// copy original bytes to our finalBytes
for (size_t i = 0; i < len; ++i) {
finalBytes[currentDestinationOffset + i] = *(char*)(currentAddress + i);
}
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline); std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
if (code.contains("%rip")) { if (code.contains("%rip")) {
CVarList tokens{code, 0, 's'}; CVarList tokens{code, 0, 's'};
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0; size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
size_t minusPresent = tokens[1][0] == '-' ? 1 : 0; size_t minusPresent = tokens[1][0] == '-' ? 1 : 0;
std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent)); std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent));
const uint64_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr); const int32_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
if (OFFSET == 0) if (OFFSET == 0)
return {}; return {};
const uint64_t DESTINATION = currentAddress + OFFSET + len; const uint64_t DESTINATION = currentAddress + OFFSET + len;
if (code.starts_with("call")) {
// call +0xdeadbeef(%rip)
assemblyBuilder += std::format("pushq %rax\nmovabs $0x{:x}, %rax\ncallq *%rax\npopq %rax\n", DESTINATION);
currentDestinationOffset += 14;
} else if (code.starts_with("lea")) {
// lea 0xdeadbeef(%rip), %rax
assemblyBuilder += std::format("movabs $0x{:x}, {}\n", DESTINATION, tokens[2]);
currentDestinationOffset += 10;
} else {
auto ADDREND = code.find("(%rip)"); auto ADDREND = code.find("(%rip)");
auto ADDRSTART = (code.substr(0, ADDREND).find_last_of(' ')); auto ADDRSTART = (code.substr(0, ADDREND).find_last_of(' '));
@ -107,31 +106,26 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
return {}; return {};
const uint64_t PREDICTEDRIP = (uint64_t)m_pTrampolineAddr + currentDestinationOffset + len; const uint64_t PREDICTEDRIP = (uint64_t)m_pTrampolineAddr + currentDestinationOffset + len;
const bool POSITIVE = DESTINATION > PREDICTEDRIP; const int32_t NEWRIPOFFSET = DESTINATION - PREDICTEDRIP;
const uint64_t NEWRIPOFFSET = POSITIVE ? DESTINATION - PREDICTEDRIP : PREDICTEDRIP - DESTINATION;
assemblyBuilder += std::format("{} {}0x{:x}{}\n", code.substr(0, ADDRSTART), POSITIVE ? '+' : '-', NEWRIPOFFSET, code.substr(ADDREND)); size_t ripOffset = 0;
currentDestinationOffset += len;
// find %rip usage offset from beginning
for (int i = len - 4 /* 32-bit */; i > 0; --i) {
if (*(int32_t*)(currentAddress + i) == OFFSET) {
ripOffset = i;
break;
} }
} else if (code.contains("invalid")) {
std::vector<uint8_t> bytes;
bytes.resize(len);
memcpy(bytes.data(), (std::byte*)currentAddress, len);
if (len == 4 && bytes[0] == 0xF3 && bytes[1] == 0x0F && bytes[2] == 0x1E && bytes[3] == 0xFA) {
// F3 0F 1E FA = endbr64, udis doesn't understand that one
assemblyBuilder += "endbr64\n";
currentDestinationOffset += 4;
} else {
// raise error, unknown op
std::string strBytes;
for (auto& b : bytes) {
strBytes += std::format("{:x} ", b);
} }
Debug::log(ERR, "[functionhook] unknown bytes: {}", strBytes);
if (ripOffset == 0)
return {}; return {};
}
// fix offset in the final bytes. This doesn't care about endianness
*(int32_t*)&finalBytes[currentDestinationOffset + ripOffset] = NEWRIPOFFSET;
currentDestinationOffset += len;
} else { } else {
assemblyBuilder += code + "\n";
currentDestinationOffset += len; currentDestinationOffset += len;
} }
@ -139,38 +133,7 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
currentAddress += len; currentAddress += len;
} }
const auto RANDOMDIR = g_pCompositor->m_szInstancePath + "/" + g_pTokenManager->getRandomUUID(); return {finalBytes};
if (std::filesystem::exists(RANDOMDIR)) {
Debug::log(ERR, "[hooksystem] random out dir exists??");
return {};
}
if (mkdir(RANDOMDIR.c_str(), S_IRWXU) < 0)
return {};
if (!std::filesystem::exists(RANDOMDIR))
return {};
std::ofstream ofs(RANDOMDIR + "/.hookcode.asm", std::ios::trunc);
ofs << assemblyBuilder;
ofs.close();
std::string ret = execAndGet(std::string{"cc -x assembler -c " + RANDOMDIR + "/.hookcode.asm -o " + RANDOMDIR + "/.hookbinary.o 2>&1 && objcopy -O binary -j .text " +
RANDOMDIR + "/.hookbinary.o " + RANDOMDIR + "/.hookbinary2.o 2>&1"}
.c_str());
Debug::log(LOG, "[functionhook] assembler returned:\n{}", ret);
if (!std::filesystem::exists(RANDOMDIR + "/.hookbinary2.o")) {
std::filesystem::remove(RANDOMDIR + "/.hookcode.asm");
std::filesystem::remove(RANDOMDIR + "/.hookbinary.asm");
return {};
}
std::ifstream ifs(RANDOMDIR + "/.hookbinary2.o", std::ios::binary);
returns = {std::vector<char>(std::istreambuf_iterator<char>(ifs), {})};
ifs.close();
std::filesystem::remove_all(RANDOMDIR);
return returns;
} }
bool CFunctionHook::hook() { bool CFunctionHook::hook() {