7 ms·
Retrofitting spatial safety to lines of C++
- Animats 2y agoNew buzzword for old thing alert.
- vintagedave 2y agoI'll say. > Attackers regularly exploit spatial memory safety vulnerabilities, which occur when code accesses a memory allocation outside of its intended bounds Isn't that... 'out of bounds memory access'?
- deleted 2y ago[deleted]
- SAI_Peregrinus 2y agoYes. It's as opposed to temporal memory safety vulnerabilities, like use-after-free or data races.
- moyix 2y ago[This is more of a reply to a deleted reply to you, but I don't want my efforts to go to waste] Spatial memory safety is a reasonably common term in the security / PL field. You can see examples of it being used at least as far back as 2009: https://scholar.google.com/scholar?hl=en&as_sdt=0%2C33&q=spatial+memory+safety&btnG= https://scholar.google.com/scholar?hl=en&as_sdt=0%2C33&q=spa... It's in contrast to temporal memory safety, which deals with object lifetimes (use after free, for example). Here Google is probably also referencing a 2022 post of theirs with a very similar title, dealing with temporal safety: https://security.googleblog.com/2022/05/retrofitting-temporal-memory-safety-on-c.html https://security.googleblog.com/2022/05/retrofitting-tempora... The terms are also in Wikipedia: https://en.wikipedia.org/wiki/Memory_safety#Classification_of_memory_safety_errors https://en.wikipedia.org/wiki/Memory_safety#Classification_o...
- aseipp 2y agoPeople (both practitioners & researchers) have been using the terms "temporal" and "spatial" to refer to different classes of C++ vulnerabilities for at least 12+ years, back when I was actually writing exploits for a job. It is not new at all, and anyone in the field within the past 6-7 years and worth their salt will instantly recognize them.
- tom_ 2y agoFor whatever it's worth, I've been doing this stupid shit - writing C++, that is - for 25 years, and this is the first time I've heard this term. (This is a data point rather than a complaint. But for a fee, it can become a complaint if you would like.)
- aseipp 2y agoI meant security engineers/exploiters actually, but yeah, I can see how most working C++ programmers who aren't security specialists might not be as familiar with it.
- epage 2y agoThis term is coming up more frequently in the C++ community as they discuss Rust's safety features so to add more nuance to the discussion and focus on subsets of the problem to solve. Note that there are some more heated takes on where these terms are being used. I tried to be as generous as possible in my description.
- pizlonator 2y agoNah, "spacial safety" is a term of art among security folks and among PL folks who work on security. It's the part of memory safety that's just about bounds. You can also call it "bounds safety" and folks will understand what you mean, but "spacial safety" is the more commonly used jargon.
- andrewstuart 2y ago>> spatial safety vulnerabilities represent 40% of in-the-wild memory safety exploits Rust advocates tend to turn stats like this into “40% of all security issues are memory safety”, which sounds very similar but is false.
- kibwen 2y ago> Rust advocates tend to turn stats like this into “40% of all security issues are memory safety”, which sounds very similar but is false. You're right that it's false. Historically it's been a much more damning 70% of vulnerabilities that were rooted in memory-unsafety. According to the Google Security Blog, in a post linked to from the OP: We’ll also share updated data on how the percentage of memory safety vulnerabilities in Android dropped from 76% to 24% over 6 years as development shifted to memory safe languages. [...] The percent of vulnerabilities caused by memory safety issues continues to correlate closely with the development language that’s used for new code. Memory safety issues, which accounted for 76% of Android vulnerabilities in 2019, and are currently 24% in 2024, well below the 70% industry norm, and continuing to drop. https://security.googleblog.com/2024/09/eliminating-memory-safety-vulnerabilities-Android.html https://security.googleblog.com/2024/09/eliminating-memory-s...
- andrewstuart 2y agoYou’re still not getting the point. OWASPs top ten security vulnerabilities are not memory safety.
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- pornel 2y agoBecause most applications aren't written in C++. People don't write web apps in C++, because they would have to deal with memory safety issues in addition to all the other issues related to auth, injections, etc.
- dzogchen 2y agoTo “lines of C++” and to “hundreds of millions of lines of C++” is quite a different title.
- alserio 2y ago> We first enabled hardened libc++ in our tests over a year ago. This allowed us to identify and fix hundreds of previously undetected bugs in our code and tests. That's something
- WalterBright 2y agoDlang added array bounds checking 20 years ago. It's a huge win. As evidenced by the article noting that 40% of the memory safety bugs were spacial. I used to have all kinds of problems with array overflows. I didn't make them very often, but when I did, they took a long time to track down. They've been gone for 20 years now. Note that it would be easy to add it to C/C++: https://www.digitalmars.com/articles/C-biggest-mistake.html https://www.digitalmars.com/articles/C-biggest-mistake.html It would be the most useful and cost-effective enhancement ever.
- omoikane 2y ago> Hardening libc++ resulted in an average 0.30% performance impact Maybe what really happened is that compiler technology has improved such that they are able to remove most redundant checks, such that it only costs 0.30% today. I can imagine things going the opposite direction 20 years ago, as in "we removed some bounds checks and gained X% of performance".
- panstromek 2y agoProbably yes, and branch prediction improved a lot since then, too. Bounds checks are easily predictable.
- Gibbon1 2y agoBounds checking feels to me like low hanging fruit for a processor designer. A low cost operation that can run in parallel or tossed away as the steam from the instruction decoder gets optimized and scheduled. Meanwhile the guys on the standards committee thinks of fixed width RISC instructions being executed by jungle logic and the ALU.
- adgjlsfhk1 2y agothe hard part about bounds checks is you need very specific semantics for bounds errors to prevent them from preventing vectorization. specifically, you don't want to promise that they are thrown when they are executed
- almostgotcaught 2y ago> preventing vectorization No one that wants to emit vectorized code is relying on auto-vectorization to emit that code.
- masklinn 2y agoBounds checks are trivially predictable though, I would hope code density was the issue rather than branch prediction. And as others note, bounds checking was the norm before the STL.
- userbinator 2y ago[flagged]
- panstromek 2y agoInterestingly, the original quote is "Those who would give up ESSENTIAL Liberty, to purchase a little TEMPORARY Safety, deserve neither Liberty nor Safety." which is quite different meaning. Otherwise you never have any safety, as safety is always at the expense of some freedom. Arguably, this kind of work is the opposite - giving up non-essential freedom (in how you write code) for non-temporary (persistent) security.
- userbinator 2y ago[flagged]
- SkiFire13 2y agoWhat does that have to do with bound checks?
- panstromek 2y agoIt's a big bound check conspiracy, actually. Basically, Google will collaborate with US government to gather all the bounds, via Android. FBI will break into your house and look for all the `i < length`, and if they don't find them, they will terminate your `i++` on the spot. This is just the begining. Next time, they will go even for `int = 0`. You'll own nothing, just `for(;;)` and you'll be happy.
- saagarjha 2y agoThe person you are replying to holds the perspective that keeping software insecure allows for a glorious overthrow of our digital overlords when appropriate. A bit like a digital 2nd amendment, really: the hackers will all band together and use their guns^H^H^H^H vulnerabilities to ensure freedom from tyranny. Is that position stupid? Well, they stop replying when you point out what those security holes are overwhelmingly used for. So you be the judge.
- titzer 2y ago> We’ve begun by enabling hardened libc++, which adds bounds checking to standard C++ data structures, eliminating a significant class of spatial safety bugs. Well, it's 2024 and remember arguing this 20+ years ago. Programs have bugs that bounds checking catches. And making it a language built-in exposes it to compiler optimizations specifically targeting bounds checks, eliminating many and bringing the dynamic cost down immensely. Just turning them on in libraries doesn't necessarily expose all the compiler optimizations, but it's a start. Safety checks should really be built into the language.
- pjmlp 2y agoBefore C++98, this used to be pretty much table stakes in C++ compiler frameworks, e.g. Turbo Vision, AppToolbox, OWL, MFC,.... I still don't get why the standard library went the other way, other than starting the tradition of standardised wrong defaults.
- IshKebab 2y agoThe C++ standards committee is still under the illusion people can read, understand and remember the entire spec, and write code without making mistakes. All these bugs are the fault of the people making mistakes, not C++.
- pjmlp 2y agoSpot on.
- tialaramex 2y agoI don't think there's any such illusion. You do not see, for example, WG21 members who are confident that they understand the entire C++ language (on the contrary they'll often accept corrections about the language from other committee members) and it's not infrequent that a committee member will agree with the statement that C++ is too large and sprawling for any individual to attain such comprehensive understanding. [Today I would guess maybe Sean Baxter, who wrote his own compiler, has the best individual understanding and I believe Sean is not a member of the committee] Instead WG21 has very clearly (but without ever admitting it and that's important) taken the path of maintaining a legacy language. Even as debate carried on about whether in future C++ could end up like COBOL, the committee has acted exactly as though it is for some years now. Compatibility is King, no price is too high for compatibility, everything must be sacrificed to make that happen and that's how you end up like COBOL. Three important opportunities to divert and pick other ways forward should be highlighted here. P1863 "ABI: Now or Never" by Titus Winters in 2020; P2137 "Goals and priorities for C++" also in 2020 but with a long list of authors and P1818 "Epochs" from 2019 by Vittorio Romeo. In all these cases WG21 chose the "hope the problem goes away" path, preferring not only not to address the critical problem highlighted and take a new route forward, but to specifically ignore the problem and press on anyway. "Hope the problem goes away" is also, quietly, the preferred strategy by WG21 for the safety problem. There's a reason (albeit a terrible one) to prefer the C++ ISO document's language over the approach of Rust. These are both general purpose languages (I might also write separately in this thread about a non-general purpose language which Google should use more, if I have time) and so must wrestle with Rice's Theorem. Rust's solution is to require the compiler to be conservative. This is very difficult and indeed there are known bugs in the code doing this conservative check in the Rust official compiler. But C++ has a much easier (but IMO fatal) path, it says that's the job of the programmer and when the programmer writes C++ software which is nonsense as a result that's their fault, not the compiler's fault for failing to reject the program. It would be extremely difficult to explain how a "standards conforming" Rust compiler can correctly accept all the programs Rust's actual compiler accepts and reject all those it rejects without essentially having a black box where the compiler implementation sits. We can explain the purpose of such rules without, but their detailed behaviour not so much. Take borrow checking. All the easy scoped borrows (which is all that worked in Rust say eight years ago) can be explained without too much trouble, but today a lot fancier (but to a human obviously correct) borrowing will compile, because the checker is smarter - now, how do you express, not in Rust source code but in the English language, all the checks to be performed, and neither miss things out nor unknowingly accept programs a real Rust compiler will reject ? C++ just needn't do that, in effect the ISO document says. "Don't do borrows that last longer than the thing borrowed, if you do, that's not C++ but your compiler won't notice so the result is arbitrary nonsense"
- dataflow 2y agoPSA: Perhaps this is stating the obvious, but if you want bounds checking in your own code, start replacing T* with std::span<T> or std::span<T>::iterator whenever the target is an array.
- jpc0 2y agostd::span is not bounds checked. gsl::span is
- dataflow 2y ago> std::span is not bounds checked. gsl::span is https://godbolt.org/z/Pda9Me45P https://godbolt.org/z/Pda9Me45P ?
- debugnik 2y agoYou've compiled with _LIBCPP_HARDENING_MODE_FAST, which still adds some extra checks not required by the standard.[1] You can also tell it's nonstandard because it doesn't really throw out_of_range, it just traps. > Fast mode, which contains a set of security-critical checks that can be done with relatively little overhead in constant time and are intended to be used in production. > Using std::span as an example, setting the hardening mode to fast will always enable the valid-element-access checks when accessing elements via a std::span object, but whether dereferencing a std::span iterator does the equivalent check depends on the ABI configuration. 1: https://libcxx.llvm.org/Hardening.html https://libcxx.llvm.org/Hardening.html
- dataflow 2y ago> You've compiled with _LIBCPP_HARDENING_MODE_FAST, which still adds some extra checks not required by the standard. The standard doesn't require any checks to begin with. It also doesn't require optimizations.
- deleted 2y ago[deleted]
- DLoupe 2y ago> The safety checks have uncovered over 1,000 bugs In most implementations of the standard library, safety checks can be enabled with a simple #define. In some, it's the default behavior in DEBUG mode. I wonder what this library improves on that and why these bugs have not been discovered before.
- dataflow 2y agoIt's a great question (_LIBCPP_DEBUG was already a thing in libc++), and AFAIK the answer is supposedly "it used to be too costly to enable these in production with libc++, and it no longer is." I have no first-hand insight as to how accurate this perception is.
- alpire 2y agoThat's exactly right. We've had extra hardening enabled in tests, and that does catch many issues. But tests can't exercise every potential out-of-bounds issue, which is why enabling it prod enabled us to find & fix additional issues.
- pjmlp 2y agoBeing actually enforced, even in release. Most folks don't use those #defines, and many still haven't leaned about them.
- saagarjha 2y agoThey turned those on and 1. checked that the software using it didn't break and 2. made sure it didn't tank performance. Source: I worked on this apparently
- vblanco 2y agoGame developers have been doing this since forever, its one of their main reasons to avoid the STL. EASTL has this as a feature by default, and unreal engine container library has the boundchecks enabled on most games. The performance cost of those boundchecks in practice is well worth the reduction of bugs even on performance sensitive code.
- pjmlp 2y agoWhich is yet another reason to assert (pun intend), how far from reality the anti-bounds check folks are, when even the game industry takes them seriously.
- TinkersW 2y agoI wonder if google really never had this turned on before? Like this has been available in the C++ standard library for decades(normally as a debug feature to catch errors in development, but some implementations such as MS support it in release also). Might explain why they claimed 70% of exploits were memory related..
- alpire 2y agoThe hardening mode we enabled is quite recent added to libc++. It was proposed in 2022: https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734 https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734. It was designed to run in prod, so it's quite fast. Previous debug modes I've seen came with a much higher costs, and therefore weren't (usually) enabled in prod.