操作系統---IO權限管理和敏感指令


簡化版

使用IOPL設置一個特權級的用戶程序對所有端口的訪問權限,使用I/O位圖對一個特權級的用戶程序設置個性化的端口訪問權限(能訪問部分端口、不能訪問另外的端口)。

用戶程序的CPL<IOPL,用戶程序能訪問所有端口。否則,從I/O位圖中查找用戶程序對端口的訪問權限。

IOPL存儲在eflags中,只能在0特權級的下通過popfiretd修改。

I/O位圖存儲在TSS中。

I/O操作也可以看作一種特權資源,也有“訪問門檻”。代碼段和數據段的訪問“門檻”是DPL,存儲在段描述符中。

I/O操作的訪問門檻存儲在eflagsIOPL位。但是否具有I/O操作的權限,還受I/O位圖影響。

敏感指令是指這些指令:in、ins、out、outs、pof、iretd

IOPL

規則

數值上,CPL <= IOPL,權限上,當前代碼段的特權級高於或等於IOPL中存儲的特權等級,當前代碼段才能執行I/O操作。

CPL = 0,用戶程序才能執行敏感指令。

eflags

eflagsflags的32位擴展寄存器,保護許多標志位,例如cf、zf等。IOPL也存儲在eflags中,占用2個bit,正好能表示四個特權級:00、01、10、11

更新

沒有能直接更新eflags的指令,只能間接修改eflags從而修改IOPL。方法是使用兩個指令:popfiretd

只有特權級是0的用戶程序才能成功修改eflags中的IOPL。特權不是0的用戶程序也能執行popfiretd來修改IOPL,只不過修改無效,也就是說,能執行、無效果、不報錯。

popf

popf的示意代碼如下:

pushf		; 把eflags中的值入棧
mov			[esp],  要更新到eflags中的值
popf		; 把棧中的值存儲到eflags

popf除了能修改IOPL,還能修改IF。這不難理解。因為popf是把棧中的整個符合eflags結構的數據更新到eflags中,只需把那個結構的IF位修改為目標值就能修改eflags中的IF位。

popf用來修改IF位的時候,和sti、cli一樣是敏感指令,需要滿足特權級檢查規則:CPL <= IOPL。

popf用來修改IOPL位的時候,需要滿足特權級檢查規則:CPL = 0。

同一個指令,修改的內容不同,需滿足的特權級檢查規則不同,這種設計,不好。若我來設計,我會設計成兩個指令,每個指令完成各自的功能。

iretd

中斷發生時,eflags會入棧中斷例程的堆棧。修改這個堆棧中的eflags的值,然后再使用iretd就能把棧中的新eflags值更新到eflags中。

IO位圖

IOPL對一個特權級的所有用戶程序的I/O權限做“一刀切”的限制,要么這個特權級的所有用戶程序擁有所有端口的I/O權限,要么擁有0個端口的I/O權限。IO位圖允許對每個用戶程序在I/O端口限制上做個性化配置。

如果用戶進程的CPL <= IOPL,那么,IO位圖的值是多少不影響用戶進程的I/O權限。如果用戶進程的CPL > IOPL,那么,IO位圖的值決定了用戶進程能讀寫哪些I/O端口。

位圖

位圖,又叫bitmap。一個bit能表示兩種值,0或1。1kb的空間擁有1024個bit,1Mb的空間擁有1024*1024個bit。

假如我們的硬件一共有65536個I/O端口,只需要8Kb的空間就能標識出這么多端口的權限狀態。給8kb空間中的65536個bit依次編號,若第0號I/O端口在能被當前用戶進程讀寫,將此bit設置為1,否則設置為0;剩余的第1到第65535個bit依次按對應的I/O端口依次設置值。

TSS的尺寸

如果用戶程序存在I/O位圖,它將出現在用戶程序的TSS的頂端。正因為如此,TSS的尺寸是不固定的。如果不包含I/O位圖,TSS的尺寸是104字節。如果包含I/O位圖,TSS的尺寸是“I/O位圖地址 + 8192字節 + 1字節”。

包含/IO位圖,TSS的尺寸為什么不是“104字節 + 8192字節 + 1字節”?

因為I/O位圖有可能不是緊挨着保存"I/O位圖地址"的那個 字節,二者之間可能有空白空間。I/O位圖地址是I/O位圖在TSS中的偏移量,注意,I/O位圖在TSS中,它與TSS中的其他元素都在TSS中。也就是說,從TSS的初始位置開始到I/O位圖地址,也許包含部分沒有存儲數據的空間,都是TSS的一部分。TSS的空間被I/O位圖地址分割為兩個部分,前一部分的大小是I/O位圖地址,后一部分是8192個字節(65536個端口需要65536個bit)+1字節(位圖的結束標志必須是0xff)。

說得簡單點,就是,I/O位圖和TSS中的其他元素可能不是緊緊挨着。

0xff

位圖為什么要用0xff作為結束標志?我沒有弄明白。

代碼

不知道TSS中的保留位是什么,更不知道怎么在代碼中表示保留位。這里的代碼只保證正確表示I/O位圖。

怎么寫代碼?

  1. 表示I/O位圖地址、I/O位圖自身。
  2. I/O位圖自身
    1. 全部bit的數量並不一定需要是65536個。
    2. 只需用0xff結尾就行。
[SECTION .tss3]
LABEL_TSS3:
			;TSS中的其他元素
			; 最糾結的語句。$ - LABEL_TSS3是當前行在TSS中的偏移量。
			; 本語句占用2個字節,2個字節之后是I/O位圖。
			dw		$ - LABEL_TSS3 + 2
times		 12		 db 	0ffh					; 12個字節,96個bit,都設置為1,表示當前用戶程序有端口0到端口95的讀寫權限。
			; 端口96到102只有端口97對當前用戶程序開放了讀寫權限。從右到左編號,所以第2個0表示97號端口。
			db		1111101b	
      ; I/O位圖的結束標志
      db		0xff


TSS3_LEN			equ				$$ - LABEL_TSS3


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM