OCALL Switchless模式

以SampleCode/Switchless为例。

从Enclave内部以Swtichless模式调用OCALL

// SampleCode/Switchless/Enclave/Enclave.cpp
void ecall_repeat_ocalls(unsigned long nrepeats, int use_switchless) {
    sgx_status_t(*ocall_fn)(void) = use_switchless ? ocall_empty_switchless : ocall_empty;
    while (nrepeats--) {
        ocall_fn();
    }
}

进入tRTS端的stub

stub是由sgx_edger8r根据App/Enclave源码动态生成的,先于App/Enclave源码编译之前生成_{t,u}.{c,h}这些stub文件,这些stub文件会在App/Enclave编译时用到。

// SampleCode/Switchless/Enclave/Enclave_t.c
sgx_status_t SGX_CDECL ocall_empty_switchless(void)
{
	sgx_status_t status = SGX_SUCCESS;
	status = sgx_ocall_switchless(1, NULL);

	return status;
}

sgx_ocall_switchless是tRTS端的函数

/*=========================================================================
 * The implementation of switchless OCall
 *========================================================================*/

sgx_status_t sgx_ocall_switchless(const unsigned int index, void* ms) 

在第一次Switchless OCALL时(通过sl_call_once使得仅执行一次),会对tRTS端的OCALL管理器进行初始化。如果Enclave初始化时候没有开启Switchless模式,那么Switchless模式的OCALL会退化成一个普通的Switch模式的OCALL。OCALL管理器初始化放到下面另起章节讲。

/* If Switchless SGX is not enabled at enclave creation, then switchless OCalls
 * fallback to the traditional OCalls */
if (sl_call_once(&g_init_ocall_mngr_done, init_tswitchless_ocall_mngr, NULL)) 
    return sgx_ocall(index, ms);

紧接着,如果没有被激活的不可信工人线程,那么OCALL从Switchless模式退化成Switch模式。

如果有休眠的工人线程,让专门用来唤醒工人线程的“叫醒者线程”去唤醒所有线程。

构建OCALL任务,并以Switchless模式处理OCALL。

// perform switchless OCALL
error = sl_call_mngr_call(&g_ocall_mngr, &call_task, g_uswitchless_handle->us_config.retries_before_fallback);

OCALL管理器初始化

// sdk/switchless/sgx_tswitchless/sgx_ocall_switchless.c
static int_type init_tswitchless_ocall_mngr(void* param){
    ...
    // check if switchless has been initialized
    ...
    // g_uswitchless_handle is checked in sl_init_switchless()
    ...
    // clone data from the untrusted side, ensuring all the relevant data is outside enclave
    ...
    // wrong manager type, attack ?
    ...
}

先检查SGX初始化时候Switchless模式是否开启了。

然后将存放在uRTS端uSwitchless句柄中的OCALL管理器,克隆一份放到tRTS端的【g_ocall_mngr】。通过下面这个函数实现克隆。

// switchless call managers are allocated on untrusted side, then pointers to data structures are passed to the enclave.
// the following function clones the data, performing all neccessary checks
//
// returns 0 on success
uint32_t sl_call_mngr_clone(struct sl_call_mngr* mngr, const struct sl_call_mngr* untrusted) {
    ...
    // copies fields of untrusted structures ensuring that all the data resided on untrusted side
    ...
    // garbage data ? probably an attack
    ...
    // clone internal pointers to siglines structure
    ...
    // check that the call manager is properly initialized 
    // if not, can indicate an attack 
    ...
    // check that the array of task structures is outside enclave
    ...
}

这里的OCALL管理器克隆类似于ECALL管理器克隆,克隆的内容包括:类型(这里是OCALL)、信号线管理器(“浅”拷贝基础上,因为当前是tRTS,是OCALL的Sender方,构建一个空闲信号线情况数据结构,来统计空闲的信号线)、调用任务(存在uRTS端,这里克隆的是指针)、OCALL表置NULL(tRTS端的OCALL表没用,uRTS端的OCALL工人线程会使用uRTS端的OCALL管理器中记录的OCALL表)、调用处理句柄置NULL(tRTS是OCALL的发送方,而不是处理方)。

检查克隆出来的OCALL管理器类型Type的确是OCALL。

Switchless模式处理OCALL,类似于Switchless模式处理ECALL。总的来说就是把OCALL任务丢给OCALL工人线程,并通过信号线让OCALL工人线程去执行OCALL任务。

OCALL工人线程接受信号线,并处理器OCALL任务

类似于ECALL工人线程的逻辑

【run_worker】->【uworker_process_calls】->【sl_call_mngr_process】->【sl_siglines_process_signals】->查看所有信号线每个Bit确定是否有信号来了->【process_switchless_call】

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值