It is now possible to greatly increase the security of FreeRTOS projects by porting them to SecureSMX®, using FRPort™. SecureSMX facilitates partitioning an application into isolated partitions. This provides strong protection against hacking since a hacker can only access code and data within the partition that he has entered. In this solution paper, we discuss the process to port a FreeRTOS application to SecureSMX and then show how SecureSMX security features are much stronger than those of FreeRTOS and SAFERTOS. FRPort also makes the large suite of SMX middleware products and drivers available to FreeRTOS projects.
- Read FRPort Tips to get oriented.
- Search your code for system calls made from ISRs. Define a Link Service Routine (LSR), if necessary, and move the code making system calls from the ISR into the LSR. Change the ISR to use smx_ISR_ENTER(), smx_LSRInvokeF(), and smx_ISR_EXIT() as in the following example from IntQueueTimer.c:
void TIM2_IRQHandler( void )
/* Clear the interrupt and call the IntQTimer test function. */
TIM2->SR = 0;
portYIELD_FROM_ISR( xFirstTimerHandler() );
void TIM2_IRQHandler( void )
/* Clear the interrupt and call the IntQTimer test function. */
TIM2->SR = 0;
In this case xFirstTimerHandler() becomes an LSR. If the system service has multiple parameters, write an LSR function to call it.
- FRPort currently covers about 80% of FreeRTOS system services. Many FR services are not necessary for smx and thus have been excluded. Others have been judged to not be useful and thus are expected to be rarely used. If you cannot easily replace such calls, please discuss it with us, and we can consider adding support for them.
FreeRTOS and SAFERTOS use the same MPU structure:
As shown in Figure 1, the top three slots are active slots. These are loaded from a task’s TCB prior to dispatching it. The bottom five slots are static slots, which are loaded once, during initialization. This is not adequate to achieve isolated partitions. Figure 2 shows what happens in a real-life scenario where there are three middleware modules: network, file system, and USB host, and three tasks that access them: tnw, tfs, tuh. Assume that the middleware, associated drivers, and the tasks run in unprivileged mode (umode).
Fig 2a shows the resulting partitions and Fig 2b shows the resulting MPU slots for each task. The bottom two slots, sys_code and sys_data are privileged slots used by the RTOS, exception handlers, other system services, and ISRs. The top three slots are used for task code, task data, and task stack. This leaves only three slots for the middleware code, data, and IO. Hence, there is no isolation between the middleware modules (as shown by the dashed module lines in Fig 2a, surrounded by the solid partition line). If a hacker gains access to one module, he has access to all. In addition, he has access to the regions of whichever task is using one of the modules at the time. Over time, he will be able access the regions of all three tasks.
IO is even worse. Bridging all of the IO registers required for Ethernet, DMA, USBH, and file system devices with one IO region brings in a dozen or more other devices that should not be accessible to these modules and tasks. Thus partition isolation is completely broken down, except for sys_code and sys_data, because they cannot be accessed in umode. We find that there is usually a domino effect in cases like this – more and more has to be put into the common middleware regions as the design progresses.
Fig 3 shows the contrasting result with SecureSMX. Fig 3a shows the partitions and Fig 3b shows the MPU slots for each task. In this case, note that the middleware modules with their drivers are now in bonafide isolated partitions as shown by solid lines in Fig 3a. A hacker gaining access to one partition, cannot access the other two paritions, nor their user task partitions. This is still not perfect, however, because each task is not isolated from the middleware that it uses, due to the function call API of the middleware. If two tasks share the same middleware, then those tasks will not be isolated from each other, either. Also there is still an IO bridge problem if a middleware driver needs to access more than one IO device, but it greatly reduced. Solving these remaining problems, requires partition portals, which are described later. First though, we will cover two other requirements for full partition isolation.
System Services from umode
utasks cannot make system calls directly, because system calls are privileged. FreeRTOS uses mpu_wrappers.h to map system calls to their MPU versions such as:
#define vTaskSuspend MPU_vTaskSuspend
and the MPU versions of system calls are defined in mpu_wrappers.c, such as:
void MPU_vTaskSuspend( TaskHandle_t pxTaskToSuspend )
BaseType_t xRunningPrivileged = xPortRaisePrivilege();
vTaskSuspend( pxTaskToSuspend );
vPortResetPrivilege( xRunningPrivileged );
This code suspends the task indicated and then changes the processor to privileged mode. There are two problems with this method: (1) a utask should not be able to suspend any task it wants, and (2) once a hacker finds the address of xPortRaisePrivilege(), he need only to call it in order to break through the pmode barrier and to access any memory location he wants. This is not adequate system protection!
SecureSMX maps system calls, as follows:
#define smx_TaskSuspend(task, tmo) smxu_TaskSuspend(task, tmo)
The smxu versions of system calls are defined in svc.c, such as:
NI BOOLEAN smxu_TaskResume(TCB_PTR task)
sb_SVC(SMX_ID_TASK_RESUME & 0xFF)
sb_SVC() invokes the SVC exception handler with the sys call ID (SMX_ID_TASK_RESUME & 0xFF) as its parameter. The process of making a system call is illustrated in Fig 4.
The SVC Handler calls the system service through the sys call jump table using the sys call ID. If the call is permitted from umode, the system service runs and returns its result via the SVC Handler and sys call shell function to the utask. A system call that is not permitted from umode causes a protection violation, which is handled by the Protection Violation Error Manager (PVEM) and then by the smx Error Manager (EM). If this happens, the utask is stopped before it can cause further damage. Some system calls are allowed to go through to the system service, but the system service checks if they are permitted from umode. For example, TaskStop() is permitted only for a utask’s child tasks. Thus a utask cannot stop any arbitrary task.
As is the case with xPortRaisePrivilege(), a hacker can find the address of any shell function since all must be accessible in umode. However, if called, the shell function will only make its designated system call, and then return to umode. Hence, it will not allow the hacker entry into pmode. If the system call is not permitted from umode, the hacker will be stopped dead in his tracks, and partition recovery or system recovery can be initiated.
Using heaps in modern application code is popular, and it is necessary to support object-oriented languages. This is a growing trend as embedded systems become more complex and are expected to do more functions – especially in IoT systems.
It is unacceptable for utasks to have direct access to the main heap. A hacker could easily bring down the whole system simply by exhausting or corrupting it. Generally, it is also not acceptable to have a heap that two or more partitions share, since malware in one partition could corrupt blocks owned by another partition or the whole heap, or it could access sensitive data of another partition. Thus, each partition that needs a heap, must have its own heap.
FreeRTOS provides only a main heap. SecureSMX uses a task-safe version of eheap (embedded heap). eheap is a bin-type heap that supports multiple heaps of all sizes for embedded systems. It is similar to dlmalloc, but it was designed specifically for the needs of embedded systems. Malloc, for example, looks like this:
void* smx_HeapMalloc(u32 sz, u32 an, u32 hn)
where sz is the desired minimum block size, an is the alignment (2^an), and hn is the heap number. eheap also is capable of allocating MPU regions with subsection disables. Heaps are easily defined per partition with about 16 lines of code and can vary from 1 to 31 customized bins. Space for heaps can be allocated by the linker or allocated from the main heap when running. eheaps can perform self-scanning and repair, bin sorting, self-recovery, and other operations useful in embedded systems. For further information, see eheap User’s Guide, and see the smx Reference Manual for task-safe versions of eheap services.
As noted above, full partition isolation requires partition portals to replace function call APIs. Portals provide a message-based calling mechanism that prevents clients from accessing any server code, data, or I/O. FreeRTOS offers no portals.
SecureSMX offers two types of portals: free message portal and tunnel portal. Both make use of smx protected messages (pmsgs). A pmsg consists of a data block, which is sized and aligned as an MPU region, and a Message Control Block (MCB), which is linked to the data block. The data block can be allocated from any heap by eheap, which can allocate region blocks. The MCB contains the region information for the data block (e.g. MPU rbar and rasr register values), which is loaded into an empty MPU/MPA slot when the pmsg is received.
The free message portal is intended for commands and small amounts of data. The tunnel portal is intended for large multi-block data transfers. For each type, functions such as create, delete, open, close, send, and receive are provided by SecureSMX. Both portals use client/server protocols. The client sends a pmsg to the server, which processes it and may send a pmsg back to the client. In the case of the free message portal, only one end can access the message at a time. In the case of the tunnel portal, the pmsg data block is accessible by either client or server as regulated by the protocol, using semaphores. This block, called pbuf, is the only common region between the client and the server. Hence, a hacker at either end cannot access code, data, nor I/O in the other end.
Which end is which depends upon the partition. If it is like a file system, it would be the server. If it is a data acquisition subsystem, it might be the client. A task is needed at each end of a portal; however an existing task may do. At the client end, a shell function is created for each server function. The shell function creates a pmsg with a function ID and function parameters and data, if required, and sends it to the server message exchange. When the server receives a pmsg from its server message exchange, it uses a switch statement to interpret the function ID, make the function call, and send the result back to the client via a pmsg. The foregoing applies to a free message portal. For a tunnel portal, operation is the same except the message remains in place and semaphores are used to coordinate client and server access to it. The important point is that a function call interface between the partitions is no longer needed.
Figure 5 shows the final result of fully isolating a partition called “SOUP” (Software Of Unknown Pedigree”). This can, of course, be applied to any partition. In this particular example, all the rest of the application is in a single pmode partition, which is connected to the umode SOUP partition via a portal. The SWI interface allows the SOUP partition to make permitted system calls. Note that there is no other path through the pmode Barrier. Thus the application is fully protected from the SOUP. This particular example is for a legacy system — a new system would normally have many umode and pmode partitions.
As shown above, SecureSMX has the necessary features to create isolated partitions in MCU-based systems, whereas FreeRTOS and SAFERTOS do not. Applications written for FreeRTOS can be ported with moderate effort to be able to utilize the security features of SecureSMX. This is accomplished by using FRPort, a free product of Micro Digital, Inc. As noted above, FRPort is not a 100% port of all FreeRTOS features. However we will provide help to add missing features if you cannot easily program around them.
A second advantage of porting to SecureSMX is that it is then easy to add any of the members of the large SMX middleware and driver family to a FreeRTOS project. Generally, SMX middleware offers features not found in equivalent open source products. Most SMX middleware is available to run in isolated umode partition form with portals or in standard function call form.
Copyright © 2021 Micro Digital, Inc. All rights reserved.