迷失現象界每日頭條 寫: ↑週日 6月 12, 2022 10:27 am CPU的運行環,特權級與保護
2019-07-21 由 底層軟件架構 發表于資訊
微信公眾號:技術原理君
可能你憑藉直覺就知道應用程式的功能受到了Intel x86計算機的某種限制,有些特定的任務只有作業系統的代碼才可以完成,但是你知道這到底是怎麼一回事嗎?在這篇文章里,我們會接觸到x86的特權級(privilege level),看看作業系統和CPU是怎麼一起合謀來限制用戶模式的應用程式的。特權級總共有4個,編號從0(最高特權)到3(最低特權)。有3種主要的資源受到保護:內存,I/O埠以及執行特殊機器指令的能力。在任一時刻,x86 CPU都是在一個特定的特權級下運行的,從而決定了代碼可以做什麼,不可以做什麼。這些特權級經常被描述為保護環(protection ring),最內的環對應於最高特權。即使是最新的x86內核也只用到其中的2個特權級:0和3。
x86的保護環
在諸多機器指令中,只有大約15條指令被CPU限制只能在ring 0執行(其餘那麼多指令的操作數都受到一定的限制)。這些指令如果被用戶模式的程序所使用,就會顛覆保護機制或引起混亂,所以它們被保留給內核使用。如果企圖在ring 0以外運行這些指令,就會導致一個一般保護錯(general-protection exception),就像一個程序使用了非法的內存地址一樣。類似的,對內存和I/O埠的訪問也受特權級的限制。但是,在我們分析保護機制之前,先讓我們看看CPU是怎麼記錄當前特權級的吧,這與前篇文章中提到的段選擇符(segment selector)有關。如下所示:
數據段和代碼段的段選擇符
數據段選擇符的整個內容可由程序直接加載到各個段寄存器當中,比如ss(堆棧段寄存器)和ds(數據段寄存器)。這些內容里包含了請求特權級(Requested Privilege Level,簡稱RPL)欄位,其含義過會兒再說。然而,代碼段寄存器(cs)就比較特別了。首先,它的內容不能由裝載指令(如MOV)直接設置,而只能被那些會改變程序執行順序的指令(如CALL)間接的設置。而且,不像那個可以被代碼設置的RPL欄位,cs擁有一個由CPU自己維護的當前特權級欄位(Current Privilege Level,簡稱CPL),這點對我們來說非常重要。這個代碼段寄存器中的2位寬的CPL欄位的值總是等於CPU的當前特權級。Intel的文檔並未明確指出此事實,而且有時在線文檔也對此含糊其辭,但這的確是個硬性規定。在任何時候,不管CPU內部正在發生什麼,只要看一眼cs中的CPL,你就可以知道此刻的特權級了。
記住,CPU特權級並不會對作業系統的用戶造成什麼影響,不管你是根用戶,管理員,訪客還是一般用戶。所有的用戶代碼都在ring 3上執行,所有的內核代碼都在ring 0上執行,跟是以哪個OS用戶的身份執行無關。有時一些內核任務可以被放到用戶模式中執行,比如Windows Vista上的用戶模式驅動程序,但是它們只是替內核執行任務的特殊進程而已,而且往往可以被直接刪除而不會引起嚴重後果。
由於限制了對內存和I/O埠的訪問,用戶模式代碼在不調用系統內核的情況下,幾乎不能與外部世界交互。它不能打開文件,發送網絡數據包,向屏幕列印信息或分配內存。用戶模式進程的執行被嚴格限制在一個由ring 0之 神所設定的沙盤之中。這就是為什麼從設計上就決定了:一個進程所泄漏的內存會在進程結束後被統統回收,之前打開的文件也會被自動關閉。所有的控制著內存或 打開的文件等的數據結構全都不能被用戶代碼直接使用;一旦進程結束了,這個沙盤就會被內核拆毀。這就是為什麼我們的伺服器只要硬體和內核不出毛病,就可以 連續正常運行600天,甚至一直運行下去。這也解釋了為什麼Windows 95/98那麼容易死機:這並非因為微軟差勁,而是因為系統中的一些重要數據結構,出於兼容的目的被設計成可以由用戶直接訪問了。這在當時可能是一個很好的折中,當然代價也很大。
原文網址:https://kknews.cc/news/34o84xg.html
從來只識神