Inside LLVM, Functions become marked with exposesReturnsTwice() if they
authorderaadt <deraadt@openbsd.org>
Fri, 7 Jun 2024 05:16:32 +0000 (05:16 +0000)
committerderaadt <deraadt@openbsd.org>
Fri, 7 Jun 2024 05:16:32 +0000 (05:16 +0000)
call a setjmp-type function (protyped with __attribute__((returns_twice)).

LLVM anticipates the longjmp type function will perform a direct branch
back (rather of a push;ret combo, almost certainly due to CET
shadow-stack coherency difficulties).  Since we have CET/IBT enforced,
LLVM makes that direct branch legal by placing an endbr64 immediately
after the callq.  Where I was placing the ret-clean sequence... this blows
up badly, in unhibernate / resume situations.

In the Functions marked exposesReturnsTwice(), skip doing ret-clean.
(placing the ret-clear after that endbr64 is much more difficult)
observed by mglocker, diagnosed by mlarkin, kettenis, guenther.

gnu/llvm/llvm/lib/Target/X86/X86RetClean.cpp

index 623bfed..4d7e3e3 100644 (file)
@@ -96,6 +96,10 @@ bool RetCleanPass::runOnMachineFunction(MachineFunction &MF) {
 
   bool modified = false;
 
+  // It a setjmp-like function is called by this function, we should not clean
+  if (MF.exposesReturnsTwice())
+    return false;
+
   for (auto &MBB : MF) {
     std::vector<MachineInstr*> fixups;
     bool foundcall = false;