[PATCH] D155485: Retain all jump table range checks when using BTI.

Simon Tatham via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 17 09:35:58 PDT 2023


simon_tatham created this revision.
simon_tatham added reviewers: danielkiss, MaskRay, peter.smith, phosek, DavidSpickett, jhenderson.
Herald added subscribers: hiraditya, kristof.beyls.
Herald added a project: All.
simon_tatham requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

A table-based branch of any kind is at risk of being a JOP gadget, if
it doesn't range-check the offset into the table. For some types of
table branch, such as Arm TBB/TBH, the impact of this is limited
because the value loaded from the table is a relative offset of
limited size; for others, such as a MOV PC,Rn computed branch into a
table of further branch instructions, the gadget is fully general.

When compiling for branch-target enforcement via Arm's BTI system,
many of these table branch idioms use branch instructions that do not
set the BTI flag, so they can target instructions without BTI landing
pads. This avoids the need to put a BTI at the start of each case
handler, so that the number of gadgets //with// BTI instructions is
reduced. But without a range check, this also opens up a larger range
of followup gadgets for an attacker's use.

A defence against this is to keep the range check on the table offset,
even if the compiler believes that no out-of-range value should be
able to reach the table branch. (Rationale: that may be true for
values generated legitimately by the program, but not those generated
maliciously by attackers who have already corrupted the control flow.)

The effect of keeping the range check and branching to an unreachable
block is that no actual code is generated at that block, so it will
typically point at the end of the function. That may still cause some
kind of unpredictable code execution (such as executing data as code,
or falling through to the next function in the code section), but even
if so, there will only be //one// possible invalid branch target,
rather than giving an attacker the choice of many possibilities.

This defence is enabled only when branch target enforcement is in use.
Without branch target enforcement, the range check is easily bypassed
anyway, by branching in to a location just after it. But with
enforcement, the attacker will have to enter the jump table dispatcher
at the initial BTI and then go through the range check. (Or, if they
don't, it's because they //already// have a general BTI-bypassing
gadget.)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155485

Files:
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/test/CodeGen/Thumb2/jump-table-bti.ll

-------------- next part --------------
A non-text attachment was scrubbed...
Name: D155485.541091.patch
Type: text/x-patch
Size: 5809 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20230717/2c9d289b/attachment.bin>


More information about the llvm-commits mailing list