code segment descriptor 的 C 位表示 code segment 是 conforming 还是 non-conforming 类型,C = 1 代表 conforming 类型,C = 0 代表 non-conforming。conforming 类型可以允许低权限向高权限转移,而不需要通过 call-gate。低权限向高权限的 non-conforming 转移则必须通过 call-gate。
显然,使用 non-conforming 比使用 conforming 更为安全,因为:
原因 1、当 far call/jmp 到 code segment 直接跳转时(使用 code segment selector):
(1)选择 conforming 类型仅需要 CPL >= DPL 权限就可以了,也就是说:可以直接从低权限向高权限的 code segment 转移,但是 CPL 是不改变的。
这样存在着隐患,由于 CPL(当前的 processor 权限)不改变,但是代码却从低权限转到了高权限,导致:若高权限的代码之中使用了高权限的指令,而 CPL 还停留在低权限上,执行这样的指令会导致异常发生,这是其一。
其二:高权限的代码使用的是高权限的 stack,但由于 CPL 不变,导致不能发生正确的 stack 切换。
(2)而选择 non-conforming 类型需要更严格的权限,需:CPL == DPL 且 RPL <= DPL。
很明显,使用 non-conforming 类型不能从低权限转向高权限,必须 CPL == DPL,只能要同级权限之中转移。这样就避免了不必要的隐患。
原因 2:当通过 call-gate 来 far call/jmp 到 code segment 时:
(1)选择 conforming 类型的需要权限:(CPL <= DPLg) && (RPL <= DPLg) 并且 (CPL >= DPLs)
(2)选择 non-conforming 虽然需要同样的权限:(CPL <= DPLg) && (RPL <= DPLg) 并且 (CPL >= DPLs)。
但是,在 non-conforming 下仅允许使用 call 指令转移到高权限,不允许使用 jmp 指令转移到高权限代码。
使用 jmp call-gate 导致产生两个问题:
其一:jmp 指令不能正确返回到原调用的代码。由于没有将原 CS:RIP 入栈保存,系统服务例程 ret 时,将会出错。
其二:由于不能正确返回,可能导致不能从高权限代码返回低权限代码,processor 将一直运行在高权限代码中。
使用 jmp call-gate 指令到 non-conforming 仅允许同级转移,即:CPL <= DPLg && RPL<= DPLg 并且 CPL == DPLs
jmp 指令只能同级转移(不能调用系统服务例程),使用 non-conforming 类型将不允许 jmp 指令转移到高权限代码,避免隐患。
-------------------------------------------------------------------------------
综上所述两个原因,使用 non-conforming 类型更符合 x86 / x64 的保护机制。
阅读(7423) | 评论(0) | 转发(0) |