>The Chromium project finds that around 70% of our serious security bugs are memory safety problems. Our next major project is to prevent such bugs at source.
>As we’ve seen, roughly 70% of the security issues that the MSRC assigns a CVE to are memory safety issues. This means that if that software had been written in Rust, 70% of these security issues would most likely have been eliminated. And we’re not the only company to have reported such findings.
Yes we do. The NSA publishes the future security standards that defense, aviation, banking, and government institute have to take into account. Once the NSA backs the technology it's generates the government push to get NIST to push a standards update for government contracts specs, which yields better security in the long run. It' silly but that's how change is implemented in government it's slow but eventually it forces adoption of better standards.
I might be the only one but I found it annoying that the NSA article seemingly chose to only omit Rust in the list of examples in the Path Forward section, after having mentioned it as an example of a memory-safe language earlier.
Wasn't safety critical DoD projects (like military avionics projects) required to be implemented in Ada at some point. But at some point that requirement was rescinded and Ada all but died. Seems nowadays Ada is more alive in Europe, many European safety critical projects done with SPARK?
As an example, it was NIST that recommended password rotation every X days (note: they no longer do), and from there every one else decided to implement that password requirement in so many corporate workplaces. It wasn't a requirement that came up out of thin air.
I don’t think the guys in India Japan and China who write the C++ code in the games and apps I use for the pay the offshorers want to pay are going to
give a fuck.
> Do we need US gov advisory in order to be convinced?
Even HN still has a fair number of comments along the lines of “C++ is fine, you just need to do things the modern way and avoid making any mistakes”...
What they always forget to mention is that not only you have to do things the modern way and avoid mistakes, everyone else contributing to your codebase has to too. Now that's a tall order!
Everyone else who has ever contributed to your codebase. "Just use modern C++" is a good way to tell who has never worked on anything but the greenest of greenfield projects.
That, plus deadlines forcing some sloppy coding, projects changing hands and, then... boom! Someone forgot to add something to the move constructor and now you dropped an allocation on the floor
Yes, disclaimer, or necessary predefense here? ;)
Looking at rust, wanting to play with it, liking it very much from what I have seen, to some degree... still it also seems to develop some complexity problems, and is it fully stable in regard to language now? Can we take it to a certification body already?
Or will it also become the next C++ with the later on-boltings? Anyway..
> “C++ is fine, you just need to do things the modern way and avoid making any mistakes”
I know I will be burned now, but:
Which is kind of true if you stick to modern C++ (>11) .. and if you do that (maybe enforced by a style checker or some new cpp standard setting?) you even strip out the "avoid making any mistakes". Again, fully admitted, C++ is kind of a grown and ugly language, with many holes that you could use if you don't systemically forbid them.. but if it just would make real step to enforce / deprecate with a safe-strict-standard all the bad old C/C++ heritage and there'd be something like an enforced safe-C++, I think it would not be too far away from Rust..
.. because I lately read a Rust paper "Safe Systems Programming in Rust" and what did I needed to read there?:
"There are a number of data types whose implementations fundamentally depend on shared mutable state and thus cannot be type-checked according to Rust’s strict ownership discipline. To support such data types, Rust embraces the judicious use of unsafe code encapsulated within safe APIs." (and more schizophrene explanations how we still can do everything in Rust, but are safe follow..)
If that is the case, then this is really not too far away from safe&modern-C++, where you only touch the unsafe parts for hard to find last bits of performance?
Especially, and hear me out .. what I'm not getting is consider the typcal embedded/automotive and similar applications, which usually run single threaded and without any dynamic memory allocation and by that already exclude all of the data-race and other problems. You are basically left with bounds-checking on arrays and similar buffers, and you can really, no you will have that if you use modern C++?
I'm really confused more than ever :) .. but the rust complexity curve does not seem to be only high for the devs, but also for the orgs who require standardization&certification. Hope that will follow now, and also some way to completely abandon unsafeness completely in Rust before we put it so high up the throne? and plea
Haven't we seen any Rust security issues because there is so little software out with it? If some memory unsafeness in some Rust program happens, will we always hear then Rust is safe, this was just unsafe code (like today it was all every time the hacker's fault?? :D )
On the topic of a “forced” C++ to be close to rust.
I guess technically if you forced all allocations to be in unique_ptr<> and then used std::move every time you passed it as a parameter, you would kind have the first part of rust (ownership rules) down.
But the borrow checker? Not sure how that’s possible. It might be (and in fairness, you could require all references to be const)
But I am not sure if there’s a way to do the usual 1 and only 1 borrowed mutable value. (Unless someone can think of a way?)
Carbon is experimental, don't make any predictions. Herb Sutter has his own that I forget the name of with interesting things that when mature are making it to C++
There is no C/C++ language. There are no C/C++ devs. So, no.
There are some who develop in both C and C++, along with any other language you can think of. I do not encounter the expression "C++/Rust dev", although it is extremely common for those programmers who do Rust at all to do both.
You may call something that does not exist anything you like except the name of a thing that does exist. Anything that you say about a thing that does not exist is vacuous.
It is objective fact that all female former US presidents can fly by flapping their wings.
This is the wrong framing: there are different companies and business interests that listen to different advisories. A government advisory bears different weight for government contractors, for example.
This recommendation can be brought to court. If you suffer a security breech in a memory related area share holder or affected customers can sue for incompetent with this as evidence that you should have known.
It may not mean much to you, but to a non technical CEO or board of directors it has meaning.
Are you discounting the broad impact having the NSA tell everyone to stop using C/C++? Almost nothing is new information if you dig deep enough. It wasn't new when the CTO of Azure said everyone should stop using C/C++.
5 years ago, there was not broad consensus by technical leaders that C/C++ was even a problem. You just needed the best programmers, throw in some *SAN to rinse all the bugs away and poof!, fast enterprise grade code!
Who delivers a message is often times more important than the message itself. The entire message is (person, says, x), I said we should stop using C/C++ 20+ years ago, doesn't make me CTO of Azure or the NSA.
There is no such language as "C/C++". Using the expression reveals tendentious bias.
Those of us using modern C++ do not ship memory usage faults, and have not done for years. So, experience with C and pre-modern C++ does not generalize.
Where there is no need for any unsafe construct, code that therefore does not use them is safe.
The same applies to, e.g., Rust: any Rust program may use unsafe blocks. That Rust programs may contain unsafe blocks does not make Rust implicitly unsafe. Even using unsafe blocks does not, by itself, make the program unsafe.
Your dodging of my question leads me to believe that the answer is "no". Therefore, "modern C++" is still unsafe.
> Even using unsafe blocks does not, by itself, make the program unsafe.
This is false. "Unsafe" means that there is the potential to cause memory safety bugs. Unsafe blocks and C++ cause this, by definition. "Unsafe" does not mean that a memory safety bug actually exists.
Moreover, I didn't mention anything about Rust in my comment.
Pedantic clarity isn't helping your argument. The fact that you can choose to write C while calling a C++ compiler means people will always call it C/C++.
It means that conclusions based on pretending it is a meaningful expression are tainted at the source, and thus may be presumed invalid without further examination.
If you are coding C or pre-modern C++, then you are not coding modern C++, regardless of the compiler you happen to build with.
C++20 is an International Standard, superseding all previous Standards. Programs that use C++20 constructs in preference to pre-C++11 constructs are objectively more modern, to the exact degree they do.
Your position could be taken seriously if, and only if, there were a version of the language which doesn't contain all the cruft. As in, there are compilers which won't compile it.
Instead, mid-90s C++, with all the leaks, is valid C++, 20 or otherwise.
No true C++20 program is memory unsafe... unless you use a normal pointer, which is always available and will bork you just as hard as in C.
Where there is no need for a native pointer to be used, as almost everywhere, and no pointer is used, that code is objectively more modern than code that uses the pointer anyway. It is very rare to need to use a native pointer in modern C++ code. The need for one is strictly less common than a need for an unsafe block in Rust.
Your argument applies equally well to Rust: any Rust program may include unsafe blocks. That any program may contain unsafe blocks does not make Rust implicitly unsafe. That a Rust program does (transitively) contain unsafe blocks does not make it an unsafe program. All substantial Rust programs at least transitively contain unsafe blocks.
“Behind the curve” isn’t really the right term. It’s not like anyone was unaware that C has downsides but rather that lots of people said it’d cost too much to replace all of that old code. Things like this are what tell companies that they should stop slacking because it’ll become increasingly common as a buyer’s requirement.
What is the implication of this to embedded software platforms like Xilinx VITIS or TI's Code Composer Studio? Both tools are based on C/C++ so why would these platforms not have switched to C# or Rust earlier? Sorry for the simple question as Im a simple hardware guy but do you see a scenario where future platforms of these tools are based on Rust?
I think embedded software will likely switch to Rust (or other non-C/C++ languages) eventually. But that transition will be behind the transition for PC/server software by probably 10 years, partly because these indeustries are just slower to change, partly because support for these kind of environments in languages like Rust isn't as mature as support for more "full OS" environments, partly because these environments are often dependent on proprietary compilers provided by vendors and getting these vendors to ship Rust compilers is going to be a slow uphill battle.
In some ways Rust is (or will be) particularly well suited to these environments. They're hard to debug so the compile-time constraints are particularly helpful. Features like async/await are perfect for modelling interactions with hardware peripherals, etc. But there are still a lot of rough edges. Most embedded development with Rust is still relying on unstable nightly features (particularly more advanced const evaluation). Although the recent stabilisation of GATs helps a lot.
Sic rebus stantibus, neither transition is realistic without enormous and painful investments.
Basically every single piece of software that matters is a C library or is exposed through a C API, because that's what other languages hook into, including Rust.
Heck, right this second I'm working on a piece of software that needs to talk to Java and Python simultaneously, so C++ with extern C it is.
Using memory safe languages when you can is good advice, but it's kind of complicated to get to a point where everything is guaranteed safe.
> neither transition is realistic without enormous and painful investments
I don't disagree, and for that reason the transition will be slow, but I still think it will happen. The benefits are too great to ignore, or they eventually will be. Nobody's going to want to use insecure foundational libraries once secure ones are available. And they're already being written.
> Heck, right this second I'm working on a piece of software that needs to talk to Java and Python simultaneously, so C++ with extern C it is.
For what it's worth, Rust is entirely viable (and arguably easier than C++) in this space right now. It's also using extern C under the hood, but there are libraries like "pyo3" and "jni" which will deal with the unsafety for you and provide you with higher-level bindings. In practice you don't lost much safety using this approach.
Well, it could be written in Java, so Java-Java communication is trivial, and you could use something like protobuf to communicate between java-python. Or just some fixed binary layout.
Or even GraalVM which is polyglot between the two languages and can even optimize across language boundaries.
Depends, i know one company that spent billions swithicg to memory safe stuff, but after a few years an experienced team did a project in both the memory safe new stuff and in parallel the same in C. The C code was done in a week, the new stuff 3 months. They are back to C for everything and the people pushing memory safety are gone.
The right tools mater. The memory safe stuff above was autosar, so not something often discussed here. Rust is getting interest from the above team but after the above burn they are slow to try new things.
The team in question had decades of c experience, and was doing all new stuff (maybe half of all work?) In autosar. I was working with them on an unrelated C++ project and I can assure you the C++ they write was not very good since the only C++ stuff was things they didn't want to do.
I work with AUTOSAR. I am fairly confident that AUTOSAR itself is the problem and not representative of the productivity you would gain from memory safe stuff. I can also say that the AUTOSAR stacks themselves offer no memory guarantee and have seen way too many bugs in those stacks to have any sort of faith in them.
I was under the impression that a substantial amount of it was being rewritten in Rust, which was part of the reason for the speedups (rewrite, not language)
It was funny, I went to see my optometrist the other day and found out he's gotten into Arduino programming but he hates C/C++, particularly the way pointers work. I told him I liked AVR8 assembly a lot better. It's not safe, but I really get to enjoy the large register file and don't have my CPU doing meaningless activities to maintain C calling conventions.
Anything that hardware can do to improve the situation? How about pointer authentication or memory tagging? Do these measures also fall into the band-aid category?
“CHERI extends conventional hardware Instruction-Set Architectures (ISAs) with new architectural features to enable fine-grained memory protection and highly scalable software compartmentalization. The CHERI memory-protection features allow historically memory-unsafe programming languages such as C and C++ to be adapted to provide strong, compatible, and efficient protection against many currently widely exploited vulnerabilities.”
Most probably yes. If it was an actual viable fix you can be almost guaranteed that it would have been implemented long ago. Engineers would love to have their cake and eat it too.
It can, but they are like trying to solve memory corruption issues with the ultimate weapon, because all other mitigation efforts from the last 50 years have failed.
Cool, maybe they could get the rest of the government agencies to stop requiring bullshit FIPS certified crypto implementations that are all written in memory-unsafe programming languages.
>around 70% of our serious security bugs are memory safety problems
Is there any information available to assess what portion of that 70% was, or could have been, identified through static code analysis, sanitizers and other memory-safety techniques that can be applied in a bulk / automated manner?
That list of languages gave you the choice between dependence on Microsoft, Google, Apple, and Oracle. So maybe they just added Ruby in there to have a neutral option?
Conspiracy: The NSA has compromised all those languages' runtimes to spy on whatever is being run and passed through them. After all, that Utah datacenter[0] isn't going to fill itself.
If you're concerned that Rust has been compromised you should consider where that leaves Python.
The NSA is both offensive and defensive. Part of their mandate is to protect American infrastructure for foreign attacks. A switch like this is one of the easier ways to protect against foreign threats and it is something that is routinely advocated for by most large tech companies and cloud providers.
As for that Datacenter in Utah - it is a large Government project. The idea that the US Government is efficient with its resources or that its operatives are trying to maximize the use of their resources is not well supported by historical precedent. If the project is written off as yet another make-work job project for a reliably red state then I am sure we can all sleep well knowing that our tax dollars have been well spent.
That's how they're supposed to operate, not how they actually operate. They've been hoarding zero-days for years, and they have even worked surreptitiously to undermine encryption by endorsing algorithms that they had already compromised. They couldn't give a single fuck about protecting US infrastructure if it comes at the cost of their offensive weapons portfolio.
You have far greater faith in the ability of a leader to create organizational alignment than I do. Are you sure there isn’t some part of the NSA which is on an ego-driven mission to prioritize national security?
It has nothing to do with leadership, just incentives. If you're a world class hacker, your most prominent options are:
1) do black hat shit and risk prison time for gains that are hard to realize
2) work in white hat security and get paid a ton of money
3) work for the government and make very little money, but get to do black hat shit with impunity
It's pretty easy to imagine that the people submitting applications to work for the NSA have no interest in protecting the US from big bad overseas hackers.
I think it doesn't require organizational alignment or faith in a leader for bad acting to occur. While I agree reality is more often obvious and mundane, the NSA has demonstrably not operated in the USA's best interests. The Snowden leak proves its inefficiencies, lack of oversight, and lack of access governance. History supports your point, but it also supports counter productive actions and nefarious self and private interests by individuals and small groups within those government agencies. It only takes a few minutes searching for leaks that made it to the main stream media to show both statements are true.
While this topic is about the NSA I feel this are relevant questions:
Why do we still have a FDA given they fail so regularly to catch food and drugs that harm people?
Why do we still have a FTC given they've fail so regularly to prevent monopolistic behavior from telecoms?
Why do we still have a FBI given they fail so regularly to prevent mass shootings and domestic terror attacks?
Why do we still have a NSA given they fail so regularly at sharing information allowing foreign entities penetrating our financial and tech sectors?
Surely you recognize at some point inefficiency must give way to the question, has this been done intentionally? Especially since that is supported historically.
Oh I'm sure bad acting does occur. That is not the question at hand.
The question at hand is: Is a recommendation to use memory-safe programming languages evidence that those languages are less safe than we previously thought?
There are two competing notions:
A. This being announced now is evidence that the NSA has recently succeeded in finding a way to subvert the security guarantees of rust.
B. This being announced now is evidence that the good actors (or actors who want to appear good) in the NSA have finally gotten through the red tape to do what is nominally their jobs.
And to be able to discern between the two possibilities, you just have to ask yourself the question: has specific NSA technology recommendation consistently been provided in our best interest?
Their track record is spotty at best, and has only gotten worse over time. So to the extent that they are recommending using memory safe languages, that's great...it's advice that would be corroborated by other institutions, researchers, and practitioners. But the moment they recommend a specific set of technologies to use, that should give you pause.
That being said, the report doesn't specifically recommend just those specific languages, and merely provides them as examples...so as long as I'm not in charge of securing an adversarial nation/state's infrastructure, I'm not gonna worry about the potential nefariousness of this recommendation.
Those questions are stupid, it's like asking why bother having software if it so regularly has bugs? There must a nefarious plan behind the software development sector!
There should have been a commission formed about the p0wn goal that was EternalBlue. Microsoft charging for security patches should get the execs thrown in jail. The NSA should be disclosing big RCEs like this to the vendor and figuring out how to ensure that everyone is patched.
A commission would find that there was no problem whatsoever.
Almost everybody misunderstands NSA's defensive mandate. They aren't corporate America's QA department, they don't have a "let's find and report exploits" mission - their defensive mission applies to "national security systems" and other "defense industrial base" ones. Those are computers/networks running fairly specific tasks; they are generally not internet connected, and sitting in secure buildings with 24 hour security and surveillance, so securing them revolves around a lot of physical security and controlled access.
YOU don't have one of these systems, corporation XYZ doesn't have one, there is no requirement NSA disclose jack shit to anybody unless they want to. And in the ETERNALBLUE case one of their tools leaked so they helped head off a lot of problems by voluntarily telling Microsoft about it.
As for who is responsible for this - I thought all the people here are free market worshipers. If Silicon Valley tech companies, one of the richest class of private enterprises in the world, need what are effectively government subsidies to cover their bug ridden insecure products, well that sounds like multiple market failures to me.
NIST Dual EC DRBG never really gained adoption. As far as I could find, some did use it for FIPS conformity until 2014. The attempt is still egregious though.
You act as if the NSA is one monolithic hive mind. They have offensive cats and defensive cats, and they don’t talk to each other as much as you’d think they do.
I thought at first that specific list of languages might have just been theregister.com's editorialized list. But it's in the actual document[1].
"These inherent language features protect the
programmer from introducing memory management mistakes unintentionally. Examples
of memory safe language include C#, Go, Java®, Ruby™, Rust®, and Swift®."
I don't think there's any conspiracy, but it is interesting they don't mention JS or Python.
I'm surprised ADA isn't on the list since it is memory safe in modern versions (like rust you can turn that off, though it isn't as obvious as unsafe when you do). Even modern C++ is reasonably memory safe, but someone needs to rewrite the old code you interface with to get that.
Ada, no need to shout its name. But even Ada 83 had a lot of safety features that made it worthwhile, it just didn't take off (for a variety of reasons including anger from developers "how dare they tell us what to use" and cost "you want how much for a compiler and we have to get a new license for a new project?!?").
Its arrays carried their size and range with them so you could safely iterate over them and safely (well, you'd get a runtime error at least versus C's "I trust you" model) access their elements. You had tasks and rendezvous since Ada 83 which could be used to protect access to data across other tasks (this was improved later with protected types in Ada 95).
You could tightly control, in the language not at runtime, the memory layout of records which was useful for over-the-wire protocols. With C you couldn't guarantee a particular packing for a struct would be uniform across compilers, with Ada you could. This also helps reduce bugs because you can apply DRY properly, in C you have to implement marshaling and unmarshaling yourself, in Ada it was just a given.
It's a very underrated language, mostly discounted because, it turns out, people are more into fashion and style than substance. "Eww, it uses keywords like `begin` and `procedure`" seems to be the #1 reason for rejecting it anymore, rather than any serious analysis.
I suppose the point GP is trying to make is that unsafe blocks don't really change the pre-existing safeties, it 'just' lets you also do things which are unsafe, but which have different syntax.
Already-safe code remains safe if you wrap it with unsafe.
The implications to a code reviewer don't change much from that, however.
What is being turned off is not safety itself, but automatic enforcement of rules.
If course no one wants to ship actually unsafe code, and it is very rare to do it in Rust or modern C++ programs. But it is depressingly common in C programs and mostly-old programs like Chromium, and in the C libraries that programs of all kinds still depend on.
I wouldn't put Python on that list because of how many packages are wrapped up C/C++ code. I know the same is done with Java and JNI but the pervasiveness of it is not at the same level.
> Even with a memory safe language, memory management is not entirely memory safe. [...] Memory safe languages can also use libraries written in non-memory safe languages and thus can contain unsafe memory functionality. Although these ways of including memory unsafe mechanisms subvert the inherent memory safety, they help to localize where memory problems could exist, allowing for extra scrutiny on those sections of code.
Which I suppose is a reasonable way to put it. It's been said elsewhere, but my read of this document is that this is not a _definitive_ list of languages you should use, but rather a list of languages that make it much more difficult for programmers to introduce memory-safety bugs.
It suffers from a GIL to prevent race conditions in the data structures of the interpreter, which is written in C. C extensions add to the problem. I'm not sure that this kind of languages can be classified as memory safe. Maybe JRuby, which runs on the JVM.
Anyway, even without C extensions a malicious input might trigger a memory related vulnerability in the interpreter. A compiled program written in a memory safe language could suffer from a compiler bug. Did it happen to Go and Rust?
Happens with all those languages. It's as simple as an "unsafe" keyword. But yes, Python is, far and away, the most egregious example.
Really, in the long term, "unsafe" and FFI interfaces should be removed from C#, Java, and Rust. That's the only way to be sure. in fact, I'd be willing to bet that in the short to medium term, with this recommendation, government contractors will soon be required to submit code that does not use these facilities. If you can't do it in C#, use Rust, if you can't do it in Rust, use Java, but you probably will no longer be allowed to pull in that wiz-bang c++ library.
With the notable exception of Ruby, these are all relatively high-performance programming languages that can reasonably used for large amounts of data processing.
I think they may simply be the first ones that came to the writer's mind.
From wiki:
> Memory safety is the state of being protected from various software bugs and security vulnerabilities when dealing with memory access, such as buffer overflows and dangling pointers
Dart has isolates, so I thought it was memory-safe.
But searching for buffer overflow or dangling pointer on dart's github repo returns results, so I'm still left wondering.
I would have thought so, considering null safety, but can't find a specific mention either in their docs or by googling. Seems like a weird thing to overlook in a modern inoffensive language.
Is there any standard to meet the requirements of being "memory safe" or is it enough for the language to just feature GC and automatic memory management? I thought only Rust and Ada (which is surprisingly not mentioned in the list) were stringent about memory safety as a language feature ... (perhaps Go too?).
It is, but they also have a competing mission to compromise the security of non-American businesses, communications, and infrastructure. Since for the most part, the same software is used by both, these missions often contradict each other. e.g. documents from Snowden revealed that the NSA had broken encryption recommended by NIST. It's difficult to know if NSA recommends something because it makes their defensive mandate easier, or their offensive mandate easier.
For this reason, experts like Schneier [1] have long advocated that the NSA be broken up so that these two missions do not fall under the same agency.
NSA's defensive mission is about securing National Security Systems. These have a fairly specific definition, and are not running in the average business.
It's definitely more work than it should be to bootstrap Rust, but we should be able to rule out most "trusting trust" scenarios with a fully bootstrapped compiler, right?
rustc has been successfully subjected to diverse-double-compilation (https://dwheeler.com/trusting-trust/) via mrustc at various points in its history, which plausibly rules out trusting-trust attacks for those versions.
This is an extremely paranoid view that relies on nobody else outside the US spotting it or any of the network traffic that it would have to generate to be useful.
I think the only instance of this kind of thing for which there is evidence is the elliptic curve debacle?
I wish that was the case. The biggest software risk to companies I have worked at are not the NSA or memory safety. It's their own product management and development staff competence.
You can leave a whale sized implementation hole in the finest of Rust applications!
So, technically, they probably meant: "unauthorized modification of a security-related system, device or process in order to gain unauthorized access". This being the jargon definition for 'compromised'. You probably should have instead posted something like: "You probably should have instead posted something like: compromised instead of comprised".
Now, I know what you're thinking: "Yeah, the definition of 'compromised' is what I meant when I said 'You mean "compromised"?'. Why do you have to be so pedantic?"
Perhaps you are correct. Maybe it's better to not correct people on the internet when what they were saying is technically incorrect, but otherwise understandable.
I'm genuinely grateful that the previous comment asked if I meant 'compromised'. Short, simple, and to the point. I do not read any bad intent into that comment, and point-outs like those seem to be protocol for HN.
Perhaps you are correct. Maybe it's better to not correct people on the internet when what they were saying is technically incorrect, but otherwise understandable.
TempleOS was an OS created by a genius programmer named Terry. Also, I very rarely use the word genius, but he was a genius by definition. He was extremely mentally ill, but his brilliance lives on through TempleOS (and HolyC). Check out this Down the Rabbit Hole video about him.
HolyC is TempleOS's primary language. Previous to its creation the author had a mental breakdown... this should explain everything quite clearly https://en.wikipedia.org/wiki/TempleOS
What’s kinda annoying about comment sections on these articles is it shows how many people have opinions on this topic that they know only a bit about.
Rust is safer than C++ because it does “opt-out” of memory safety, rather than modern C++ which is more “opt-in”
But Rust (other than for threads) is definitely not more memory safe than Go/Java etc. Safe rust code can still memory leak. Unsafe rust code can have memory errors (and does frequently) that those others would stop.
I'd put Rust as more memory safe than golang as golang's memory safety guarantees fall apart under data races, which are not prevented in the language. Rust will still require you type unsafe. You can cause memory safety in golang without using any unsafe facilities.
> Safe rust code can still memory leak.
Which is not at all a violation of memory safety, so is moot here.
> Unsafe rust code can have memory errors (and does frequently) that those others would stop.
Unsafe C#, unsafe Java, safe Go, Python all suffer from the same types of memory errors.
> What’s kinda annoying about comment sections on these articles is it shows how many people have opinions on this topic that they know only a bit about.
I'd invite you to pause and ask yourself if you know as much about the topic as you think you might, as there are either clear misunderstandings or intentional misleadings about these languages in your very short post.
Caveats are that it requires cgo, and it might have lower performance, so enable it during development but not during production. Also detection requires actually triggering the data race, so you need good tests to try to exercise those areas of code.
Although Rust prevents them outright, that does seem to come at the expense at some flexibility, and the actual security risk of a data race in Golang seems to be moot. For example, if you know that a shared object will only be used when the program is starting up and in single-threaded mode, then you can safely use it then without a mutex.
Even when Golang does have a data race, the race causes the program (or at least the thread) to panic and thus is probably not directly exploitable, unlike older languages.
In other words, golang changes the risk of a data race from being a vulnerability to just a program-crashing bug. [EDIT: please see comments below which indicates that this may not be true in all cases, especially if you're trying to sandbox untrusted code!]
Beyond that, Go provides special capabilities (channels) to allow communications across goroutines (which are analogous to threads but can also automatically use different cores, unlike regular threads). Channels are like a vastly improved version of Erlang's mailboxes, and are the best way to pass information between goroutines.
So, rather than use mutexes, channels are Golang's idiomatic way to eliminate data races entirely. You can pass any complex object through a channel to another listener (blocking or non-blocking) on the other side. This excellent video is actually what convinced me to switch to Go for concurrent coding (which is the only place where you run into data races anyway):
Looking at the attack vector (https://blog.stalkr.net/2019/11/the-gomium-browser-google-ct...), this is a pretty tightly constrained circumstance where you are permitting an attacker to execute unknown Golang code within the context of your process. (perhaps like the Go Playground, if that's not starting a new process for each user.)
I don't personally think that's really that applicable to regular golang users, unless they're trying to sandbox Golang code somehow within the language itself. (And if you are allowing untrusted code, then it's basically game over anyway).
But it's still interesting and I added a note to my comment above about your point.
I’m not at all saying I do know a lot on the topic, I am saying I know enough to recognize comments that are wrong.
For starters just cause you “can” have memory safety issues doesn’t mean it’s the same as Rust.
I mean Rust “can” have memory safety issues, so I guess it’s equal to C++? No that’s ridiculous.
So just cause you “can” have unsafety in python doesn’t mean suddenly it’s not better than rust.
If you think memory issues mean rust is better than C++, then you must recognize all GC languages are better than rust. Rust should be used where GCs cannot.
Memory leaks are still a very real issue. Just cause they aren’t a security issue doesn’t mean they don’t affect reliability, which is important.
Both Java and Go also have unsafe, and are often used for FFI/Performance, and some popular/foundational libraries (like Google's Protobuf library in Java) use unsafe just for added performance. Heck, Go has an Assembler. So that's off the table as far as safety comparisons go. "But they don't use it as much" is also not an argument. #[forbid(unsafe_code)] and rely on the RustBelt formally verified standard library, problem solved.
Memory leaks are not a memory safety error, especially when deliberate (think calling malloc without ever calling free is perfectly safe, especially if you intend it as a static duration allocation). Unintentional memory leaks like Rc/Arc cycles are not a problem that occurs in garbage collected language, true, but also not a memory safety issue, unless it's unsafe code that relies on drop() being called or something.
So if we count data races, which you mentioned, Rust is in fact safer than Java/Go.
“But they don’t use it as much” is not an argument?
It’s the whole case for Rust > modern C++ based on that?
Rust can have memory issues, but “it doesn’t use unsafe as much” as modern C++. Forbidding unsafe code doesn’t guarantee vulnerabilities are gone.
why is it that when talking about C++ memory safety, even a bit more is worth everything, but when talking about rust vs python, suddenly it doesn’t matter if it’s less.
No one is writing kernels, raw register level volatile DMA bit-banging embedded code, and other "impossible without unsafe" code in Java/Go (Ok, almost no one, don't @ me, pjmlp, there are kernels built in memory-safe languages and there's tinygo for embedded etc. But they obviously use unsafe all the same). So they don't need to use it as much (standard library, core primitives and runtime implementation notwithstanding, and boy oh boy is it unsafe!)
Shifting the discussion to Vulns., Modern C++ is moving the goalposts a bit, don't you feel?
> Forbidding unsafe code doesn’t guarantee vulnerabilities are gone
It does, because if it doesn't, or GC'd languages offer more protection, then it's a bug in rustc/spec/core libs, for all intents and purposes.
Might as well mention /proc/self/mem and other filesystem/IO related exploits, because Rust can't protect you from them, and therefore it's completely and utterly unsafe and unfit for use.
I am not saying rust is unfit and I think your first sentence gets to sorta my point.
I agree no one writes actual kernels in GC languages. 100% Rust is the best choice where GCs can’t be.
I think my argument is that if you can use a GC, I think it’s considered best practice to use a GC. If you need thread safety, use a GC language like Elixir that handles concurrency well.
Like there’s no reason to act like Java community and try to force rust into every area. It’s very good at what it does, let it stay there.
I don't even disagree with these points! But if you go down to language lawyering and semantics, I think one could technically make a case for Rust being safer (in the memory safety sense) than Java/Go/(insert any GC'd memory safe language that features synchronization primitives as an opt-in feature, think volatile in Java), if only on the merit of protecting you from data races.
Elixir is great, use elixir. I certainly am not stopping you, it's completely safe and fault tolerant. Or maybe I'm saying this because I don't know as much about Elixir/BEAM internals compared to the aforementioned languages, who knows.
That’s not true - if anything, Java is much more memory safe. Even data races are well-defined and are not prone to “out-of-thin-air” values.
If you ever go down the safe road in Rust (be it a buggy library n layers down that you use from entirely safe code), you can no longer be sure in anything, a data race is entirely undefined behavior.
How is it different from "If you ever go down the JNI road in Java"? Be it a library the bundles RocksDB, or Android stuff, doesn't matter that your average Spring Boot developer probably won't be having any native dependencies (unless they use Kafka Streams or something else that bundles a native dependency that had CVEs that needed to be patched). Just as a Rust high-level Back-End developer that works with axum, sqlx, tokio etc. (vs Netty/NIO in Java for example, which also use unsafe/native code) hopefully won't be using buggy unsafe libraries.
Does the JVM protect you from partial reads? On Hotspot or on say, GraalVM's LLVM runtime too? Does Go? I assume they at least protect you from stale read UAFs by virtue still being traceable. (This is a genuine question).
Java is probably the most self-reliant platform out there, it is almost completely pure, as in being written in Java or in another JVM language. Besides places where it is absolutely necessary (e.g. opengl), there is simply no JNI used, or only very rarely.
It’s a lot harder to memory leak in Go and Java than rust.
Just like it’s harder to have a memory safety issue in rust than C++.
if you are worried about data races, use a language like elixir that’s more safe than rust and is great for concurrency.
If you are a rust dev that forces your language into areas where a GC would suffice, than you are just like C++ devs who refuse to use rust for memory safety.
You are introducing memory issues just cause you don’t want to use a better tool.
I have only dabbled in Rust and have no experience with C++/Java/Go. Can you help me understand how those languages would be more memory safe than Rust? My understanding was that safe code was a solution to memory leaks. What’s the benefit to safe rust code if it isn’t getting rid of memory leaks?
Thanks. So what does it mean for a program to be memory safe if it can still memory leak? An example or pointing to a resource for further reading would be much appreciated.
It prevents data races, use-after-free, double-free, buffer overflow, invalid type punning, etc. You can still do all those things in unsafe code though, and you could in safe code if the unsafe code you depend on (including the kernel) behave/are programmed incorrectly. You can also have hardware issues and stochastic bit flips that Rust and SPARK can't deal with.
That’s not correct. Memory safety consists of properties necessary for type safety to be upheld. Leaks alone can crash a program but can’t defeat type safety.
Memory safe code does not prevent applications from using too much memory; it prevents applications from accessing the wrong memory (e.g., by using a variable after its underlying value has been freed and the memory reallocated).
Dumb question, it always seems like people say Rust is the gold standard for memory safety. Why is Rust better at memory safety than C#, Go, Java, Ruby or Swift?
Rust just imposes constraints on references using the type system, so the compiler knows to emit the free in the right spot. For regular application code there's no real benefit. It's not really a systems language because of all the hidden memory allocations and lack of a stable ABI. It's garbage for embedded because of all the gratuitous copies you have to make to appease the borrow checker. It blows up your memory budget.
> For regular application code there's no real benefit
Can't disagree, naive garbage collected code would outperform naive Rust code that allocates Strings and Vecs up the wazoo.
And performance isn't a real issue with simple CRUD/ORM-type services.
Wrapping business logic in newtypes and enforcing specific invariants for them and serde style "parse don't validate", can do wonders for business logic, but then again you can probably just use a garbage collected functional language with dependent typing and a bunch of other tricks in its hat, and get more mileage out of it, if that's the code you write.
> It's not really a systems language because of all the hidden memory allocations
C and C++(especially) can hide memory allocation just fine themselves.
Allocations are pretty explicit in Rust, but layers of libraries can hide those (if you don't use no_std and the like), just like in C or C++.
> lack of a stable ABI
there is the C ABI, a stable Rust ABI at any stage would just be an optimization killer and a massive PITA, ask C++. Stable ABI, international standard, and multiple implementations of the compiler, are not a requirement for a systems language.
For a language that relies on compile-time monomorphization, a stable ABI beyond what C already provides gives precious little. Swift ABI forgoes monomorphization, but it's not really a trade-off a systems language should embrace. The template header issue in C++, I won't even touch.
There are also crates in the ecosystem that can generate 2-way FFI glue code to provide a stable ABI for Rust based on extern "C".
> It's garbage for embedded because of all the gratuitous copies you have to make to appease the borrow checker. It blows up your memory budget.
We use embedded Rust on a memory constrained MCU and besides slightly increasing the maximum stack size (because less is allocated on the heap), memory budget is not an issue we have. And in LLVM 16, Rust's stack usage will decrease even more, due to recent optimizations.
You don't need to use "gratuitous copies", you can statically allocate just fine, and if your value is ephemeral and is read/mutated by multiple threads, heap allocating with reference counting is just fine.
My understanding is that Rust provides memory safety with less overhead than languages that provide memory-safety via garbage collection. This comes at the price of some extra cognitive load for developers, but is appropriate for many applications where the added performance is needed.
(Not necessarily "better" overall, but a better choice for certain applications.)
It depends on exactly what features you class in the safety umbrella. Both languages protect against classic C mistakes but Rust has a far more advanced type system and better safety culture. For example, Java has had issues with data races which would have been caught by Rust and things like null safety have historically been an issue.
Both are better than C but I’d expect a good programmer to be more productive in Rust and to avoid more logic errors (which may or may not be security issues), not to mention the many problems caused by widely used open-source libraries written during the bad old days which have extensive dependencies and often enable risky behaviors by default. Culture isn’t a core language feature but it matters.
NPE itself isn’t likely to be exploitable, no, but what I had in mind was more along the lines of code with logic errors handling rare cases where something is null. There’s a lot of tooling designed to catch things like that but the worst code bases tend not to use them because they’d need a lot of cleanup.
No, in Java a data race is a well-defined behavior - the observable values of the field are only those that were actually set by any Java thread, also called no out-of-thin-air values.
This is not generally true of other languages, where it is allowed for the compiler to do whatever it wants in these cases, meaning that once you go down the happy path, nothing can be guaranteed. Also, safe rust preventing data races is again not that big of a thing because if you want to use the same memory region (not read-only) from multiple threads you will have to use unsafe either way.
Rust’s scoping rules prevent most double free errors. You can get them with certain techniques but it’s also possible, say, use JNI to shoot yourself in the foot, too.
Basically, I’d say that at fond point this gets to be a lot more complicated because you’re talking about which sets of features & cultural practices make you more or less likely to make exploitable errors. Does using a GC buy you enough to balance out the complexity fetish common in the open source Java world? Which is safer probably depends on what type of projects you work on.
Note that the sentence continued to describe common open source libraries. Rust code may or may not be more complicated than the core Java language but Java as practiced by many people has lots of heavyweight dependencies with various patterns and conventions you have to understand to use them correctly. It's not a linear relationship but the more code you're running the more likely it is that you have something unsafe.
That's also why I mentioned culture: for various reasons, a lot of Java programmers sought ways to make tons of behaviour configurable which also means that there's both plenty of scope for log4j-style mistakes and lots of optional behaviours which might be exploitable even if few people use them. Rust's culture tends not to encourage that kind of thing as much so even though certain types of errors are possible in any language they're not equally common.
> One increasingly popular approach to ensuring safe concurrency is message passing, where threads or actors communicate by sending each other messages containing data. Here’s the idea in a slogan from the Go language documentation: “Do not communicate by sharing memory; instead, share memory by communicating.”
> To accomplish message-sending concurrency, Rust's standard library provides an implementation of channels. A channel is a general programming concept by which data is sent from one thread to another.
> You can imagine a channel in programming as being like a directional channel of water, such as a stream or a river. If you put something like a rubber duck into a river, it will travel downstream to the end of the waterway.
> This type of attack exploits the fact that most computers (which use a Von Neumann architecture) do not make a general distinction between code and data,[6][7] so that malicious code can be camouflaged as harmless input data. Many newer CPUs have mechanisms to make this harder, such as a no-execute bit. [8][9]
> Ghidra can be used as a debugger since Ghidra 10.0. Ghidra's debugger supports debugging user-mode Windows programs via WinDbg, and Linux programs via GDB. [11]
Every time I hear people bashing C++ for not being memory safe, I somehow get reminded of the teens that were eating Tide Pods a few years ago. So let's put a big warning and lock away the Tide Pods because people might eat them. Well FFS, I just want to do my laundry and I know what I'm doing.
Sure, I introduced my share of memory bugs in C++ code early in my career when the standard was older and the (static analysis) tools were missing, but working with the modern C++ ecosystem now is a pleasure, and I don't want to have a hand tied behind my back and locked into the playpen with the Tide Pod gourmands for "safety". </rant>
The problem isn't novices stubbing their toes in their own homes. The problem is professional programmers beneath your skill level who are making those same old mistakes in government offices and major corporations.
If large groups of people and especially large groups of experts keep making the same mistakes with a tool, it's not the users that's the problem, it's the tool.
I don't get how the other languages are on that list. I mean, yes, I guess they're marginally better than C and C++ at memory-safety, but... just barely...?
I’m a big fan of Rust, and I think it’s reasonable for those languages to be listed: with the exception of a few niches, most of the code written in those languages will be spatially and temporally memory safe. They’re also popular languages with large ecosystems, so listing them “grounds” the guidance.
What do you mean just barely? They're exactly as safe as Rust. Perhaps they're not making it a selling point because it's been obvious for a few decades that automatic memory management tends to be memory safe.
In fact some languages are even safer (e.g. Scheme and various Lisp implementations don't have integer overflows due to having bignums by default).
Null pointers are not a memory safety issue in most managed languages. It is completely well-defined behavior in Java for example, you can safely catch any NPE and go on as if nothing happened. This is not true of C, where dereferencing a nullptr is incredibly unsafe.
I think the key thing is ironclad protection against memory corruption or gain unintended code execution access (barring a bug in the implementation of the compiler/runtime which can of course affect any language).
I've actually heard claims of memory safety in Ruby for the last few years and I was always skeptical...but this gives those claims a lot more merit for sure.
NSA guidance on how to protect against software memory safety issues [pdf] - https://news.ycombinator.com/item?id=33553668 - Nov 2022 (90 comments)