基于多内核页表的内核动态数据隔离以及保护技术的制作方法

文档序号:11250719阅读:515来源:国知局
基于多内核页表的内核动态数据隔离以及保护技术的制造方法与工艺

本发明涉及linux内核隔离和防护领域,特别是一种基于多内核页表的内核动态数据隔离以及保护技术。



背景技术:

linux是目前在计算机操作系统上运行越来越快,越来越强大的内核之一。基于linux内核也已经涌现出了大量的发行版,无论是在服务器还是客户端中都占有着举足轻重的地位。同时,linux也是一个庞大的开源项目,本身包含千万级别的代码量,甚至该数量仍然在不断扩充。更多的代码意味着更多的漏洞。不仅如此,linux系统本身还具有很高的可扩展性和灵活性,允许通过插入模块的方式向内核中增加代码,这在进一步增加了linux代码量的同时,不可信的模块插入也对于系统运行造成很大的风险,导致系统变得更加不安全。虽然我们通常将linux认为是系统运行中的可信软件,但是仍然需要承认其中存在不可避免的不可信问题。而这些不可信因素通常也给了攻击者可乘之机,被用来获取系统root权限、窃取系统机密信息或者修改系统关键数据等等。

针对内核的不可信问题,存在着大量的研究方向。内核隔离作为其中的一个重要方向得到广泛的研究,其中通过页表构建独立执行空间的思想得到广泛的应用。但是当前基于页表的隔离实现中存在一个普遍的问题:小动态数据的混合页问题。无论是通过hypervisor页表实现隔离还是通过linux内核页表实现内核组件的隔离,隔离后的linux主内核和被隔离组件的小内存数据通常存在混合分布的情况,导致无法利用页粒度的保护对于不同来源的小内存空间进行限制,而通常对于这些混合页面需要引入额外的控制机制,带来很大的空间和时间上的开销。



技术实现要素:

针对以上现有技术中的不足,本发明的目的在于提供一种内核不同来源的动态数据隔离和保护技术。避免来自不同来源的小动态数据混合分布在同一组页框中的情况。从而便于实现隔离不同来源的动态数据的需求,解决内核隔离中常见的动态数据混合页的问题。同时进一步提出了一种通过多内核态页表在内核运行过程中为内核不同来源的动态数据构建隔离空间的方法。通过在内核空间建立多套内核页表,从而在内核空间构建多个内存视图。内核运行过程中通过切换页表的方式实现不同内存视图的迁移。

内核的正常运行需要代码和数据之间的协作。通过将内核不同组件的动态数据隔离到不同的内存视图中,可以对于内核运行在特定组件时能够访问的内存区域进行限制。内核仅仅可以访问当前使用的内核页表限定为可见的内存位置,而无法直接访问当前内存视图中不可见的内存。从而防止内核运行过程中的不可信行为对于任意内核内存区域的破坏。

本发明的技术方案如下:一种基于多内核态页表实现的内核动态数据隔离和保护方法,主要包含以下三个部分:

1)多内核页表的构建:用于在内核空间中通过这多套内核态页表构建多个内存视图。内核运行在特定内核页表构建的内存视图下的时候不能访问当前内核页表中被设置为不可见的内存空间,从而限制内核此时能够访问的内存空间范围。

2)支持分配来源标识以实现动态分配内存隔离的内存分配器构建:通过分配来源标志判定分配请求来源,然后将不同来源的动态内存在不同的内核页表中设置不同的访问权限,使得只有在特定的内核页表的作用下才能完成对于该内存区域的正常访问。

3)多内核页表交叉访问引发的缺页异常的处理:如果内核运行过程中有意或者无意地访问了当前内核页表作用下不可见的内存空间,则会触发内核态缺页异常,通过在缺页异常处理函数中增加额外的逻辑对于该情况进行处理。

进一步,可以将上面的三个部分归结为如下的实现步骤:

步骤1:在系统初始化的时候建立多套内核态页表。初始化时期在这多套内核态页表建立一致性的映射关系。对于内核空间中的直接映射区域将映射关系建立在不同的内核页表页上以便于后期的权限差异化设置,对于内核空间的其他区域,则通过共享低层页表页的方式建立一致性的映射,因为动态数据的隔离不需要对于除了直接映射区域之外的其它空间的页表项进行设置。每个页表用于构建一个相对隔离的内存环境。使用页表的好处就是地址翻译过程构建在其基础之上,内核运行过程中通过内核态页表来完成虚拟地址到物理地址的转换。通过限制内核态页表中页表项的_page_present属性,就可以使得内核运行在某套内核态页表的时候只能看到部分内存视图。而这个部分内存视图则构成内核当前运行的一个受限的环境。

步骤2:修改linux内核中内存分配器的实现。对于伙伴系统而言,需要在内存分配时,通过传入的预先定义的gfp_t内存分配标志位来判定内存分配请求的来源,以此设置分配的内存对应于各个内核态页表的可见性。对于slub而言,我们预先为每一套内核态页表定义一套kmem_cache缓存管理数据结构,这样我们就可以根据分配接口传递过来的内存分配标志将来自于不同来源的slub动态内存分配请求分发到相应的kmem_cache缓存对象中,从而实现不同来源的小动态数据的底层物理页框的隔离。因为slub缓存中的slab对象是通过伙伴系统的接口分配内存来构建,因此可以将对于内核态页表可见性的设置汇集到伙伴系统中进行统一处理。

步骤3:捕捉新增的缺页异常,当发生内核态缺页异常的时候,需要针对新引入的内核态缺页情况进行处理。主要就是处理内核运行中访问了当前页表中不可见的内存而引发的异常。这种异常在正确实现的内核中属于错误情况,可以认为是内核受到了破坏,从而使用指定的响应方式进行处理。

通过采用上面的技术方案,本发明实现了如下效果:

1)通过新增加的内存来源分配标志以及新增加的slub缓存管理对象可以将不同来源请求分配的动态内存对应到不同的物理页框中,从而解决了传统隔离实现中的混合页问题。

2)通过在内核态引入多套内核页表,从而可以为不同内核组件的动态数据构建相对独立的地址空间,通过将不同内核组件的动态数据隔离到不同的内核页表中,使得内核在运行在特定组件下的时候不能对于不可见的其他组件的动态数据直接修改,从而限制了内核运行在某个组件下时可访问的内存空间位置。即使运行在内核态,内核可访问的内存空间也是受到当前使用的内核页表限制的,从而对于其他组件的动态数据进行保护。

3)通过修改内核态的缺页处理,使得我们可以捕获内核态页表作用下的异常内存访问情况,并对其完成特定的处理过程。

附图说明

下面结合附图和具体实施方式对本发明做更进一步的具体说明。

图1是本发明的整体框架图。

图2是本发明中多套内核页表的关系图。

图3是本发明的伙伴系统内存分配流程图。

图4是本发明的slub内存分配流程图。

图5是本发明的内核空间内存访问触发缺页的流程图。

具体实施方式

下面结合附图给出一个非限定性的实施例对本发明做进一步阐述。

本发明提供一种基于多内核态页表实现的内核隔离和保护方法,整个方法的实现效果如图1所示,其包括如下步骤:

步骤1:在内核初始化时期建立多套linux内核页表,对于内核地址空间中的直接映射区域,通过在不同的内核页表页中设置相同的页表项来建立一致性映射关系,对于非直接映射区域则通过共享页表页的方式建立共享映射关系。直接映射区域的内核建立过程主要实现在init_mem_mapping函数中,其通过init_memory_mapping函数实现主要的映射逻辑。通过在init_memory_mapping中添加对于其他内核页表直接映射区域的页表构建逻辑,从而在初始化时期在各个内核态页表中对直接映射区域建立相同的映射关系。直接映射区域之外的其他内核空间所涉及的页表页的结构和关系定义在arch/x86/kernel/head_64.s文件中,通过在该文件中建立新的顶层页目录页表以及构建初始页表结构使得这多套内核页表共享其他内核空间区域对应的低层页表页,从而在系统运行过程中共享页表页中建立起来的映射。vmalloc区域需要针对页表项的惰性同步进行额外的处理,在缺页异常处理中针对vmalloc错误,如果判定当前cr3寄存器中的页表是我们为了隔离构建的其它内核页表,则需要将swapper_pg_dir中对应的页目录同步到该内核页表对应位置的顶层页目录项同步到当前cr3的内核页表中。最终建立起来的这多套linux内核页表之间的关系如图2所示。

步骤2:在内核初始化时期为每套内核页表建立特定的slub通用缓冲区对象数组和信息数组,定义位置位于mm/slab_common.c文件中。同时在create_kmalloc_caches函数中为新增加的各个slub缓冲区进行初始化,初始化过程直接通过调用new_kmalloc_cache接口来实现。此外,为了便于对linux内核中当前各个kmem_cache缓冲区的情况进行实时观测,系统在初始化slub内存分配器的时候为其建立了一套sysfs内存文件系统文件结构,通过该文件系统,我们就可以直接通过对于/sys/kernel/slab来获取系统中当前各个kmem_cache缓冲区所处的状态。因此如果我们想利用sysfs追踪新增加的slub缓冲区的实时状态,还需要在create_unique_id函数中为新增加的kmem_cache缓冲区定义新的命名规则防止命名冲突。

步骤3:内存分配器收到内存分配请求后,进行实际的内存分配。如果是通过伙伴系统申请内存分配,则进入步骤4;如果是通过slub分配器申请内存分配,则进入步骤5。

本发明中,所述的内存分配器,主要是指linux系统中的伙伴系统和slub分配器。伙伴系统主要是针对物理页框的倍数级别的内存空间的分配,slub分配器则主要针对小内存,最小分配的内存大小是8字节,最大的内存空间大小是8k。如果向slub内存分配器申请超过8k大小的空间,则slub转而请求底层的伙伴系统分配内存。

本发明中,所述的通过伙伴系统进行内存分配,指的是通过伙伴系统的一系列接口进行内存分配的情况。这些接口包括alloc_page、get_zeroed_page、__get_free_pages、__get_dma_pages、alloc_pages等等。对于伙伴系统分配的内存,可以很容易的通过页表项进行可见性的限制。因为页表项的粒度针对的就是页。所以可以在每次分配内存成功之后修改相应的页表项的_page_present属性即可。

本发明中,所述的通过slub分配器进行内存分配,指的是调用一系列slub接口进行内存分配的情况,这些接口主要是指kmalloc和kmem_cache_alloc。对于slub分配器分配的内存,因为通常分配的大小小于一个页框,所以不能直接在内存分配的时候进行修改,而应该在slub请求触发底层调页的时候通过伙伴系统进行可见性的限定。但是为了在slub中能够实现页的限定,我们需要为每一套内核态页表定义一套slub管理数据结构,因为我们已经使用了分配标志来对于对应的内核态页表进行区分,因此只需要调用相同的接口就可以了。

步骤4:伙伴系统分配内存时,根据内存分配请求中传入的gfp_t标志参数,来设置对应目标空间的内核态页表中的对应页表项的_page_present属性。设置逻辑实现在__alloc_pages_nodemask函数中,该函数是伙伴系统内存分配的核心函数。__alloc_pages_nodemask函数修改之后的逻辑如图3所示。

本发明中所述的gfp标志,指的是内存分配标志。我们可以通过增加gfp标志来指示当前分配的内存的目标空间,即针对每一个目标空间定义一个gfp标志与其对应。但是需要注意,能够新增的gfp标志数受限于gfp_t类型的位数。内存分配标志定义在include/linux/gfp.h文件中,在其中增加新的__gfp_come_from_source1、__gfp_come_from_source2等作为标识内存分配请求来源的标志。

本发明中所述的设置页表中对应页表项的_page_present属性,指的是设置页表项的_page_present属性位。通过设置该属性位,使得使用目标页表进行地址翻译时该内存位置可见。对于其他空间的内核页表中对应的页表项,则清除其_page_present属性位使得分配的内存页在其中不可见。

步骤5:slub分配器分配内存时,如果对应的slub缓冲区中的slab能够满足分配需要,则直接从相应的slab中获取合适的空间返回。如果当前对应的slub缓冲中无法满足需要,则需要建立新的slab。此时需要向伙伴系统申请内存构建新的slab。进入步骤4,从步骤4返回之后再完成内存分配请求。修改之后的slub分配流程图如图4所示。

步骤6:内核运行过程中,通过切换内核态页表的方式对于某一时段内核可见的内存区域进行限制。如果运行过程中发生了内核态缺页,则进入步骤7。

步骤7:如果系统运行在某个页表上时发生了内核态缺页,则进入异常处理程序。此时判定内核异常发生的原因,如果是因为新的多套内核态页表的引入而触发的缺页,则认为当前内核运行在一种异常状态。可以认为是发生了某些不可信行为。此时可采取如下的相应措施:宕机(panic)/重启(kernel_restart),也可以利用内核审计系统接口audit_log生成出错信息的详细的审计记录。

本发明中所属的内核态缺页,指的是内核虚拟地址空间的缺页。具体的处理逻辑如图5所示。当前,内核空间发生缺页异常的情况主要包含以下几种:

情况一:vmalloc错误。该错误是由于init_mm的惰性更新引发,通过将当前的内核态页表和init_mm的页表(即swapper_pg_dir)中异常地址的页目录项进行同步来解决。

情况二:如果是kmemcheck检查引发的缺页,则设置缺页地址在页表中对应的页表项的_page_present属性,这个是kmemcheck实现的正常逻辑。

情况三:本发明中新引入的一种内核态缺页的情况。即访问了当前用于地址翻译的页表中的不可见的内核态内存地址而引发的缺页。此时采用我们新增的逻辑进行处理。

情况四:虚假错误检查。检查是否是由于陈旧的tlb导致的虚假的缺页。发生的原因是因为tlb的延迟flush。如果判定为这种虚假错误,则直接返回即可。

情况五:kprobes错误。依据kprobes所处的不同状态对于缺页异常进行处理。kprobes是linux中的一个简单的轻量级装置,使得用户可以将断点插入正在运行的内核中。使用kprobes可以轻松地收集处理器寄存器和全局数据结构等调试信息。开发者甚至可以使用kprobes来修改寄存器值和全局数据结构值。

情况六:对于非法地址的访问造成。在内核中产生这样结构的情况主要有两种:一种就是内核通过用户空间传递的系统调用参数,访问了无效的地址,通过异常修复机制修复该内核地址空间缺页状况;另一种就是内核设计中固有的缺陷,此时内核将强制用sigkill结束当前进程。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1