查看OSdev wiki for details on sysenter
,包括關於如何避免安全/安全問題的說明。另請參閱英特爾/ AMD手冊。它們涉及操作系統開發人員所需的大量細節。有關鏈接,請參閱x86標記wiki。
的各種系統調用指令概述:
int
:可用自永遠(8086)
- 通過執行一個無效的指令陷阱,顯然是the fastest way to enter the kernel on 80386。 (但情況不再如此)。
- call gate(即,
far call
)。請參閱OSdev鏈接以獲取有關該細節和陷阱的詳細信息。
sysenter
:(http://wiki.osdev.org/Sysenter)英特爾在x86-64之前推出,不久之後被AMD採用(多年前)。適用於所有現代x86 CPU。非常簡約的設計需要用戶空間合作才能使內核能夠返回,因爲它不會將EIP,ESP或EFLAGS保存在任何地方。
Linux僅在32位和64位內核中支持32位進程的系統調用。 IDK,如果你可以設計一個用於64位系統調用的內核。 (我知道這不是問題,但它是相關的。)
使用sysenter
需要用戶空間合作來提供返回地址並保存它自己的ESP和EFLAGS。在Linux中,內核會導出一個代碼頁面,其中包含跳舞的用戶空間。用戶空間預計call
這個代碼,而不是直接使用sysenter
,但隨意設計你的操作系統,但你想要的。如果你在其他地方找不到示例,那麼查看Linux的代碼可能對此舞蹈的雙方都有用。
從64位用戶空間syscall
:隨處可見,因爲英特爾實現了它與AMD64的其餘一起。精心設計的接口在進入內核之前會屏蔽RFLAGS(帶有可配置的掩碼),因此您可以避免競爭窗口(如果必須使用cli
手動禁用中斷)。與swapgs
一起用於內核訪問其堆棧等。
在主流x86操作系統(如Linux)上,syscall
是進行64位系統調用的唯一方法。
syscall
從32位用戶空間:從長模式syscall
,僅在AMD處理器可用一個完全不同的指令。對於32位內核(傳統模式)與運行32位用戶空間(compat模式)的64位內核,內核端接口不同。
Linux內核有它的一些有用的意見:
entry_64_compat.S
32-bit SYSCALL entry(32位syscall
入口點到64位內核)
/* ...
* - Most programmers do not directly target AMD CPUs, and the 32-bit
* SYSCALL instruction does not exist on Intel CPUs. Even on AMD
* CPUs, Linux disables the SYSCALL instruction on 32-bit kernels
* because the SYSCALL instruction in legacy/native 32-bit mode (as
* opposed to compat mode) is sufficiently poorly designed as to be
* essentially unusable.
也許玩具操作系統可以使用它,而不必擔心任何問題使其不適用於Linux,IDK。但除非你只是好奇,否則不要浪費時間。 OTOH,如果你對CPU設計感興趣,找出ISA設計的問題可能會很有趣。
順便說一句,當AMD在設計AMD64,他們得到了來自Linux內核開發者認爲改善64位syscall
設計的AMD64郵件列表上的一些反饋(以可配置掩蓋RFLAGS),因爲他們最初的設計本來問題適用於Linux 。鏈接到那些已存檔的郵件列表帖子in this answer。
建議:使用sysenter
爲32位內核。它應該可以在任何地方使用,包括在AMD CPU上使用多年。不支持它的古代CPU可以使用int 0x80
ABI(或者您爲操作系統挑選的任何數字),如果您想添加第二個兼容性ABI。
Linux內核入口點的註釋很好,寫得相當易讀。在編寫What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?時,我很容易地通過使用syscall
(原生64位系統調用)或int 0x80
或sysenter
(32位系統調用,通常來自compat)來確定在64位內核的入口點發生了什麼。模式,但int 0x80
是支持64位的進程。但它仍然調用32位ABI!)有複雜的東西的情況下,要在一堆各種跟蹤/調試啓用,但其他部分是相當容易跟隨。查看這個答案,瞭解一些Linux的系統調用處理內部。
在arch/x86/entry
,這些都是利益的主要文件:
entry_32.S
:從用戶空間進入32位內核代碼。 (遺留模式)
entry_64_compat.S
:用於從32位用戶空間(compat模式 - >長模式)輸入的64位內核代碼。
entry_64.S
:用於從64位用戶空間(長模式 - >長模式)進入的64位內核代碼。
你應該能夠找到的sysenter
舞蹈是傳遞內核,它需要返回到用戶空間的值的用戶空間側的Linux的VDSO代碼。 (What is better "int 0x80" or "syscall"?)。相關:What is better "int 0x80" or "syscall"?和The Definitive Guide to Linux System Calls將提供有關Linux所做設計選擇的一些有用信息。
是真的,sysret
指令是不是安全?
當返回到64位用戶空間時,英特爾和AMD都有與非規範RIP分離的錯誤。例如英特爾,Linux's entry_64.S
這樣描述:
/*
* On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
* in kernel space. This essentially lets the user take over
* the kernel, since userspace controls RSP.
如果ptrace
系統調用(例如,通過一個調試器中進行)改變了進程的RIP
的保存價值,非規範的地址,可以發生。 Linux檢查是否可以使用sysret
,如果不使用它的iret
返回路徑。 (sysret
路徑速度足夠快,因此值得做更多的工作來檢查它是否安全)。
注意,如果一個系統調用塊/睡眠狀態時,「主副本」用戶空間的整數寄存器狀態的是它的內核堆棧,系統調用入口點推它。 (在Linux中,其他設計是可能的!)但是,無論如何,這就是爲什麼最終會出現奇怪的保存狀態,用戶空間不能運行syscall
(因爲它將在jmp
上違反非規範地址)或saved_rcx != saved_RIP
(64位syscall
設置RCX = RIP,和R11 = RFLAGS(屏蔽之前),所以它則會覆蓋RCX和R11,但允許內核恢復RIP和RFLAGS。)
我不知道該怎麼32位syscall
作品,對不起,我在這裏得到話題。但是我懷疑你可能讀到的有關sysret
不安全的內容是關於64位內核的。
IDK如果在32位內核sysret
或64位內核sysret
-to-compat-mode中有任何類似的錯誤。
您是否嘗試過在手動或在線資源中查看?你發現了什麼? – fuz
可能重複[什麼是更好的「int 0x80」或「系統調用」?](https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall) –
@BoPersson問題似乎不相關:另一個問題只關注Linux;這個問題關注於一個自編寫的內核。 –