Achieving full MCU partition isolation: Portals - Embedded.com

Achieving full MCU partition isolation: Portals

Achieving full microcontroller (MCU) partition isolation is essential for achieving high security for MCU-based systems. Continuing our series, this article discusses the need for portals between partitions in order to achieve full partition isolation.

This is the fourth article in a series on achieving high security for MCU-based systems. The first article covered security basics and partitions; the second article covered MPU management; and the third article covered the need for multiple heaps and desirable heap characteristics for partitioned embedded systems. In this article we cover the need for portals between partitions in order to achieve full partition isolation. Two types of portals are discussed: free-message portals and tunnel portals. This is not intended as a tutorial. The references listed in the first article may be helpful for that.

Protected Blocks and Messages

In the second article in this series, dynamic regions were discussed, and in the third article, a method for obtaining region blocks from a heap was presented. In particular, protected blocks (pblocks) and protected messages (pmsgs) were mentioned. Here we delve into these a little deeper.

pblocks

If a buffer is needed and there is a spare slot in a task’s memory protection array (MPA), it is desirable to allocate a pblock for the buffer. This can be done from an outside heap (normally the main heap), a block pool, or a statically defined block (e.g. block[100]). A region for the pblock is automatically created and loaded into the MPU and into the task’s MPA. pblocks can be used for partition heaps, temporary buffers, work areas, structures, etc..

Such a block would normally have RW and XN attributes. It could also have cache, strongly ordered, and shareable attributes, which might be useful for DMA buffers, for example. A pblock immediately detects overflow and underflow and triggers an MMF. This defeats certain hacker buffer tricks. Additionally, if allocation of pblocks is restricted to pmode, attributes such as XN cannot be changed in umode, which provides additional protection.

pmsgs

A normal message consists of a Message Control Block (MCB) linked to a data block, which contains the actual data. Tasks exchange messages via exchanges. An exchange can enqueue tasks waiting for messages, or messages waiting for tasks. Both tasks and messages can be enqueued by priority or by time of arrival.

A protected message (pmsg) is a normal message for which the data block is an MPU region and the MCB contains the corresponding region information (e.g. RBAR from bp and shapxn and RASR/RLAR), as shown in Figure 1.


Figure 1: Protected Message. (Source: Author)

In Figure 1, pmsg is the handle of the protected message. When a pmsg is received by a task, its region information is loaded into a free slot in the MPU and into the same slot in the task’s MPA. pmsg attributes are normally RW and XN, but they could be RO and XN. pmsgs are, in effect, self-contained, traveling regions.

Portals

One year into our four-year quest for the Holy Grail, we thought we had a good solution, and we decided to try it on our middleware. Unfortunately our euphoria was short-lived. The problem we found is that servers, such as file systems, have function APIs. For example, to open a file, fopen() is called and thus the fopen() function must be accessible to the application partition that is calling it. So must any subroutines and data used by fopen(). The net result is that code and data common regions are needed between clients and servers.

Although a few common regions here and there might be acceptable, there tends to be a domino effect due to the MPU slot limitation. For example, if it is necessary to access a thumb drive via the file system, then parts of the USB host code and data must accessible. If two MPU slots for these are not available, then they must be added to the common file system regions. If another application partition needs a USB host function, then it may need to share this growing common region. Common regions are super highways for hackers. In this case, a hacker could access both application partitions, the file system partition, and the USB host partition from whichever one he infected.

Portals between partitions provide a solution to this problem. A portal eliminates the need for common regions by converting function call APIs to message APIs. Basically, function calls are converted to pmsgs in the client and converted back to function calls in the server. SecureSMX provides two types of portals: free-message portals and tunnel portals. These are discussed next.

Free Message Portal

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 determine its fate. Hence, free message portals provide strong isolation. They are generally used for commands and small amounts of data.

Portal Operation

The free message portal gets its name from the fact that the pmsgs are not bound to the client as they are for the tunnel portal. Hence they are free. The free message protocol primarily makes use of protected messaging capabilities, as discussed previously. Figure 2 illustrates three of many possible free message protocol configurations. Hash marks indicate waiting messages at the message exchanges shown.


Figure 2 Free Message Protocol Configurations. (Source: Author)

Figure 2A is the simplest configuration: Client C gets a pmsg from memory, fills it, and sends it to Server S via exchange SX. Note that multiple messages can accumulate at SX. Server S processes the pmsg and returns it to memory. Figure 2B is a more efficient configuration. In this case, Server S sends pmsgs to exchange RX from which they are obtained by Client C. In this case, the return pmsgs may have ACK/NAK status and possibly data. Also, the pmsgs would all be the same size, whereas in 2A messages could differ in size. Figure 2C is an extension of 2B where two clients are using the same server. In this case, the pmsgs must all be the same size since they come from a single resource exchange, RX.

Normally pmsgs have priorities. In 2C, for example, messages from C2 might have higher priority than pmsgs from C1 and thus be serviced ahead of C1 pmsgs. In addition, SX is a pass exchange, which means that the pmsg priority is passed on to server task S. If S < C, the pmsg will be processed some indeterminate time in the future. This might be satisfactory for logging. If S == C, the pmsg will be processed when C is done. If S > C, C will be preempted for S to run. This is most analogous to a direct call.

Note that the client is the master, and it initiates all transactions. Should the server need to initiate a transaction, such as for a client callback, a separate portal is required. If a pmsg comes from a client region, the client can use an auxiliary slot for its region (see Figure 3 in the previous article). Otherwise the client must use an active slot. Similarly for the server. v8M introduces a complexity here because it does not permit overlapping regions.

The task in a client that was making direct calls to the server is now making and sending pmsgs. The task in the server which is handling the portal is serving as a proxy for the client task.

Portal Initialization

Figure 3 illustrates how a free message portal is created and initialized. There is a Free Portal Server Structure (FPSS) for each free portal in a server. (A server has a portal for each interface that it presents to the rest of the system.) There is a Free Portal Client Structure (FPCS) for each server that a client can access. In addition, for each FPSS, there is a Permitted Client List (PCL) array of pointers to all of its client FPCSs, to specify which clients can access its portal. All structures and arrays are defined at compile time and thus are static during run time. All of these structures are in pmode and not accessible from umode.


Figure 3: Free Message Portal Initialization. (Source: Author)

Server portal initialization code, which must be called in pmode does the following:

  • Creates the portal exchange.
  • Loads the portal exchange handle and the portal name into the client FPCSs using the PCL pointers (c1ptr and c2ptr in Figure 3).
  • Creates the portal server task.
  • Loads the portal exchange handle, portal name, and the task handle into the FPSS.
  • Causes the server task to wait at the portal exchange for the first pmsg.

Each client calls portal open code, which creates a resource exchange, rxchg, gets n pmsgs, sends the n pmsgs to rxchg, and loads FPCS fields, except name and sxchg. This is consistent with Figure 2B. If n = 0, rxchg is not created, and no pmsgs are obtained, as shown in Figure 2A. For Figure 2C, C1 gets n pmsgs and rxchg, and C2 gets no pmsgs and shares rxchg.

The above may seem overly elaborate. It is not. C1 and C2 are isolated from S. Hence, the only way C1 and C2 can get the sxchg handle is if it is copied into their regions. The portal name is optional, but it helps to avoid confusion if there is more than one portal structure in a partition.

Tunnel Portals

A tunnel portal is similar to a free message portal, except that the pmsg sent by a client sticks to the server until the multi-block transmission is complete and the portal is closed by either end. Also, the client remains the owner of the pmsg, and server is just the host. The pmsg data block becomes a temporary common region between the client and the server, called the portal buffer, pbuf. As shown below, pbuf operates like an airlock – only one door is open at a time.


Figure 4: pbuf Open to Client. (Source: Author)

The airlock, or half-duplex operation, is controlled by two semaphores. For example, the client can load data into pbuf, signal ssem (server semaphore), then wait at csem (client semaphore). This closes the client’s door and opens the server’s door. The server can read the data, load a return value or data into pbuf, then signal csem and wait at ssem, which reverses the doors. Tunnel portals are used for large, multi-block data transfers, such as files or network packets. When the tunnel portal is closed by both ends, the pmsg is recycled or deleted.

Tunnel portal initialization is similar to free message portal initialization, except that the structures are different: Tunnel Portal Server Structure (TPSS) and Tunnel Portal Client Structure (TPCS). Portal creation is very similar. A single pmsg is obtained by the client and sent to the server. Then the client initiates a multi-block send or receive, where the blocks are pbuf-size with the last block possibly smaller. Naturally the larger pbuf is, the better the performance. If pbuf is as big as the data being sent, no-copy operation may be implemented.

Shell Functions

Each portal has protocol functions such as Create(), Open(), Close(), Send(), and Receive() for using the portal. 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 back 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 via pmsg.


Figure 5: Portal Operation. (Source: Author)

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)
{
   mp_PTL_CALLER_SAV();
   SFSP_SH* shp = (SFSP_SH*)pch->shp;
   char* mdp1 = (char*)pch->mdp;
   char* mdp2 = mdp1 + strlen(filename)+1;
   strcpy(mdp1, filename);
   strcpy(mdp2, mode);
   mp_SHL2(SFS_ID_FOPEN, (u32)mdp1, (u32)mdp2, NULL);
   mp_TPortalCall(pch, SFSP_CTMO);
   return (FILEHANDLE)shp->ret;
}

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 */
    switch (shp->fid)
     {
      …
      case SFS_ID_FOPEN:
         shp->ret = (u32)sfs_fopen((const char *)shp->par1,
                                                                  (const char*)shp->par2);
         break;
      …
   }
}

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 pmsg and direct calls until the portal is fully operational.

Conclusion

In the foregoing we have examined why portals are necessary to achieve fully isolated partitions. Two types of portals have been examined, free message portals and tunnel portals, both of which utilize pmsgs. In addition we have looked into how a function call API can be converted to a message API. The next article wraps up this series with a variety of topics:  how system services are implemented via the SVC handler, ISR vulnerability, protecting critical sections, v7M memory optimization, debugging, Arm PSA, and recommendations for chip vendors.


Ralph Moore is a graduate of Caltech. He and a partner started Micro Digital Inc. in 1975 as one of the first microprocessor design services. In 1989 Ralph decided to get into the RTOS business and he architected the smx RTOS kernel. After 20 years of selling Micro Digital products and managing the business, he went back into product development. Currently he does the whole job from product definition, architecture, design, coding, debug, documentation, patenting, to promotion. Recent products include eheap, SecureSMX, and FRPort. Ralph has three children and six grandchildren and lives in Southern California.

Related Contents:

For more Embedded, subscribe to Embedded’s weekly email newsletter.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.