CLR 中代码访问安全检测实现原理(3)

发表于:2007-05-25来源:作者:点击数: 标签:代码安全检测CLR访问实现
过于如何遍历调用对象,因为涉及到比较复杂的堆栈帧类型处理,这里就不详细解释,等有空专门写篇文章介绍。目前需要了解的是 CLR 将堆栈切分成各种不同类型的帧,每个帧代表一种状态的迁移。例如调用一个函数、从一个 Assembly 调用另一个 Assembly、从一个
  过于如何遍历调用对象,因为涉及到比较复杂的堆栈帧类型处理,这里就不详细解释,等有空专门写篇文章介绍。目前需要了解的是 CLR 将堆栈切分成各种不同类型的帧,每个帧代表一种状态的迁移。例如调用一个函数、从一个 Assembly 调用另一个 Assembly、从一个 AppDomain 调用另一个 AppDomain、乃至从 Managed 代码调用 Unmanaged 代码等等。而这些帧又通过链表被串到一起。堆栈遍历的工作实际上就是从当前调用帧开始,反向遍历所有的堆栈帧,处理能够处理的,跳过不能处理的,最终到栈顶结束遍历。如果遍历过程中,堆栈帧的回调处理函数发现问题,则可以通过设置标志中断堆栈遍历操作,返回异常给上级程序进行处理。如 CodeAclearcase/" target="_blank" >ccessCheckStackWalkCB 发现某个调用链上的方法所在 Assembly 权限不够,则中断遍历操作抛出异常。

  对检测某个组件是否拥有权限的 CodeAccessCheckStackWalkCB 函数 (ComCodeAccessSecurityEngine.cpp:449) 来说,其主要工作如下:

以下内容为程序代码:

enum StackWalkAction {
  SWA_CONTINUE  = 0,  // continue walking
  SWA_ABORT    = 1,  // stop walking, early out in "failure case"
  SWA_FAILED   = 2   // couldn't walk stack
};

// 堆栈帧的封装类
class CrawlFrame {
 // ...
};

static StackWalkAction CodeAccessCheckStackWalkCB(CrawlFrame* pCf, VOID* pData)
{
 // CheckInternal 填充的检测数据
 CheckWalkHeader *pCBdata = (CheckWalkHeader*)pData;

 // 获取当前帧的相关信息
 MethodDesc * pFunc = pCf->GetFunction();
 Assembly *pAssem = pFunc->GetModule()->GetAssembly();
 AppDomain *pAppDomain = pCf->GetAppDomain();

 // 遍历操作回调函数的返回动作,SWA_CONTINUE 继续;SWA_ABORT 中断;SWA_FAILED 失败。
 StackWalkAction action ;

 // 跳过特殊情况的帧
 if (Security::SecWalkCommonProlog (&(pCBdata->prologData), pFunc, &action, pCf))
   return action ;

 if (pAssem != pCBdata->pPrevAssembly)
 {
  // 当 Assembly 变化时进行 CAS 检测
  // ...

  pCBdata->pPrevAssembly = pAssem;
 }

 if (pAppDomain != pCBdata->pPrevAppDomain)
 {
  // 当 AppDomain 变化时进行 CAS 检测
  // ...

  pCBdata->pPrevAppDomain = pAppDomain;
 }

 OBJECTREF *pFrameObjectSlot = pCf->GetAddrOfSecurityObject();
 if (pFrameObjectSlot != NULL && *pFrameObjectSlot != NULL)
 {
  // 当帧保护安全对象时进行 CAS 检测
  // ...
 }

 return SWA_CONTINUE;
}


  从当前帧中可以获取各种需要检测的信息,如方法、Assembly和AppDomain。只有当 Assembly 或 AppDomain 发生变化时,对新的对象进行 CAS 检测,同时如果帧具有显式的安全对象,也要进行 CAS 检测。不过对于符合 Security::SecWalkCommonProlog 函数 (Security.cpp:406) 定义的特殊帧,将完全跳过 CAS 检测。

原文转自:http://www.ltesting.net