zoukankan      html  css  js  c++  java
  • 操作系统开发系列—5.特权级及特权级的转移

    CPL——当前执行的程序或任务的特权级,它被存储在cs和ss的第0位和第1位上。

    DPL——段或者门的特权级,如果是数据段DPL则规定了可以访问此段的最低特权级

    RPL——通过段选择子的第0位和第1位表现出来的。处理器通过检查RPL和CPL来确认一个访问请求是否合法。RPL保证了操作系统不会越俎代庖地代表一个程序去访问一个段。

    我们先来展示一下特权级错误访问版本。

    先把LABEL_DESC_DATA对应的段描述符的DPL修改为1:

    LABEL_DESC_DATA:   Descriptor    0,      DataLen-1, DA_DRW+DA_DPL1    ; Data
    

    继续修改,把选择子的RPL改为3:

    SelectorData		equ	LABEL_DESC_DATA		- LABEL_GDT + SA_RPL3
    

    运行结果如下:

    虚拟机崩溃。因为RPL & CPL 必须 <= DPL

    下面就演示一下从低特权转到高特权的方法:

    通过jmp和call所能进行的代码段间转移是非常有限的,对于非一致代码段,只能在相同特权级代码段之间转移。遇到一致代码段也最多能从低到高,而且CPL不会改变。如果想自由地进行不同特权级之间的转移,显然需要其他几种方式,即运用门描述符或者TSS。调用门描述符格式如下:

    一个门描述了由一个选择子和一个偏移所指定的线性地址,程序正是通过这个地址进行转移的。

    以下是通过调用门转移的目标段:

    [SECTION .sdest]; 调用门目标段
    [BITS	32]
    
    LABEL_SEG_CODE_DEST:
    	;jmp	$
    	mov	ax, SelectorVideo
    	mov	gs, ax			; 视频段选择子(目的)
    
    	mov	edi, (80 * 12 + 0) * 2	; 屏幕第 12 行, 第 0 列。
    	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
    	mov	al, 'C'
    	mov	[gs:edi], ax
    
    	retf
    
    SegCodeDestLen	equ	$ - LABEL_SEG_CODE_DEST
    ; END of [SECTION .sdest]
    

    下面是代码段描述符,选择子及初始化描述符的代码:

    LABEL_DESC_CODE_DEST: Descriptor 0,SegCodeDestLen-1, DA_C+DA_32; 非一致代码段,32
    
    SelectorCodeDest	equ	LABEL_DESC_CODE_DEST	- LABEL_GDT
    
    ; 初始化测试调用门的代码段描述符
    	xor	eax, eax
    	mov	ax, cs
    	shl	eax, 4
    	add	eax, LABEL_SEG_CODE_DEST
    	mov	word [LABEL_DESC_CODE_DEST + 2], ax
    	shr	eax, 16
    	mov	byte [LABEL_DESC_CODE_DEST + 4], al
    	mov	byte [LABEL_DESC_CODE_DEST + 7], ah
    

    现在添加调用门:

    LABEL_CALL_GATE_TEST: Gate SelectorCodeDest,   0,     0, DA_386CGate+DA_DPL0
    

    宏Gate的定义在pm.inc中

    描述符的属性是DA_386CGate表明是一个调用门。里面指定的选择子是SelectorCodeDest,表明目标代码段是刚刚新添加的代码段。偏移地址是0,表示将跳转到目标代码段的开头处。另外,我们把其DPL指定为0.

    现在调用门准备就绪,它指向的位置是SelectorCodeDest:0,即标号LABEL_SEG_CODE_DEST处的代码。

    假设我们想由代码A转移到代码B,运用一个调用门G,即调用门G中的目标选择子指向代码B的段。代码B的DPL记做DPL_B,在用call指令时,要求目标代码DPL_B<=CPL;在用jmp指令时,只能是DPL_B=CPL。

    现在添加一个低特权的代码段ring3和堆栈:

    LABEL_DESC_CODE_RING3: Descriptor 0,SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3
    LABEL_DESC_STACK3:     Descriptor 0,      TopOfStack3, DA_DRWA+DA_32+DA_DPL3
    
    ; 堆栈段ring3
    [SECTION .s3]
    ALIGN	32
    [BITS	32]
    LABEL_STACK3:
    	times 512 db 0
    TopOfStack3	equ	$ - LABEL_STACK3 - 1
    ; END of [SECTION .s3]
    
    ; CodeRing3
    [SECTION .ring3]
    ALIGN	32
    [BITS	32]
    LABEL_CODE_RING3:
    	mov	ax, SelectorVideo
    	mov	gs, ax
    
    	mov	edi, (80 * 14 + 0) * 2
    	mov	ah, 0Ch
    	mov	al, '3'
    	mov	[gs:edi], ax
    
    	jmp	$
    SegCodeRing3Len	equ	$ - LABEL_CODE_RING3
    ; END of [SECTION .ring3]
    

    执行如下:

    打印了红色的3,表明我们由ring0到ring3的转移成功。接下来试验一下调用门的使用。

    把调用门的描述符和选择子改成特权等级为3.还有从低特权级到高特权级转移的时候,需要用到TSS,我们来准备一个TSS。

    LABEL_DESC_TSS:        Descriptor 0,          TSSLen-1, DA_386TSS
    
    ; TSS
    [SECTION .tss]
    ALIGN	32
    [BITS	32]
    LABEL_TSS:
    		DD	0			; Back
    		DD	TopOfStack		; 0 级堆栈
    		DD	SelectorStack		;
    		DD	0			; 1 级堆栈
    		DD	0			;
    		DD	0			; 2 级堆栈
    		DD	0			;
    		DD	0			; CR3
    		DD	0			; EIP
    		DD	0			; EFLAGS
    		DD	0			; EAX
    		DD	0			; ECX
    		DD	0			; EDX
    		DD	0			; EBX
    		DD	0			; ESP
    		DD	0			; EBP
    		DD	0			; ESI
    		DD	0			; EDI
    		DD	0			; ES
    		DD	0			; CS
    		DD	0			; SS
    		DD	0			; DS
    		DD	0			; FS
    		DD	0			; GS
    		DD	0			; LDT
    		DW	0			; 调试陷阱标志
    		DW	$ - LABEL_TSS + 2	; I/O位图基址
    		DB	0ffh			; I/O位图结束标志
    TSSLen		equ	$ - LABEL_TSS
    

    我们需要在特权级变换之前加载它

    	mov	ax, SelectorTSS
    	ltr	ax
    

    运行结果如下:

     

    看到字母C表明从低特权级到高特权级的转移。

    一个码农的日常 

    源码

  • 相关阅读:
    Mysql日志管理
    Mysql 安全和DCL语句
    Mysql DDL语句之视图
    Mysql增删改查(DML、DQL)
    Mysql操作之部分DDL语句
    如何做事情
    temp
    asp.net入门
    希望尽快回忆起来
    需求?
  • 原文地址:https://www.cnblogs.com/joey-hua/p/5374216.html
Copyright © 2011-2022 走看看