我们在写驱动模块的时候,一定会包含 <linux/module.h>
,在我们的驱动模块代码中,一定会写MODULE_LICENSE("GPL");
这个语句发生了什么,起到了什么作用?不写会怎么样?
在kernel/module.c 和 include/linux/module.h
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
__used __attribute__((section(".modinfo"), unused, aligned(1))) \
= __stringify(tag) "=" info
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
MODULE_LICENSE展开
MODULE_INFO(license,"LIG")
-->
__MODULE_INFO(license, license, "LIG")
-->
static const char __UNIQUE_ID(license)[] __used __attribute__((section(".modinfo"), unused, aligned(1))) = __stringify(license) "=" "LIG"
-->
static const char __PASTE(__PASTE(__UNIQUE_ID_, license), __LINE__)[] __used __attribute__((section(".modinfo"), unused, aligned(1))) = __stringify(license) "=" "LIG"
-->
static const char __UNIQUE_ID_license288[] __used __attribute__((section(".modinfo"), unused, aligned(1))) = __stringify(license) "=" "LIG"
-->
static const char __UNIQUE_ID_license288[] __used __attribute__((section(".modinfo"), unused, aligned(1))) = "license" "=" "LIG"
//static const char __UNIQUE_ID_license288[] 定义一个静态的const char数组
//__used __attribute__((section(".modinfo"), unused, aligned(1))) 这是对这个数组的修饰
// __used 应该是防止编译器警告,我猜的
// (section(".modinfo"),这个数组放置在".modinfo"段
// unused表示这个变量后续程序可能不使用,但是编译器不要对其进行优化
// aligned(1) 表示这个数组1字节对齐,
//"license" "=" "LIG" : 这个根据C语音的字符串常量规则,会自动拼接成 "license=LIG"`
最终展开的的语句语义为: 在.modinfo段,定义一个名称为__UNIQUE_ID_license288
(288是行号)的static const char[]
类型常量,这个常量赋值为"license=LIG"
一个helloworld驱动模块代码:
>>> cat -n helloworld.c
1 #include <linux/init.h>
2 #include <linux/module.h>
3
4 //程序入口
5 static int helloworld_init(void)
6 {
7 printk("%s\n", __func__);
8 return 0;
9 }
10
11 //程序出口
12 static void helloworld_exit(void)
13 {
14 printk("%s\n", __func__);
15 }
16
17 //告诉内核入口和出口
18 module_init(helloworld_init);
19 module_exit(helloworld_exit);
20
21 //添加许可声明
22 MODULE_LICENSE("GPL"); //是个.c都要加
查看驱动模块中的符号
objdump -s hello.ko
...
Contents of section .modinfo:
0000 6c696365 6e73653d 47504c00 73726376 license=GPL.srcv
0010 65727369 6f6e3d30 46373644 38433430 ersion=0F76D8C40
0020 30373444 30444232 39363444 31300000 074D0DB2964D10..
0030 64657065 6e64733d 00726574 706f6c69 depends=.retpoli
0040 6e653d59 006e616d 653d6865 6c6c6f00 ne=Y.name=hello.
0050 7665726d 61676963 3d342e31 352e302d vermagic=4.15.0-
0060 3133362d 67656e65 72696320 534d5020 136-generic SMP
0070 6d6f645f 756e6c6f 61642036 38362000 mod_unload 686 .
...
objdump -t hello.ko
00000000 l O .modinfo 0000000c __UNIQUE_ID_license20
可以看到里面有
6c696365 6e73653d 47504c00 license=GPL.
如果删掉 MODULE_LICENSE("GPL");
sudo insmod hello.ko
cat /var/log/kern.log
May 8 17:54:01 alex-ubuntu-pad kernel: [33958.746580] hello: loading out-of-tree module taints kernel.
May 8 17:54:01 alex-ubuntu-pad kernel: [33958.746587] hello: module license 'unspecified' taints kernel.
May 8 17:54:01 alex-ubuntu-pad kernel: [33958.746588] Disabling lock debugging due to kernel taint
May 8 17:54:01 alex-ubuntu-pad kernel: [33958.746648] hello: module verification failed: signature and/or required key missing - tainting kernel
May 8 17:54:01 alex-ubuntu-pad kernel: [33958.748070] helloworld_init
(imx_4.1.15_2.0.0_ga)>>> grep -r "module verification failed" *
kernel/module.c: pr_notice_once("%s: module verification failed: signature "
SYSCALL_DEFINE3(init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
-->static int copy_module_from_fd(int fd, struct load_info *info)
-->
pos = 0;
while (pos < stat.size) {
bytes = kernel_read(f.file, pos, (char *)(info->hdr) + pos,
stat.size - pos);
if (bytes < 0) {
vfree(info->hdr);
err = bytes;
goto out;
}
if (bytes == 0)
break;
pos += bytes;
}
info->len = pos;
-->static int load_module(struct load_info *info, const char __user *uargs, int flags)
-->module_sig_check (struct load_info *info)
-->mod_verify_sig(const void *mod, unsigned long *_modlen)/*这里面有一些数字签名认证*/
--> pr_notice_once("%s: module verification failed: signature "
对于内核驱动模块,通过SYSCALL_DEFINE3进入内核,内核获取.modinfo的信息,进行判断
struct load_info {
Elf_Ehdr *hdr;
unsigned long len;
Elf_Shdr *sechdrs;
char *secstrings, *strtab;
unsigned long symoffs, stroffs;
struct _ddebug *debug;
unsigned int num_debug;
bool sig_ok;
struct {
unsigned int sym, str, mod, vers, info, pcpu;
} index;
};
SYSCALL_DEFINE3是个哈?
在include/linux/syscalls.h
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...) \
SYSCALL_METADATA(sname, x, __VA_ARGS__) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define SYSCALL_METADATA(sname, nb, ...) \
static const char *types_##sname[] = { \
__MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \
}; \
static const char *args_##sname[] = { \
__MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \
}; \
SYSCALL_TRACE_ENTER_EVENT(sname); \
SYSCALL_TRACE_EXIT_EVENT(sname); \
static struct syscall_metadata __used \
__syscall_meta_##sname = { \
.name = "sys"#sname, \
.syscall_nr = -1, /* Filled in at boot */ \
.nb_args = nb, \
.types = nb ? types_##sname : NULL, \
.args = nb ? args_##sname : NULL, \
.enter_event = &event_enter_##sname, \
.exit_event = &event_exit_##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
}; \
static struct syscall_metadata __used \
__attribute__((section("__syscalls_metadata"))) \
*__p_syscall_meta_##sname = &__syscall_meta_##sname;
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
__attribute__((alias(__stringify(SyS##name)))); \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
__MAP(x,__SC_TEST,__VA_ARGS__); \
__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
return ret; \
} \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
展开后
SYSCALL_DEFINE3(init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
SYSCALL_DEFINEx(3, _init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
SYSCALL_METADATA(_init_module, 3, void __user *, umod,unsigned long, len, const char __user *, uargs) __SYSCALL_DEFINEx(3, _init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
//SYSCALL_METADATA(sname, nb, ...)
//SYSCALL_METADATA(_init_module, 3, void __user *, umod,unsigned long, len, const char __user *, uargs)
static const char *types__init_module[] = {
__MAP(3,__SC_STR_TDECL,void __user *, umod,unsigned long, len, const char __user *, uargs)
};
static const char *args__init_module[] = {
__MAP(3,__SC_STR_ADECL,void __user *, umod,unsigned long, len, const char __user *, uargs)
};
SYSCALL_TRACE_ENTER_EVENT(_init_module);
SYSCALL_TRACE_EXIT_EVENT(_init_module);
static struct syscall_metadata __used __syscall_meta__init_module = {
.name = "sys_init_module",
.syscall_nr = -1, /* Filled in at boot */
.nb_args = 3,
.types = 3 ? types__init_module : NULL,
.args = 3 ? args__init_module : NULL,
.enter_event = &event_enter__init_module,
.exit_event = &event_exit__init_module,
.enter_fields = LIST_HEAD_INIT(__syscall_meta__init_module.enter_fields),
};
static struct syscall_metadata __used __attribute__((section("__syscalls_metadata"))) *__p_syscall_meta__init_module = &__syscall_meta__init_module;
//__SYSCALL_DEFINEx(x, name, ...)
//__SYSCALL_DEFINEx(3, _init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
asmlinkage long sys_init_module(__MAP(3,__SC_DECL,void __user *, umod,unsigned long, len, const char __user *, uargs)) __attribute__((alias(__stringify(SyS_init_module))));
static inline long SYSC_init_module(__MAP(x,__SC_DECL,,void __user *, umod,unsigned long, len, const char __user *, uargs));
asmlinkage long SyS_init_module(__MAP(x,__SC_LONG,,void __user *, umod,unsigned long, len, const char __user *, uargs));
asmlinkage long SyS_init_module(__MAP(x,__SC_LONG,,void __user *, umod,unsigned long, len, const char __user *, uargs))
{
long ret = SYSC_init_module(__MAP(x,__SC_CAST,,void __user *, umod,unsigned long, len, const char __user *, uargs)); \
__MAP(x,__SC_TEST,,void __user *, umod,unsigned long, len, const char __user *, uargs); \
asmlinkage_protect(x, ret,__MAP(x,__SC_ARGS,,void __user *, umod,unsigned long, len, const char __user *, uargs)); \
return ret; \
} \
static inline long SYSC_init_module(__MAP(x,__SC_DECL,,void __user *, umod,unsigned long, len, const char __user *, uargs));
(真尼玛长) 待续