Their notes about vulnerability severity are particularly interesting.
Defenders of C/C++ frequently note that memory safety bugs aren't a significant percentage of the total bug count, and argue that this means it's not worth the hassle of switching to a new language.
Google's data suggests that while this is true, almost all severe vulnerabilities are related to memory safety. Their switch to memory-safe languages has led to a dramatic decrease in critical-severity and remotely-exploitable vulnerabilities even as the total number of vulnerabilities has remained steady.
It's even worse. The majority, not of all bugs, but all vulnerabilities (of all severities) do come from memory safety bugs. TFA: "For more than a decade, memory safety vulnerabilities have consistently represented more than 65% of vulnerabilities across products, and across the industry."
On top of that, memory safety vulnerabilities are disproportionately high severity: "Memory safety vulnerabilities disproportionately represent our most severe vulnerabilities. In 2022, despite only representing 36% of vulnerabilities in the security bulletin (NOTE: down to 36% from 65% because of moving from C++ to Rust and other memory safe languages), memory-safety vulnerabilities accounted for 86% of our critical severity security vulnerabilities, our highest rating, and 89% of our remotely exploitable vulnerabilities. Over the past few years, memory safety vulnerabilities have accounted for 78% of confirmed exploited “in-the-wild” vulnerabilities on Android devices."
> NOTE: down to 36% from 65% because of moving from C++ to Rust and other memory safe languages
Imagine if in any other field, a process or technology were developed that cuts the number of high-severity issues in half.
For example, a modification to the standard anesthesia protocols that demonstrably reduces anesthesia-related fatalities by 50% in clinical practice.
And now imagine, in reaction to this revolutionary development, thousands of anesthesiologists publicly said things like "what matters is not the technique but the skill of the physician", "good anesthesiologists don't make mistakes like that in the first place", "but this new technique takes 1%-3% longer than the previous one" or similar.
Utterly unthinkable, isn't it?
Yet in software engineering, this is exactly what has been happening every day for more than a decade.
> Defenders of C/C++ frequently note that memory safety bugs aren't a significant percentage of the total bug count, and argue that this means it's not worth the hassle
C-nile developers have been making incorrect arguments for a while now. The reality is which almost everyone can see is that memory safe languages are pretty much always what you want to be using for new code. OS and security sensitive components are the prime targets for rewrites in more secure languages.
Now Google has put this to the test and has the data to prove it. We should not allow the worlds technology security to be held hostage by a group of people too lazy to adapt with the times.
> and argue that this means it's not worth the hassle of switching to a new language.
Defenders of C++ argue that there's no reason to change the language, because new features around safety guarantees are being introduced into every C++ standard starting from C++11 at a remarkable pace, so remarkable that compilers implement them faster than the existing adoption rate. And the adoption rate speaks volumes about existing capacity to port/rewrite big codebases in entirely new stacks. The new stacks also tend to have fewer custom static code quality analyzers from third-party vendors, and they are used a lot in mission-critical C++ codebases.
> The new stacks also tend to have fewer custom static code quality analyzers from third-party vendors, and they are used a lot in mission-critical C++ codebases.
Are these static code quality analyzers detecting code quality problems that Rust and company are also vulnerable to? Or are they mostly looking out for the hundreds of legacy footguns that C++ still officially supports?
While new safety features in C++ may be impressive, Google's data shows that memory safety vulnerabilities are still a major issue. Switching to a memory-safe language like Rust can help reduce the risk of vulnerabilities and improve the overall security and reliability of a product. The potential benefits make it a worthwhile investment, even if it requires some effort to migrate from C++. #RustIsTheRealDeal
> Defenders of C/C++ frequently note that memory safety bugs aren't a significant percentage of the total bug count
Well, first of all, this is said but not proven.
But it's easy to prove that memory safety bugs are not a significant percentage of the total number of bugs, even Google agrees.
Vulnerabilities are not the same thing as bugs, a vulnerability like spectre or meltdown are not due to a bug in the software, have an ubiquitous immediate impact on 100% of the devices and are much harder to fix or mitigate, sometimes it's could even prove impossible.
The same bias can be explained using the exact same words used in the article
"Despite most of the existing code in Android being in C/C++, most of Android’s API surface is implemented in Java. This means that Java is disproportionately represented in the OS’s attack surface that is reachable by apps."
It can be read as: of course most of the vulnerabilities are due to memory safety bugs, it's much harder to gain root privileges exploiting a bug on the colors of a specific element of the UI, assuming it would be possible.
It can also be read as: most of the userland software is based on Java, which is memory safe by default, assuming there are no bugs in the implementation of the JVM, which is entirely not Java.
Given that, the problems become
- rewriting the entire ecosystem in memory safe languages requires rewriting everything from scratch, which is a task that even Google will have huge problems to complete (reminder: Google is the number one killer of its own projects) in reasonable time or without wasting more money that it's worth on it. Is an half complete not battle tested complete rewrite actually safer? Historical data says it usually isn't.
- are the user actually safer when memory is safe? I mean, memory safety bugs gave us jailbreaking for locked devices, memory safe languages gave us bugs like CVE-2021-44832
I wouldn't classify the issue as black/white, there's a lot of grey to be considered.
> Vulnerabilities are not the same thing as bugs, a vulnerability like spectre or meltdown are not due to a bug in the software, have an ubiquitous immediate impact on 100% of the devices and are much harder to fix or mitigate, sometimes it's could even prove impossible.
Using language-independent bug example in discussion about language-caused bug vectors isn't exactly honest.
Rust would stop Heartbleed for example, and that was one of huge vulnerabilities
Ah, yes, the age-old debate of memory safety vs. total bug count. It's like choosing between having a really bad headache or a really bad cold - either way, you're still feeling pretty lousy. But in all seriousness, I think Google's data shows that prioritizing memory safety can have a significant impact on the overall security of a product. I'm sure the C/C++ defenders will continue to argue their case, but at least now they have some hard numbers to contend with.
...but still, even with Android's importance and Google's resources, they're not planning to "rewrite it in Rust", at least not for now - only new code will use Rust.
The overwhelming majority of bugs of any sort live in new code. The longer a piece of code has been around, the safer it generally is (with occasional high-profile exceptions). This means two things:
1) The most cost-effective way to eliminate the majority of memory bugs is to just start writing all new code in a memory-safe language. If you were going to write new code anyway, you may as well do it safely.
2) Going back and re-writing existing code that doesn't need to be changed may solve latent memory bugs, but it will likely introduce other regressions that could be worse for security or for user experience. If code doesn't need to change, it's often better to leave it as is.
Not that a rewrite is never called for, but it's not necessarily the best course of action by any metric (even when neglecting the cost).
Mostly new code. They've rewritten some core, high-importance pieces. But any mature OS is a massive codebase, so it just wouldn't be feasible to systematically rewrite the entire thing indiscriminately
Seems like drawing too many conclusions from evidence while arguing against a straw man?
Defenders of C might note that Android is java and IOS is not and compare the security of those two systems and say clearly memory-safe is focusing on the wrong thing. This is equally true but no more valid an argument.
The one that really bothers me in all these language-booster discussions (that we should and need to have) is the functional programming formal verification claims. We have no ssl library written in a memory-safe, functional language that has been proven correct that has dominated the space. Heartbleed wasn't yesterday.
WireGuard is a recent and prominent example of a system that has been formally verified (https://www.wireguard.com/formal-verification/). There are implementations in a variety of languages due to integration considerations.
You will find at the bottom of that page C implementations of curve25519 that are proofed and derived from F* and Coq. Curve25519 is a relatively simple implementation and only one part of any system that uses it. As you can see in both of these implementations the papers recognize a team of contributors each - this should provide some insight as to the cost of such work. That doesn't make it unimportant, it just makes it rare.
> We have no ssl library written in a memory-safe, functional language that has been proven correct that has dominated the space. Heartbleed wasn't yesterday.
> Safety measures make memory-unsafe languages slow > > Mobile devices have limited resources and we’re always trying to make better use of them to provide users with a better experience (for example, by optimizing performance, improving battery life, and reducing lag). Using memory unsafe code often means that we have to make tradeoffs between security and performance, such as adding additional sandboxing, sanitizers, runtime mitigations, and hardware protections. Unfortunately, these all negatively impact code size, memory, and performance.
Even more evidence that the negative performance impact of bounds checking is minimal, nay, it can even be positive.
No it isn't. It's just evidence that it's a trade-off you might want to make in order to achieve some other goal, specifically security.
But if "security" isn't remotely a concern for a given project (like almost anything graphics / gaming related), this is not at all evidence for changing anything. It could be that Rust's optimizer eliminates the bounds checking so regularly as to be a moot point, but this isn't saying anything of the sort. It's saying that the cost, whatever it was, was judged to be worth paying for the improved security for these projects
> But if "security" isn't remotely a concern for a given project (like almost anything graphics / gaming related)
Gaming platforms have gotten a lot less lenient over time, and with pretty much every game these days having online components, "security isn't remotely a concern" has become a lot less true.
I take it the opposite: C programmers out of abundance of caution of putting in bounds checks for code that will never be called with out of bound data. As such rust is eliminating code that is being manually written. If you don't write the bounds check in C, and rust for the equivalent determines that the bounds check isn't needed the code should be the same (to the assembly level). However if you write a bounds check in C the optimizer might not eliminate it.
It's not just about bounds checks. I am way more agressive about borrowing fields of other types, particularly mutable borrows in ways that I wouldn't attempt in C to protect myself from future code from breaking invariants I'd have to rely on. This means I can write the hyper optimized version of an algorithm on any language, but I'm more likely to even attempt it in Rust.
There were (or are?) some older call of duty games being sold on steam that had unpatched RCE vulnerabilities in them. Simply joining a server ran by a malicious host can result in the players system being totally compromised.
These games would go on sale once a year or whatever and attract new players, and people would post warnings in the steam forums and whatnot to try to stop people from being effected by the issue, but I am sure some people either didn't listen or didn't notice the warnings.
I haven't looked into the issue in a few years at this point, but it's very possible that the games are still unpatched and being listed in the store to this day.
Anything that connects to the internet needs to be strongly concerned about security!
I wonder how much of the positive performance is just because we have not proved that some impossible case is really impossible and so we have if statements checking for a situation that mathematically cannot happen just out of caution. (note that in many cases we don't even have the theoretical tools to prove the code)
Though that makes non-memory safe code more reliable in the case of a bit flip. (this is not a serious advantage - only some bit flips can be prevented this way)
Glad to see robust work here. This strongly supports what should already be obvious, but sadly is not always understood; that memory safe languages are radically safer than memory unsafe languages. The impact is blatantly demonstrated here.
When Heartbleed was a topic of discussion, some pointed out that Rust wouldn't have 100% protected from that vulnerability. So it is good to see some proof that using a safer language does in fact pay off in terms of fewer defects. I just wish there were some info around cost associated with development effort. Did the Rust code take longer to develop? If initial development was longer, what if we include time saved from reduced effort for bug resolution?
An example from an experiment to benchmark Rust and Java I did recently, where I sent files from one app to another: perf was good enough without tuning, with tuning I could triple the speed and final total time on both versions was comparable. Memory was much greater for Java (even with graalvm). The Rust version didn't suffer from any memory safety issues or race conditions when sending multiple files, but I did have a vuln where you could specify a relative path that could escape and write anywhere in the receiver's filesystem. Rust didn't protect me from that, and those are the kind of vulnerabilities that we'll continue seeing regardless of language. But the threat surface I had to be scared about was much smaller than it would have been in other languages. And because the fallible APIs are obvious, I handled many edge cases that I might have forgotten about otherwise.
I think even heartbleed would be mitigated with (safe) Rust. IIRC heartbleed was caused by a missing bounds check, which allowed attackers to read past the message buffer and leak secrets from nearby memory. Safe Rust would just panic (crash) if you tried to slice past the end of the buffer.
I think this indeed echoes similar experiences and studies at other large companies (e.g. Apple, Microsoft, Meta, etc.) regarding the characteristics of their recent investments into rust code vs. C/C++ code. I don't think it is surprising to anyone at this point. But it is nice to see it re-confirmed.
Rust (despite the common understanding) is not a memory-safe language in its entirety. It is a language designed to have a strict division of safe/unsafe which makes it easier for developers to compartmentalize code to achieve memory-safety.
Is there any practical programming language that is memory safe in its "entirety"? Python, for example, certainly is not. It has unsafe escape hatches (via ffi, at the very least). Yet, everyone I know of says and thinks of Python as a memory safe language. I do as well.
> which makes it easier for developers to compartmentalize code to achieve memory-safety
The problem here is that this is incomplete. Many many many languages have achieved this before Rust. Where Rust is (somewhat although not entirely) unique is bringing this compartmentalization into a context that (mostly) lacks a runtime and garbage collection.
I have no problems calling Rust a "memory safe language" precisely because I have no problems calling Java or Python "memory safe languages." What matters isn't whether the language is "entirely" memory safe. What matters is what its default is. C and C++ are by default unsafe everywhere. Rust, Java, Python and many others are all safe by default everywhere. This notion is, IMO, synonymous with the more pithy "memory safe language."
The blog speaks to this explicitly, in the "what about unsafe Rust" section. The tl;dr is that the number of unsafe sections is a small fraction of the total code size, and it's much easier to audit the usage of unsafe, as the reason to justify it is focused. Thus, the use of unsafe in Rust is not a significant driver of actual vulnerabilities.
I think this has always been the goal, but it wasn't obvious at the outset that it would be achievable. The fact that we now have empirical evidence in real shipping products is significant.
- great standard library, especially all the iter methods. having 'obscure' stuff like `try_for_each` just makes me so happy as a dev
- unit tests built into the lang
- tooling is great
- docs are top notch
The memory safety aspect is... sometimes helpful, sometimes irritating. I prefer zig solution (BYO allocator, special one for testing that reports errors) over rusts, which simplifies a lot of stuff and lets you make cyclical data structures without a lot of hoop jumping.
Rust does require structuring programs in a "Rust way" to avoid fighting with things it can't prove to be safe.
However, I appreciate that Rust tries to achieve safety through improving program correctness, not merely crashing sooner.
Of course Rust has run-time panics (hasn't solved the halting problem yet), but it also has many patterns catching problems at compile-time. For example, a hardened allocator can detect use-after-free bugs when they happen, but borrow checking can prevent them from existing in the code in the first place.
> Rust does require structuring programs in a "Rust way" to avoid fighting with things it can't prove to be safe.
That was my concern that I had when I started learning the language. I think it is true, but I was surprised how quickly I managed to get used to the Rust way.
What I like about this language is the crazy amount of creative and insightful discussions about language features and stabilization.
It's because Rust hits the spot for MANY different domains and people. System programmers, functional programmers, backend, db engineers, GUI, devs from the formal verification/mission critical camp, OS devs, graphics and even frontend with WASM.
For me personally, the thing I miss in Rust is better const fn/comptime/metaprogramming (like in C++). Without them, I find writing generic high-perf data structures quite tedious (and proc macros just aren't a suitable replacement for generics)
I love Rust, but I kind of believe in the conspiracy that comptime code features are less loved by the Rust language maintainers because they increase compile time even more.
- It has the best parts of C (code generation is predictable, no mandatory extra thread for GC or similar, interoperates very well with C code)
- It also has some of the niceties that were popularized after C (type inference, an equivalent of unions that isn't terrible, macros that are not terrible, functional features)
- The thread safety stuff. Async has issues, but the core thread safety constructs (send, sync, mutex vs atomic, etc) are just so well designed that rust is by far my favorite language for writing synchronous, shared-memory threaded code. It's quite possible to mess it up, but it's far easier to keep that system in my head than any comparable one that I've used. Of course shared-nothing is even easier, and rust lets you do that too!
I don't use it for everything, but when I do encounter a thing rust is good at, it's just a treat.
Rust has some amazing libraries, too. I recently found out about `rayon`, and I applied it to a compute-heavy program I was writing. It was literally a one-line change (as promised!) to go from sequential to parallel, and I didn't need to worry at all that there might be some data race somewhere (unlike, say, #pragma omp parallel).
Sorry to disappoint you but if Rust had adopted higher-kinded types they wouldn't need to write a function `try_for_each` because it would just be a generic fold-and-collect-effect function that works for all effects not just Try:
traverse_ :: Foldable t => (a -> ExceptT e IO b) -> t a -> ExceptT e IO ()
Of course I'm not saying Rust should have this (there are good reasons why this isn't a good fit for Rust, see http://smallcultfollowing.com/babysteps/blog/2016/11/09/asso...) but it really caught my eye that you called `try_for_each` obscure; it could have been an everyday function if it had a bit more expressiveness.
In my opinion a very good point about Rust is that it is built by people who know these functional programming concepts and why they are yseful, but are pragmatic enough to give them names that are easier to grasp for folks who don't know these concepts.
And it's possible the lack of higher kinded types, forcing reimplementation, actually gave the opportunity to look for frindlier names.
I guess what I really meant was - they've captured a lot of common patterns in the iterator library so I don't have to write them myself.
No experience with haskell - sometimes I try and learn it and give up when stack complains about version conflicts - but regardless I try not to get too many hangups about functions not being super generic, just that they are there when I need them.
> This matches the expectations published in our blog post 2 years ago about the age of memory safety vulnerabilities and why our focus should be on new code, not rewriting existing components.
and
> As we noted in the original announcement, our goal is not to convert existing C/C++ to Rust, but rather to shift development of new code to memory safe languages over time.
For those working on C/C++ code bases, how does the incremental addition of Rust work in practice? What strategies and tools come in handy? Also, what are some good case studies where Rust was introduced to add new features, but still needed to work within a system mainly composed of C/C++? I've seen some of the first steps with Linux, but I'm thinking of a project where more substantial additions have been made.
Wrapping of C libraries in a Rust interface works quite well, and makes them safer. For stable battle-tested libraries I think it's even preferable to rewrites.
Many informal rules of C libraries like: "don't call read() after close()", "pointer must never be null", or "keep this data alive for as long as the handle is in use" in Rust can be expressed using the type system, and enforced at compile time. Cleanup can be automated. This catches bugs in user code and shields the library form misuse.
Nit: these are not informal rules, they’re clear UBs, they’re “just” not checked.
An informal rule would be “don’t use gets” before it was deprecated, or “don’t use the str* functions”, or “don’t pass a user-provided format to printf”.
Brave Browser has some Rust components too (e.g. the adblocking engine). Rust in C++ works very well for components with a small, well-defined API surface that involve a lot of logic. You only need to build a small FFI layer for the direct interfaces between the two languages. CXX [1] makes this even easier, too.
Brave is definitely not aiming to convert the entire browser to Rust, but it's increasingly chosen for new development.
I've only started scratching the surface, but that rust really wants you to use Cargo, while we have our own homegrown package manager, and cmake creates a lot of friction.
I can tell you that bad programmers can write bad code in Rust.
This was the interesting point for me too; noting that _new_ C/C++ is where most of the bugs are found, and so it's less important to rewrite old code than it is to transition to memory-safe languages for everything new that gets written.
Perhaps this is an obvious point, but I found it interesting .
This probably also applies to the Linux kernal work in Rust too; if only new device drivers get written in Rust and the core remains C, it could still be a major win for kernel security.
> how does the incremental addition of Rust work in practice?
Not being aware of how vulnerabilities are detected and despite being a big fan of Rust, I wonder if there are other variables that drive down the ability to find bugs in the short term. If a researcher is only familiar with C and C++, is it possible that they're just ill equipped to find similar bugs in Rust?
Rust programs can have vulnerabilities, but thankfully the fuzzer scene is well developed. Recently a memory safety bug was found in a Rust library (that used unsafe) and it turns out the original C++ implementation had it too. So here, fuzzing the Rust rewrite led to improvements in the original C++ library. I guess it's because there is higher interest in increasing the safety of Rust programs.
There's definitely a learning curve for looking for vulns in Rust vs C/C++, especially compared to C. Exploitation in particular will be the trickier part, imo, since it requires not just understanding the vuln but also the context and reachability.
That said, there are a ton of ways that auditing for vulnerabilities is just as easy or way easier. In particular, most tooling for C/C++ can be applied to rust - fuzzers and sanitizers, for example. Additionally, one only has to "grep for unsafe" and work from there to find Rust vulns, which largely amounts to "what are the assertions for this unsafe block, are they complete, are they held?".
They're also explicitly tracking new code by language, and talking about memory safety vulnerabilities per year, and they also link to [1] which talks about how most memory safety bugs they get are in new code.
> As Android migrates away from C/C++ to Java/Kotlin/Rust, we expect the number of memory safety vulnerabilities to continue to fall. Here’s to a future where memory corruption bugs on Android are rare!
Much of Android is written in Java/Kotlin. Transitions from the JVM to C/Rust and back are not going to be free due to extra wrappers and the inability to optimize across the boundary. So for some usecases Java will be faster. But anything CPU or memory intensive will probably be cheaper in Rust.
Defenders of C/C++ frequently note that memory safety bugs aren't a significant percentage of the total bug count, and argue that this means it's not worth the hassle of switching to a new language.
Google's data suggests that while this is true, almost all severe vulnerabilities are related to memory safety. Their switch to memory-safe languages has led to a dramatic decrease in critical-severity and remotely-exploitable vulnerabilities even as the total number of vulnerabilities has remained steady.
On top of that, memory safety vulnerabilities are disproportionately high severity: "Memory safety vulnerabilities disproportionately represent our most severe vulnerabilities. In 2022, despite only representing 36% of vulnerabilities in the security bulletin (NOTE: down to 36% from 65% because of moving from C++ to Rust and other memory safe languages), memory-safety vulnerabilities accounted for 86% of our critical severity security vulnerabilities, our highest rating, and 89% of our remotely exploitable vulnerabilities. Over the past few years, memory safety vulnerabilities have accounted for 78% of confirmed exploited “in-the-wild” vulnerabilities on Android devices."
Imagine if in any other field, a process or technology were developed that cuts the number of high-severity issues in half.
For example, a modification to the standard anesthesia protocols that demonstrably reduces anesthesia-related fatalities by 50% in clinical practice.
And now imagine, in reaction to this revolutionary development, thousands of anesthesiologists publicly said things like "what matters is not the technique but the skill of the physician", "good anesthesiologists don't make mistakes like that in the first place", "but this new technique takes 1%-3% longer than the previous one" or similar.
Utterly unthinkable, isn't it?
Yet in software engineering, this is exactly what has been happening every day for more than a decade.
This says more about those C++ defenders.
Now Google has put this to the test and has the data to prove it. We should not allow the worlds technology security to be held hostage by a group of people too lazy to adapt with the times.
Defenders of C++ argue that there's no reason to change the language, because new features around safety guarantees are being introduced into every C++ standard starting from C++11 at a remarkable pace, so remarkable that compilers implement them faster than the existing adoption rate. And the adoption rate speaks volumes about existing capacity to port/rewrite big codebases in entirely new stacks. The new stacks also tend to have fewer custom static code quality analyzers from third-party vendors, and they are used a lot in mission-critical C++ codebases.
Are these static code quality analyzers detecting code quality problems that Rust and company are also vulnerable to? Or are they mostly looking out for the hundreds of legacy footguns that C++ still officially supports?
If they’re saying that C++ can’t be saved, maybe they’re worth listening to.
Yes, things have gotten better. Smart pointers are a godsend. Sanitizers are a godsend. Various static analysis tools work pretty well.
But even codebases that adopt all of these things religiously still are riddled with security vulns.
Well, first of all, this is said but not proven.
But it's easy to prove that memory safety bugs are not a significant percentage of the total number of bugs, even Google agrees.
Vulnerabilities are not the same thing as bugs, a vulnerability like spectre or meltdown are not due to a bug in the software, have an ubiquitous immediate impact on 100% of the devices and are much harder to fix or mitigate, sometimes it's could even prove impossible.
The same bias can be explained using the exact same words used in the article
"Despite most of the existing code in Android being in C/C++, most of Android’s API surface is implemented in Java. This means that Java is disproportionately represented in the OS’s attack surface that is reachable by apps."
It can be read as: of course most of the vulnerabilities are due to memory safety bugs, it's much harder to gain root privileges exploiting a bug on the colors of a specific element of the UI, assuming it would be possible.
It can also be read as: most of the userland software is based on Java, which is memory safe by default, assuming there are no bugs in the implementation of the JVM, which is entirely not Java.
Given that, the problems become
- rewriting the entire ecosystem in memory safe languages requires rewriting everything from scratch, which is a task that even Google will have huge problems to complete (reminder: Google is the number one killer of its own projects) in reasonable time or without wasting more money that it's worth on it. Is an half complete not battle tested complete rewrite actually safer? Historical data says it usually isn't.
- are the user actually safer when memory is safe? I mean, memory safety bugs gave us jailbreaking for locked devices, memory safe languages gave us bugs like CVE-2021-44832
I wouldn't classify the issue as black/white, there's a lot of grey to be considered.
Using language-independent bug example in discussion about language-caused bug vectors isn't exactly honest.
Rust would stop Heartbleed for example, and that was one of huge vulnerabilities
https://www.youtube.com/watch?v=ELeZAKCN4tY
#RustForTheWin
1) The most cost-effective way to eliminate the majority of memory bugs is to just start writing all new code in a memory-safe language. If you were going to write new code anyway, you may as well do it safely.
2) Going back and re-writing existing code that doesn't need to be changed may solve latent memory bugs, but it will likely introduce other regressions that could be worse for security or for user experience. If code doesn't need to change, it's often better to leave it as is.
Not that a rewrite is never called for, but it's not necessarily the best course of action by any metric (even when neglecting the cost).
Deleted Comment
Defenders of C might note that Android is java and IOS is not and compare the security of those two systems and say clearly memory-safe is focusing on the wrong thing. This is equally true but no more valid an argument.
The one that really bothers me in all these language-booster discussions (that we should and need to have) is the functional programming formal verification claims. We have no ssl library written in a memory-safe, functional language that has been proven correct that has dominated the space. Heartbleed wasn't yesterday.
I look down the list here: https://en.wikipedia.org/wiki/Comparison_of_TLS_implementati...
And I think something is not being discussed as far as replacing memory unsafe languages of critical security infrastructure. What is it?
You will find at the bottom of that page C implementations of curve25519 that are proofed and derived from F* and Coq. Curve25519 is a relatively simple implementation and only one part of any system that uses it. As you can see in both of these implementations the papers recognize a team of contributors each - this should provide some insight as to the cost of such work. That doesn't make it unimportant, it just makes it rare.
Heartbleed didn't affect https://hackage.haskell.org/package/tls even though it isn't formally verified.
Even more evidence that the negative performance impact of bounds checking is minimal, nay, it can even be positive.
But if "security" isn't remotely a concern for a given project (like almost anything graphics / gaming related), this is not at all evidence for changing anything. It could be that Rust's optimizer eliminates the bounds checking so regularly as to be a moot point, but this isn't saying anything of the sort. It's saying that the cost, whatever it was, was judged to be worth paying for the improved security for these projects
Gaming platforms have gotten a lot less lenient over time, and with pretty much every game these days having online components, "security isn't remotely a concern" has become a lot less true.
These games would go on sale once a year or whatever and attract new players, and people would post warnings in the steam forums and whatnot to try to stop people from being effected by the issue, but I am sure some people either didn't listen or didn't notice the warnings.
I haven't looked into the issue in a few years at this point, but it's very possible that the games are still unpatched and being listed in the store to this day.
Anything that connects to the internet needs to be strongly concerned about security!
Though that makes non-memory safe code more reliable in the case of a bit flip. (this is not a serious advantage - only some bit flips can be prevented this way)
Dead Comment
Deleted Comment
> which makes it easier for developers to compartmentalize code to achieve memory-safety
The problem here is that this is incomplete. Many many many languages have achieved this before Rust. Where Rust is (somewhat although not entirely) unique is bringing this compartmentalization into a context that (mostly) lacks a runtime and garbage collection.
I have no problems calling Rust a "memory safe language" precisely because I have no problems calling Java or Python "memory safe languages." What matters isn't whether the language is "entirely" memory safe. What matters is what its default is. C and C++ are by default unsafe everywhere. Rust, Java, Python and many others are all safe by default everywhere. This notion is, IMO, synonymous with the more pithy "memory safe language."
I think this has always been the goal, but it wasn't obvious at the outset that it would be achievable. The fact that we now have empirical evidence in real shipping products is significant.
- great standard library, especially all the iter methods. having 'obscure' stuff like `try_for_each` just makes me so happy as a dev
- unit tests built into the lang
- tooling is great
- docs are top notch
The memory safety aspect is... sometimes helpful, sometimes irritating. I prefer zig solution (BYO allocator, special one for testing that reports errors) over rusts, which simplifies a lot of stuff and lets you make cyclical data structures without a lot of hoop jumping.
However, I appreciate that Rust tries to achieve safety through improving program correctness, not merely crashing sooner.
Of course Rust has run-time panics (hasn't solved the halting problem yet), but it also has many patterns catching problems at compile-time. For example, a hardened allocator can detect use-after-free bugs when they happen, but borrow checking can prevent them from existing in the code in the first place.
That was my concern that I had when I started learning the language. I think it is true, but I was surprised how quickly I managed to get used to the Rust way.
It's because Rust hits the spot for MANY different domains and people. System programmers, functional programmers, backend, db engineers, GUI, devs from the formal verification/mission critical camp, OS devs, graphics and even frontend with WASM.
For me personally, the thing I miss in Rust is better const fn/comptime/metaprogramming (like in C++). Without them, I find writing generic high-perf data structures quite tedious (and proc macros just aren't a suitable replacement for generics)
- It has the best parts of C (code generation is predictable, no mandatory extra thread for GC or similar, interoperates very well with C code)
- It also has some of the niceties that were popularized after C (type inference, an equivalent of unions that isn't terrible, macros that are not terrible, functional features)
- The thread safety stuff. Async has issues, but the core thread safety constructs (send, sync, mutex vs atomic, etc) are just so well designed that rust is by far my favorite language for writing synchronous, shared-memory threaded code. It's quite possible to mess it up, but it's far easier to keep that system in my head than any comparable one that I've used. Of course shared-nothing is even easier, and rust lets you do that too!
I don't use it for everything, but when I do encounter a thing rust is good at, it's just a treat.
And it's possible the lack of higher kinded types, forcing reimplementation, actually gave the opportunity to look for frindlier names.
There are some ways to get around it, by simulation and using ‘as’ but it isn’t particularly safe.
No experience with haskell - sometimes I try and learn it and give up when stack complains about version conflicts - but regardless I try not to get too many hangups about functions not being super generic, just that they are there when I need them.
and
> As we noted in the original announcement, our goal is not to convert existing C/C++ to Rust, but rather to shift development of new code to memory safe languages over time.
For those working on C/C++ code bases, how does the incremental addition of Rust work in practice? What strategies and tools come in handy? Also, what are some good case studies where Rust was introduced to add new features, but still needed to work within a system mainly composed of C/C++? I've seen some of the first steps with Linux, but I'm thinking of a project where more substantial additions have been made.
Many informal rules of C libraries like: "don't call read() after close()", "pointer must never be null", or "keep this data alive for as long as the handle is in use" in Rust can be expressed using the type system, and enforced at compile time. Cleanup can be automated. This catches bugs in user code and shields the library form misuse.
An informal rule would be “don’t use gets” before it was deprecated, or “don’t use the str* functions”, or “don’t pass a user-provided format to printf”.
The most famous example of that is AFAIK Firefox. There's a (perhaps outdated) list at https://wiki.mozilla.org/Oxidation#Rust_Components of places where Rust was used to replace some component in Firefox; the most famous of these are probably the CSS style calculation which came from the Servo project (https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-en...), and a renderer also from the Servo project (https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-f...).
Brave is definitely not aiming to convert the entire browser to Rust, but it's increasingly chosen for new development.
[1] https://cxx.rs/
I can tell you that bad programmers can write bad code in Rust.
Of course. The question rust users seem to put forth is that bad programmers write _better_ (not good) rust code than C code.
That bad programmers write bad code is to expected. That is, after all, a likely explanation for why they're bad.
Perhaps this is an obvious point, but I found it interesting .
This probably also applies to the Linux kernal work in Rust too; if only new device drivers get written in Rust and the core remains C, it could still be a major win for kernel security.
> how does the incremental addition of Rust work in practice?
Probably a good starting point: https://firefox-source-docs.mozilla.org/writing-rust-code/cp...
I think folks who write languages should have a typographer on their team because something like this:
use std::collections::HashMap
Is a typographic nightmare. While I understand “form follows function”, it’s tough to be excited to program in something like this.
But that use statement is not a good example of it, and if that's the biggest criticism then Rust is faring fantastically well.
https://dwrensha.github.io/capnproto-rust/2022/11/30/out_of_...
Another explanation is that fuzzing is generally expensive and it's easier to focus on unsafe parts of Rust programs than whole C++ programs.
That said, there are a ton of ways that auditing for vulnerabilities is just as easy or way easier. In particular, most tooling for C/C++ can be applied to rust - fuzzers and sanitizers, for example. Additionally, one only has to "grep for unsafe" and work from there to find Rust vulns, which largely amounts to "what are the assertions for this unsafe block, are they complete, are they held?".
Most of the graphs here are about new code.
[1]: https://security.googleblog.com/2021/04/rust-in-android-plat...
> As Android migrates away from C/C++ to Java/Kotlin/Rust, we expect the number of memory safety vulnerabilities to continue to fall. Here’s to a future where memory corruption bugs on Android are rare!