一种内核故障注入方法及电子设备的制造方法_2

文档序号:9765886阅读:来源:国知局
申请实施例中出现的相关名词的含义。
[0048]Kprobes结构体:内核动态探针Kprobes模块的数据结构,该结构体是Kprobes体系的基础,所有的故障注入行为均围绕该结构体展开,其主要成员包括:
[0049]hlist:所有注册的Kprobes结构体都会添加到kprobe_table哈希表中,hlist成员用来链接到某个槽位中;
[0050]list:如果在同一个位置注册了多个Kprobes结构体,这些Kprobes结构体会形成一个队列,队首是一个特殊的Kprobes实例,list成员用来用来链接到这个队列中。当探测点被触发时,队首的Kprobes实例中注册的handler会逐个遍历队列中注册的handler ;
[0051]addr:这个成员有两个作用,一个是用户在注册前指定探测点的基地址(加上偏移得到真实的地址),另一个是在注册后保存探测点的实际地址。在注册前,这个可以不指定,由Kprobes来初始化。如果没有指定,必须指定探测的位置的符号信息,例如函数名;
[0052]symbol_name:探测点的符号名称。名称和地址不能同时指定,否则注册时会返回EINVAL 错误;
[0053]offset:探测点相对于addr地址的偏移;
[0054]pre_handler:这个接口在断点异常触发之后被调用;
[0055]fault_handler:如果执行过程中出错,则调用该接口。如果返回1,则表示错误由Kprobes处理,否则由内核来处理;
[0056]break_handler:在调用Kprobes的处理函数(比如pre_handler接口 )时触发了断点异常会调用该接口,断点异常是通过中断门来处理的,在调用相应的处理函数前会自动关闭中断。关闭中断的情况下虽然不会接收可屏蔽的中断,但是CPU引发的异常或者匪I还是会接收到,所以有可能会发生断点异常处理嵌套;
[0057]ainsn:保存了被探测指令的拷贝。
[0058]实际情况中,Kprobes结构体还包括有其他的成员,本申请实施例在此不再予以详述。
[0059]动态可加载内核模块(Loadable Kernel Module, LKM):Linux内核向外部提供的一个扩展插口。由于Linux内核是单内核,虽然具有较高的效率,但是可扩展性和可维护性相对较差。LKM正是为了弥补这一缺陷而引入的,LKM能够在Linux内核运行过程中动态插入和卸载内核模块,进而在不重新编译内核的情况下扩展内核的功能。因此,通过将Kprobes结构体加载到LKM,即可通过Kprobes进行内核故障注入。
[0060]断点指令:使程序中断在需要的位置的指令,以便进行故障注入,例如在i386和x86_64架构中的int3指令。
[0061]回调函数:一个通过函数指针调用的函数。回调函数在特定的事件或条件发生时由另外的函数调用,用于对该事件或条件进行响应。本申请实施例中,针对不同的内核故障,可以定义相应的回调函数,进而在执行回调函数时达到对应的故障注入的目的。
[0062]实施例1
[0063]参见图2,为本申请实施例提供的内核故障注入方法的流程示意图,该流程包括:
[0064]步骤101:在加载到内存中的内核指令集合中有指令被内核动态探针Kprobes结构体中的断点指令替换时,处理器在执行该断点指令时,转向执行Kprobes结构体中与断点指令关联的回调函数;
[0065]步骤102:处理器在执行完回调函数时,转向执行被替换的指令所在函数返回后的下一条内核指令。
[0066]为了便于理解,首先介绍探测点的设置,即用断点指令替换被探测的内核指令的过程,该过程是在Kprobes结构体的注册过程中实现的。需要说明的是,Kprobes结构体的注册是在步骤101发生之前实现的。
[0067]在注册Kprobes结构体时,首先需要对内核程序进行相关配置,为加载Kprobes结构体做准备。具体配置工作包括将Kprobes相关代码编译进内核、启用用于检索内核函数地址的函数、启用内核的可插入模块功能等步骤。
[0068]在内核程序配置完毕后,就可以将Kprobes结构体加载到LKM,实现在内核程序中插入Kprobes结构体。首先会执行注册探测点的操作,该操作由register_kprobe O函数(以下简称:注册器)完成。注册器在进行相关的正确性检查后,保存被探测指令的指令码到struct_kprobe结构的ainsn中。接着注册器会把Kprobes实例添加到kprobe_table哈希表中,最后,注册器把被探测指令的第一个字节或者头几个字节替换为断点指令。本申请实施例中,被探测指令可以为任意内核指令。
[0069]通过上述步骤即可实现将被探测的内核指令替换为断点指令,完成Kprobes结构体的注册。
[0070]步骤101中,在处理器运行内核程序的过程中,当执行到断点指令时,将转向执行与断点指令关联的回调函数。具体来讲,当处理器执行到断点指令时,将引起一次软件异常,处理器会查找出中断描述符表中与该软件异常相符合的中断处理函数,处理器在运行中断处理函数时会调用一系列的相关函数,最终实现转向执行与断点指令关联的回调函数。
[0071]下面以int3断点指令引起的异常处理流程为例,详细介绍处理器在执行到断点指令时的处理流程,但以下流程仅仅是处理器由执行断点指令转向执行与断点指令关联的回调函数的一种实现方式,不能以此限定本申请实施例的范围。
[0072]当处理器执行int3时,引起软件异常,处理器查找出并执行int3对应的中断处理函数,KPR0BE_ENTRY(int3)就是该中断处理函数的入口,处理器执行KPR0BE_ENTRY (int3)函数时会调用do_int3()函数,而在执行do_int3 O函数时会调用notify_die O函数,notify_die()函数的主要作用是调用内核代码注册的异常的回调函数。在Kprobes的初始化代码(init_Kprobes O函数)中调用了 register_die_notifier O用于注册异常回调函数。Kprobes注册的异常回调函数为probe_except1ns_notify O ,因此在执行notify_die O函数时会调用Kprobes结构体中的probe_except1ns_notify O函数,执行权由内核程序转移至Kprobes。
[0073]而probe_except1ns_notify O函数中的val参数能够判断当前的调用是由什么异常产生的,这里异常是由int3指令引起的,因此收到的参数为DIE_INT3,然后将调用kprobe_handler ()函数,kprobe_handler ()函数是 Kprobes 处理 int3 异常的主要实现函数,通过该函数能够根据Kprobes注册时记录的探测点地址到哈希表中找到已注册的struck kprobe结构中的pre_handler函数,pre_handler函数中即可保存与断点指令关联的回调函数,执行prejiandler函数中保存的回调函数,即可实现故障注入。
[0074]因此,处理器在处理由断点指令引起的软件异常时,通过运行中断处理函数,调用一系列的相关函数可以转向执行与断点指令关联的回调函数。
[0075]步骤102中,处理器在执行完回调函数后,通过Kprobes结构体中保存的被替换的内核指令,定位出被替换的指令所在函数返回后的下一条内核指令,处理器直接执行该定位出的函数返回后的下一条内核指令。
[0076]步骤102之后,将开始等待下一轮故障注入的执行周期,在下一轮执行周期中重复步骤101?102,再次实现内核故障的注入,直至将Kprobes结构体从LKM上卸载,Kprobes的生命周期才会结束。
[0077]本申请实施例上述技术方案中,处理器在执行到断点指令时,转向执行Kprobes结构体中与断点指令关联的回调函数,进而实现故障注入,并在实现故障注入之后,直接执行被断点指令替换的内核指令所在的函数返回后的下一条内核指令,减少了处理器所执行的指令数量,减少了下一次内核故障注入的等待时间,缩短了应用程序的开发周期。
[0078]进一步,本申请实施例中能够针对不同的内核故障定义对应的回调函数,以此实现注入不同类型的内核故障。下面分别介绍两种处理器执行回调函数实现故障注入的方式。
[0079]其一,步骤101中,处理器执行Kprobes结构体中与断点指令关联的回调函数,包括:处理器将回调函数中设定的错误状态码写入数据寄存器。
[0080]具体来讲,处理器在执行回调函数时,能够将回调函数中的保存的设定的错误状态码写入数据寄存器,实现返回错误状态码这类内核故障的注入。
[0081]其二,步骤101中,处理器执行Kprobes结构体中与断点指令关联的回调函数,包括如下步骤:
[0082]处理器读取Kprobes结构体中保存的被替换的指令的数据返回位置的位置信息,并确定出数据返回位置;
[0083
当前第2页1 2 3 4 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1