10 ms·
Memory Safety for Skeptics
- whobre 1y agoUgh. I know all that and I am still sick of hearing about memory safety. My teammates spend way more time fixing security issues in “safe” languages than C/C++/whatever. It simply doesn’t matter…
- kazinator 1y agoIt's hard to compare the two. A low-level memory safety issue can intersect with security. So can a flaw in logic that touches on security, but is reproducible and not undefined in any way. The latter can often be more easily exploited than the former, but the former can remain undetected longer, affect more components and installations, and be harder to reproduce in order to identify and resolve. As an exmaple of "more easily exploited". Say that you have a web application that generates session cookies that are easy to forge, leading to session hijack. Not much skill is needed to do that, compared to exploiting a memory safety problem (particuarly if the platform has some layers defenses against it: scrambled address space, non-executable stacks, and whatnot).
- mrkeen 1y agoWhat security issues are biting you in safe languages that wouldn't also appear in C/C++ ?
- quotemstr 1y agoPerhaps he's talking about risk compensation (https://en.wikipedia.org/wiki/Risk_compensation https://en.wikipedia.org/wiki/Risk_compensation) --- e.g. maybe safe languages structurally excluding memory corruption and concurrency problems tempts developers to let their guard down with respect to correctness generally and produce security vulnerabilities that wouldn't occur in a language with C's need for rigor. Doubtlessly, there is some of that going on. I doubt the risk compensation erases the benefit of memory safety, but let's not kid ourselves.
- bluGill 1y agoA large number of real world security issues are attacks on humans not software. No programming language can solve social engineering problems.
- kazinator 1y ago> If you're tired of hearing about memory safety, this article is for you. Tell me more about memory safety, any time; just hold the Rust. Rust skeptics are not memory safety skeptics. Hopefully, there are no memory safety skeptics, other than rhetorical strawmen.
- Yoric 1y agoI've spoken with quite a few C++ developers who swear that they don't need memory safety tooling because they're good enough to achieve it on their own. More than a few also expect that the worst that can happen from breaking memory safety is a SEGFAULT, which also suggests that they don't understand memory safety. So, I'd say that there is still some outreach to do on the topic. On the other hand, you're absolutely right that Rust is only one of the many ways to get there.
- kazinator 1y agoOK, so those are skeptics about tooling, not about memory safety per se. And not even about tooling per se, since achieving safety on their own doesn't literally mean on their own; they are relying on tooling. True Scotsman's "on your own" means working in assembly language, in which you have to carefully manage even just calling a function and returning from it: not leaving stray arguments on the stack, saving and restoring all callee-saved register that are used in the function and so on. Someone who thinks that their job is not to have segfaults is pretty green, obviously.
- yjftsjthsd-h 1y ago> True Scotsman's "on your own" means working in assembly language, in which you have to carefully manage even just calling a function and returning from it: not leaving stray arguments on the stack, saving and restoring all callee-saved register that are used in the function and so on. I've actually been trying to figure out if it's practical to write assembly but then use a proof assistant to guarantee that it maintains safety. Weirdly feels easier than C insofar as that you don't have (C's) undefined behavior to contend with. But formal methods are a whole thing and I'm very very new to them so it remains to be seen whether this is actually a good idea, or awful and stupid:) (Edit: ...or merely impractical, for that matter)
- eptcyka 1y agoRust certainly was not the first "systems programming" language that was memory safe, ADA was aiming for the same title and I think achieved it way before Rust.
- Yoric 1y agoWhile Ada is a great and sadly underused language, if my memory serves, it's not out-of-the-box memory-safe by today's definitions. I seem to recall that it takes Spark to make it memory-safe.
- themafia 1y ago> by today's definitions. What are todoay's definitions? If Ada simply had more thorough rules but introduced an "unsafe {}" construct, then what would the practical difference actually be? Compiler defaults?
- RavSS 1y agoSPARK is practically just a restricted version of Ada with a few added features for formal verification. You can write a program primarily in SPARK but disable said restrictions based on circumstance by setting the `SPARK_Mode` pragma/aspect to `off` on a package, procedure, function, etc. Mixing Ada and SPARK is trivial. I guess it is similar to Rust code that uses `unsafe {}` as the other poster mentioned (maybe `unsafe fn` for a closer analogy). My knowledge of Ada/SPARK is much greater than what I know about Rust, so I might be guessing wrong.
- Measter 1y agoSo in Rust an unsafe block and an unsafe function mean two different things. An unsafe block allows you to do things that are unsafe, such as dereference raw pointers, access union fields, calling unsafe functions, etc. Unsafe functions mark that the caller is responsible for upholding the invariants necessary to avoid UB. In the 2021 and earlier editions, they also implicitly created an unsafe block in the body, but don't in 2024. Or, in a more pithy tone: an unsafe block is the "hold my beer" block, while an unsafe function is a "put down your beer" function.
- deleted 1y ago[deleted]
- faustocarva 1y ago> a roughly 70 percent reduction in memory-safety vulnerabilities. Couldn't find this in the reference text. Is it my interpretation? https://www.memorysafety.org/docs/memory-safety/#how-common-are-memory-safety-vulnerabilities https://www.memorysafety.org/docs/memory-safety/#how-common-...
- burakemir 1y agoThis is a good article. Small nit: As someone curious about a definition of memory safety, I had come across Michael Hicks' post. He does not use the list of errors as definition, and argues that such a definition is lacking rigor and he is right. He says; > Ideally, the fact that these errors are ruled out by memory safety is a consequence of its definition, rather than the substance of it. What is the idea that unifies these errors? He then offers a technical definition (model) involving pointers that come with capability of accessing memory (as if carrying the bounds), which seems like one way to be precise about it. I have come to the conclusion that language safety is about avoiding untrapped errors, also known as "undefined behavior". This is not at all new, it just seems to have been forgotten or was never widely known somehow. If interested, find the argument here https://burakemir.ch/post/memory-safety-the-missing-def/ https://burakemir.ch/post/memory-safety-the-missing-def/
- tptacek 1y agoWhat's important is the context in which the term is used today: it's specifically about security and software vulnerabilities, not about a broader notion of correctness and program reliability. Attempts to push past that have the effect of declaring languages like Java and Python memory-unsafe, which is not a defensible claim.
- burakemir 1y agoThis is a false dichotomy. Language design choices are the causes of security and software vulnerabilites. It is possible to recognize the value of GC languages and have precise technical terminology at the same time. We can invent new words. I believe everyone who cares about memory safety appreciates that certain bugs cannot occur in Java and go, and if the world calls that memory safe, that is ok. There are hard, well-defined guarantees that a language and implementation must make, and a space of trade-offs. We need language and recognition for the ability to push the boundary of hard, well-defined guarantees further. That, too, is memory safety and it will be crucial for moving the needle beyond what can be achieved with C and C++. No one has a problem with applications being ported from low-level to GC-ed languages, the challenge is the ones where this is not possible. We need to talk about memory safety in this specific context, and mitigations and hardening will not solve the entire problem, only pieces of it.
- pizlonator 1y agoThis article comes up with yet another definition of memory safety. Thankfully, it does not conflate thread safety with memory safety. But it does a thing that makes is both inaccurate (I think) and also not helpful for having a good discussion: TFA hints at memory safety requiring static checking, in the sense that it's written in a way that would satisfy folks who think that way, by saying thingys like "never occur" and including null pointer safety. Is it necessary for the checking to be static? No. I think reasonable folks would agree that Java is memory safe, yet it does so much dynamic checking (null and bounds). Even Rust does dynamic checking (for bounds). But even setting that aside, I don't like how the way that the definition is written in TFA doesn't even make it unambiguous if the author thinks it should be static or dynamic, so it's hard to debate with what they're saying. EDIT: The definition in TFA has another problem: it enumerates things that should not happen from a language standpoint, but I don't think that definition is adequate for avoiding weird execution. For example, it says nothing about bad casts, or misuses of esoteric language features (like misusing longjmp). We need a better definition of memory safety.
- tptacek 1y agoI want to be there with you, but the definition this piece uses is, I think, objectively the correct one --- "memory safety", at least as used in things like "The Case For Memory Safe Roadmaps" government guidance, is simply the property of not admitting to memory corruption vulnerabilities. I don't see where you're seeing the article drawing a line between static and dynamic defenses. The article opens by noticing Rust isn't the first memory safe language. It is by implication referring to things like Java, which have dynamic, runtime-based protections against memory corruption.
- deleted 1y ago[deleted]
- pizlonator 1y ago> I want to be there with you, but the definition this piece uses is, I think, objectively the correct one --- "memory safety", at least as used in things like "The Case For Memory Safe Roadmaps" government guidance, is simply the property of not admitting to memory corruption vulnerabilities. This piece does not define memory safety as "not admitting memory corruption vulnerabilities". If it was using that definition, then: - You and I would be on the same page. - I would have a different complaint, which is that now we have to define "memory corruption vulnerability". (Admittedly, that's maybe not too hard, but it does get a bit weird when you get into the details.) The definition in TFA is quoted from Hicks, and it enumerates a set of things that should never happen. It's not defining memory safety the way you want.
- _zagj 1y agoIt seems obvious that with hardware-level memory safety on the way[1], just gradually modernizing existing C and C++ codebases to take advantage of safer constructs (like smart pointers or checked arithmetic) makes much more sense than rewriting everything in Rust. Even better, thanks to GCC, is that you don't need to sacrifice any portability to take advantage of even bleeding-edge features, due to its front-end/back-end separation and multitude of supported platform back-ends. Fish shell had to drop support for some platforms when it was rewritten in Rust[2]. [1] https://community.intel.com/t5/Blogs/Tech-Innovation/open-intel/ChkTag-x86-Memory-Safety/post/1721490 https://community.intel.com/t5/Blogs/Tech-Innovation/open-in... [2] http://fishshell.com/blog/rustport/ http://fishshell.com/blog/rustport/
- dwattttt 1y ago> It seems obvious that with hardware-level memory safety on the way[1], just gradually modernizing existing C and C++ codebases to take advantage of safer constructs (like smart pointers or checked arithmetic) makes much more sense than rewriting everything in Rust I read this in the opposite way: if the hardware is going to be stricter about memory accesses being valid, that suggests that software is going to have to meet a higher standard in order to successfully run. Imagine if you had to satisfy the Rust borrow checker, except you're still writing C and don't have additional tooling during compilation to show how a problem could trigger, you just have more crashes.
- TinkersW 1y agoYa ever heard of this thing called a debugger? They have this amazing ability to show you what the problem is right when it happens!
- bgwalter 1y agoIf the 5 eye agencies recommend memory safety, can we conclude that they already get all their information via "AI" data harvesting in Office 365 and similar? What will happen to Pegasus? Or do they have yet unknown backdoors in Rust?
- adrianN 1y agoI believe they also recommend encryption but I wouldn’t conclude that encrypted data doesn’t make their job harder.
- bgwalter 1y agoThey do indeed recommend encryption, sometimes with deliberate backdoors: https://en.wikipedia.org/wiki/Dual_EC_DRBG https://en.wikipedia.org/wiki/Dual_EC_DRBG So viewing their recommendations with caution seems wise.
- iambvk 1y agoWhat is the justification to call `Null pointer dereference` as a memory safety issue?
- K0nserv 1y agoIt's worse than a memory safety issue, it's undefined behaviour (at least in C, C++, and Rust)
- tptacek 1y agoUB is in fact not worse than a memory safety issue, and the original question is a good one: NULL pointer dereferences are almost never exploitable, and preventing exploitation is the goal of "memory safety" as conceived of by this post and the articles it references.
- K0nserv 1y agoUB can lead to memory safety issues[0], among other terrible outcomes. Hence it’s worse than memory safety issues. 0: https://lwn.net/Articles/342330/ https://lwn.net/Articles/342330/
- tptacek 1y agoNo, that doesn't hold logically.
- boris 1y agoI believe the point is if something is UB, like NULL pointer dereference, then the compiler can assume it can't happen and eliminate some other code paths based on that. And that, in turn, could be exploitable.
- tptacek 1y agoYes, that part was clear. The certainty of a vulnerability is worse than the possibility of a vulnerability, and most UB does not in fact produce vulnerabilities.
- matu3ba 1y ago1 The numbers on memory safety should nowadays separate between spatial ones (bounds-checked in most languages with sane flags) and temporal ones. Temporal ones will be lower than 70%. 2 The article does not mention (compilation) time costs of static checks and its influence on growing code bases, which is a more fundamental system trade-off on scalability and development velocity/efficiency. > Wrap unsafe code with safe interfaces 3 That sounds like an equivalent of using permission-based separation logic hopefully soon available for LLVM. > "Get good" is not a strategy 4 Being good is all about knowing exactly techniques, processes, and tools with exact trade-offs and applying them; so I would expect here teaching process knowledge about static and dynamic analysis strategies, tooling and tactics to eliminate bug classes. However, neither have we sane bug classes overviews nor can we generate sane probabilities/statistics of occurrence based on source code and available static and dynamic analysis even when ignoring functionality requirements. This reads somewhat like developers should "stay mediocre" and "trust the tools", even though "Get good and improve processes for groups" is probably the here intended strategy.
- tptacek 1y agoWhat do you mean by "temporal ones will be lower than 70%"? Are you suggesting --- referring to the article's cite --- that subcomponent ports to Rust reduce spatial vulnerabilities more than temporal ones? If so, why do you believe that?
- matu3ba 1y agoI would expect more of the opposite for languages offering easy to enable bound checks. Only observing the general trend for when bound checks are available (and used) would be helpful information. Temporal ones will remain tricky to debug until at least static + dynamic analysis via scheduling in kernel, hypervisor/simulation and/or run-time will become common-place. Probably even longer, because analysis is cumbersome for bigger programs without Seperation Logic (like Rust has).
- tptacek 1y agoIf you're talking about the impact of replacing a subcomponent in a larger C/C++ codebase with a memory safe language and saying you'd expect that to make less of an impact on the temporal memory safety issues latent in the remaining C/C++ code, I guess I get that. If you're saying that you think memory safe languages are less successful at dealing with their own temporal memory safety concerns than spatial memory safety concerns, that doesn't make sense to me and I would push back on it.
- TinkersW 1y agoI think memory safety is fine, but I plan to do it in C++ not Rust-- nothing in this article is remotely new either, just repeating the same tired stuff. It seems pretty clear statistical hardware level memory safety is coming(Apple has it, Intel/AMD have a document saying they are planning to add it), the safety zealots can turn that on, or you can use FilC if you need absolute memory safety, but really C++ with various hardening features turned on is already fairly solid. Also I think that memory safety is generally less important than thread safety(because memory safety is rather easy to achieve and detect violations), which almost all those languages recommended by this article blow chunks at. Rust could actual make a solid argument here, instead of wasting time yammering about memory safety.
- vlovich123 1y agoRust’s thread safety story is a subset of broader memory safety - it just guarantees that concurrent programs still are memory safe. This also happens to correspond to the most frequent sources of bugs in concurrent programs, but it’s not all there is to thread safety. It’s talked about all the time but whenever people talk about memory safety, thread safety is implied. Statistical hardware memory safety is more a security feature. But knowing that your code is correct before you even try it is a huge productivity boost and valuable in and of itself for all sorts of reasons. It’s weird the pushback from c++ people considering that Rust makes high performing code easier to achieve because of rules around aliasing and auto-optimizing struct layouts among other things. This is stuff c++ will never get.
- mk89 1y agoSome days ago I took again a look at Rust. I don't like the syntax at all, and coming from a Scala background that should say a lot. I will never like it, unless they simplify it. However, they implemented at compile time all the rules that someone wrote in the CPP guidelines about memory, or in dozens of books about how to write safe code. Now you can say: so you see, if you are good at c++, you achieve the same as Rust. True. But I don't buy it. I don't believe that even hardcore c++ developers never make a memory related mistake. I have been in the industry for a while and shit does happen, even to the best of us, unless you have "guardrails" around, and even then, so many things can go wrong... So a few days ago I asked on HN why not to use hardened allocators, which would basically block entirely the possibility to deploy such mistakes, a bit like OpenBSD allocator. It seems 1) people who develop low level stuff don't even need the heap, or use anyways a limited subset of things, 2) such allocators slow down the runtime significantly. So what I hear is: 1) I know what I am doing, I don't need a compiler to tell me that. 2) I anyway need a subset of that, so ... who cares. 3) runtime tooling helps me. Except for 2 (like writing something for Arduino or by using some very specific subsets of C/C++), everything else sounds pretty much hypocrite to me, and the proof is that even the top of the top of the engineers have to fix double free or things like that. If C++ broke the ABI and decided tomorrow to adopt memory safety at compile time, you would see that most people would use it. However, this holy war against Rust "because" is really antithetical of our industry which should be driven by educated people that use the right tool for the right job. As I said, ok for very low level/subsets, but why would you start today a CLI tool in C/C++ (if not for some very specific reasons )? For me this has more with fear of learning/doing something new. It makes no sense otherwise to reject a language that guarantees that a random developer missed the lifetime of that object etc... A language that is only improving, not dying anytime soon, with one of the fastest growing ecosystem, not "one person's weekend project" or things like that. As I mentioned multiple times, I dislike particularly Rust syntax. I love the C syntax the most, although C++ has deviated from that significantly with templates etc. But if something is better suited, sorry, we need to use it. If the C/C++ committee are the slowest things on the planet, why should my company/software pay for that? Everyone said python would die after the backward incompatible 2->3 upgrade. Sure.
- fainpul 1y agoWhat if, instead of fighting the symptom of people writing faulty, exploitable software, by explaining to them that Rust (as a stand in) is good, we try to fix the cause? Imagine if for every data breach, every ransomware attack, every intrusion which used privilege escalation etc. there would be an investigation if the company in question is at fault for using insecure software (i.e. written in unsafe languages and not properly vetted). And if the company is found guilty, it is punished accordingly, so that every company is motivated to prevent such cases. Of course people can still write C / C++ programs as a hobby or publish their software with open source licenses. But the people or organizations using that software must make sure (within reason) that it is safe or they are held liable if it inflicts damage. It would automatically make software written in safe languages much more attractive to them, because safety is much easier to prove – no evangelist needed.