Playing it safe: Safe programming with Rust

If you look at the history of system programming over the last few decades, with dominating programming languages ​​such as C or C ++, one thing above all stands out: freedom from errors or information security are often only viewed after the implementation of an application or as process issues.

High test coverage and the use of static code analysis are recommended or prescribed, particularly for applications that have to meet standards for safety-critical systems. This is the case, for example, in medical technology or in banking and finance.

This article comes from the new iX Developer special issue “Developing Safe Software”. On 156 pages it covers topics such as web application security, code analysis and cloud security.

The focus on the programming languages ​​shows the security concepts of Rust and another article helps to detect and avoid memory errors in C ++. Those who develop with Java will find an overview of the changes to the security from Java 11 to Java 17.

The subject area of ​​cryptography goes from the basics to the pitfalls when integrating cryptographic procedures in your own applications to the outlook on post-quantum cryptography. Another focus of DevSecOps shows methods, tools and maturity models.

The magazine is now available in the heise shop as a PDF for 12.99 euros. The printed version can be pre-ordered for 14.90 euros. A bundle of printed output plus PDF is also available.

One of the reasons for such recommendations and specifications is to be found in the programming languages ​​used. Both C and the downward compatible C ++ allow their constructs to be used in such a way that they can lead to undefined behavior of a program (see Listing 1).

int main() {
    unsigned long a[1];
    a[3] = 0xaaaabbbbdeadbeefUL;
    return 0;
}

Listing 1: Syntax highlighting in C

This standard-compliant, but obviously faulty example can be translated into an executable program and executed by any C / C ++ compiler. The behavior of the program is undefined according to the C / C ++ standard:

“Undefined Behavior: Behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements.” (From the specification: ISO / IEC 9899: 2018, Chapter 3.)

Implementations of these standards are free to choose how they deal with undefined behavior. In the best case, the compiler recognizes the danger and issues a warning or even an error, or, as in most cases, nothing happens. This opens the door to unintentional errors and security loopholes, which are all the more important in our highly networked world, as you can see from the (IT) news almost every day.

This is often where the time comes for tools for static code analysis that are able to detect such errors. However, these tools are usually quite expensive to purchase and first have to be integrated into the development process at great expense. In principle, they do not recognize all potential errors by far.

It would make more sense to design a system programming language from the outset in such a way that it largely prevents undefined behavior. With this claim, the Rust programming language has been promoted by an international open source community since 2010. Initially started as a project by the developer Graydon Hoare at Mozilla Corporation and supported by them, the language is now enjoying growing popularity. Big players like Microsoft or Amazon also use and support Rust.

From the very beginning, the aim of developing Rust was to develop a programming language that would bring the issues of safety (safety), speed (performance) and concurrency under one roof, while remaining as user-friendly as possible. To achieve these goals, Rust implements various concepts that will be considered in more detail below.