Linux平台的挂钩函数安装方法及装置转让专利

申请号 : CN202211583193.9

文献号 : CN115827099B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 姜向前王世元姚纪卫

申请人 : 安芯网盾(北京)科技有限公司

摘要 :

本发明实施例涉及一种Linux平台的挂钩函数安装方法及装置,所述方法包括:获取第一函数在Linux内核中的地址并保存至第一函数指针中;调用所述第一函数指针以获取全局变量的地址并保存到全局变量指针中;根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址并保存至第一变量中;以第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;采用可加载内核模块中的LSM挂钩函数的地址原子地替换已有LSM挂钩函数指针并保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。本发明实施例的技术方案,避免了现有技术中存在的稳定性风险。

权利要求 :

1.一种Linux平台的挂钩函数安装方法,其特征在于,包括步骤:获取第一函数在Linux内核中的地址;

将所获取的第一函数在Linux内核中的地址保存至第一函数指针中;

调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;

根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中;

以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;

采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。

2.根据权利要求1所述的方法,其特征在于,获取第一函数在Linux内核中的地址,包括步骤:在可加载内核模块的初始化函数中注册kprobe,以获取第一函数在Linux内核中的地址。

3.根据权利要求2所述的方法,其特征在于,所述方法还包括:在获取所述第一函数在Linux内核中的地址后,反注册所述kprobe。

4.根据权利要求1所述的方法,其特征在于,根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,包括步骤:将所述全局变量指针的值与待安装的LSM挂钩函数链表头在第一类型结构体中的偏移相加,得到待安装的LSM挂钩函数链表头在Linux内核中的地址。

5.根据权利要求1‑4中任意一项所述的方法,其特征在于,所述方法还包括卸载可加载内核模块,包括步骤:采用所述第三指针变量中的地址原子地替换第二指针变量中保存的已有的LSM挂钩函数指针。

6.根据权利要求1所述的方法,其特征在于,所述全局变量的类型为第一类型结构体;

所述第二指针变量的类型为第二类型结构体。

7.一种Linux平台的挂钩函数安装装置,其特征在于,包括:第一函数地址获取模块,用于获取第一函数在Linux内核中的地址,并将所获取的第一函数在Linux内核中的地址保存至第一函数指针中;

全局变量地址获取模块,用于调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;

挂钩函数地址获取模块,用于根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中,以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;

挂钩函数安装模块,用于采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。

8.根据权利要求7所述的装置,其特征在于,所述挂钩函数地址获取模块,根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,包括:将所述全局变量指针的值与待安装的LSM挂钩函数链表头在第一类型结构体中的偏移相加,得到待安装的LSM挂钩函数链表头在Linux内核中的地址。

9.一种电子设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的可执行指令,其特征在于,所述处理器执行程序时实现如权利要求1‑6中任一项所述的方法。

10.一种计算机可读存储介质,其上存储有计算机可执行指令,其特征在于,所述可执行指令被处理器执行时实现如权利要求1‑6中任一项所述的方法。

说明书 :

Linux平台的挂钩函数安装方法及装置

技术领域

[0001] 本发明实施例涉及Linux操作系统技术领域,尤其涉及一种Linux平台的挂钩函数方法及装置。

背景技术

[0002] LSM(Linux Security Modules)是Linux内核提供的用于访问控制的通用框架,其在很多Linux系统调用的关键执行路径上安装了挂钩函数。现有技术中,在某些linux内核版本上安装挂钩函数的方法是找到挂钩函数安装点的链表插入保存有安全模块提供的挂钩函数指针的类型为特定类型的节点以达到安装挂钩函数的目的,但是这种方法存在有稳定性风险。因此,亟待提供一种具有高稳定性的Linux平台的挂钩函数安装方法。

发明内容

[0003] 基于现有技术的上述情况,本发明实施例的目的在于提供一种Linux平台的挂钩函数方法及装置,尤其是在某些高版本Linux系统中安装LSM挂钩函数的高稳定性方法及装置,通过原子地替换各个挂钩函数链表上已经存在的节点里的挂钩函数指针来安装挂钩函数,避免了现有技术中挂钩函数安装方法存在的稳定性风险。
[0004] 为达到上述目的,根据本发明的第一个方面,提供了一种Linux平台的挂钩函数安装方法,包括步骤:
[0005] 获取第一函数在Linux内核中的地址;
[0006] 将所获取的第一函数在Linux内核中的地址保存至第一函数指针中;
[0007] 调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;
[0008] 根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中;
[0009] 以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;
[0010] 采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。
[0011] 进一步的,获取第一函数在Linux内核中的地址,包括步骤:
[0012] 在可加载内核模块的初始化函数中注册kprobe,以获取第一函数在Linux内核中的地址。
[0013] 进一步的,所述方法还包括:在获取所述第一函数在Linux内核中的地址后,反注册所述kprobe。
[0014] 进一步的,根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,包括步骤:
[0015] 将所述全局变量指针的值与待安装的LSM挂钩函数链表头在第一类型结构体中的偏移相加,得到待安装的LSM挂钩函数链表头在Linux内核中的地址。
[0016] 进一步的,所述方法还包括卸载可加载内核模块,包括步骤:
[0017] 采用所述第三指针变量中的地址原子地替换第二指针变量中保存的已有的LSM挂钩函数指针。
[0018] 进一步的,所述全局变量的类型为第一类型结构体;所述第二指针变量的类型为第二类型结构体。
[0019] 根据本发明的第二个方面,提供了一种Linux平台的挂钩函数安装装置,包括:
[0020] 第一函数地址获取模块,用于获取第一函数在Linux内核中的地址,并将所获取的第一函数在Linux内核中的地址保存至第一函数指针中;
[0021] 全局变量地址获取模块,用于调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;
[0022] 挂钩函数地址获取模块,用于根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中,以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;
[0023] 挂钩函数安装模块,用于采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。
[0024] 进一步的,所述挂钩函数地址获取模块,根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,包括:
[0025] 将所述全局变量指针的值与待安装的LSM挂钩函数链表头在第一类型结构体中的偏移相加,得到待安装的LSM挂钩函数链表头在Linux内核中的地址。
[0026] 根据本发明的第三个方面,提供了一种电子设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的可执行指令,所述处理器执行所述程序时实现如本发明第一个方面所述的方法。
[0027] 根据本发明的第四个方面,提供了一种计算机可读存储介质,其上存储有计算机可执行指令,所述可执行指令被处理器执行时实现如本发明第一个方面所述的方法。
[0028] 综上所述,本发明实施例提供了一种Linux平台的挂钩函数安装方法及装置,所述方法包括步骤:获取第一函数在Linux内核中的地址;将所获取的第一函数在Linux内核中的地址保存至第一函数指针中;调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中;以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。本发明实施例的技术方案,通过原子地替换各个挂钩函数链表上已经存在的节点里的挂钩函数指针来安装挂钩函数,从而避免了现有技术中LSM挂钩函数安装方法在某些版本号的Linux内核中带来的潜在稳定性风险。

附图说明

[0029] 图1是本发明实施例提供的Linux平台的挂钩函数安装方法的流程图;
[0030] 图2是本发明实施例提供的Linux平台的挂钩函数安装装置的构成框图;
[0031] 图3是本发明实施例提供的电子设备的结构示意图。

具体实施方式

[0032] 为使本发明的目的、技术方案和优点更加清楚明了,下面结合具体实施方式并参照附图,对本发明进一步详细说明。应该理解,这些描述只是示例性的,而并非要限制本发明的范围。此外,在以下说明中,省略了对公知结构和技术的描述,以避免不必要地混淆本发明的概念。
[0033] LSM(Linux Security Modules)是Linux内核提供的用于访问控制的通用框架,其在很多Linux系统调用的关键执行路径上安装了挂钩函数。每当Linux系统调用执行时,这些挂钩函数就可以得到执行。用户可以通过编写一个可加载内核模块(Loadable Kernel Module,以下简称“LKM”)安装这些挂钩函数以实现安全检测,从而提供安全防护。LSM在版本号为4.1.52及以前的Linux内核中导出了类型为struct security_operations*的全局变量security_ops指针或者内核符号里有类型为struct security_operations*的security_ops指针,security_ops指针指向的内存里包含了Linux内核提供的所有的LSM挂钩函数指针,在这些Linux内核版本上安装挂钩函数的方法是直接原子替换security_ops指针指向的内存里包含的相应的函数指针,这种挂钩方案不会造成稳定性风险问题。但是,LSM在版本号为4.2.0及以后的Linux内核中不再导出类型为struct security_operations*的全局变量security_ops指针,而且符号里没有类型为struct security_operations*的security_ops指针,而是在符号里提供了类型为struct security_hook_heads的全局变量security_hook_heads,而且security_hook_heads变量里不再是保存的各个LSM挂钩函数的指针,而是LSM挂钩函数的链表(可能为双链表,也可能为哈希链表),因此,在这些Linux内核版本上安装挂钩函数的方法是找到挂钩函数安装点的链表插入保存有安全模块提供的钩子函数指针的类型为struct security_hook_list的节点以达到安装挂钩函数的目的。但是这种方案有稳定性风险,因为Linux内核不但没有导出安装LSM挂钩函数的security_add_hooks函数,符号里也没有security_add_hooks函数,security_add_hooks函数内部通过调用list_add_rcu函数或者hlist_add_tail_rcu函数来添加节点,这两个函数在访问链表上的节点时并没有加锁保护,而且也没有提供移除LSM挂钩函数的接口函数,如果用户采用直接向全局变量security_hook_heads里的各挂钩函数链表里添加或者移除节点来安装和移除LSM挂钩函数时就会有很低概率导致机器宕机的稳定性问题,并且安全软件在移除之前安装的LSM挂钩函数时也会有很低概率导致机器宕机的稳定性问题。
[0034] 针对上述问题,本发明的实施例提供了一种Linux平台的挂钩方法,有效地解决了在Linux平台中编写LKM时安装和卸载LSM挂钩函数的稳定性问题。下面结合附图对本发明实施例的技术方案进行详细说明。图1中示出了该Linux平台的挂钩方法的流程图,包括如下步骤:
[0035] S202、在可加载内核模块(LKM)的初始化函数中注册kprobe(kprobe是内核开发者们专门为了便于跟踪内核函数执行状态所设计的一种轻量级内核调试技术),以获取第一函数在Linux内核中的地址。在编写LKM时,在其初始化函数init_module中注册kprobe以获取第一函数,例如为kallsyms_lookup_name函数,在Linux内核中的地址。
[0036] S204、将所获取的第一函数在Linux内核中的地址保存至第一函数指针中,并反注册所述kprobe。如果步骤S202中,注册kprobe失败,或者虽然注册kprobe成功但是获取kallsyms_lookup_name函数在Linux内核中的地址失败,则跳出该函数不再执行;否则,即当在初始化函数中注册kprobe成功后,在该步骤中,把所获取到的kallsyms_lookup_name函数在Linux内核中的地址保存到第一函数指针,例如函数指针pfn_kallsyms_lookup_name中并反注册kprobe以释放注册kprobe时申请的资源。
[0037] S206、调用第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;其中,所述全局变量的类型为第一类型结构体。该步骤中,通过调用该第一函数指针pfn_kallsyms_lookup_name,获取全局变量security_hook_heads,以保存LSM挂钩函数的链表头,该全局变量的类型为结构体struct security_hook_heads。如果获取失败,则返回;如果获取成功,则把该全局变量的地址保存到全局变量指针security_hook_heads_ptr中。
[0038] S208、将所述全局变量指针的值与待安装的LSM挂钩函数链表头在第一类型结构体中的偏移相加,得到待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中。该步骤中,将全局变量指针security_hook_heads_ptr的值加上待安装的LSM挂钩函数链表头在第一类型结构体struct security_hook_heads中的偏移,即为待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量head中。
[0039] S210、以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中,所述第二指针变量的类型为第二类型结构体。以第一变量head作为链表头,检查该链表上是否有一个已经存在的节点。如果没有,则返回;如果有,则把该节点的地址保存到第二指针变量security_hook_list中,该第二指针变量security_hook_list的类型为第二类型结构体struct security_hook_list*。该步骤中的内存访问是安全的,没有稳定性风险。因为链表上的节点所属的内存是Linux内核安全组件分配的内存,而Linux内核安全组件在系统初始化时为节点分配内存,且在系统关机时释放内存,因此通过本发明的该步骤能够实现内存的安全访问。
[0040] S212、采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。该步骤中,用LKM中的的LSM挂钩函数(例如为lkm_lsm_func函数)的地址原子地替换第二指针变量security_hook_list中保存的已有的LSM挂钩函数指针,并把已有的LSM挂钩函数指针保存到第三指针变量ori_lsm_func_ptr中以供LKM提供的LSM挂钩函数lkm_lsm_func调用。至此,安装LSM挂钩函数完成,由于原子写内存操作本身就没有风险,因此该步骤也没有稳定性风险。
[0041] 根据某些可选的实施例,本方法还包括卸载LKM的步骤,包括:
[0042] 采用所述第三指针变量中的地址原子地替换第二指针变量中保存的已有的LSM挂钩函数指针。该卸载步骤中,采用步骤S212中保存在第三指针变量ori_lsm_func_ptr(即保存原来已有的LSM挂钩函数指针)中的地址原子地替换第二指针变量security_hook_list中保存的已有的LSM挂钩函数指针。至此,卸载LSM挂钩函数完成,该步骤没有稳定性风险。
[0043] 本发明的实施例中,还提供了一种Linux平台的挂钩函数安装装置,图2中示出了该挂钩函数安装装置的结构框图,如图2所示,该装置包括:
[0044] 第一函数地址获取模块201,用于获取第一函数在Linux内核中的地址,并将所获取的第一函数在Linux内核中的地址保存至第一函数指针中。
[0045] 全局变量地址获取模块202,用于调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中。
[0046] 挂钩函数地址获取模块203,用于根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,具体包括:将所述全局变量指针的值与待安装的LSM挂钩函数链表头在第一类型结构体中的偏移相加,得到待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中,以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中。
[0047] 挂钩函数安装模块204,用于采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。
[0048] 本发明实施例提供的Linux平台的挂钩函数安装装置中,各模块实现其功能的具体步骤与本发明前述实施例提供的Linux平台的挂钩函数安装方法的各步骤相同,在此将省略其重复描述。
[0049] 本发明的实施例中,还提供了一种电子设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的可执行指令,所述处理器执行所述程序时实现如本发明上述实施例中所述的方法。图3所示为本发明该实施例提供的电子设备的结构示意图。如图3所示,该电子设备包括:一个或多个处理器301和存储器302;以及存储在存储器302中的计算机可执行指令,可执行指令在被处理器301运行时使得处理器301执行如上述实施例的Linux平台的挂钩函数安装方法。处理器301可以是中央处理单元(CPU)或者具有数据处理能力和/或指令执行能力的其他形式的处理单元,并且可以控制电子设备中的其他组件以执行期望的功能。存储器302可以包括一个或多个计算机程序产品,计算机程序产品可以包括各种形式的计算机可读存储介质,例如易失性存储器和/或非易失性存储器。易失性存储器例如可以包括随机存取存储器(RAM)和/或高速缓冲存储器(cache)等。非易失性存储器例如可以包括只读存储器(ROM)、硬盘、闪存等。在计算机可读存储介质上可以存储一个或多个计算机程序指令,处理器301可以运行程序指令,以实现上文的本发明实施例的Linux平台的挂钩函数安装方法中的步骤以及/或者其他期望的功能。在一些实施例中,电子设备还可以包括:输入装置303和输出装置304,这些组件通过总线系统和/或其他形式的连接机构(图3中未示出)互连。例如,在该电子设备是单机设备时,该输入装置303可以是通信网络连接器,用于从外部的可移动设备接收所采集的输入信号。此外,该输入设备303还可以包括例如键盘、鼠标、麦克风等。该输出装置304可以向外部输出各种信息,例如可以包括例如显示器、扬声器、打印机、以及通信网络及其所连接的远程输出设备等。
[0050] 本发明的实施例中,还提供了一种计算机可读存储介质,其上存储有计算机程序,所述计算机程序被处理器执行时实现如本发明上述实施例中所述的方法中的步骤。计算机可读存储介质可以采用一个或多个可读介质的任意组合。可读介质可以是可读信号介质或者可读存储介质。可读存储介质例如可以包括但不限于电、磁、光、电磁、红外线、或半导体的系统、装置或器件,或者任意以上的组合。可读存储介质的更具体的例子(非穷举的列表)包括:具有一个或多个导线的电连接、便携式盘、硬盘、随机存取存储器((RAM)、只读存储器(ROM)、可擦式可编程只读存储器(EPROM或闪存)、光纤、便携式紧凑盘只读存储器(CD‑ROM)、光存储器件、磁存储器件、或者上述的任意合适的组合。
[0051] 应当理解的是,本发明实施例中的处理器可以为中央处理单元(Central Processing Unit,CPU),该处理器还可以是其他通用处理器、数字信号处理器(Digital Signal Processor,DSP)、专用集成电路(Application Specific Integrated Circuit,ASIC)、现成可编程门阵列(Field Programmable Gate Array,FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件等。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等。
[0052] 综上所述,本发明实施例涉及一种Linux平台的挂钩函数安装方法及装置,所述方法包括步骤:获取第一函数在Linux内核中的地址;将所获取的第一函数在Linux内核中的地址保存至第一函数指针中;调用所述第一函数指针以获取全局变量的地址,并将全局变量的地址保存到全局变量指针中;根据所述全局变量指针获取待安装的LSM挂钩函数链表头在Linux内核中的地址,并将该地址保存至第一变量中;以所述第一变量作为链表头,若该链表上有一个已经存在的节点,则将该节点的地址保存到第二指针变量中;采用可加载内核模块中的LSM挂钩函数的地址原子地替换第二指针变量中保存的已有LSM挂钩函数指针,并将已有LSM挂钩函数指针保存至第三指针变量中以供可加载内核模块提供的LSM挂钩函数调用。本发明实施例的技术方案,通过原子地替换各个挂钩函数链表上已经存在的节点里的挂钩函数指针来安装挂钩函数,从而避免了现有技术中LSM挂钩函数安装方法在某些版本号的Linux内核中带来的潜在稳定性风险。
[0053] 应当理解的是,以上任何实施例的讨论仅为示例性的,并非旨在暗示本发明的范围(包括权利要求)被限于这些例子;在本发明的思路下,以上实施例或者不同实施例中的技术特征之间也可以进行组合,步骤可以以任意顺序实现,并存在如上所述的本发明一个或多个实施例的不同方面的许多其它变化,为了简明它们没有在细节中提供。本发明的上述具体实施方式仅仅用于示例性说明或解释本发明的原理,而不构成对本发明的限制。因此,在不偏离本发明的精神和范围的情况下所做的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。此外,本发明所附权利要求旨在涵盖落入所附权利要求范围和边界、或者这种范围和边界的等同形式内的全部变化和修改例。