I highly recommend reading the article from the Android Security team that the original post linked. In particular, the article focuses on a “near-miss” where they almost shipped one (1) memory safety vulnerability in Rust:
This near-miss inevitably raises the question: “If Rust can have memory safety vulnerabilities, then what’s the point?”
The point is that the density is drastically lower. So much lower that it represents a major shift in security posture. Based on our near-miss, we can make a conservative estimate. With roughly 5 million lines of Rust in the Android platform and one potential memory safety vulnerability found (and fixed pre-release), our estimated vulnerability density for Rust is 0.2 vuln per 1 million lines (MLOC)
Our historical data for C and C++ shows a density of closer to 1,000 memory safety vulnerabilities per MLOC. Our Rust code is currently tracking at a density orders of magnitude lower: a more than 1000x reduction.
…
The primary security concern regarding Rust generally centers on the approximately 4% of code written within
unsafe{}blocks. This subset of Rust has fueled significant speculation, misconceptions, and even theories that unsafe Rust might be more buggy than C. Empirical evidence shows this to be quite wrong.Our data indicates that even a more conservative assumption, that a line of unsafe Rust is as likely to have a bug as a line of C or C++, significantly overestimates the risk of unsafe Rust. We don’t know for sure why this is the case, but there are likely several contributing factors:
- unsafe{} doesn’t actually disable all or even most of Rust’s safety checks (a common misconception).
- The practice of encapsulation enables local reasoning about safety invariants.
- The additional scrutiny that unsafe{} blocks receive.
I totally understand the concern but there’s so many big old C(++) projects that have integrated Rust and “safety of the bindings” is an obvious concern everyone has and it just… doesn’t end up being that big of a deal in practice?
In practical specific terms, it’s often reported that Rust often makes implicit ownership/lifetime constraints in C APIs explicit and easier to work with. The Rust bindings to C functions can include lifetimes that enforce these contracts (and yes a lot of C APIs map onto lifetimes and ownership well).