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


    本文参考文章:保护模式对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 异常产生,转去处理异常 */
    }



  • 相关阅读:
    阿里云centos7.2自己安装mysql5.7远程不能访问解决方案
    Delphi中的线程类
    简单说说Delphi中线程的释放
    delphi杀进程的两种方式
    delphi备份恢复剪切板(使用了GlobalLock API函数和CopyMemory)
    Delphi 7下使用Log4Delphi 0.8日志组件
    Demo+在Linux下运行(CentOS7+dotnetcore sdk)
    反射
    解析表达式树
    JS面向对象编程之:封装、继承、多态
  • 原文地址:https://www.cnblogs.com/javaadu/p/11742664.html
Copyright © 2020-2023  润新知