简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1.前言
- 🌻2.Linux内核之hook机制介绍
- 🐓2.1 call_void_hook内核源码中定义
- 🐓2.2 call_void_hook介绍
- 🌻3.代码实例
- 🐓3.1 注册钩子函数并调用
- 🐓3.2 模拟内核注册函数
- 🐓3.3 自定义钩子函数
🌻1.前言
本篇目的:Linux内核之hook机制:call_void_hook用法实例
🌻2.Linux内核之hook机制介绍
🐓2.1 call_void_hook内核源码中定义
struct hlist_node {
struct hlist_node *next, **pprev;
};
struct hlist_head {
struct hlist_node *first;
};
union security_list_options {
int (*binder_set_context_mgr)(const struct cred *mgr);
};
struct security_hook_list {
struct hlist_node list;
struct hlist_head *head;
union security_list_options hook;
char *lsm;
} __randomize_layout;
struct security_hook_heads {
struct hlist_head binder_set_context_mgr;
};
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_entry_safe(ptr, type, member) \
({ typeof(ptr) ____ptr = (ptr); \
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
})
#define hlist_for_each_entry(pos, head, member) \
for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
pos; \
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
#define call_void_hook(FUNC, ...) \
do { \
struct security_hook_list *P; \
\
hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \
P->hook.FUNC(__VA_ARGS__); \
} while (0)
🐓2.2 call_void_hook介绍
- 在Linux内核中,
call_void_hook
宏是一种用于调用安全模块钩子的便捷方式。它允许内核代码在特定的钩子点执行所有注册的安全模块回调函数。这种机制是Linux安全模块(LSM)框架的一部分,它允许不同的安全模块以插件的形式加入到内核中,从而提供各种安全特性,如访问控制、审计等。 call_void_hook
宏的定义如下:
#define call_void_hook(FUNC, ...) \
do { \
struct security_hook_list *P; \
\
hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \
P->hook.FUNC(__VA_ARGS__); \
} while (0)
- 这个宏接受一个钩子函数名
FUNC
和一个可变参数列表...
。它的工作原理如下:
do { ... } while (0)
构造确保了宏展开后成为一个独立的语句,避免了由于宏展开可能导致的语法错误。struct security_hook_list *P;
声明了一个指向security_hook_list
结构的指针P
,这个结构用于表示钩子列表中的元素。hlist_for_each_entry
宏遍历&security_hook_heads.FUNC
双链表中的每个元素,并将当前元素赋值给P
。hlist_for_each_entry
宏定义了如何从列表中获取条目,并且它使用hlist_entry_safe
来安全地获取条目。P->hook.FUNC(__VA_ARGS__);
调用当前钩子列表项中对应的函数FUNC
,并传递__VA_ARGS__
(可变参数)。
- 在Linux内核中,
hlist_node
和hlist_head
结构用于实现哈希链表,这是一种内存效率较高的链表实现,特别适用于哈希表。hlist_node
包含指向链表中下一个节点的指针和指向前一个节点的前指针的指针。hlist_head
则包含指向链表第一个节点的指针。
security_list_options
联合用于存储不同类型的安全钩子函数指针。在security_hook_list
结构中,hook
字段是一个security_list_options
类型的联合,用于存储钩子函数的指针。 security_hook_heads
结构包含了一个或多个hlist_head
类型的字段,每个字段对应一个特定的钩子点。在call_void_hook
宏中,&security_hook_heads.FUNC
表示特定钩子点的钩子列表头。- 通过使用
call_void_hook
宏,内核开发者可以在不修改现有代码的情况下,为特定的钩子点添加新的安全检查或操作。这种机制为内核的安全性提供了极大的灵活性和可扩展性。 - 例如,当内核需要检查是否允许一个进程设置为binder上下文管理器时,它会调用
binder_set_context_mgr
钩子。使用call_void_hook
,内核代码可以这样调用钩子:
call_void_hook(binder_set_context_mgr, current_cred());
- 这个调用会遍历
security_hook_heads.binder_set_context_mgr
钩子列表,并调用列表中每个钩子项的binder_set_context_mgr
函数,传递当前进程的凭证作为参数。每个注册的安全模块都会有机会检查这个操作是否允许,并返回相应的结果。
🌻3.代码实例
🐓3.1 注册钩子函数并调用
#include <stdio.h>
// 定义钩子函数的数据结构
struct security_hook_list {
void (*hook)(int);
};
struct {
struct security_hook_list FUNC;
} security_hook_heads;
// 定义调用钩子的宏
#define call_void_hook(FUNC, ...) \
do { \
struct security_hook_list *P; \
P = &security_hook_heads.FUNC; \
if (P->hook) \
P->hook(__VA_ARGS__); \
} while (0)
void my_hook_function(int arg) {
printf("Hook function called with argument: %d\n", arg);
}
int main() {
// 注册钩子函数
security_hook_heads.FUNC.hook = my_hook_function;
// 调用钩子函数
call_void_hook(FUNC, 42);
return 0;
}
🐓3.2 模拟内核注册函数
#include <stdio.h>
// 定义钩子函数的数据结构
struct security_hook_list {
void (*hook)(int);
};
//全局变量 security_hook_heads,其中包含钩子函数的链表
struct {
struct security_hook_list FUNC;
} security_hook_heads;
// 定义调用钩子的宏
#define call_void_hook(FUNC, ...) \
do { \
struct security_hook_list *P; \
P = &security_hook_heads.FUNC; \
if (P->hook) \
P->hook(__VA_ARGS__); \
} while (0)
void register_hook_in_kernel(void (*hook_func)(int), struct security_hook_list *hook_list) {
hook_list->hook = hook_func;
}
void my_hook_function(int arg) {
printf("Hook function called in kernel with argument: %d\n", arg);
}
int main() {
// 在内核中注册钩子函数
register_hook_in_kernel(my_hook_function, &security_hook_heads.FUNC);
// 调用钩子
call_void_hook(FUNC, 100);
return 0;
}
🐓3.3 自定义钩子函数
#include <stdio.h>
// 定义钩子函数的数据结构
struct security_hook_list {
void (*hook)(int);
};
//全局变量 security_hook_heads,其中包含钩子函数的链表
struct {
struct security_hook_list FUNC;
} security_hook_heads;
// 定义调用钩子的宏
#define call_void_hook(FUNC, ...) \
do { \
struct security_hook_list *P; \
P = &security_hook_heads.FUNC; \
if (P->hook) \
P->hook(__VA_ARGS__); \
} while (0)
void my_hook_function(int arg) {
printf("Custom hook function called with argument: %d\n", arg);
}
int main() {
// 注册自定义钩子函数
security_hook_heads.FUNC.hook = my_hook_function;
// 调用自定义钩子函数
call_void_hook(FUNC, 200);
return 0;
}