The history of computing has pursued speed, power, and accessibility. In the early days, machines like the DEC PDP-1, CDC 1604, and Honeywell 800, with their meagre memory capacities, were largely the domain of a few computer scientists. In 2023, computer programming is no longer confined to exclusive experts. Tech has become a booming enterprise like no other industry before it and lowering the barrier of entry to programming jobs has facilitated this growth. However, traditional computer languages such as C and C++ still require deep underlying knowledge of allocating CPU and RAM.
This article reviews what memory-safe languages are, their growing importance in the context of contemporary software development, and their ability to improve security and make development operations more efficient.
A memory-safe language is a language where memory allocation and deallocation (aka "garbage collection") are handled by the programming language itself, removing the responsibility from the programmer. The most popular memory-insecure languages, C and C++, were developed with a focus on performance, prioritizing speed and efficiency over safety. At the time of their development cyber attacks were few and far between.
These languages provide programmers with direct access to memory, which allows for optimal control but opens the door to errors in memory management. Combining the vulnerability of memory-insecure languages with a pressing appetite for computer programmers creates a high potential for memory-based vulnerabilities like buffer overflows and dangling pointers.
In the mid-1990s the concept of memory safety gained widespread recognition, and progressively, the increasing demand for software programmers led to higher-level languages that are easier to learn, can be used to develop applications faster, and have built-in memory management features.
Some of the most popular memory-safe languages today include:
Java: The concept of memory safety emerged with the release of Java in the mid-1990s. Java enforces strict memory safety, making it a popular choice for secure and scalable cross-platform software development
Python: Python is a high-level, interpreted language, and while it offers many advantages in terms of fast development, ease of use, versatility, and memory safety, these benefits often come at the cost of raw performance. Python has a high adoption rate, but it may not be the best choice for high-performance applications
Rust: Rust is a Low Level Virtual Machine (LLVM) language meaning that the primary compiler for Rust, rustc, uses LLVM as its backend similar to other high-performance languages such as C, C++, Objective-C, and Ruby, as well as some newer additions to the LLVM language family such as Swift, and Kotlin. LLVM uses multi-pass optimization to transform the human-readable code making it high-performance. If high-performance and built-in memory safety is a top priority Rust is a good choice
Swift: Swift is a memory safe language designed for building iOS, macOS, watchOS, and tvOS applications. As an LLVM language it is high-performance and enforces strict memory safety, reducing the likelihood of vulnerabilities
Kotlin: Kotlin runs on the Java Virtual Machine (JVM), thus integrates with Java, and can also be compiled to JavaScript. Kotlin isn't always adopted specifically for it's memory safety, but it's use for Android development continues to increase in 2023.
Java introduced the idea of automatic memory management through garbage collection, significantly reducing the risk of memory-related vulnerabilities and marking a significant milestone in the evolution of memory-safe languages. So, since the concept of memory safety in a programming language has been around for so long, why would anyone use a memory-insecure language?
The fact is that Java and Python are not as performant as LLVM languages such as C and C++. This is the main reason why developers have continued to use memory-insecure languages.
Memory-insecure languages, due to their lack of built-in safeguards for memory management, are rife with vulnerabilities that can pose significant risks to software systems and data security. Here are some common vulnerabilities associated with memory-insecure languages:
Buffer Overflow: Buffer overflow vulnerabilities occur when a program writes more data to a memory buffer (like an array) than it can hold, leading to overwriting adjacent memory locations. This can allow attackers to execute arbitrary code, potentially leading to system compromise
Dangling Pointer: Dangling pointers occur when a pointer continues to reference a memory location after the memory it points to has been deallocated (freed) or has gone out of scope. In other words, the pointer "dangles" because it no longer points to a valid object or memory location. Dangling pointers often lead to unpredictable behavior, which means that the program crashes, data becomes corrupted, or other potential security vulnerabilities
Use After Free (UAF): In memory insecure languages, it's possible to continue using memory after it has been deallocated (freed). UAF is a form of dangling pointer where a pointer is dereferenced (used) after the memory it points to has been freed. This can result in crashes, data corruption, or, in some cases, exploitation by attackers to gain control of a program
Null Pointer Dereference: Memory insecure languages often lack mechanisms to handle null or uninitialized pointers. Dereferencing a null pointer typically leads to an immediate runtime error, such as a segmentation fault or access violation. It happens because the pointer does not point to a valid memory location but instead contains the null value
Memory Leaks: Failing to deallocate memory properly in these languages can result in memory leaks, where memory is not released even after it's no longer needed. Over time, this can lead to resource exhaustion and system instability.
Arbitrary Code Execution: Vulnerabilities in memory-insecure languages can enable attackers to inject and execute arbitrary code within a program's memory space, potentially compromising the entire system
Stack and Heap Overflows: Stack and heap overflows occur when a program exceeds the memory limits allocated for its stack or heap, potentially leading to crashes or code execution exploits
Memory-safe languages prevent memory-based vulnerabilities by automatically managing RAM instead of relying on the programmer. While early computer languages like C and C++ offer raw performance, they require more experienced developers and lack inherent security features, making them susceptible to memory-based vulnerabilities.
The emergence of modern languages such as Java, Python, Rust, Swift, and Kotlin means that developers can worry less about memory safety in their applications. In some cases memory memory-safe languages are also vastly easier to use such as Python, allowing less skilled developers to compete in application design. At the same time, Rust and Swift are memory-safe and still a very high-performance LLVM-based language that requires highly skilled developers.
Reach out to our team today or sign up for our newsletter to stay up-to-date on the latest cybersecurity resources, trends, and news.
October 24 - Blog
Packetlabs is thrilled to have been a part of SecTor 2024. Learn more about our top takeaway's from this year's Black Hat event.
September 27 - Blog
InfoStealer malware plays a key role in many cyber attacks, enabling extortion and lateral movement via stolen credentials. Learn the fundamentals about InfoStealers in this article.
September 26 - Blog
Blackwood APT uses AiTM attacks that are set to target software updates. Is your organization prepared? Learn more in today's blog.
© 2024 Packetlabs. All rights reserved.