Linux内核之hook机制:call_void_hook用法实例(六十一)

发布于:2024-04-24 ⋅ 阅读:(26) ⋅ 点赞:(0)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🌻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 和一个可变参数列表 ...。它的工作原理如下:
  1. do { ... } while (0) 构造确保了宏展开后成为一个独立的语句,避免了由于宏展开可能导致的语法错误。
  2. struct security_hook_list *P; 声明了一个指向 security_hook_list 结构的指针 P,这个结构用于表示钩子列表中的元素。
  3. hlist_for_each_entry 宏遍历 &security_hook_heads.FUNC 双链表中的每个元素,并将当前元素赋值给 Phlist_for_each_entry 宏定义了如何从列表中获取条目,并且它使用 hlist_entry_safe 来安全地获取条目。
  4. P->hook.FUNC(__VA_ARGS__); 调用当前钩子列表项中对应的函数 FUNC,并传递 __VA_ARGS__(可变参数)。
  • 在Linux内核中,hlist_nodehlist_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;
}