Transitioning to memory-safe languages: Challenges and considerations
In this Help Net Security interview, Omkhar Arasaratnam, General Manager at the Open Source Security Foundation (OpenSSF), discusses the evolution of memory-safe programming languages and their emergence in response to the limitations of languages like C and C++.
Memory safety concerns, prevailing for over five decades, involve abstracting programmers from memory management tasks. Modern languages like Java, Rust, Python, and JavaScript alleviate these concerns by handling memory management on behalf of the programmer, thereby allowing a focus on code quality without the risks associated with low-level memory management.
Can you discuss the evolution of memory-safe programming languages? How have they emerged as a response to the limitations of languages like C and C++ in terms of memory safety?
Concerns regarding memory safety have been around for more than 50 years. Memory safety involves abstracting the programmer from detailed memory management functions, which are difficult to perform safely.
For example, in C or C++, programmers have to allocate and deallocate memory, which can be complex to manage. They must track how much memory they allocate and ensure that only appropriately allocated memory is used. Once that memory is no longer required, the programmer must dispose of it safely. Languages like Java, Rust, Python, and JavaScript prevent the programmer from being “memory unsafe” as they handle the nuance of memory management on the programmer’s behalf.
What are the primary advantages of using memory-safe languages in software development, especially in high-stakes environments like system programming or kernel development?
An operating system kernel runs with complete authority over the entire system. This means security issues such as unsafe memory handling can harm the whole system’s security.
While it’s possible for a developer to precisely use memory-unsafe languages like C or C++ without causing memory safety issues, history has shown us otherwise. Microsoft estimated that 70% of CVEs in their products were rooted in memory safety issues. Google conducted a similar study and found that 90% of Android CVEs could be correlated to memory safety.
Go, Python, Rust, and Java are excellent examples of memory-safe languages. Unfortunately, not all of these languages can be used for kernel development. Rust is on its way to becoming the second official language supported in the Linux kernel. Once this is complete, it will allow Linux kernel developers to rewrite sensitive portions of the kernel in a fully memory-safe language.
What challenges do developers and organizations face when transitioning to memory-safe languages, particularly in legacy systems?
When transitioning to memory-safe languages, several issues must be considered:
1. Developers — When transitioning to a new language, you need to educate your existing developers or find ones who are familiar with it. You may also need to change your debug and build systems to support it.
2. Hardware support — Older languages like C and C++ are supported on a wide variety of different platforms, whereas newer languages like Rust have more limited support. A lack of hardware support may prevent you from transitioning to this new language.
3. Regulatory requirements — Some safety-critical systems have very stringent technical or safety requirements that may preclude switching to a new memory-safe language due to a lack of assurance or certification.
4. Bugs — Refactoring old code into a new language may introduce bugs. In some cases, while adept programmers may avoid introducing new logic errors, old code rewritten in a new language may unintentionally behave differently, resulting in unexpected errors in production.
In practical terms, how can existing codebases in languages like C/C++ be incrementally adapted or rewritten to leverage the benefits of memory-safe languages?
Rewriting code in Rust is a significant task. We acknowledged this challenge when OpenSSF responded to the ONCD Request for Information last year. We don’t believe the answer is to rewrite everything in Rust.
We encourage the community to consider writing in Rust when starting new projects. We also recommend Rust for critical code paths, such as areas typically abused or compromised or those holding the “crown jewels.” Great places to start are authentication, authorization, cryptography, and anything that takes input from a network or user.
While adopting memory safety will not fix everything in security overnight, it’s an essential first step. But even the best programmers make memory safety errors when using languages that aren’t inherently memory-safe. By using memory-safe languages, programmers can focus on producing higher-quality code rather than perilously contending with low-level memory management.
However, we must recognize that it’s impossible to rewrite everything overnight. OpenSSF has created a C/C++ Hardening Guide to help programmers make legacy code safer without significantly impacting their existing codebases. Depending on your risk tolerance, this is a less risky path in the short term.
Once your rewrite or rebuild is complete, it’s also essential to consider deployment. Many critical infrastructure industrial control systems are not easily accessible by the corporate network, so redeploying the rewritten code may take longer than the rewrite itself.
What is your perspective on the future of memory-safe programming languages? Do you foresee them becoming the standard in specific sectors, or will there always be a place for traditional languages?
When considering specific industries or sectors, there’s an interesting dichotomy. You don’t want to rush to transition the crucial systems to a new language, but ironically, that is where some of these security properties are most valuable. We don’t know that memory-safe languages will become standard in specific sectors, and some industries will be slower to adopt them as they have more conservative transition requirements for safety or reliability reasons. There is an inverse correlation between system stability and rate of change.
Beginning new projects in memory-safe languages has general-purpose benefits. For example, Alpha-Omega has funded the development of Rustls, a project by Prossimo that aims to implement TLS and QUIC in Rust. By implementing these protocols in a memory-safe language, we can avoid issues like the OpenSSL Heartbleed vulnerability.
How important is the role of education and community support in promoting the adoption of memory-safe languages? What initiatives or resources would you recommend for developers looking to transition?
Education is the best cybersecurity defense we have. Many grade schools have begun teaching Python as a first programming language. In the future, we hope to see other memory-safe languages like Rust introduced at an early age as well.
Additionally, the Rust Foundation provides a handful of tools and materials, including “The Rust Programming Language” — a respected book that provides an overview of Rust. It’s also developing a training and certification program.
Read more:
White House: Use memory-safe programming languages to protect the nation