Introduction
A common attack vector for IoT and embedded devices is to put a task into an infinite loop. This blocks all equal and lower-priority tasks from running. Although higher-priority tasks can still run, this may be sufficient disruption of device operation to bring the entire system down. This article looks into how this kind of attack can be prevented.
Runtime limiting (RTL) assures that a task can run only a limited amount of time per time frame before it is suspended for the rest of the frame. This prevents the above attack vector. However, runtime limiting is a double-edged sword: too much and tasks will miss their deadlines; too little and it is ineffective. Also, it must not block a critical task from having enough time to do its job under extreme conditions (e.g. stopping a crane from tipping over in a high wind). To do so would be as bad as malware, itself.
Design Considerations
For operating systems like Windows or Linux, runtime limiting is implemented by giving each process a slice of processor time. This is simple to do and generally works well to enforce fairness between processes. Realtime systems are different. Rather than fairness, the main goal is for tasks to meet their deadlines. Assigning runtime limits to tasks can be at odds with this goal. Further complicating this matter, is that task workloads may vary significantly from time to time.
A developer cannot anticipate everything that might go wrong and then assign a runtime limit sufficient to cover them all. On the other hand, an important task may require a high priority to get its job done in a timely manner, yet be vulnerable to exploitation and therefore require a runtime limit. In a case like this, the developer must decide how much time the task needs to do its job in a timely manner, without giving it too much time in the event that it is compromised.
For runtime limiting to work there must be a time period, at the end of which, all RTL-suspended tasks are resumed with their runtime limits restored. This is called a runtime frame. But, a fixed runtime frame is not a good solution for embedded systems. For example, if non-RTL task activity is low and RTL task activity is high, the latter will time out and wait for the end of the frame even though the processor is idle. This is not efficient processor usage, assuming the RTL tasks are running normally and doing useful work.
On the other hand, if non-RTL task activity is high, an RTL task may not time out, even though it has been compromised and should time out. As a result, idle and other low-priority tasks may be blocked from running for many frames. This could cause unexpected problems. In this case, runtime limiting is not working effectively.
Therefore, it is necessary for the runtime frame length to be adaptable to the current load.
A good way to accomplish this is to end the runtime frame when the idle task has run a certain number of passes. Since it is a minimum-priority task and runs round-robin with other minimum-priority tasks, this assures that all tasks have run as much as necessary to do their jobs before the frame ends. In the example of a crane tipping over, RTL tasks will time out, permitting lower-priority tasks to log what caused the crane to tip.
RTL Guidelines
To deal with the above problems, the following guidelines have been used for developing the runtime limit algorithm used by SecureSMX:
- Mission-critical tasks should not have runtime limits because limits could cause more harm than good. Hence, critical tasks are not required to have runtime limits. If a hacker reaches mission-critical code, it is game up, anyway, so runtime limits do not help.
- Child tasks share parent task’s runtime limits. Then, as child tasks are spawned it is not necessary to readjust limits. Also, child tasks might vary considerably in their use of processor cycles at different times and it would be hard to assign individual runtime limits to them. Assuming that the typical partition has only one parent task, this amounts to assigning runtime limits to partitions, which makes sense since they are usually subsystems of known importance.
- The runtime frame must not be fixed. Introducing fixed limits in real-time systems, often results in complexities. Flexible designs work better.
- The idle task must be allowed to run some minimum number of times per runtime frame in order to perform its background functions. When the idle pass count reaches 0, the runtime frame ends and all RTL suspended tasks are resumed.
- A task is only suspended if it reaches its or its parent’s limit. If it is not running nor attempting to run, it is not suspended. This is simpler and results in less tasks to resume at the end of the frame.
- When the runtime frame ends, all parent RTL counters are restored to their limits. Not having child counters saves time.
Implementation

Examples:
1. Typical code to create and start a ptask with a runtime limit of 10 milliseconds:

2. Typical code to create and start a child ptask t2ac1 of parent ptask t2a:

3. Typical code to create and start a utask with a runtime limit of 20 milliseconds:

The above code must run in pmode, but ut2a runs in umode.
4. Typical code to create and start a child utask ut2ac1 of parent utask ut2a:

This code must run in umode, and it can create only a child task, which shares its parent’s rtlim and rtlimctr. In the above, MPU[0,1] are static slots, and MPU[2,7] are active slots that are loaded when ut2ac1 starts running. The ut2ac1 MPA has six slots as indicated by the 6 parameter of MPACreate(). The 0xc3 parameter of MPACreate() causes it to load regions 0, 1, 6, and 7 of mpa_tmplt_ut2ax into MPA[2-5], 0 into MPA[6], and the stack region into MPA[7]. This allows a single template to be shared by all tasks in a partition. A template can have however many regions are necessary to do this.
Conclusion
This article, has reviewed the need for runtime limits and how they are implemented in SecureSMX. SecureSMX is available under a dual GPL/commercial license and the full source is available for free.
Notes
[1] If a child task spawns child tasks, then its parent is called the top parent.