Linux Security Modules (LSM) 框架在内核中的多个关键点提供了一系列的挂钩点,这些挂钩点允许安全模块在不同的操作发生时进行介入以实施安全策略。这些挂钩点覆盖了内核的几乎所有重要部分,包括进程管理、文件系统访问、网络操作、IPC 以及能力(capabilities)。
以下是一些关键的挂钩点的分类和例子:
- 进程管理挂钩点: 这些挂钩点涉及到进程的创建、销毁、权限变更等操作。例如,当一个新进程通过
fork
或execve
被创建时,相关的挂钩点可以用于控制进程的创建或者对新进程进行权限设置。 - 文件系统访问挂钩点: 这些挂钩点包括文件的打开、关闭、读取、写入等操作。它们允许安全模块基于文件和目录的安全策略来允许或拒绝这些操作。
- 网络操作挂钩点: 网络相关的挂钩点包括套接字的创建、传输数据、接收数据等。安全模块可以使用这些挂钩点来检查和过滤网络数据包,或者控制网络连接和监听。
- IPC 操作挂钩点: 涉及到进程间通信(IPC)的挂钩点,可以控制信号量、消息队列和共享内存等IPC机制的安全策略。
- 系统调用挂钩点: 对于系统调用的监控和控制,例如挂载(mount)、改变权限(chmod/chown)等系统调用通常会被挂钩,以实施访问控制策略。
- 功能管理挂钩点(Capabilities): 这些挂钩点控制进程的特殊能力,比如一个进程是否能够监听低端口或者发送原始套接字。
- 用户和组管理挂钩点: 涉及到用户管理和鉴权的操作,可以通过这些挂钩点控制用户组的变更或者是新用户的创建。
在实现上,每个挂钩点实际上是一个函数指针,它指向了注册的安全模块为该挂钩点实现的函数。当内核或内核的其它部分执行到需要安全检查的地方时,它将调用这些挂钩点。如果没有注册的安全模块实现这个挂钩点的函数,那么通常是一个空操作或默认通过的操作。
通过这些挂钩点,LSM允许安全模块无需改动内核核心代码的情况下,实现功能强大的安全策略,可以进行访问控制、资源管理、日志审计等工作。要了解所有的挂钩点细节,最佳的方法是查阅Linux内核源码中的LSM框架代码(通常在security/目录下)以及内核文档。
在Linux内核中,LSM框架为了提供安全检查的机制,定义了很多的函数指针(也就是挂钩点),并在内核的各个适当位置调用这些函数指针。这些函数指针被集中定义在一个或多个结构体中,并在系统初始化时为它们赋值。如果一个安全模块需要在特定的时间点实施安全策略,它必须提供一个或多个函数实现,并在初始化时注册这些函数到相应的挂钩点。
举个具体例子,我们可以看一下进程创建时的安全检查挂钩点是如何工作的。在Linux源码中,调用进程创建相关的安全挂钩点通常如下:
int security_task_create(unsigned long clone_flags)
{
return call_int_hook(task_create, 0, clone_flags);
}
这里的call_int_hook是一个宏,它负责调用名为task_create的挂钩点函数。我们假设SELinux是当前启动的安全模块,SELinux在初始化时设置了这个挂钩:
int selinux_task_create(unsigned long clone_flags)
{
// SELinux安全策略检查代码...
}
static int __init selinux_init(void)
{
security_ops->task_create = selinux_task_create;
// ...其他安全函数的注册...
return 0;
}
在上面的代码中,selinux_task_create是SELinux为进程创建定义的特定函数。selinux_init是SELinux初始化函数,在此函数中,它将selinux_task_create赋值给安全操作结构体(security_ops)的task_create成员。
当一个新的进程被创建时,它经过如do_fork和copy_process等一系列内核函数调用。在这个过程中,security_task_create函数将会在适当的时机被调用,这时,call_int_hook宏会检查是否有函数注册到名为task_create的挂钩点并调用它。如果SELinux的安全策略设置了挂钩,那么selinux_task_create就会被执行来做安全检查。如果这个检查失败,那么可能会返回一个非零的错误码,并阻止进程的创建。
如果没有任何安全模块提供这个挂钩点,那么宏就会返回默认值(通常是0,表示成功)。使用这样的机制保证了内核可以在没有任何安全模块启用的情况下继续工作,并且安全模块可以非常容易地插入自己的安全规则。