Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

What is your opinion on deploying C++ codebases with mitigations like CFI and bounds checking?

Let us say I have a large C++ codebase which I am unwilling to rewrite in Rust. But I:

* Enable STL bounds checking using appropriate flags (like `-DGLIBCXX_ASSERTIONS`).

* Enable mitigations like CFI and shadow stacks.

How much less safe is "C++ w/ mitigations" than Rust? How much of the "70% CVE" statistic is relevant to my codebase?



We recorded an episode (there's a transcript) about this exact issue:

https://securitycryptographywhatever.com/2024/10/15/a-little...


With due respect, the blog you have linked looks like the average Rust marketing material. It does absolutely nothing to address my concerns. I did a `Ctrl-F` and found zero hits of any of the following terms:

* CFI

* isoheaps or type-stable allocators

* Shadow stacks

(There is just a single hit of "C++"...)

Ignoring the appeal to authority, I have a hard time believing that incrementally rewriting my C++ code in Rust or just writing new code in Rust ("vulnerabilities exponentially decay" and all that) is going to give me more actual security than the mitigations stated above. Most, if not all, high-profile exploits stem from out-of-bounds accesses and type confusions, which these mitigations prevent at very low cost.

Thanks for replying, though.


If what you're interested in is an "everything must be Rust" vs. "everything must be C++" knock-down drag-out, I'm not interested.


They prevent but do not entirely mitigate.


I am not interested in adhering to some arbitrary purity standard (like "memory safety" in this case). Almost always, purity ideologies are both irrational and harmful. What I am actually interested is to prevent real problems like remote code execution and Heartbleed-esque leakage of private data and for this, mitigations like CFI, shadow stacks and bounds checking are enough.

> They prevent but do not entirely mitigate.

Ignoring the semantic difference between "prevent" and "mitigate", if at the end of the day, the security provided by the two different approaches are quite similar, I don't get the problem.

If you have an example of a successful widespread exploit that would have happened even with these mitigations, please share.


They’re not enough. For example the field I work in (mobile exploits) continues to bypass CFI (PAC) via clever data-only attacks or abusing TOCTOU issues.


I may be wrong, but that issue is specific to PA. Shadow stacks can't be tampered with. Smartphones probably went with PA because shadow stacks require more memory. My use case specifically is targeting desktop/server systems with Clang CFI and Intel CET.

Note that I am not very knowledgeable in security, and I am really willing to be educated but it feels like most of the replies to my comments are just trying to prove me wrong.


PAC as implemented is stronger than shadow stacks, as it aims to provide CFI for more cases and not just function returns. Overwriting function pointers gives code execution under shadow stacks (which only protect return addresses) but is much more difficult to do so when the pointers are signed. Mobile platforms are very memory sensitive (one of the major reasons that MTE hasn't rolled out, for example) but I don't really see them wanting to adopt shadow stacks.

I can't really speak to your comments as you haven't posted many of them. I'm not here to prove you wrong but just to share my views on these mitigations. I'm not an expert by any means but I do get to think about these for work so I can usually do at least a quick once-over to try to figure out how effective they might be.


Thanks for your reply.

> Overwriting function pointers gives code execution under shadow stacks

As you are probably aware, there are two kinds of CFI - forward-edge and backward-edge. Forward-edge CFI prevents tampered function pointers, vtables and such from being invoked. Whereas backward-edge CFI protects does the same for return addresses. Clang's and MSVC's (CFG) implementations of CFI only provide forward-edge protection, hence the need for shadow stacks. Without hardware support, shadow stacks can not be prevented from tampered, which is why Intel (CET) and AMD added shadow stacks.

> Mobile platforms are very memory sensitive

Agreed. I'd guess this applies to embedded too. But all things considered, I do hold the opinion that language-level memory safety is being overplayed a lot.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: