1. 6
    1. 3

      Great to see this working on other platforms (Andrew Paverd and I added support for Windows CFG to LLVM and Rust around four years ago and even made it work with Objective-C). Some of the initial work by MSRC found that Rust’s lack of CFI was a problem in programs that were not pure Rust (I.e. all real programs). Some classes of memory safety bugs in C are hard to turn into arbitrary code execution because of the CFI checks, but if you linked in some Rust you had things calling function pointers without doing CFI checks, which were then easy to exploit (corrupt a function pointer called by Rust, now you have arbitrary code execution).

      1. 1

        I am having difficult time interpreting this paragraph. I am not clear what the word ‘unfortunately’ means in the context:

        Similar to the Microsoft Windows CFG implementation, this is unfortunately the implementation hardware assistance for forward-edge control flow protection (e.g., ARM BTI and Intel IBT) were initially designed based on, and as such, they provide equivalent protection with the addition of specialized instructions. Microsoft Windows eXtended Flow Guard (XFG), ARM Pointer Authentication-based forward-edge control flow protection, and Intel Fine Indirect Branch Tracking (FineIBT) aim to solve this by combining hardware assistance with software-based function pointer type testing similar to LLVM CFI. This is also known as “fine-grained CFI”.

        Also, thinking out-loud here, building languages that compile to C (eg Nim, Janet) seems like a good forethought, because the complexity that comes with native code generators (even LLVM based) to match this level of security and integration is just too much for an indie language designer.

        1. 3

          I think this is highlighting the lack of type checking. BTI and CET are both based on an NSA recommendation from an MSR project. This protects forward edges but at a very coarse granularity: the target of the arc must be a valid target in the control flow graph, but it doesn’t have to be a valid one for this call site. CFG maintains a set of address-taken functions and ensures that indirect branches are branches to these functions. It doesn’t prevent type confusion of arguments, and that can lead to stack corruption (this is the main user-visible difference between my Objective-C implementation and Apple’s: theirs makes accidental stack corruption easy).

          XFG and similar schemes use the type of the callee. XFG hashes the type encoding of the function and stores it before the start of the function. This is quite nice because the check is just one load and compare with an address that you already have in a register. This doesn’t prevent you from substituting system for puts, but does prevent a load of other control-flow hijacking approaches.

          For what it’s worth, getting CFG implemented in Rust and ObjC was about two days of work, most of that as Andrew’s first LLVM project. Using C would not have made it much easier and would have made XFG much harder to support.

      2. 1

        Control flow integrity for Rust definitely interests me, but is there a version that doesn’t require JavaScript to view?