The paper starts by calling Aleph One. 1996. Smashing the stack for fun and profit "One of the first memory corruption attacks described in the literature", ROP a "new attack technique", goes on saying that "In practice, backward-edge CFI is named ShadowCallStack", and "Stack-based buffer overflow vulnerabilities are prominent targets for attacks." So we're off to a great start.
The paper is about SeeCFI, a python tool based on angr to statically detect the presence/absence of CFI in given binaries via a "generic" approach. The approach isn't generic at all, as it only considers clang CFI on aarch64:
- for backward-edge CFI it checks if
str x18, <ret_addr>is present in the prologue of functions, and ifldr <ret_addr>, x18>in the epilogue. - for forward-edge:
- for cross-dso, it checks the presence of the
__cfi_checkand__cfi_slowpathsymbols by usinggrep(!!) - for non-cross-dso, it builds the complete CFG of the binary, to then checks if all branching nodes with 2 possible
targets land in blocks with either an
udor ancallinstruction, if the register used in the branch is used in thecallinstruction. If it happens at least once single, then it's a win.
- for cross-dso, it checks the presence of the
The paper doesn't consider non "memory-unsafe" binaries, which is odd, but it seems that the authors aren't aware that those libraries/binaries also contains valid gadgets:
Android developers started moving from writing low-level code in memory-unsafe languages such as C and C++ to the memory-safe language Rust, eliminating the need for CFI completely
Horrifyingly, "On average SeeCFI needed 1.5 minutes to analyze each binary, resulting in an overall runtime of, for instance, 45.8 hours in the case of Android 13 (Pixel 7 Pro).", which is likely due to the fact that they're lifting the whole CFG of every single binary for no reason, instead of doing it lazily block by block.
Also, some binaries didn't load, and the diagnostic was "Most of the errors occur due to an angr issue", without explaining what the issue is/was, nor if they sent some patches to get it fixed.
The paper considering only clang type-based CFI is absurdly bad, as the ecosystem is moving to ARMv9 BTI/PAC-RET as an additional layer. For example, BTI/PAC is enabled for all userland and kernel-land on GrapheneOS, which isn't the case on stock Android. This should have been obvious when they wrote "GrapheneOS adds ∼16.7% to the Pixel 3 series, ∼14.2% of binaries to the Pixel 4 and 5 series, and <1% to the Pixel 6 and 7 series. Out of the additional binaries ∼14.5% (Pixel 3 series), ∼11.5% (Pixel 4 and 5 series), and 0% (Pixel 6 and 7 series) are compiled using forward-edge CFI."
This shouldn't have been a paper, let alone published in the "ACM Transactions on Software Engineering and Methodology", it's at best two weeks of work by an intern. Heck, the GrapheneOS project published a detailed analysis on the topic as a rebuttal in a couple of hours, and it's way better than the paper itself.