Managed vs. Unmanaged C: Increasing Security and Reliability of Embedded Applications
Security and reliability are both crucial components of any trustworthy system. Building an embedded application that is both secure and reliable is difficult because it is likely to be written in C or C++ language. Even after so many years, C and C++ remain the preferred language for embedded software development. The C or C++ program execution is called “unmanaged,” which means execution is not managed by any runtime.
Typically, in the “managed” world, an environment commonly referred to as “runtime” is responsible for compiling the code into machine code and then executing it. Further, the runtime also provides several important services, such as automatic memory management, security boundaries, type safety, etc. But such protections are only available for high-level programming languages, such as .NET framework and its runtime, CLR.
In contrast, unmanaged code is executed by the operating system and runs directly on the underlying hardware. Everything else, from memory management to security considerations, are the burden of the programmer.
How to increase the security of embedded applications?
Security risks come from adversaries who are actively trying to exploit system vulnerabilities. When designing for security, it has to be assumed that an adversary could be trying to make things go wrong at any point. Here are key elements to consider:
- Simplicity in design
Keeping system design as simple as possible is one of the best ways to improve the security of a system. A simpler design reduces the attack surface and decreases the potential for unanticipated system interactions.
- Secure boot
Secure boot is a feature where the system validates the device boots using only software that is trusted by the equipment manufacturer. It leverages the signature provided by a device trust anchor, the public part of the root of the public key infrastructure (PKI) used to sign the device code. When the embedded system boots, the boot image will be validated using this public key and the corresponding trust chain to ensure that boot-time software has not been tampered with.
- Usage of HSM
A hardware security module (HSM) handles encryption and decryption tasks as well as embeds OS and application management. These modules traditionally come in the form of a system-on-a-chip or plug-in card that attaches directly to an embedded system. During manufacturing, a private key can be generated on a chip or injected into each chip to serve as a root of trust. When the private key is certified by a public key infrastructure or PKI, the secure device identifier can become a foundational component of trusted device connectivity.
How to improve the reliability of embedded applications?
The primary reliability risks are not malicious in nature—for example, a physical device failure. When designing for reliability, it has to be assumed that things can go wrong at some point in time. There are plenty of techniques that a programmer can adapt to make the embedded application reliable:
- Implementation of failsafe
In embedded coding, the programmer is in charge of almost everything. Hence, it is important to implement an adequate failsafe mechanism for all possible system failures to avoid irrational behavior when an error occurs.
- Check for data integrity
It is important to check the integrity of the critical variables and data structures for an extended run time. This can be achieved by keeping a CRC or checksum in the memory and verifying the status periodically.
- Avoid dynamic memory allocation
Typical embedded systems don’t have the bandwidth to afford fragmented memory. Dynamic allocation of memory can lead to memory leakage in such resource-constrained embedded systems and hence should be avoided.
- Use of memory protection unit
The memory protection unit, often referred to as the MPU, is an optional component present in many ARM-based microcontrollers. The MPU is used to separate sections in memory by setting local permissions and attributes. This mechanism has several uses in real-life scenarios, such as preventing access to the memory when the CPU is running in user mode or preventing fetching code to execute from writable locations in RAM. When the MPU is enabled, it enforces the rules by triggering a memory exception interrupt when those are violated.
- Use of watchdog
Most modern microprocessors support a watchdog timer to provide the ability to recover from certain types of system hangs. It can identify software freezes within a few milliseconds and reset the system appropriately, preventing further system failure.
Security and reliability have a lot in common—both are inherent properties of all information systems that are tempting to sacrifice initially but costly to fix later. Despite the hopes and the optimism of the developers, embedded systems can shake their faith in microcontrollers. Every bit and byte requires maintenance and meticulous dedication to ensure that, over time, the software runs correctly and securely with the associated hardware. These few methods might not be sufficient to design for security and reliability; based on the criticality of security and reliability, other appropriate methods must be chosen.
About the Author
Specialist in automotive software with 12 years of experience in application and middleware development for software-defined vehicle, intelligent automotive lighting, digital instrument clusters, in-vehicle infotainment and navigation systems.