- The hardware enforced pmode barrier prevents umode access to pmode data and code.
- The MPU cannot be turned off nor altered from umode.
- The Background Region (BR) is ineffective in umode.
These combine to form a very strong barrier for a hacker who has penetrated a umode partition. Thus umode is “uptown”. There are, however, some disadvantages to umode:
- Some system services are not permitted and others are limited.
- Slower system services due to using a software interrupt (SWI) interface.
- Slower partition services (e.g. file IO) due to using portals.
- Interrupt disable is not available in umode.
Therefore, a fully partitioned system is likely to have both kinds of partitions, as illustrated above in Figure 1. In the Where’s the Gold solution paper, we discussed the process for safely adding networking to an existing embedded system, using SecureSMX. In the What’s in Your SOUP solution paper, we discussed moving SOUP (Software Of Unknown Pedigree) from an embedded system in a single pmode partition to its own umode partition, again using SecureSMX. In both cases the goal is to increase security for existing systems by isolating vulnerable or weak software.
This solution paper is aimed at achieving fully isolated partitioning for new and existing systems. There are some additional advantages beyond security to this:
- Easier incorporation of legacy software by using isolated partitions.
- Recovery via partition reboot rather than full system reboot.
- Partition updates rather than full system updates.
- Better plug-in modularity.
- More disciplined design.
Generally speaking, partitioning simply leads to better and more robust designs.
Most software starts off running in pmode due to being legacy software or due to being easier to develop and debug software in pmode, so that is the focus of this solution paper. Note, however, that once familiarity with umode is established it may be more efficient to develop and test new code in umode.
We’ll assume that the process of moving all needed code and data into regions for the pmode partition, parA, has been accomplished and the partition task is running with the MPU loaded similarly to Figure 2.0.
In Figure 2.0, slot 7 is reserved for the task stack, slot 6 is unused, slots 3 and 2 contain the code and data regions for parA. Slots 5 and 4 contain common code and data shared between parA and other partitions with which parA has functional interactions. Common regions are necessitated by function call APIs between the partitions. However, they constitute a breakdown in isolation between those partitions. Slots 1 and 0 permit parA to make direct calls for system services (e.g. RTOS calls).
The first step is to eliminate direct system calls. This is done by including xapiu.h instead of xapi.h in the parA code modules. This maps system calls to umode shell functions, for example:
#define smx_SemSignal(sem) smxu_SemSignal(sem)
and include svc.c in the project, which contains svc shell functions, for example:
NI BOOLEAN smxu_SemSignal(SCB_PTR sem)
sb_SVC(SMX_ID_SEM_SIGNAL & 0xFF)
There is a shell function for each system call. Each shell function invokes the SVC handler with a function ID, as shown above. Now all parA system calls will be re-directed through the SVC handler. This may reveal that parA is making some prohibited or limited system calls. For example, calling smx_TaskLock() results in a Privilege Violation error. There are a few ways to deal with these problems:
- Make code changes, if easy to do and there are only a few minor ones.
- Keep the main partition task in pmode until it has performed all of the disallowed calls, and then have it restart itself in umode.
- Split the partition into a pmode partition and a umode partition.
- If all of the above fail, leave this partition downtown and get another one.
The next step is to introduce portals. A portal eliminates common regions between tasks by converting function call APIs to message APIs. SecureSMX provides two types of portals: tunnel portals and free-message portals. Both use protected messages (pmsgs), which consist of a data block that is an MPU region linked to a Message Control Block (MCB). The MCB, in addition to other information, has the region information (e.g. RBAR and RASR) for the data block. When a server receives a pmsg, it loads its region information into a spare MPU slot, thus allowing the server to access the pmsg data block. So pmsgs can be viewed as traveling regions.
In a free message portal, each pmsg is used one time. It is sent from a client to a server and when the server is done with it, it is recycled or deleted. After being sent, the client can no longer access it. After being released, the server can no longer access it, nor can the server determine its fate. Hence, free pmsgs provide very strong isolation. Free message portals are generally used for commands and small amounts of data.
In a tunnel portal, a pmsg sent by a client sticks to the server until the portal is closed by either end. The data block is referred to as the portal buffer, pbuf. As shown below in Figure 3,
pbuf operates like an airlock – only one door is open at a time. So, for example, the client can load data into pbuf, then signal the server, which closes the client’s door and opens the server’s door. The server can then read the data, load a return value or data into pbuf, then signal the client, which reverses the doors. Tunnel portals are used for large, multi-block data transfers, such as files. When the tunnel portal is closed by both ends, the pmsg is recycled or deleted.
SecureSMX takes care of the protocols for both types of portals and provides protocol functions such as create(), open(), close(), send(), and receive() for using them. Figure 4 shows how a portal converts an API function call to a pmsg, in the client, then uses a switch statement to convert the pmsg to the function call in the server. The server performs the function, and then it sends the return value and data, if any, back to the client.
This structure is similar to the SWI interface. The fmap.h header file converts function names to similar shell function names, for example:
#define sfs_fopen(filename, mode) sfsp_fopen(filename, mode, SFSP_PCH)
where sfsp_open() is the shell function, and it is implemented as follows:
FILEHANDLE sfsp_fopen(const char* filename, const char* mode, TPCS* pch)
SFSP_SH* shp = (SFSP_SH*)pch->shp;
char* mdp1 = (char*)pch->mdp;
char* mdp2 = mdp1 + strlen(filename)+1;
mp_SHL2(SFS_ID_FOPEN, (u32)mdp1, (u32)mdp2, NULL);
At the server end:
void sfsp_server(TPSS* ph)
TPMH* mhp = (TPMH*)ph->mhp; /* msg header pointer */
SFSP_SH* shp = (SFSP_SH*)ph->shp; /* service header pointer */
shp->ret = (u32)sfs_fopen((const char *)shp->par1,
where shp->ret is the value returned to the client. Although the above code is relatively simple and repetitive, portals seem to be hard to debug. For this reason, it is best to stay in pmode so it is easy to switch back and forth between portal (Fig. 2.2) and direct (Fig 2.1) calls until the portal is fully operational.
If the partition is making heap calls, define a heap for it – isolated partitions cannot share a heap. Heaps are outside of the scope of this paper, but will be covered in a future paper.
Start the partition task(s) in umode. If you do not get MMFs and privilege violations, and the partition runs, you’re done! Otherwise there may be some work to do, but it won’t last long.
In this solution paper, we have covered the process for converting a pmode partition into a fully isolated umode partition, thus moving it “uptown”. The process is fairly simple and not overly difficult to accomplish; however, it is different than most embedded system programming. We believe that it is a new methodology, whose time has come, in view of the exponential growth of hacking incidents and the damage caused by them. The more partitions that can be moved to umode, the more secure and safe an embedded system will be.
 pmode means privileged or protected mode.
 umode means unprivileged or user mode.
Copyright © 2021 Micro Digital, Inc. All rights reserved.