When an enclave writer develops an enclave which may employ more than one thread, the developer must be aware that untrusted code controls the binding of an untrusted thread to the Trusted Thread Context (composed of a TCS page, SSA, Stack, and Thread Local Storage Variables). Thus, the developer must follow the policies on using Thread Local Storage and thread synchronization objects within the enclave.
The developer may select one of the following Thread Binding Policies for an enclave:
- Non-Binding Mode: in this mode, the untrusted runtime (uRTS) selects any available Trusted Thread Context when a root call is made into the enclave. A root call is defined as an enclave call that is not nested within another enclave call (or does not occur within the context of an enclave out call). The uRTS then uses the same Trusted Thread Context for the duration of the enclave call. In other words, it will pick the same context for a nested enclave call. As the selection of the Trusted Thread Context is arbitrary in this mode, the trusted runtime within the enclave will initialize the entire Thread Local Storage data set on each root enclave call. This means that all Thread Local Storage variables will be reset at the beginning of each root enclave call.
- Binding Mode: in this mode, the uRTS binds an untrusted thread with a Trusted Thread Context within the enclave. This means that the uRTS always selects the same Trusted Thread Context for a specific application thread. Essentially, the uRTS binds an untrusted thread and a trusted thread together. In this mode, the trusted runtime does not reinitialize the Thread Local Storage data-set on each root enclave call.
The Thread Binding Policy is stored both inside the enclave as a trusted parameter (which is also measured) and outside the enclave as an untrusted parameter in the uRTS. The trusted parameter affects whether the trusted runtime system re-initializes Thread Local Storage variables on each root enclave call; while the untrusted parameter determines how the uRTS selects a Trusted Thread Context to use for each call.
Thread synchronization objects, mutexes in particular, cannot be used safely across root enclave calls regardless the Thread Binding Policy. Synchronization objects maintain state information, such as a mutex ownership, within the enclave. Thus a thread must not exit an enclave returning from a root enclave call after acquiring the ownership of mutex.
An application thread that reenters an enclave with a different Trusted Thread Context than what was used to acquire a mutex cannot release the mutex because the mutex ownership is mapped to the Trusted Thread Context.
An application thread that enters an enclave with the Trusted Thread Context that was previously used by another thread to acquire a mutex does not have the ownership of the said mutex.
These scenarios may only occur when the critical section protected by the mutex or other thread synchronization object is split across root enclave calls. Therefore, avoid such practice.
Since the uRTS selects which Trusted Thread Context to use for an enclave call, and the uRTS is untrusted code, the developer must be aware that an attacker can manipulate this selection. Thus, the attacker may switch the binding mode that the uRTS employs or even select a specific Thread Context for each call.