在 x86-64 上,核心會使用 SYSRET
和 IRETQ
指令分別從系統呼叫和中斷中傳回。請務必小心,不要在這些操作說明中使用非標準回傳位址 (至少在 Intel CPU 上),因為這會導致指令在核心模式下出錯,並不安全。相較之下,在 AMD CPU 中使用非標準傳回地址時,SYSRET
會錯誤讓使用者模式運作。
這些操作說明會在核心模式下發生錯誤,其中一個問題是,在中斷或系統呼叫處理機制結束時,操作說明會在 gs
註冊從核心 x86_percpu
變為由使用者空間控管的值後出現。當核心模式發生例外狀況時,由於目前的 gs
註冊屬於核心,因此不會變更 gs
登錄。這會讓核心透過使用者控制的 x86_percpu
結構處理錯誤,並輕鬆導致核心程式碼執行。
通常的非負數非標準位址最低為 0x0000800000000000
(== 1 << 47)。如果使用者程序可能會使系統呼叫傳回地址不是標準網址,其中一種方法是將 4K 執行檔對應至該位址 (位於 0x00007ffffffff000
) 下方、在該頁面結尾加入 SYSCALL
指令,然後執行 SYSCALL
指令。
如何避免發生這個問題:
如果下列網頁的虛擬位址不是標準網址,我們不允許對應網頁。
我們不允許使用
zx_thread_write_state()
將RIP
註冊設為非標準位址。不允許將執行緒進入點設為
ThreadDispatcher::MakeRunnable()
中的非標準位址。我們不允許在
zx_thread_start()
和zx_process_start()
中設定非使用者空間的地址。