Try   HackMD

2024q1 Homework6 (integration)

contributed by < Lccgth >

實驗環境

$ gcc --version
gcc (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0

$ lscpu
Architecture:           x86_64
  CPU op-mode(s):       32-bit, 64-bit
  Address sizes:        39 bits physical, 48 bits virtual
  Byte Order:           Little Endian
CPU(s):                 8
  On-line CPU(s) list:  0-7
Vendor ID:              GenuineIntel
  Model name:           Intel(R) Core(TM) i7-9700KF CPU @ 3.60GHz
    CPU family:         6
    Model:              158
    Thread(s) per core: 1
    Core(s) per socket: 8
    Socket(s):          1
    Stepping:           13
    CPU max MHz:        4900.0000
    CPU min MHz:        800.0000
    BogoMIPS:           7200.00
Caches (sum of all):    
  L1d:                  256 KiB (8 instances)
  L1i:                  256 KiB (8 instances)
  L2:                   2 MiB (8 instances)
  L3:                   12 MiB (1 instance)
NUMA:                   
  NUMA node(s):         1
  NUMA node0 CPU(s):    0-7
  
$ uname -r
6.5.0-28-generic

自我檢查清單

閱讀〈 Linux 核心模組運作原理

解釋 insmod

$ man insmod
NAME
       insmod - Simple program to insert a module into the Linux Kernel

DESCRIPTION
       insmod is a trivial program to insert a module into the kernel. Most
       users will want to use modprobe(8) instead, which is more clever and
       can handle module dependencies.

       Only the most general of error messages are reported: as the work of
       trying to link the module is now done inside the kernel, the dmesg
       usually gives more information about errors.

insmod 是一個用於將模組加載到 linux 核心中的命令。使用此命令時,首先需要準備好需要加載的模組,通常以 .ko 為副檔名。接著,系統會檢查此模組的所需的其他模組,並嘗試加載缺少的模組。然後,使用 insmod 命令將模組加載到核心中。加載模組後,系統會執行模組的初始化函式 (module_init),該函式負責初始化模組所需的資源,當加載完畢時,系統會將模組的資訊紀錄在核心中,包括模組的名稱、版本、作者等。此後,此模組可以被核心或其他模組所使用。

Linux 核心模組的符號 (symbol) 如何被 Linux 核心找到

根據 kernel/moudle.c 的描述,find_symbol 函式用來尋找指定的符號,此過程中會使用到 each_symbol_section 逐一走訪核心模組的符號,而其中使用 list_for_each_entry_rcu 走訪已載入的模組。

MODULE_LICENSE 巨集指定的授權條款對核心有什麼影響

根據 include/linux/module.h 的描述,MODULE_LICENSE 巨集定義了幾種被標記為免費的授權,包括 GPL、GPL v2、GPL and additional rights、Dual BSD/GPL、Dual MIT/GPL、Dual MPL/GPL,以及一種非免費的授權 Proprietary,這些設定的原因有數個,首先是讓使用者可以透過 modinfo 查詢模組是否免費,其次可以讓 Linux 開發社群能夠忽略包含專有模組的錯誤報告,最後可以讓供應商可以根據自己的策略做出對應的處理。

藉由 strace 追蹤 Linux 核心的掛載,涉及哪些系統呼叫和子系統

hello.ko 為例:

$ sudo strace insmod hello.ko
...                  
getcwd("/home/scream/hello", 4096)      = 19
newfstatat(AT_FDCWD, "/home/scream/hello/hello.ko", {st_mode=S_IFREG|0664, st_size=112344, ...}, 0) = 0
openat(AT_FDCWD, "/home/scream/hello/hello.ko", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1", 6)               = 6
lseek(3, 0, SEEK_SET)                   = 0
newfstatat(3, "", {st_mode=S_IFREG|0664, st_size=112344, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 112344, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7a2ffa0d4000
finit_module(3, "", 0)                  = 0
...

在掛載模組到核心的過程中,因為 kernel module 執行在 kernel space 中,而 insmod 是在 user space 的程序,所以需要呼叫管理記憶體的 system call,將 user space 的資料複製到 kernel space 中。

此外,核心會讀取一個檔案,在此為 hello.ko,並獲取其 file descriptor,傳至 finit_module 中,參考 finit_module 得知 finit_module 使用方法和 init_module 類似,差別在 finit_module 從 file descriptor 中讀取要掛載的模組,如此以來可以避免使用加密簽名的模組確認掛載模組的開銷。

The finit_module() system call is like init_module(), but reads the module to be loaded from the file descriptor fd. It is useful when the authenticity of a kernel module can be determined from its location in the file system; in cases where that is possible, the overhead of using cryptographically signed modules to determine the authenticity of a module can be avoided.

閱讀〈 The Linux Kernel Module Programming Guide

紀錄疑惑

UEFI SecureBoot 是什麼 (1.7 Before We Begin)

參考 SecureBoot,UEFI SecureBoot 是一種驗證機制,確保由 UEFI 韌體啟動的程式碼是可以被信任的,用於保護系統不被啟動過程早期加載的惡意程式碼攻擊,當系統啟用此設定時,任何嘗試執行不可信程式的操作都會被禁止,而驗證的過程是通過加密金鑰來實現的。

off-by-one error 是什麼 (5.5 Code space)

參考 Off-by-one error,這是一種邏輯上的錯誤,涉及一個數字與預期的值相差了 1,例如在迴圈的判斷中多進行了一次迭代或少做了一次迭代,舉例來說如果一個迴圈要計算 i 為 0 到 9 時的總和,但在條件中使用了 i <= 10,導致多計算一個元素,此錯誤會導致程式碼無法正確的存取陣列等資料結構中的元素,使得資料處理發生錯誤。