0%

Linux:Linux内核级安全开发基础(2)内核模块开发方法

Linux内核级安全开发基础

1.2 内核模块开发方法

1.源代码组成

Linux动态内核模块一般需要包括三部分

  1. 模块初始化部分:模块的注册、数据和变量的初始化

    该模块以初始化函数的形式存在,在模块加载到内核运行时,系统就会自动调用该函数完成模块的初始化

  2. 模块的注销部分:完成资源的释放

    该部分以注销函数的形式出现,在模块从内核卸载时,系统就会自动调用该函数完成模块的注销工作

  3. 模块的主体功能部分:用于实现模块的具体功能

    该部分通常以一组函数形式存在,不会自动运行,在需要的时候由用户通过系统调用或其他的功能模块调用

2.外部符号引用
  • 应用程序vs内核模块的外部资源

    应用程序的开发通常需要调用一些外部的资源,如库函数、系统调用等,以实现较为复杂同样 Linux的内核模块编程也经常需要使用外部资源,不同的是应用程序中使用的外部资源是库函数或者系统调用,而对内核模块而言,要使用的外部资源是在 Linux基本内核或其他内核模块中定义的资源(函数、全局变量等)等。

  • 与应用程序编程所使用的库函数不同,基本内核或其他内核模块中定义的外部符号(简称为内核符号)缺乏相应的使用文档。比如 Linux 中可以通过 man(或 info)命令列出一个库函数详细的使用文档,包括函数名、兩数功能、返回值类型、参数个数,以及每个参数的类型等。而 Linux 中的内核符号没有详细的使用文档,这给内核模块开发人员造成了很大困难。

3.编译和运行模式

运行环:x86系列的处理器而言,存在4种运行模式,每种模式对应不同的执行权限级别,按执行权限级别从大到小的次序依次为0、1、2、3,由于这些级别的执行权限像同心圆一样存在严格的包含关系,这些执行权限级别常被人称为运行环,即0环至3环共4个环。

  • 当CPU运行于0环时具有最高的权限,能够执行所有的指令和特权操作,如访问控制寄存器等,运行于3环时则权限最低,无法执行任何特权指令,也无法访问硬件。在这些运行环中,通常只用到两个环,即0环和3环,并将 CPU 运行在0环时称为 CPU 处于特权态,而将CPU 运行在3环时称为 CPU 处于非特权态。
  • 操作系统的内核代码运行在特权态,特权态又称管态、系统态或内核态,而让运行在操作系统之上的应用程序代码运行在非特权态,该态一般又称为目标态或用户态。

cpu在不同模式运行的区别

  • CPU 运行在系统态时,能够执行所有的系统指令,如开中断、关中断指令等,在寻址方式上采用实地址模式。

  • CPU运行在用户态时,不能执行特权指令,如果所执行的应用程序代码中包含特权指令,CPU 运行时将会出错,此外 CPU在解析程序代码的指令地址和数据地址时采用虚地址方式。

    换言之,运行在不同 CPU模式下的程序代码特性也存在不同,一段拟在用户态运行的代码,将其在系统态运行会出错。

    内核模块的代码在加载到系统内核后,将在CPU 的系统态下执行。

  • 源程序的角度来看,系统态下的程序和用户态下的程序并没有本质的区别,只不过编译器会根据程序员的不同要求,生成适合系统态运行的目标代码,或生成适合在用户态运行的目标代码。

  • 编制好内核模块对应的源程序后,在将源程序编译成目标代码模块 .o(或.ko)文件时,要告知编译器需要编译的是内核模块的代码。具体方式:gcccc选项中添加D_MODULE,这样就能生成适合在系统态运行的Linux内核模块。

4.调试和信息输出

内核调试工具:KDB

KDB以内核源程序补丁的形式存在,通过修改内核源程序将调试器的源代码嵌入到内核中,从而提供方便的调试手段。

因此,使用KDB进行调试,需要重新编译内核,使编译后的内核中包含KDB的调试器代码

其他调试方法:添加一些信息输出语句

linux基本内核中,定义了一个格式化输出的全局函数printk(),将获得的进程信息输出到控制台或日志文件中,该函数在头文件include/linux/printk.h中声明。