Chinese (Traditional)

Warning

此文件的目的是爲讓中文讀者更容易閱讀和理解,而不是作爲一個分支。因此, 如果您對此文件有任何意見或改動,請先嘗試更新原始英文文件。如果要更改或 修正某處翻譯文件,請將意見或補丁發送給維護者(聯繫方式見下)。

Note

如果您發現本文檔與原始文件有任何不同或者有翻譯問題,請聯繫該文件的譯者, 或者發送電子郵件給胡皓文以獲取幫助:<2023002089@link.tyut.edu.cn>。

Original

Linux Magic System Request Key Hacks

翻譯

黃軍華 Junhua Huang <huang.junhua@zte.com.cn>

校譯

司延騰 Yanteng Si <siyanteng@loongson.cn>

Linux 魔法系統請求鍵駭客

針對 sysrq.c 的文檔說明

什麼是魔法 SysRq 鍵?

它是一個你可以輸入的具有魔法般的組合鍵。 無論內核在做什麼,內核都會響應 SysRq 鍵的輸入,除非內核完全卡死。

如何使能魔法 SysRq 鍵?

在配置內核時,我們需要設置 ‘Magic SysRq key (CONFIG_MAGIC_SYSRQ)’ 爲 ‘Y’。 當運行一個編譯進 sysrq 功能的內核時,/proc/sys/kernel/sysrq 控制着被 SysRq 鍵調用的功能許可。這個文件的默認值由 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 配置符號設定,文件本身默認設置爲 1。以下是 /proc/sys/kernel/sysrq 中可能的 值列表:

  • 0 - 完全不使能 SysRq 鍵

  • 1 - 使能 SysRq 鍵的全部功能

  • >1 - 對於允許的 SysRq 鍵功能的比特掩碼(參見下面更詳細的功能描述):

      2 =   0x2 - 使能對控制檯日誌記錄級別的控制
      4 =   0x4 - 使能對鍵盤的控制 (SAK, unraw)
      8 =   0x8 - 使能對進程的調試導出等
     16 =  0x10 - 使能同步命令
     32 =  0x20 - 使能重新掛載只讀
     64 =  0x40 - 使能對進程的信號操作 (term, kill, oom-kill)
    128 =  0x80 - 允許重啓、斷電
    256 = 0x100 - 允許讓所有實時任務變普通任務
    

你可以通過如下命令把值設置到這個文件中:

echo "number" >/proc/sys/kernel/sysrq

這裏被寫入的 number 可以是 10 進制數,或者是帶着 0x 前綴的 16 進制數。 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 必須是以 16 進制數寫入。

注意,/proc/sys/kernel/sysrq 的值隻影響通過鍵盤觸發 SySRq 的調用,對於 通過 /proc/sysrq-trigger 的任何操作調用都是允許的 (通過具有系統權限的用戶)。

如何使用魔法 SysRq 鍵?

在 x86 架構上

你可以按下鍵盤組合鍵 ALT-SysRq-<command key>

Note

一些鍵盤可能沒有標識 ‘SySRq’ 鍵。’SySRq’ 鍵也被當做 ‘Print Screen’鍵。 同時有些鍵盤無法處理同時按下這麼多鍵,因此你可以先按下鍵盤 Alt 鍵, 然後按下鍵盤 SysRq 鍵,再釋放鍵盤 SysRq 鍵,之後按下鍵盤上命令鍵 <command key>,最後釋放所有鍵。

在 SPARC 架構上

你可以按下鍵盤組合鍵 ALT-STOP-<command key>

在串行控制檯(只針對 PC 類型的標準串口)

你可以發一個 BREAK ,然後在 5 秒內發送一個命令鍵, 發送 BREAK 兩次將被翻譯爲一個正常的 BREAK 操作。

在 PowerPC 架構上

按下鍵盤組合鍵 ALT - Print Screen (或者 F13) - <命令鍵>Print Screen (或者 F13) - <命令鍵> 或許也能實現。

在其他架構上

如果你知道其他架構的組合鍵,請告訴我,我可以把它們添加到這部分。

在所有架構上

寫一個字符到 /proc/sysrq-trigger 文件,例如:

echo t > /proc/sysrq-trigger

這個命令鍵 <command key> 是區分大小寫的。

什麼是命令鍵?

命令鍵

功能

b

將立即重啓系統,不會同步或者卸載磁盤。

c

將執行系統 crash,如果配置了系統 crashdump,將執行 crashdump。

d

顯示所有持有的鎖。

e

發送 SIGTERM 信號給所有進程,除了 init 進程。

f

將調用 oom killer 殺掉一個過度佔用內存的進程,如果什麼任務都沒殺, 也不會 panic。

g

kgdb 使用(內核調試器)。

h

將會顯示幫助。(實際上除了這裏列舉的鍵,其他的都將顯示幫助, 但是 h 容易記住):-)

i

發送 SIGKILL 給所有進程,除了 init 進程。

j

強制性的 “解凍它” - 用於被 FIFREEZE ioctl 操作凍住的文件系統。

k

安全訪問祕鑰(SAK)殺掉在當前虛擬控制檯的所有程序,注意:參考 下面 SAK 節重要論述。

l

顯示所有活動 cpu 的棧回溯。

m

將導出當前內存信息到你的控制檯。

n

用於使所有實時任務變成普通任務。

o

將關閉系統(如果配置和支持的話)。

p

將導出當前寄存器和標誌位到控制檯。

q

將導出每個 cpu 上所有已裝備的高精度定時器(不是完整的 time_list 文件顯示的 timers)和所有時鐘事件設備的詳細信息。

r

關閉鍵盤的原始模式,設置爲轉換模式。

s

將嘗試同步所有的已掛載文件系統。

t

將導出當前所有任務列表和它們的信息到控制檯。

u

將嘗試重新掛載已掛載文件系統爲只讀。

v

強制恢復幀緩存控制檯。

v

觸發 ETM 緩存導出 [ARM 架構特有]

w

導出處於不可中斷狀態(阻塞)的任務。

x

在 ppc/powerpc 架構上用於 xmon 接口。 在 sparc64 架構上用於顯示全局的 PMU(性能監控單元)寄存器。 在 MIPS 架構上導出所有的 tlb 條目。

y

顯示全局 cpu 寄存器 [SPARC-64 架構特有]

z

導出 ftrace 緩存信息

0-9

設置控制檯日誌級別,該級別控制什麼樣的內核信息將被打印到你的 控制檯。(比如 0 ,將使得只有緊急信息,像 PANICs or OOPSes 才能到你的控制檯。)

好了,我能用他們做什麼呢?

嗯,當你的 X 服務端或者 svgalib 程序崩潰,unraw(r) 非原始模式命令鍵是非常 方便的。

sak(k)(安全訪問祕鑰)在你嘗試登陸的同時,又想確保當前控制檯沒有可以獲取你的 密碼的特洛伊木馬程序運行時是有用的。它會殺掉給定控制檯的所有程序,這樣你 就可以確認當前的登陸提示程序是實際來自 init 進程的程序,而不是某些特洛伊 木馬程序。

Important

在其實際的形式中,在兼容 C2 安全標準的系統上,它不是一個真正的 SAK, 它也不應該誤認爲此。

似乎其他人發現其可以作爲(系統終端聯機鍵)當你想退出一個程序, 同時不會讓你切換控制檯的方法。(比如,X 服務端或者 svgalib 程序)

reboot(b) 是個好方法,當你不能關閉機器時,它等同於按下”復位”按鈕。

crash(c) 可以用於手動觸發一個 crashdump,當系統卡住時。 注意當 crashdump 機制不可用時,這個只是觸發一個內核 crash。

sync(s) 在拔掉可移動介質之前,或者在使用不提供優雅關機的 救援 shell 之後很方便 -- 它將確保你的數據被安全地寫入磁盤。注意,在你看到 屏幕上出現 “OK” 和 “Done” 之前,同步還沒有發生。

umount(u) 可以用來標記文件系統正常卸載,從正在運行的系統角度來看,它們將 被重新掛載爲只讀。這個重新掛載動作直到你看到 “OK” 和 “Done” 信息出現在屏幕上 纔算完成。

日誌級別 0 - 9 用於當你的控制檯被大量的內核信息衝擊,你不想看見的時候。 選擇 0 將禁止除了最緊急的內核信息外的所有的內核信息輸出到控制檯。(但是如果 syslogd/klogd 進程是運行的,它們仍將被記錄。)

term(e)kill(i) 用於當你有些有點失控的進程,你無法通過其他方式殺掉 它們的時候,特別是它正在創建其他進程。

“just thaw it(j) ” 用於當你的系統由於一個 FIFREEZE ioctl 調用而產生的文件 系統凍結,而導致的不響應時。

有的時候 SysRq 鍵在使用它之後,看起來像是“卡住”了,我能做些什麼?

這也會發生在我這,我發現輕敲鍵盤兩側的 shift、alt 和 control 鍵,然後再次敲擊 一個無效的 SysRq 鍵序列可以解決問題。(比如,像鍵盤組合鍵 alt-sysrq-z ) 切換到另一個虛擬控制檯(鍵盤操作 ALT+Fn ),然後再切回來應該也有幫助。

我敲擊了 SysRq 鍵,但像是什麼都沒發生,發生了什麼錯誤?

有一些鍵盤對於 SysRq 鍵設置了不同的鍵值,而不是提前定義的 99 (查看在 include/uapi/linux/input-event-codes.h 文件中 KEY_SYSRQ 的定義) 或者就根本沒有 SysRq 鍵。在這些場景下,執行 showkey -s 命令來找到一個合適 的掃描碼序列,然後使用 setkeycodes <sequence> 99 命令映射這個序列值到通用 的 SysRq 鍵編碼上(比如 setkeycodes e05b 99 )。最好將這個命令放在啓動腳本 中。 哦,順便說一句,你十秒鐘不輸入任何東西就將退出 “showkey”。

我想添加一個 SysRq 鍵事件到一個模塊中,如何去做呢?

爲了註冊一個基礎函數到這個表中,首先你必須包含 include/linux/sysrq.h 頭 文件,這個頭文件定義了你所需要的所有東西。然後你必須創建一個 sysrq_key_op 結構體,然後初始化它,使用如下內容,A) 你將使用的這個鍵的處理函數, B) 一個 help_msg 字符串,在 SysRq 鍵打印幫助信息時將打印出來,C) 一個 action_msg 字 符串,就在你的處理函數調用前打印出來。你的處理函數必須符合在 ‘sysrq.h’ 文件中 的函數原型。

sysrq_key_op 結構體被創建後,你可以調用內核函數 register_sysrq_key(int key, const struct sysrq_key_op *op_p);, 該函數在表中的 ‘key’ 對應位置內容是空的情況下,將通過 op_p 指針註冊這個操作 函數到表中 ‘key’ 對應位置上。在模塊卸載的時候,你必須調用 unregister_sysrq_key(int key, const struct sysrq_key_op *op_p) 函數,該函數 只有在當前該鍵對應的處理函數被註冊到了 ‘key’ 對應位置時,纔會移除 ‘op_p’ 指針 對應的鍵值操作函數。這是爲了防止在你註冊之後,該位置被改寫的情況。

魔法 SysRq 鍵系統的工作原理是將鍵對應操作函數註冊到鍵的操作查找表, 該表定義在 ‘drivers/tty/sysrq.c’ 文件中。 該鍵表有許多在編譯時候就註冊進去的操作函數,但是是可變的。 並且有兩個函數作爲操作該表的接口被導出:

register_sysrq_key 和 unregister_sysrq_key.

當然,永遠不要在表中留下無效指針,即,當你的模塊存在調用 register_sysrq_key() 函數,它一定要調用 unregister_sysrq_key() 來清除它使用過的 SysRq 鍵表條目。 表中的空指針是安全的。:)

如果對於某種原因,在 handle_sysrq 調用的處理函數中,你認爲有必要調用 handle_sysrq 函數時,你必須意識到當前你處於一個鎖中(你同時也處於一箇中斷處理 函數中,這意味着不能睡眠)。所以這時你必須使用 __handle_sysrq_nolock 替代。

當我敲擊一個 SysRq 組合鍵時,只有標題打印出現在控制檯?

SysRq 鍵的輸出和所有其他控制檯輸出一樣,受制於控制檯日誌級別控制。 這意味着,如果內核以發行版內核中常見的 “quiet” 方式啓動,則輸出可能不會出現在實際 的控制檯上,即使它會出現在 dmesg 緩存中,也可以通過 dmesg 命令和 /proc/kmsg 文件的消費訪問到。作爲一個特例,來自 sysrq 命令的標題行將被傳遞給所有控制檯 使用者,就好像當前日誌級別是最大的一樣。如果只發出標題頭,則幾乎可以肯定內核日誌 級別太低。如果你需要控制檯上的輸出,那麼你將需要臨時提高控制檯日誌級別,通過使用 鍵盤組合鍵 alt-sysrq-8 或者:

echo 8 > /proc/sysrq-trigger

在觸發了你感興趣的 SysRq 鍵命令後,記得恢復日誌級別到正常情況。

我有很多問題時,可以請教誰?

請教在內核郵件列表上的人,郵箱:

linux-kernel@vger.kernel.org

致謝