I sometimes work on the infosec side of the house. It's easy to point at vulnerabilities due to endless memory access problems in C code and fixate on that. And it's true, so it feels satisfying.
Just rewrite everything in not-C and this is fixed! And that's true as well. But remeber here the word "this" refers to the memory access bugs. It doesn't refer to vulnerabilities in that sentence.
Plenty of systems without a single line of C/C++ code and we have no shortage of ways to break in anyway. So in one sense, everything changed. But wearing the black hat, nothing really changed since I compromised the system anyway. A new language without all the engineering process parent post describes, won't magically get there.
For an existing system "just rewrite everything" will guarantee way more bugs for years to come simply because the old system has been battle-tested and reinforced for years. In the long haul the rewrite will converge to a better state but that haul is long (and assumes budget will remain in place long enough, which might not happen so you end up with a half-baked rewrite).
For new systems starting from scratch that may in any way ever be run in a security relevant context, sure, starting with not-C is a good idea today.
Unfortunately Rust seems to be the only alternative for use cases where C was actually needed (if it could be written in Java or Go or Python or ... then it didn't really need to be in C in the first place). And sadly rust is fairly user-hostile language so my guess is plenty of new projects will start with C for a long time due to lack of friendly alternatives. And tooling.
Could you elaborate on that? I started using Rust at the end of last year, and have found it to be one of the most user-friendly languages I've learned. There is clear documentation that is easy to generate with the standard toolchain, along with a very good language guide.
The compiler error messages are an absolute joy as somebody coming from C++. Pointing out exactly where the borrow checker found errors, or exactly what the type signature should be for a trait, is really useful.
For example, in the case of const generics, I've used the equivalent in C++ to make a class for a geometric vector in N dimensions. The size varies depending on the number of elements, but is known and can be checked at compile time. The existence of const generics is very closely matched to this particular use case.
Forcing it down to an overly simplistic setting, if I need to add 5 to a number I can increment 5 times, or add 2 and then 3, or just add 5. Which of those options should we remove?
Perhaps we mean, instead, that there should be one best way, but (sliding into metaphor, I hope) what about when we have a language without 5 and we are considering adding it? Is the use case already handled by 2+3? How are we to decide?
Language wise rust is better the python in every way except for compile times.
Language-wise, it feels like they are intended to solve different problems, so Python vs Rust is a weird comparison. Granted, that may because I started learning Rust as a replacement for C++, so that has been my point of comparison.
Rust seems to me to be user-frienndly, though for the cases where it's safety features are critical and at the fore, it front-loads pain that would be dealt with eventually, which can make it feel intimidating. But its forcing you to confront things that are likely to cause subtle bugs if dealt with sloppy (or overlooked), not actually adding unnecessary complexity.
Rewriting C or C++ applications in Rust won't fix all security problems. But it would be forward progress. It's just like wearing seat belts won't stop people from being injured in car crashes. You could say that "safety isn't a product but a process," which is fine, but if your safety testing process finds that wearing seatbelts reduces injuries substantially it seems pretty obvious that using a seatbelt product is the way forward. At least until someone invents a better replacement for seat belts, or supplements them with other features like airbags, automatic braking systems, self-driving, etc...
True, but if the process discovers that a lot of lives are lost because of the use of unsafe tools, it changes the tools to add safety features (https://en.wikipedia.org/wiki/Chainsaw_safety_features), or ditches them altogether (https://en.wikipedia.org/wiki/Hazard_substitution#Processes_...)
So, yes “rewrite in rust” isn’t the full answer, but that does not imply “don’t write it in C” isn’t part of the answer.
The simple classes of bugs enforced by rust, are also caught fairly quickly with any kind of memory sanitizer (valgrind?), combined with static analysis tools (coverty?), and automated code quality standards (misra). Run a CI/Code coverage monitor while looking for for these kinds of errors, and I would bet the results are actually better than plain rust due to the maturity of some of these tools.
About valgrind or sanitizers: they're runtime, so just like tests they can only show the presence of errors, not their absence. Like dynamic type checking.
IMHO, Rust simply isn't good enough at catching all types of bugs to justify rewrites at this point, and its likely when you look at some of the work being done at the processor manufacturing companies that they don't believe it either.
Consider: https://en.wikichip.org/wiki/arm/mte, https://en.wikipedia.org/wiki/Intel_MPX, and https://lwn.net/Articles/718888/
There are quite a number of these in the pipeline, which make some of what rust does redundant.
Valgrind might not catch 100% of errors, but at least what it catches are actual errors I care about.
If you're writing safety-critical software though, being forced to restructure your code to satisfy the type checker (which, in this case, is kind of a simple proof assistant) seems like a sane tradeoff.
Yes, but do the programming languages / tools we choose make the security process easier?
There is no perfect solution, but some programming languages / tools are better than others for preventing unexpected behavior that can lead to insecure programs.
(Caveat: Obviously 'unsafe' is relevant to this discussion, but at least you only have very small areas of code you need to check extra carefully.)
Security is the process. It contains continuous risk assessment, penetration testing, fuzzing and using various other tools throughout the product development to eliminate attack vectors. Only then you could build a secured product. Just rewriting everything in Rust won't make it.