RustIEC is a VLAIO TETRA project (grant HBC.2021.0066) with the goal of teaching Flanders' companies proficiency in the Rust programming language. The project has a specific focus on secure IoT systems, secure edge computing, and secure cloud computing.
Problems with memory, such as memory leaks, buffer overflows, and memory dumps, are well-known issues with software that could be exploited by attackers. The amount of cyber attacks increases year after year. Not only large companies, but also smaller companies are more often the target of attacks, and could face severe consequences.
With most programming languages like C and C++, these issues with memory management are noticed late, usually during runtime. They might not appear during compilation or debugging. When these problems only become apparent in production, they can lead to great damage. The search to their root cause can also be time consuming.
The Rust programming language provides an adequate answer. The compiler will not allow the developer to write unsafe code. Inherently by its design, the amount of mistakes in written Rust code is lower. As a consequence, mistakes are more often avoided by their conception, which makes maintenance of software easier. Rust allows, at the same time, to write performant code. This programming language is well-documented, and many libraries are available for embedded systems as well as for regular platforms.
The most important goal of this project is to acquiant companies with the advantages that Rust could provide them, such that they can make the trade-off of using Rust for future projects for themselves.
We envision these results:
- Two complete case-studies, for which the code will be shared openly.
- Benchmarks made for comparing the performance of Rust and more mainsteram programming languages such as C, C++ and Python, for some frequent and representative algorithms in the IoT and security domains.
- Research to interoperability of Rust with other programming languages and the portability to other platforms.
- Research of the efficiency of conversion tools surch as C2Rust and CRUST.
- Organisation of one introductory and one more advanced hands-on workshop about learning Rust, and publishing the workshop material.
- Integrating the gained knowledge in at least three courses for both research institutions.
Kris Steenhaut (Vrije Universiteit Brussel) has been guiding the ETRO/IRIS/Smartnets group since 2005. Her research activities focus on the design, implementation and experimental evaluation of Wireless Sensor Networks and their integration in the Internet and the Word Wide Web. Topics of particular attention are interoperability, security and privacy as well as the interworking with fog and cloud. Kris Steenhaut has guided several ITEA and SBO projects and several EU projects on Internet of Things, smart grid, smart lighting and environmental monitoring. She plays an active role in development cooperation with Cuba and Vietnam.
An Braeken (Vrije Universiteit Brussel) became professor in 2007 at the Erasmushogeschool Brussel (currently since 2013, Vrije Universiteit Brussel) in the Industrial Sciences Department. Her current interests include security and privacy protocols for IoT, cloud and fog, blockchain and 5G security. She has cooperated and coordinated more than 12 national and international projects.
Jorn Lapon (KU Leuven) is a Research Manager in Secure Software of the DistriNet Research Group of KU Leuven located in Gent. He has been active in both industry and academics and obtained his PhD on Anonymous Credential Systems back in 2012. Topics of particular interest are IoT security, with a focus on secure development and security testing. His close collaboration with industry has proven to be valuable for both the companies and academic research.
Stijn Volckaert (KU Leuven) is een assistant professor bij imec-DistriNet, KU Leuven - Technology Campus Ghent. Zijn onderzoek focust op exploit mitigation, software diversity, multi-variant execution en geautomatiseerd overzetten van legacy code naar veilige programmeertalen.
Ruben De Smet (Vrije Universiteit Brussel) has been actively developing in Rust since 2016, and has contributed to multiple Rust "crates", among which in the asynchronous ecosystem, the cryptographic ecosystem, and the "qmetaobject" library. He co-maintains a set of Signal libraries and develops a Signal client in Rust. For his PhD research, he works on a peer-to-peer application. Ruben joined the Belgium Rust User Group in 2017, and has been organiser of this group since 2020.
Diana Deac (Vrije Universiteit Brussel) recently started developing in Rust after working with Contiki-NG which is written in the C programming language. She designed an adaptive scheduler for Time Slotted Channel Hopping (TSCH) for Contiki-NG. She is currently working on implementing the RPL protocol in Rust. The focus of her PhD research is enhancing protocols for wireless sensor networks with security in mind.
Thibaut Vandervelden (Vrije Universiteit Brussel) is a Rust crate contributor since 2019. His main focus is writing software for embedded devices that use low power wireless communication protocols, such as IEEE802.15.4. He has contributed to the smoltcp crate, where he implemented the 6LoWPAN protocol and is currently working on a RPL protocol implementation. The performance of the Rust programming language on embedded devices is the focus of his PhD research.
Robrecht Blancquaert (Vrije Universiteit Brussel) focusses on fast, safe implementations of elliptic curves for low-power embedded devices, with automatic specialisation for different CPU architectures.
Alicia Andries (KU Leuven) is a PhD researcher at the imec-DistriNet research group of KU Leuven under supervision of Stijn Volckaert. She werks on semi-automatic migration of code in unsafe programming languages to safer alternatives, such as Rust. For example, she works on translating drivers to Rust, researching the current limitations of automatic migration tools, and she researches Rust for Linux.
Part of the RustIEC project goal is the organisation of at least one introductory and two advanced hands-on workshops about learning Rust.
RustIEC 101 is our introductory Rust course, based on the A-modules of the "101-rs" course by Tweede Golf. The materials are available at https://101.rustiec.be/, and the source code is available at https://gitlab.com/etrovub/smartnets/rustiec-101/.
This course will be taught in the form of two workshops on:
- March 14 2023 on the VUB campus;
- March 27 2023 on the VUB campus;
- March 28 2023 on the VUB campus;
with a total expected participant count of 35.
The second part of the RustIEC 101 course teaches more advanced features of the Rust language.
- September 13 2023 on the VUB campus;
- October 19 2023 on the Barco campus;
For questions that are directly related to the study area of one of the collaborators or contributors, feel free to directly contact the relevant team members.
Would you have interest in joining the project with your company, you can contact An Braeken, on firstname.lastname@example.org.
For questions pertaining to the content of the project, you can directly contact the collaborators and contributors.
For questions regarding cloud or web technology, or for asynchronous programming, you may contact Ruben De Smet on email@example.com.
For questions regarding embedded programming, you can contact Thibaut Vandervelden and Diana Deac
For questions pertaining to automatic translation or Linux kernel development, you can contact Stijn Volckaert en Alicia Andries.
Welcome to the first newsletter for the RustIEC project. First, we would like to thank the participants of the first Rust Hands-On workshop, for which we received very good and insightful feedback. In September, the second session of this Rust Hands-On workshop will take place. Based on the results of the questionnaire, we decided that a specialized workshop at a later date will be focussed on embedded programming uisng Rust.
In this newsletter, we provide you with updates on the progress made by the RustIEC teams.
The VUB team is currently finishing the implementation and evaluation of the Routing Protocol for Low-power and lossy networks called RPL. The implementation is written in Rust and added to the smoltcp TCP/IP library, a lightweight TCP/IP protocol stack. As an embedded operating system, we used the Embassy framework. Both are written in the Rust programming language.
Figure 1: Protocol and application stack of Embassy with smoltcp and Contiki-NG.
We used a simulator to evaluate the correctness of the RPL implementation, as a first step. Afterwards, real devices were employed, specifically the nRF52840 development kit. The network under evaluation consisted of devices running the smoltcp RPL implementation with the Embassy framework and devices running the well-established Contiki-NG RPL implementation, written in C, which is part of the Contiki-NG operating system. Figure 1 illustrates the protocol stacks for both smoltcp and Contiki-NG.
The testbed comprised of three nodes, as depicted in Figure 2. One of the nodes served as the root, another acted as a router, and the third operated as a leaf node. Multiple setups were evaluated, combining the Contiki-NG implementation with the smoltcp implementation. This approach aimed to test the compatibility of the Rust RPL implementation against an existing RPL implementation written in C.
Figure 2: Testbed of nRF52840-DK's running smoltcp and Contiki-NG.
The Rust-based RPL with smoltcp is robust, but requires 145.5 KB of flash memory, whereas RPL with Contiki-NG in C requires 47.7 KB. The firmware without RPL requires 117.3 KB for smoltcp and 38.1 KB for Contiki-NG. However, it is important to note that this Rust implementation is a first iteration, leaving ample room for optimization and further refinement.
The VUB team worked, in collaboration with a master student, on the implementation of the Generic Header Compression (GHC) protocol. This protocol serves as an extension of the 6LoWPAN adaptation layer for IPv6. The implementation was also added to the Rust smoltcp library. After the evaluation, they concluded that GHC demonstrates its utility primarily in specific scenarios. IPv6 addresses are part of the dictionary used in the compression algorithm, resulting in only being efficient when the payload to be compressed contains IPv6 addresses.
The VUB team is now focussing on researching how to implement the Data Link layer in Rust for embedded devices, more specifically, Medium Access Protocols (MAC) such as Carrier Sense Multiple Access (CSMA) and Time Slotted Channel Hopping (TSCH). When these protocols are implemented in Rust, a full stack in a safe programming language is available for devices using the IEEE 802.15.4 standard.
The KU Leuven team finished their case study of the Rust for Linux kernel. They successfully made a prototype of a parallel port driver in Rust and have learned some important lessons on the interoperability of C and Rust. For example, you should consider the kind of security features you added to the C code, and whether they ought to be added to the Rust code. Domen Puncen Kugler has uncovered some interesting examples of this. Also, if you translate a part of your C code base to Rust you will have to use a lot of unsafe calls to be able to interact with the C code from the new Rust code. It is important to wrap such unsafe functions in safe ones that can do memory safety checks before simply letting Rust code use a pointer that was provided by C code. While the KU Leuven team may have set aside their study of the Rust for Linux kernel for the time being, they are keeping an eye on significant developments. For example, the further Rust integrations into the mainline Linux kernel with the release of kernel version 6.2. The Rust integrations for this version are mostly low-level support code. It will still be quite a long time before any substantial Rust driver will be supported by the mainline kernel.
The KU Leuven team is currently evaluating the state-of-the-art on automatically translating C into safe Rust. The three publications of particular interest are Mehmet Emre et al.’s OOPSLA 2021 paper "Translating C to Safer Rust", Bryan Tan Yao Hong’s MSc thesis entitled "From C Towards Idiomatic & Safer Rust Through Constraints-Guided Refactoring", and Hanliang Zhang et al.'s VAC 2023 paper "Ownership guided C to Rust translation" They discussed the two first papers at the previous user group meeting. All three publications have very distinct techniques for transforming C to safe Rust, but they all use C2Rust by Immunant as a stepping stone as it can generate non-idiomatic unsafe Rust from C code. C2Rust does not aid in making a program safer or proving a program was safe in the first place. All it was built to do is make a syntactical translation. However, this syntactical translation does already remove a first hurdle for anyone trying to generate idiomatic Rust code from C code.
Because all three publications do use C2Rust, the start of their workflow is very similar. They all follow the workflow shown in Figure 3. They first use C2Rust to generate unsafe Rust, then they add their own contribution in the Refactoring block. While the papers share a similar workflow for transpiling, they have different ways of evaluating the effectiveness of their tools which makes comparing their different architectures arduous.
Figure 3: overview of the workings of C2Rust.
Mehmet Emre et al.'s architecture is the most straightforward. They simply transform every pointer of a specific type they come across to a Rust reference. If the transformations do not compile, they automatically look at the compiler errors and the proposed fixes and apply those. This is a very aggressive technique. The architecture proposed by Bryan Tan Yao Hong on the contrary, is very precise. They prepare transformations for some very specific cases like transforming array pointers into Rust types. Lastly, Hanliang Zhang et al.'s proposed architecture is based on finding pointers that fit into Rust's ownership model. The basics of the idea are very much like those of Immunant's Ownership Analysis.
After extensive experimentation, the KU Leuven team found that all the designs show promise, but the implementations of these architectures have several fundamental design flaws and shortcomings. The KU Leuven team is currently summarizing the strengths and weaknesses of the designs and will then formulate guidelines and recommendations that should serve as a starting point for a new and improved design.
Rust is a compiled systems programming language, like C and C++. Each language has its own strengths and weaknesses. The following are the advantages (non-exhaustive) of Rust compared to C and C++.
Memory safety: Rust has a strong ownership system and borrow checker that enforces strict rules at compile time, preventing common memory-related errors such as null pointer dereferencing, dangling pointers, and buffer overflows. This can lead to more reliable and secure code.
Zero-cost abstraction: Rust provides high-level abstractions without sacrificing performance. The ownership system allows for fine-grained control over memory allocation and deallocation, and the language includes features like pattern matching, algebraic data types, and type inference that enable expressive code without runtime overhead.
Community and ecosystem: Rust has a growing and active community that values safety, performance, and modern software engineering practices. The Rust ecosystem includes a package manager (Cargo) that simplifies dependency management and makes it easy to integrate third-party libraries.
C compatibility: Rust can be easily integrated with C and C++ code. It provides foreign function interface (FFI) capabilities that allow Rust code to call C functions and vice versa. This makes it feasible to gradually introduce Rust into existing C or C++ projects.
Built-in Testing: Rust has a built-in testing framework that makes it easy to write and run tests. Testing is considered an integral part of Rust development, and the language encourages developers to write tests for their code, promoting a culture of code quality and reliability.
However, Rust also has its own disadvantages (non-exhaustive):
Steep learning curve: Rust has a steeper learning curve compared to C and C++. The ownership system and borrow checker introduce new concepts that may be unfamiliar to developers, especially those who are new to systems programming.
Maturity of the Ecosystem: While Rust's ecosystem is growing rapidly, it may not be as mature as C++'s, which has been around for much longer. C and C++ have well-established libraries and frameworks for various domains, and Rust may still be catching up in certain areas.
Limited Legacy Code Support: C and C++ have a large codebase in existing projects, and Rust's integration with legacy C or C++ code might not be as seamless as using these languages together. There may be additional effort required to interface with existing codebases.
Limited support for some architectures: While Rust supports many architectures, it might have limited support for very niche or specialized platforms compared to C and C++, which have been used in a wide range of environments for a longer period.
It's important to note that while these considerations highlight potential disadvantages of Rust compared to C, Rust brings significant advantages in terms of memory safety, concurrency, and modern language features.
More information about the pros and cons of Rust can be found in Stijn Volckaert's presentation.
The Rust ecosystem is rather young, but grows quickly and contains quite many high-quality tools and libraries ("crates"). We presented an overview of the Rust ecosystem in November 2022, which is hereby summarized.
Cargo, Crates.io, Docs.rs, Lib.rs, Rust Analyzer: Central to the Rust development environment are tools designed to streamline development of Rust code. Cargo is the de facto package manager, automating tasks such as building, testing, and project management. Crates.io functions as the primary repository for Rust packages, facilitating seamless sharing and discovery of libraries. Docs.rs automates documentation generation for crates, while Lib.rs serves as a community-driven catalog for alternative crate exploration. Rust Analyzer offers a sophisticated language server for enhanced IDE features, and ties into several different IDEs.
FFI: c2rust, cbindgen: In the domain of interoperability between Rust and C, c2rust and cbindgen are notable projects. c2rust is a tool expressly designed for the migration from C to Rust, facilitating the conversion of C code to Rust. cbindgen automatically generates C bindings for Rust code, offering communication between Rust and C components.
Rayon, Crossbeam: Parallelism is a cornerstone of Rust's design philosophy, and two libraries, Rayon and Crossbeam, contribute significantly to this paradigm. Rayon simplifies data parallelism, providing an accessible means to craft parallel code. Crossbeam, meanwhile, offers essential low-level building blocks for concurrent programming, addressing synchronization and parallelism requirements.
env_logger, log: In the domain of logging, Rust offers tools such as env_logger and log. The env_logger crate, configurable through environment variables, and log, a flexible logging facade, collectively empower developers to adopt logging practices tailored to specific project requirements. Many other logging backends exist for
logis the de-facto standard libraries.
thiserror, anyhow: Rust's capabilities in error handling are extended through the thiserror and anyhow crates. The thiserror crate provides a straightforward mechanism for defining custom error types, while anyhow offers a versatile framework for handling any error types, simplifying error management within Rust applications.
Serde: Serialization and deserialization are fundamental tasks in software development, and serde stands as Rust's premier library for these operations. Supporting a diverse array of data formats, Serde ensures seamless data exchange within Rust applications through subcrates such as
AreWeAsyncYet.rs, AreWeGameYet.rs, AreWeWebYet.org, AreWeLearningYet.com, ...: Community-driven initiatives, encapsulated in websites like AreWeAsyncYet.rs, AreWeGameYet.rs, AreWeWebYet.org, AreWeLearningYet.com, serve as comprehensive resources tracking Rust's progress across diverse domains. These platforms offer valuable insights into Rust's evolution in areas such as asynchronous programming, game development, web development, learning resources, and community well-being.
Async-Await: Rust introduces language-level features in the form of async-await syntax to facilitate the development of asynchronous code. This syntax enhances code readability and maintains a commitment to the principles of safety and concurrency. A whole ecosystem is being very actively developed around this asynchronous programming paradigm; see below.
Tokio, Mio, Async-std: Asynchronous programming is pivotal in modern software development, and Rust provides robust solutions through Tokio, Mio, and async-std. Mio provides a zero-cost asynchronous I/O library, and serves as the I/O framework for most asynchronous executors. It abstracts away from operating system specific asynchronous APIs, but does not provide async-await integration. Tokio functions as a runtime for asynchronous applications, and provides a whole framework to work with asynchronous I/O with async-await syntax. Async-std offers utilities for asynchronous programming, and serves as an alternative to the now more popular Tokio. Collectively, these crates empower developers to build efficient and scalable systems
Hyper, Actix-Web: For web development in Rust, libraries such as Hyper and frameworks like Actix-Web play essential roles. Hyper offers a fast and low-level HTTP implementation both at client and server side. Actix-Web is a powerful and ergonomic web framework. Both projects are built on top of the asynchronous Tokio framework.
Wasm-Pack, Yew: In the context of WebAssembly (WASM) and web development, Rust is one of the major go-to languages. Rust offers tools such as wasm-pack. This utility streamlines the building and integration of WebAssembly projects. Yew, a Rust framework tailored for client-side web applications, leverages the power of Rust and WebAssembly to deliver a seamless and performant web development experience.
In summary, the Rust ecosystem boasts a collection of sophisticated tools and libraries that collectively enhance the development experience, addressing a wide spectrum of programming needs. These tools and libraries were presented during our kick-off meeting, during the "ecosystem" presentation, which was presented by Ruben and Thibaut.
Rust and C are compiled languages that use the LLVM code generation tool, implying comparable runtime speed and memory usage. However, due to differences in programming styles, it's challenging to make assertions about their performance. Various Rust language-specific overheads contribute to this complexity:
- In Rust, slices and str are represented by a pointer and the element count. When passed to a function, both the pointer and element count are transmitted. In contrast, C might only require a pointer, assuming the size is known or inferred from context.
- Bound checks are inserted by the compiler when indexing an array. In most cases, these bound checks can be optimized out by the compiler. This can prohibit the compiler to do autovectorization of some operations.
- In some cases, the Rust borrow checker is too strict, simply because that edge case is not implemented by the compiler. For these cases, adding copies or use reference counting is the solution. Lukely, there are very few edge cases where this is necassery.
- Using generics in Rust can potentially increase the executable size, as the compiler generates optimized functions for each type used with a generic function, leading to multiple instances in the binary.
Rust also has places where it ends up being more efficient and faster than C:
- Struct fields are reordered to minimize padding, enhancing memory utilization.
- Rust is good in inlining functions, even those from dependencies.
- Rust makes optimized versions of generic implementations, like C++ templates.
This is not possible with C, where macros need to be used or less efficient implementations with
- Rust enforces thread-safety, even for dependencies.
We also ran our own benchmarks, benchmarking 3 sorting algorithms written in Rust and in C. These algorithms were implemented in a straightforward manner, without any specific focus on code optimization. Utilizing Criterion, a benchmarking tool in Rust, we performed multiple runs of sorting arrays with random data across various sizes. The benchmarks ran on an HP EliteBook 745 G6 running Fedora 39. The following graphs depict the performance of each sorting algorithm's Rust implementation, its C counterpart, and the built-in standard library sorting function.
For Bubble sort, the compiler is unable to optimize all bound checks for indexing arrays. Note that we consider this as an optimization that is missed by the compiler. The Rust compiler still has places where optimizations are lacking.
Performance of Quick sort is around equal for the Rust and C implementations.
For the Heap sort implementation, the Rust version is faster than the C implementation.
Comparing the performance of Rust and C can be challenging since both are compiled languages sharing the same compiler backend (LLVM). While a comparison using the GCC compiler for C is possible, it introduces a comparison between GCC and LLVM rather than a comparison between the languages themselves.
Note that Rust has a rich standard library.
Sorting anything that is sortable can be achieved by just calling the
This feature contributes to Rust's rich and user-friendly programming environment.