查看原文
其他

sel4源码解析(二) - CSpace

书意 Linux阅码场 2022-12-14

作者简介

书意,内核工程师新人,主要方向ebpf和网络,个人csdn:mr0cheng,github page: chengshuyi.github.io,欢迎大家关注!



文章目录

CNode

capability

用户程序API

Capability查找流程

Capability derive tree



Sel4采用基于capability的访问控制模型,进程对系统资源的访问控制权限组成一个capability space,所有的cap存放在CNode里。CSpace是由CNode构成,CNode可以看成一个数组,数组元素称为slot,每一个slot里面可以存放一个cap或者为空。

Sel4提供CDT(capability derive tree)结构保存权能的拷贝

1.CNode


CNodes本质是一个结构体数组,该数组的元素是cte(capability table entry),cte中包含一个cap_t结构体和mdb_node_t结构体。CNodescte称为slot,下面是slot的结构体:


cap:包含权限和指向具体cap的指针;

cteMDBNode:保存cap之间的关系,比如:untyped cap衍生出的其它对象的cap。


struct cte { cap_t cap; mdb_node_t cteMDBNode;};


CNodes本身是一个内核对象,也有相应的cap。下面是CNode cap的结构体:


capCNodeGuard:具体的guard数值;

capCNodeGuardSize:guard占的位数;

capCNodeRadix:CNode的最大slot个数;

capCNodePtr:指向CNode的指针;


block cnode_cap(capCNodeRadix, capCNodeGuardSize, capCNodeGuard, capCNodePtr, capType) { field capCNodeGuard 64 field capType 5 field capCNodeGuardSize 6 field capCNodeRadix 6 field_high capCNodePtr 47}


2.capability


capability的结构体的大小是16字节,它包含两部分,一部分是seL4_CapRights,另一部分是指向具体对象cap的指针。下面是cap的结构体和seL4_CapRights结构体:


struct cap { uint64_t words[2];};
block seL4_CapRights { padding 32 padding 28 field capAllowGrantReply 1 field capAllowGrant 1 field capAllowRead 1 field capAllowWrite 1}


sel4定义了如下几类cap(不同的架构可能会不同,本例是arm32架构):


enum cap_tag { cap_null_cap = 0, cap_untyped_cap = 2, cap_endpoint_cap = 4, cap_notification_cap = 6, cap_reply_cap = 8, cap_cnode_cap = 10, cap_thread_cap = 12, cap_small_frame_cap = 1, cap_frame_cap = 3, cap_asid_pool_cap = 5, cap_page_table_cap = 7, cap_page_directory_cap = 9, cap_asid_control_cap = 11, cap_irq_control_cap = 14, cap_irq_handler_cap = 30, cap_zombie_cap = 46, cap_domain_cap = 62};


从上面可以看出每一类cap里面具体包含了一些私有的访问控制规则,以endpoint为例:endpoint cap里面包含了四项权限,分别是:capCanGrantReply()、capCanGrant()、capCanReceive(该endpoint能否接受消息)、capCanSend(该endpoint能否发送消息)。


同时cap_t也包含三个通用的规则,分别是 capAllowGrantReply、capAllowGrant、capAllowRead和capAllowWrite。


下面是endpoint cap结构体:


block endpoint_cap(capEPBadge, capCanGrantReply, capCanGrant, capCanSend, capCanReceive, capEPPtr, capType) { field capEPBadge 64 field capType 5 field capCanGrantReply 1 field capCanGrant 1 field capCanReceive 1 field capCanSend 1 padding 7 field_high capEPPtr 48}

3.用户程序API


seL4_CNode_CopyseL4_CNode_DeleteseL4_CNode_MintseL4_CNode_MoveseL4_CNode_MutateseL4_CNode_RevokeseL4_CNode_RotateseL4_CNode_SaveCaller

seL4_CNode_Mint为例,该函数的参数有:


  • seL4_CNode _service:新的cap所在的CNode;

  • seL4_Word dest_index:新的cap在CNode的偏移;

  • seL4_Uint8 dest_depth:新的cap在CNode中查找过程中guardbits和radixbits之和;

  • seL4_CNode src_root:原cap所在的CNode;

  • seL4_Word src_index:原cap在CNode的偏移;

  • seL4_Uint8 src_depth:原新的cap在CNode中查找过程中guardbits和radixbits之和;

  • seL4_CapRights_t rights:新的cap的权限;

  • seL4_Word badge:新的cap的标识符;


seL4_CNode_Mint函数具体工作流程如下:


1.通过系统调用执行到decodeCNodeInvocation函数,该函数的具体功能如下:

a. 从ipc buffer里面取出上述的参数信息;

b. 通过_service、dest_index、dest_depth参数可以找到目的slot

c. 通过src_root、src_index、src_depth参数可以找到源slot

d. 通过rights和源slot参数,调用maskCapRights函数,得到带有新的rightscap

e. 更新capbadge信息;

f. 根据label调用invokeCNodeInsert函数。

2.invokeCNodeInsert函数调用cteInsert函数将新cap插入到目的slot中;
3.完成。


4.Capability查找流程


resolveAddressBits根据CNode(nodeCap)、index(capptr)和depth(n_bits)找到slot。具体流程如下:


1.从CNode cap取出radixBitsguardBits,将它们相加得到当前级别的CNode的比特数(比如一级的CNode对应的radixBits是12);
2.从capptr取出guardBits对应的guard,同CNodeguard作比较;
3.从capptr取出capCNode中的偏移量;
4.找到对应的slot,判断该slot中的cap是否位CNode,如果是则到第一步,否则进入第五步;
5.完成;


indexn_bits位数是一致的。


resolveAddressBits_ret_t resolveAddressBits(cap_t nodeCap, cptr_t capptr, word_t n_bits){ ...... while (1) { radixBits = cap_cnode_cap_get_capCNodeRadix(nodeCap); guardBits = cap_cnode_cap_get_capCNodeGuardSize(nodeCap); levelBits = radixBits + guardBits; capGuard = cap_cnode_cap_get_capCNodeGuard(nodeCap); guard = (capptr >> ((n_bits - guardBits) & MASK(wordRadix))) & MASK(guardBits); if (unlikely(guardBits > n_bits || guard != capGuard)) { current_lookup_fault = lookup_fault_guard_mismatch_new(capGuard, n_bits, guardBits); ret.status = EXCEPTION_LOOKUP_FAULT; return ret; }
if (unlikely(levelBits > n_bits)) { current_lookup_fault = lookup_fault_depth_mismatch_new(levelBits, n_bits); ret.status = EXCEPTION_LOOKUP_FAULT; return ret; }
offset = (capptr >> (n_bits - levelBits)) & MASK(radixBits); slot = CTE_PTR(cap_cnode_cap_get_capCNodePtr(nodeCap)) + offset;
if (likely(n_bits <= levelBits)) { ret.status = EXCEPTION_NONE; ret.slot = slot; ret.bitsRemaining = 0; return ret; }
/** GHOSTUPD: "(\<acute>levelBits > 0, id)" */
n_bits -= levelBits; nodeCap = slot->cap;
if (unlikely(cap_get_capType(nodeCap) != cap_cnode_cap)) { ret.status = EXCEPTION_NONE; ret.slot = slot; ret.bitsRemaining = n_bits; return ret; } }
ret.status = EXCEPTION_NONE; return ret;}


5.Capability derive tree


sel4提供cdt来保存cap的变化过程,其本质是一个双向链表。比如:在删除某一个cap时,如果有其他的cap是通过该cap mint创建的,则也需要删除。


//mapping databaseblock mdb_node { padding 16 field_high mdbNext 46 field mdbRevocable 1 field mdbFirstBadged 1 field mdbPrev 64}

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存