第四章---关于系统调用的权限检查

本文参考文章:保护模式对CPL、RPL、DPL的总结

在本章,首先开始讲了系统调用过程,系统调用过程中涉及到用户空间和系统空间之间的转换,有关的权限检查也是不可少的。由于跳转的方式有两种:(1)直接转移(far call 及 far jmp);(2)使用call gate 进行控制权的转移;(3)中断门或者陷阱门转移。

书上分类分得补清楚,而且也没有说清楚Int 0x80的跳转过程实际上是使用中断门或者陷阱门进行转移

其中,中断门符及陷井门必须存放在IDT中,IDT表也可以存放call gate。

1、 中断调用时的权限检查
   用中断门符进行转移时,所作的权限检查同call gate相同,区别在于intterrupt gate 转移不需要检查RPL,因为,没有RPL需要检查。
★ 必须有足够的权限访问门符,CPL <= DPLg
★ 向同级权限代码转移时,CPL == DPLs,向高权限代码转移时,CPL > DPLs

总结

if (CPL <= DPLg) { /* 有足够权限访问门符 */
    if (CPL >= DPLs) {
        /* 允许访问目标代码头 */
    } else {
         /* 失败,#GP异常发生 */
    }

} else {
/* 失败,#GP异常发生 */
}

2、 控制权的转移
   发生异常或中断调用时
★ 用中断向量在中断描述符表查找描述符:中断向量×8,然后加上IDT表基址得出描述符表。
★ 从查找到的描述符中得到目标代码段选择子,并在相应的GDT或LDT中获取目标代码段描述符。
★ 目标代码段描述符的基址加上门符中的offset,确定最终执行入口点。

例子:

INT 0X80的实际情况是(跟书上的代码一样,但是很明显,该书并没有讲清楚它到底是为那个分类举例):

vector = 0x80;
INTGATE_DESCRIPTOR gate_descriptor = IDTR.base + vector * 8;
CODESEG_DESCRIPTOR target_descriptor;
TSS tss = TR.base;               /* 得到TSS 内存块 */
DPLg = gate_descriptor.DPL;
target_cs = gate_descriptor.selector;
if (CPL <= DPLg) {            /* 允许访问门符 */

if (target_cs.TI == 0) {   /* index on GDT */
    target_descriptor = GDTR.base + target_cs.SI * 8;
} else {              /* index on LDT */
target_descriptor = LDTR.base + target_cs.SI * 8;
    }

DPLs = target_descriptor.DPL;


if (CPL > DPLs) {     /* 向高权限代码转移 */

    /* 根据目标代码段的DPL值来选取相应权限的stack结构 */
    switch (DPLs) {
    case 0 :     /* 假如目标代码处理0级,则选0级的stack结构 */
             SS = tss.ss0;
             ESP = tss.esp0;
             break;
        case 1:
             SS = tss.ss1;
            ESP = tss.esp1;
             break;
        case 2: 
             SS = tss.ss2;
             ESP = tss.esp2;
             break;
    }

       /* 以下必须保护旧的stack结构,以便返回 */
    *--esp = SS;          /* 将当前SS入栈保护 */
    *--esp = ESP;         /* 将当前ESP入栈保护 */

} else if (CPL == DPLs) {
     /* 同级转移,继续向下执行 */
} else {
    /* 失败,#GP异常产生,转去处理异常 */
}


*--esp = EFLAGS;          /* eflags 寄存器入栈 */

     /* 分别将 NT、NT、RF及VM标志位清0 */
EFLAGS.TF = 0;            
EFLAGS.NT = 0;
EFLAGS.RF = 0;
EFLAGS.VM = 0;

if (gate_descriptor.type == I_GATE32) { /* 假如是中断门符 */
EFLAGS.IF = 0;          /* 也将IF标志位清0,屏蔽响应中断 */
     }
             
     *--esp = CS;              /* 当前段选择子入栈 */
     *--esp = EIP;             /* 当前EIP 入栈 */
  CS = target_selector;      /* 加载目标代码段 */
CS.RPL = DPLs;            /* 改变当前执行权限级别 */
EIP = gate_descriptor.offset; /* 加载进入EIP */

/* 执行中断例程 */
goto target_descritptor.base + gate_descriptor.offset; 

} else {
/* 失败,#GP 异常产生,转去处理异常 */
}



posted @ 2013-11-21 19:42  javaadu  阅读(370)  评论(1编辑  收藏  举报