Currently, E9Patch will disable all Intel Control-Flow Enforcement Technology (CET) features in the rewritten binary. This is because there are several problems with the interaction of E9Tool/E9Patch and Intel CET, specifically:
Indirect Branch Tracking (IBT):
E9Patch cannot rewrite the endbr64 instruction. If the endbr64 is replaced by a jump-to-trampoline, then an indirect call/jump to this location will fail.
~E9Tool's if f() goto instrumentation will fail unless the goto happens to target an endbr64 instruction. This is because the goto instrumentation is compiled down into an indirect jump in the rewritten binary.~ \
Edit: the indirect jump can use the NOTRACK prefix, which disables IBT for the instruction.
Shadow Stack (SHSTK):
In trampoline code, E9Patch translates call instructions into an explicit push+jump combination. This ensures the "original" return address (i.e., as if the program were uninstrumented) is pushed onto the stack, as opposed to a return address belonging to the trampoline. However, this will break SHSTK since the push+jump will not push anything on to the shadow stack.
Possible Solutions
Never rewrite/replace endbr64 instructions.
~Disable CET only if if f() goto (or other incompatible feature) is used.~
Implement calls as calls in trampoline code (as a user option). This may break transparency, but most programs do not care.
Intel CET Opportunities
Intel CET also helps the E9Tool/E9Patch toolchain:
E9Tool's control-flow recovery analysis is more accurate since some indirect jump/call targets are explicitly annotated with the endbr64 instruction. This is already implemented.
~E9Tool can feasibly detect when an instruction is never a jump/call target. This information could be used by E9Patch to further optimize the coverage/speed of the rewritten binary. For example, if the current instruction cannot be patched and is definitely not a target, then the previous instruction could be patched instead. Similarly, if the next instruction is not a target, it can be overwritten without the need for instruction punning.~\
Edit: unfortunately this will not work if the program uses the NOTRACK prefix, which seems to be common for things like switches (to avoid endbr64 proliferation).
Update (18/06/22): I had overlooked the optional NOTRACK prefix for indirect calls/jumps, so the comment is updated accordingly.
Currently, E9Patch will disable all Intel Control-Flow Enforcement Technology (CET) features in the rewritten binary. This is because there are several problems with the interaction of E9Tool/E9Patch and Intel CET, specifically:
Indirect Branch Tracking (IBT):
endbr64
instruction. If theendbr64
is replaced by a jump-to-trampoline, then an indirect call/jump to this location will fail.if f() goto
instrumentation will fail unless thegoto
happens to target anendbr64
instruction. This is because thegoto
instrumentation is compiled down into an indirect jump in the rewritten binary.~ \ Edit: the indirect jump can use theNOTRACK
prefix, which disables IBT for the instruction.Shadow Stack (SHSTK):
call
instructions into an explicitpush
+jump
combination. This ensures the "original" return address (i.e., as if the program were uninstrumented) is pushed onto the stack, as opposed to a return address belonging to the trampoline. However, this will break SHSTK since thepush
+jump
will not push anything on to the shadow stack.Possible Solutions
endbr64
instructions.if f() goto
(or other incompatible feature) is used.~call
s ascall
s in trampoline code (as a user option). This may break transparency, but most programs do not care.Intel CET Opportunities
Intel CET also helps the E9Tool/E9Patch toolchain:
endbr64
instruction. This is already implemented.NOTRACK
prefix, which seems to be common for things like switches (to avoidendbr64
proliferation).Update (18/06/22): I had overlooked the optional
NOTRACK
prefix for indirect calls/jumps, so the comment is updated accordingly.