First, an article from the US National Security Agency: NSA Releases Guidance on How to Protect Against Software Memory Safety Issues:

This article is a translation of two articles. The first is an interpretation of the US National Security Agency's cybersecurity information sheet on "Software Memory Safety". The second explains what memory safety is and why it matters.
Part 1: To Avoid Memory Attacks, the NSA Recommends Rust, C#, Go, Java, Ruby, and Swift, While Setting C and C++ Aside
This article is translated (with the help of Google Translate).
Original author: Liam Tung
Original title: NSA to developers: Think about switching from C and C++ to a memory safe programming language
Original link: https://www.zdnet.com/article/nsa-to-developers-think-about-switching-from-c-and-cpp-to-a-memory-safe-programming-language/

For many developers, this likely means switching to C#, Go, Java, Ruby, Rust, and Swift.
The US National Security Agency (NSA) is urging developers to switch to memory-safe languages—such as C#, Go, Java, Ruby, Rust, and Swift—to protect their code from remote code execution or other hacker attacks.
Among the languages mentioned, Java is the most widely used in enterprise and Android application development, while Swift is in the top 10, partly thanks to iOS app development. In system programming, there is growing attention on Rust as a replacement for C and C++.
"The NSA recommends that organizations consider a strategic shift from programming languages that provide little or no inherent memory protection (such as C/C++) to memory-safe languages where possible. Some examples of memory-safe languages include C#, Go, Java, Ruby, and Swift," the NSA said.
The spy agency cited recent research from Google and Microsoft showing that 70% of their security issues (in Chrome and Windows, respectively) are memory-related, many of which are a result of using C and C++, which are more prone to memory-based vulnerabilities.
Additionally: Cybersecurity, cloud, and coding: Why these three skills will lead demand in 2023
In the NSA Cybersecurity Information Sheet on "Software Memory Safety", it states: "Malicious cyber actors can exploit these vulnerabilities for remote code execution or other adverse effects, which often compromise devices and become the first step in large-scale network intrusions."
"Commonly used languages like C and C++ offer great freedom and flexibility in memory management while heavily relying on programmers to perform the necessary checks on memory references."
Therefore, the agency recommends using memory-safe languages wherever possible, whether for application development or system programming.
"NSA recommends using memory-safe languages whenever possible," it said.
While most information security experts are familiar with the debate over memory-safe languages, perhaps not all developers are. However, given that this is a decades-old problem, they probably should be, as Java creator James Gosling recently noted in a discussion about how and why Java was created.
If nothing else, the NSA document provides a clear, easy-to-understand explanation for developers of the technical reasons behind switching to memory-safe languages. Among memory safety discussions, Rust is arguably the most talked-about language and a prime candidate to replace C and C++.
Following the Android Open Source Project, the Linux kernel recently introduced Rust as a second language alongside C. These projects won't replace old C/C++ code but will prefer Rust for new code. Additionally, Microsoft Azure CTO Mark Russinovich recently called on all developers to use Rust instead of C and C++ for all new projects.
"By leveraging these types of memory issues, malicious actors not subject to the usual constraints of software use may find that they can input unusual data into a program, causing memory to be accessed, written, allocated, or freed in unexpected ways," the NSA explained.
But—as experts have pointed out in the debate over Rust vs. C/C++ —the NSA warns that simply using a memory-safe language does not by default preclude the introduction of memory errors into software. Additionally, languages often allow the use of libraries that are not written in a memory-safe language.
"Even when using memory-safe languages, memory management is not entirely memory-safe. Most memory-safe languages recognize that software sometimes needs to perform unsafe memory management functions to accomplish certain tasks. Therefore, features deemed non-memory-safe are available and allow programmers to perform potentially unsafe memory management tasks," the NSA said.
"Some languages require that anything memory-unsafe be explicitly annotated to make both programmers and any reviewers of the program aware that it is unsafe. Memory-safe languages can also use libraries written in non-memory-safe languages and thus may contain unsafe memory functionality. Although these approaches that incorporate memory-unsafe mechanisms undermine inherent memory safety, they help locate where memory issues may exist, allowing additional scrutiny of those code sections."
Additionally: Cybersecurity: These are the new things to worry about in 2023
The NSA notes that some memory-safe languages may come at a performance cost, requiring developers to learn a new language. It also points out that developers can take some measures to harden non-memory-safe languages. For example, Google's Chrome team is exploring multiple methods to harden C++, but these also incur performance overhead. C++ will remain in Chrome's codebase for the foreseeable future.
The NSA recommends static and dynamic application security testing to uncover memory issues. It also suggests exploring memory hardening methods such as Control Flow Guard (CFG), which restricts where code can execute. Similarly, address space layout randomization (ASLR) and data execution prevention (DEP) are recommended.
Part 2: What Is Memory Safety and Why Does It Matter?
This article is translated (with the help of Google Translate).
Source: https://www.memorysafety.org
Original title: What is memory safety and why does it matter?
Original link: https://www.memorysafety.org/docs/memory-safety/
Memory safety is a property of some programming languages that prevents programmers from introducing certain types of bugs related to how memory is used. Because memory safety vulnerabilities are often security issues, memory-safe languages are more secure than non-memory-safe languages.
Memory-safe languages include Rust, Go, C#, Java, Swift, Python, and JavaScript. Memory-unsafe languages include C, C++, and assembly.
Types of Memory Safety Vulnerabilities
To begin understanding memory safety vulnerabilities, let's consider an example application that maintains to-do lists for many users. We'll look at several of the most common types of memory safety errors that can occur in a memory-unsafe program.
Out-of-Bounds Read and Write
If we have a to-do list with ten items and we ask for the eleventh item, what happens? Obviously we should get some kind of error. We should also get an error if we ask for the negative first item.
In these cases, a memory-unsafe language might allow the program to read whatever memory content happens to exist just before or after the valid content of the list. This is called an out-of-bounds read. The memory before the first item of the list might be the last item of someone else's list. The memory after the last item might be the first item of another person's list. Accessing this memory would be a serious security vulnerability! Programmers can prevent out-of-bounds reads by carefully checking the index of the item they request against the length of the list, but programmers make mistakes. It is better to use a memory-safe language that protects you and your users from such errors by default.
In a memory-safe language, we would get a compile-time error or a runtime crash. A program crash may seem severe, but it's better than allowing users to steal each other's data!
A closely related vulnerability is out-of-bounds write. In this case, suppose we try to modify the eleventh item or the negative first item in the to-do list. Now we're changing someone else's to-do list!
Use-After-Free
Imagine we delete a to-do list and then request the first item of that list. Obviously we should get an error because we shouldn't be able to retrieve items from a deleted list. A memory-unsafe language allows the program to access memory that it has already finished with and that is now available for other uses. The memory location might now contain someone else's to-do list! This is called a use-after-free vulnerability.
How Common Are Memory Safety Vulnerabilities?
Extremely. A recent study found that 60-70% of vulnerabilities in iOS and macOS are memory safety vulnerabilities. Microsoft estimates that over the past decade, 70% of all vulnerabilities in its products are memory safety issues. Google estimates that 90% of Android vulnerabilities are memory safety issues. An analysis of zero-days found to be widely exploited found that over 80% of exploited vulnerabilities were memory safety issues¹.
The 2003 Slammer worm (a measure specifically of software vulnerabilities, not including very common things like credential phishing) was a buffer overflow (out-of-bounds write). So was WannaCry (out-of-bounds write). The Trident vulnerability targeting iPhones exploited three different memory safety vulnerabilities (two use-after-free and one out-of-bounds read). HeartBleed was a memory safety issue (out-of-bounds read). So was Stagefright on Android (out-of-bounds write). The Ghost vulnerability in glibc? You bet (out-of-bounds write).
Because C and C++ are not memory-safe, these vulnerabilities, and the exploitation of others, are made possible. Organizations that write a lot of C and C++ inevitably produce a large number of vulnerabilities directly attributable to lack of memory safety. These weaknesses are exploited, putting hospitals, dissidents, and health policy experts at risk. Using C and C++ is bad for society, bad for your reputation, and bad for your customers.
What Other Problems Are Associated with Memory-Unsafe Languages?
Memory-unsafe languages also negatively impact stability, developer productivity, and application performance.
Because memory-unsafe languages tend to have more bugs and crashes, they can greatly affect application stability. Even if crashes are not security-sensitive, they are still a very poor user experience.
Worse, these bugs are difficult for developers to track down. Memory corruption often causes crashes to occur far from the actual location of the error. When multi-threading is involved, tiny differences in thread timing can trigger other bugs, making errors even harder to reproduce. The result is that developers often have to stare at crash reports for hours to determine the cause of a memory corruption bug. These bugs may go unfixed for months, with developers fully convinced that a bug exists but not knowing how to make progress in finding its cause and fixing it.
Finally, there is performance. Over the past few decades, one could expect CPUs to become faster every year or two. This is no longer the case. Instead, CPUs now come with more cores. To take advantage of additional cores, developers need to write multi-threaded code.
Unfortunately, multi-threading exacerbates problems associated with lack of memory safety, and as a result, efforts to leverage multi-core CPUs in C and C++ are often tricky. For example—before finally (successfully) rewriting the system in multi-threaded Rust, Mozilla attempted multiple times to introduce multi-threading into Firefox's C++ CSS subsystem, all of which failed.
What Is the Right Path Forward?
Use memory-safe languages! There are many great options. Writing an operating system kernel or a web browser? Consider Rust! Building for iOS and macOS? Swift can handle it. Web servers? Go is a good choice. These are just a few examples, and there are many other excellent memory-safe languages to choose from (and many other great use-case pairings!).
Changing the programming language your organization uses is not trivial. It means changing the skills you look for in hiring, retraining your employees, and rewriting a lot of code. Nevertheless, we believe it is necessary in the long run, so we want to illustrate why the alternative of adopting new programming languages has not succeeded.
If we take it as given that using unsafe languages will produce some vulnerabilities, then the question we want to ask is: can we take some techniques to reduce this risk without forcing ourselves to completely change programming languages? The answer is yes. Not all projects written in unsafe languages are equally insecure and unreliable.
Some practices that can reduce the risk of using unsafe languages are:
- Using some modern C++ idioms can help produce safer and more reliable code
- Using fuzzers and sanitizers to help find bugs before they are shipped to production
- Using exploit mitigation techniques to help increase the difficulty of exploiting vulnerabilities
- Privilege separation to reduce the blast radius even if a vulnerability is exploited
These practices meaningfully reduce the risk of using unsafe languages, and if we fail to convince you to switch languages and you intend to continue writing C and C++, adopting these practices is imperative. Unfortunately, they are also severely insufficient.
Browser and operating system developers are at the forefront of developing modern C++ idioms, fuzzers, sanitizers, exploit mitigation, and privilege separation techniques—exactly the groups we highlighted at the beginning with statistics on the prevalence of memory safety issues. Despite their investments in these techniques, their use of unsafe languages holds them back. At the large hacking competition pwn2own in 2019, over half of the exploited vulnerabilities in these products were due to lack of memory safety, and with one exception, every successful attack exploited at least one memory safety vulnerability.
Is It Really Feasible to Give Up C and C++?
Hopefully by now we've convinced you that unsafe languages like C and C++ are the root cause of a large amount of insecurity in our products, and that while there are steps you can take to reduce the risk, you cannot come close to eliminating it. All of this may still feel like changing the programming language you use, with millions of lines of code, is an overwhelming task. By breaking it down into manageable pieces, we can start making progress—our goal is not a big-bang rewrite of the world, but to make progress in reducing risk.
First, there are brand new projects. For these, you can choose to simply use a memory-safe language. These projects have the lowest risk because you don't need to start by rewriting any code, although projects like this often do require improvements to testing or deployment infrastructure to support a new programming language. This is the approach taken by ChromeOS's CrosVM (a brand new component of the operating system).
If you don't have new projects, the next place to look for opportunities to use a memory-safe language is in new components of existing projects. Some memory-safe languages offer first-class support for interoperation with C and C++ codebases (e.g., Rust and Swift). This requires a slightly higher initial investment because it requires integration into the build system, as well as building abstractions for objects and data that need to cross the boundary between the two languages. This strategy was successfully used when WebAuthn was implemented as a new component of Firefox, as well as a project supporting writing Linux kernel modules in Rust.
A common feature of the first two approaches is that they both deal with new code. This has the advantage of well-defined interaction points with existing code, and you can start working without rewriting anything. It also gives you a chance to stop the bleeding: with no new components using unsafe languages, we can gradually handle existing code. For projects that have no natural new components to start using memory-safe languages, the challenge is greater.
In this case, you need to find some existing components to rewrite from an unsafe language to a safe one. Preferably, you choose a component you were already considering rewriting: perhaps for performance, security, or because the code is too difficult to maintain. You should try to choose something as small in scope as possible for your first memory-safe rewrite to help the project succeed and ship quickly; this helps minimize the inherent risk in rewriting. Stylo, the rewrite of Firefox's CSS engine in Rust, is a successful example of this approach.
Regardless of which approach best fits your organization, there are some things to keep in mind to maximize your chances of success. The first is to ensure you have internal champions and senior engineers who can provide code reviews and guidance using a language that is new to many team members. A natural extension of this is to ensure that engineers who will work with the new language have access to resources like books, training, or internal guides. Finally, you need to ensure that the new language has the same shared infrastructure as the old one, such as build systems, testing, deployment, crash reporting, and other integrations.
Conclusion
Adopting a new programming language and beginning the migration process is not easy. It requires planning, resource allocation, and ultimately investment across the organization. Life would be much easier if we didn't have to think about these things. Unfortunately, the review of data clearly shows that we simply cannot consider continuing to use unsafe languages for security-sensitive projects.
Data has proven time and again that projects using unsafe languages like C and C++ suffer from a large number of security vulnerabilities. No matter how talented the engineers, or how much investment in privilege reduction and exploit mitigation, using a memory-unsafe language simply results in too many bugs. These bugs significantly degrade security, stability, and productivity.
Fortunately, we don't have to settle for the status quo. Over the past few years, excellent alternatives to C and C++ have emerged, such as Rust, Swift, and Go. This means we don't have to carry memory corruption vulnerabilities as an albatross around our necks for many years to come, as long as we choose not to. We look forward to a day when choosing to use an unsafe language is considered as negligent as not having multi-factor authentication or not encrypting data in transit.
Thanks to Alex Gaynor
With permission, this explanation is based on Alex Gaynor's blog post An Introduction to Memory Unsafety for VPs of Engineering.
Summary of This Article
I hope you get something from these two translated articles.