The figure below shows the security structure of typical microcontroller embedded software.
There is no structure! A hacker who has gained access to the system, has access to anything he wants, including keys and other secrets. This undermines the security afforded by encryption, authentication, and other security methods employed in modern systems.
This figure shows the ideal partitioning of the same microcontroller embedded software. Each partition is isolated from all of the other partitions. If a hacker gains access to one partition, he is blocked from access to other partitions. What goes on in a partition stays in the partition. The pmode barrier separates unprivileged mode (umode) from privileged mode (pmode). This barrier is hardware-enforced by the processor. Note that the “Vault”, which contains keys and other secrets, is below the pmode barrier and that networking and other I/O partitions are above the pmode barrier. It is impossible for a hacker to break through the pmode barrier from one of these partitions in order to access the Vault.
It should be noted that the complete system partitioning shown above is not likely to be necessary for legacy systems. Often, much less partitioning is needed to achieve security goals. For new systems, full partitioning may or may not be required, depending upon perceived threats. Ordinarily, partitions that interface to the outside world (blue) are considered to be the most vulnerable to hacking. Application partitions (green) are not vulnerable, but it is desirable to keep them safe, since they do the important work. Below the pmode barrier are the most trusted partitions (purple). The exception to this is ISRs, which are there because they must run in pmode. They are vulnerable, but careful code construction and code minimization can make them resistant to hacking.
Steps to achieve isolated partitions
- Effective pmode/umode processor control.
- Efficient, flexible task-based Memory Protection Unit (MPU) control.
- Software Interrupt (SWI) API for system services.
- Multi-heap support.
- Partition portals.
These are discussed below.
The Cortex-v7M and v8M architectures, which are supported by SecureSMX, permit tasks to run in either pmode or umode. When a task is created, its mode is specified. When it is dispatched, the task scheduler switches the processor to umode for utasks and leaves the processor in pmode for ptasks. ptasks can directly access all system services, whereas utasks must use the software interrupt API, as discussed below, to access system services. Hence ptasks must be trusted. When a task is suspended or stops, control reverts to SecureSMX in pmode.
Normally, embedded applications run entirely in pmode, when they are first ported to SecureSMX, since this requires only minor modifications to be made to them. Then vulnerable and untrusted code are moved into isolated umode partitions in order to protect the rest of the system from hacking and from malware.
Memory Protection Unit
The above figure illustrates how a task accesses memory via slots in an MPU. Each slot permits access to a contiguous region of memory having attributes such as ReadWrite, ReadOnly, ExceuteNever, etc. If a task attempts an access outside of or not permitted by its regions, a Memory Manage Fault (MMF) occurs, the task is stopped, and pmode recovery software takes over. This severely clips a hacker’s wings with regard to the common hacking tricks that he might employ – he is tip-toeing in a mine field!
SecureSMX supports secure boot and system initialization in pmode, it then switches to task mode and dispatches tasks running in pmode (ptasks) and tasks running in umode (utasks). Each pmode partition has one or more ptasks; each umode partition has one or more utasks. Every task has its own Memory Protection Array (MPA), which is loaded from an MPA template when the task is created. Typically tasks within a partition share the same template. When a task switch occurs, its MPA is loaded into the MPU. The task is then dispatched to run in umode or pmode.
Software Interrupt (SWI) API
ptasks can directly call system services, which also run in pmode. However, utasks require an SWI API for system services such as waiting at or signaling a semaphore. The SWI API is implemented using the Cortex-M svc n instruction; it causes an SVC exception that results in switching to pmode where the system service is executed. The parameter n selects the system service to perform. The svc instruction is the only way that a utask can penetrate the pmode barrier and then only to run a permitted system service. When the system service completes, the utask is resumed in umode with the return value from the service.
Not only system services but also the structures they use (e.g. task control blocks) reside in pmode and thus are not accessible to a hacker from umode. In addition, services that could cause system damage are not permitted from utasks. Attempted use of such a service results in the utask being stopped and pmode recovery software taking control, thus clipping the hacker’s wings some more.
umode offers the ultimate in isolation and protection. However, pmode offers good safety, reliability, and security from umode. pmode is a good place for proven, trusted, and mission-critical software.
Multi-heap support is necessary because using a common heap between partitions destroys their isolation from each other. A hacker could damage a common heap and bring down all partitions using it. SecureSMX uses eheap, a heap similar to dlmalloc, but designed for embedded systems. eheap has numerous attractive features beyond the scope of this paper. Of importance here is that it provides simple multi-heap support and that each heap can be customized for the partition it is in. This minimizes legacy software rewriting and supports object-oriented designs, e.g. C++.
Libraries, servers, and other code typically employ function-call APIs. This means that to use a function, it must be called by the client. To do so, the server functions must be accessible to the client – i.e. they must be in regions shared by the client and the server. Typically subroutines and global data also must be shared. Thus isolation between the client and the server breaks down. Since servers often are vulnerable (e.g. network servers) this is not a good thing.
Portals are the solution to this problem. SecureSMX provides two types of portals: tunnel portals for high-speed, multi-block transfers and free message portals for commands, callbacks, and low-speed data transfers.
A header file that can be included in client software modules, maps server function calls from client software to shell functions. The shell functions, which have slightly different names, convert the server function calls to protected messages, pmsgs, and send them to portal exchanges. There is one portal exchange per portal and typically one portal per server. pmsgs are queued at the portal exchange in priority order, when the server is busy.
Protected messages are so named because they are small MPU regions, which carry their region information (e.g. rbar and rasr) with them. When received by a server, the pmsg region is plugged into an MPU slot and voila! the pmsg becomes accessible to the server.
After accepting a pmsg from its portal exchange, a switch function in the server converts the pmsg to its corresponding function call and issues the call. The function return value and data, if any, is passed back to the client software via the pmsg and shell function. Thus client software sees no difference between direct calls and portal calls, except small increases in execution times. Yet client and server are fully isolated from each other. Other than sending faulty messages or faulty return values, there is nothing a hacker can do to break down the barrier between client and server – his wings have fallen off!
For further information on SecureSMX, see www.smxrtos.com/securesmx or call Micro Digital at 714 437 7333.
Copyright © 2021 Micro Digital, Inc. All rights reserved.