# 2024q1 Homework6 (integration) contributed by < ChengChaoChun > ## Linux 核心模組掛載機制 ksort 使用的授權條款: `MODULE_LICENSE("Dual MIT/GPL");` 目前自由軟體模組被接受的授權條款: ``` * The following license idents are currently accepted as indicating free * software modules * * "GPL" [GNU Public License v2] * "GPL v2" [GNU Public License v2] * "GPL and additional rights" [GNU Public License v2 rights and more] * "Dual BSD/GPL" [GNU Public License v2 * or BSD license choice] * "Dual MIT/GPL" [GNU Public License v2 * or MIT license choice] * "Dual MPL/GPL" [GNU Public License v2 * or Mozilla license choice] ``` 在 `include/linux/module.h` 中 `MODULE_LICENSE` 的定義 ``` #define MODULE_LICENSE(_license) MODULE_FILE MODULE_INFO(license, _license) ``` 根據註解可以知道 `MODULE_FILE` 在建構模組時不會有作用 ``` /* * MODULE_FILE is used for generating modules.builtin * So, make it no-op when this is being built as a module */ #ifdef MODULE #define MODULE_FILE #else #define MODULE_FILE MODULE_INFO(file, KBUILD_MODFILE); #endif ``` 因此將 `MODULE_LICENSE("Dual MIT/GPL");` 展開後就是 `MODULE_INFO(license, "Dual MIT/GPL")` 。 `MODULE_INFO` 是這樣定義的 ``` /* Generic info of form tag = "info" */ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ``` 接著再展開,`__MODULE_INFO(license, license, "Dual MIT/GPL")`。 `__MODULE_INFO` 的定義在 `/include/linux/moduleparam.h` ``` #define __MODULE_INFO(tag, name, info) \ static const char __UNIQUE_ID(name)[] \ __used __section(".modinfo") __aligned(1) \ = __MODULE_INFO_PREFIX __stringify(tag) "=" info ``` 展開: ``` static const char __UNIQUE_ID(license)[] \ __used __section(".modinfo") __aligned(1) \ = __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL" ``` `__UNIQUE_ID` 的定義在 `include/linux/compiler.h` `#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)` 展開: ``` static const char __PASTE(__PASTE(__UNIQUE_ID_, license), __COUNTER__)[] \ __used __section(".modinfo") __aligned(1) \ = __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL" ``` `__PASTE` 的定義在 `include/linux/compiler_types.h` ``` /* Indirect macros required for expanded argument pasting, eg. __LINE__. */ #define ___PASTE(a,b) a##b #define __PASTE(a,b) ___PASTE(a,b) ``` 先將內層`__PASTE`展開: ``` static const char __PASTE(__UNIQUE_ID_license), __COUNTER__)[] \ __used __section(".modinfo") __aligned(1) \ = __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL" ``` 再展開外層`__PASTE`: ``` static const char __UNIQUE_ID_license__COUNTER__[] \ __used __section(".modinfo") __aligned(1) \ = __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL" ``` `__MODULE_INFO_PREFIX` 定義在 `include/linux/moduleparam.h`,在這裡 `__MODULE_INFO_PREFIX` 的定義為空。 ``` /* You can override this manually, but generally this should match the module name. */ #ifdef MODULE #define MODULE_PARAM_PREFIX /* empty */ #define __MODULE_INFO_PREFIX /* empty */ #else #define MODULE_PARAM_PREFIX KBUILD_MODNAME "." /* We cannot use MODULE_PARAM_PREFIX because some modules override it. */ #define __MODULE_INFO_PREFIX KBUILD_MODNAME "." #endif ``` `__stringify` 的定義在 `include/linux/stringify.h` #define __stringify_1(x...) #x #define __stringify(x...) __stringify_1(x 展開: ``` static const char __UNIQUE_ID_license__COUNTER__[] \ __used __section(".modinfo") __aligned(1) \ = "license = Dual MIT/GPL" ``` 藉由 strace 追蹤 Linux 核心的掛載 ``` $ sudo strace insmod sort.ko execve("/usr/sbin/insmod", ["insmod", "sort.ko"], 0x7fffe5fd7228 /* 27 vars */) = 0 brk(NULL) = 0x5ee115bcd000 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffef17b6760) = -1 EINVAL (Invalid argument) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7bfb20698000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) ... finit_module(3, "", 0) = 0 munmap(0x7bfb2053b000, 321504) = 0 close(3) = 0 exit_group(0) = ? +++ exited with 0 +++ ``` [Linux 核心模組運作原理](https://hackmd.io/@sysprog/linux-kernel-module) 中提到在 Linux kernel v6.8.5 中, finit_module 系統呼叫的實作方式已變更,呼叫 idempotent_init_module 後在該函式當中還會呼叫 init_module_from_file ,在 init_module_from_file 才真正呼叫到 load_module。