一种工作于内核态的进程间持久性内存保护方法与流程

文档序号:18475842发布日期:2019-08-20 21:03阅读:374来源:国知局
一种工作于内核态的进程间持久性内存保护方法与流程

本发明属于持久性内存保护技术领域,具体涉及一种工作于内核态的进程间持久性内存保护方法。



背景技术:

随着云技术和大数据的迅猛发展,海量数据给计算和存储系统带来了巨大的挑战。虽然当数据位于内存时处理速度很快,但是由于内存的容量限制、易失性等问题,使得传统的数据处理解决方案,需要在内外存之间交换数据,而这已经成为了系统性能颈点之一。近年来,诸如rram、pcm、mram、sttram等持久性内存取得了长足进步,其持久性、大容量、高密度、低能耗、读写速度快、磨损周期长等优势,使研究人员看到了解决内外存数据交换性能瓶颈的希望。

从硬件层面看,由于持久性内存读写速度近似于dram,因此,它可被直接连入到处理器内存子系统中,完全或部分替换dram。这种持久性内存使用方式,远快于通过pci-e总线将其与cpu相连。从软件层面看,目前应用程序有两种方式使用持久性内存。一是,将持久性内存映射到应用程序地址空间中,通过访存指令直接操作。二是,通过使用文件操作接口进入内核态,由文件系统或块设备驱动程序等访问持久性内存。这两种使用方法各有优劣:前者能充分挖掘持久性内存硬件本身带来的性能提升,然而需要对已有的应用程序进行重新设计和大量的修改;后者虽然有陷入内核、存储i/o栈逻辑处理等所带来的开销,但是由于保持了接口不变,因此应用程序在使用持久性内存时,无需进行任何特殊的设计和修改。由于兼容性,这种通过传统文件操作接口,访问持久性内存的方式将会长期存在。考虑上述因素,本专利针对的持久性内存应用场景,即在硬件方面直接连入cpu内存子系统,在软件方面使用文件操作接口访问持久性内存。

在上述应用场景中,持久性内存将会被文件系统、块设备驱动等工作在内核态的软件系统所访问。而在目前主流操作系统实现中,如linux,内核态地址空间是共享的。即若无特殊处理,工作在内核中的其他任何代码都能访问持久性内存。这意味着,持久性内存上的数据很容易遭到内核代码的破坏。比如,由于某个内核程序错误,产生了一个悬挂指针,而该指针又错误地指向了持久性内存中的某个地址。这样一来,如果通过该指针进行写操作,势必会破坏持久性内存上的原有数据。由于其持久性,即掉电后数据依然存在,显然这个悬挂指针造成的错误将是永久性的。不但是写操作,读操作也存在隐患。内核代码通过这个错误的悬挂指针,可以任意读取持久性内存上的数据,极大地增加了数据泄露的风险。因此,即使只能在内核态下访问持久性内存,也需要对其进行一定程度的保护,以防止出现上述因悬挂指针而导致的隐患。

目前,针对悬挂指针所带来的问题,通常有两类解决方案,一类是基于页表机制,另一类是基于非页表机制。在基于页表机制的保护方案中,目前主要存在两种方法,即将持久性内存页面设置为只读、私有页表映射。

将持久性内存页面设置为只读,在一般情况下可以阻止悬挂指针对持久性内存的错误写操作。但是,当要写持久性内存时,必须将页面的只读属性修改成可读写属性。这样一来,其他内核模块在页面修改成可读写属性期间,就能写持久性内存。显然,此时对于悬挂指针而言,存在着读写持久性内存的时间窗口,即依然有可能破坏持久性内存上的数据。

私有页面映射机制只有在需要读写持久性内存时,才建立映射到持久性内存的页表。并且,它为每个cpu分配不同的内核线性地址区域读写持久性内存,以避免tlb污染。然而,由于内核地址空间是共享的,一旦建立好到持久性内存的映射,其他内核代码就拥有了读写持久性内存的时间窗口。显然,即使使用私有页面映射机制,也不能完全规避悬挂指针错误导致的持久性内存数据被破坏的问题。

基于非页表的保护机制,主要与特定处理器相关。例如,在x86处理器中,cr0寄存器的wp位,可用于只读页面的写操作。使用cr0/wp技术,能够阻止运行在其他cpu上的内核代码对持久性内存的写访问,在一定程度上做到了持久性内存的写保护。然而,由于持久性内存一直以只读方式映射到内核地址空间,因此通过悬挂指针是有可能读到持久性内存数据,从而增加数据泄露的风险。在性能方面,使用cr0/wp技术对持久性内存进行写操作,其性能较差,相当于在不使用任何缓存机制情况下执行写操作。另外,不是所有处理器都有wp位。在缺乏wp位支持的处理器中,无法使用上述机制。相比之下,基于页表的持久性内存保护机制更为通用。intel近期推出的cpu开始支持pkru(protectionkeyrightsforuserpages)机制,该机制可用于页面保护,但针对的是用户态页面,而本专利的目标是内核态持久性页面保护。因此,该项技术和本专利针对的是不同的场景,互不相关。

由此可见,到目前为止,尚没有一种机制能在内核态,完全阻止悬挂指针对持久性内存的读、写访问。

在现有的相关技术中,提供了一种基于页表读写属性的持久性内存保护机制;在现代处理器和操作系统中,物理地址通常是不能被直接使用的,而程序代码能直接使用的地址实际上是逻辑地址或线性地址。当应用程序或内核代码需要访问内存时,处理器会根据它们提供的地址,查询页表得到对应的物理地址,之后再根据该地址访问物理内存。操作系统可以在页表中设置不同的属性,以控制处理器对物理内存的访问。在这些属性中,页表项的r/w标志位可用于控制物理内存的读写权限。当r/w位等于0时,其对应的物理页面只能读不能写;当r/w位等于1时,其对应的物理页面既可以读又可以写。

根据上述原理,基于页表读写属性的持久性内存保护机制,首先会在内核页表中,为持久性内存建立线性地址映射关系,以使内核代码能通过相应的线性地址访问持久性内存页。然后在内核页表中,把所有持久性内存页面对应的r/w标志位设置为0,即整个持久性内存只能读不能写。下面以构建于intelx64cpu的64位linux操作系统为例,说明持久性内存的映射方法,而图1则给出了映射示意。如图1所示在64位系统中,内核页表由四级页表(即pgd、pud、pmd、pt)构成,linux内核使用swapper_pg_dir管理内核页表,它实际是指向第一级页表pgd的指针。在pgd表中,表项0~0xff属于用户地址空间,而表项0x100~0x1ff属于内核地址空间。在映射持久性内存时,首先需要在pgd表的内核地址空间部分选择要使用的表项,而图1假设选择的表项是m。若表项m存放有有效的pud表地址信息,则在pud表中选取表项;否则,就会构建新的pud表,并在m中存放新表的地址信息。按照上述方法,依次处理其余各级页表。在处理pt表时,需要选择未使用的表项以存储持久性内存页的地址,从而完成内核线性地址区域到持久性内存的映射。图1给出了两个pt表项映射持久性内存页的示例,其中表项包含了前述的r/w位,可控制对应的持久性页面的读写属性。

当上述映射建立好后,内核代码就可以访问持久性内存。对于读操作而言,无需进行其他特殊处理,在内核页表机制下直接读取即可。但是当要写持久性内存时,首先会将待写页面对应的pt表项的r/w标志位设置为1,即允许写持久性内存。之后,即可执行若干写操作。当写操作执行完毕后,再将r/w标志位改回0,即又只允许读持久性内存。

虽然基于页表读写属性的持久性内存保护机制,将持久性页面设置为只读时,能够阻止悬挂指针对持久性内存上数据的破坏。但是,它也存在着如下问题。

(1)该机制并不能完全阻止悬挂指针对持久性内存数据的破坏。

如前所述,当要写某个持久性内存页时,必须将相应页表项的r/w位改为1,即允许对该内存页进行写。而内核地址空间是由所有进程共享的,因此,在其他核上运行的内核代码,在r/w位为1期间也能够写对应的持久性内存页。这样一来,如果上述内核代码中存在悬挂指针,持久性内存数据就有被破坏的危险。图2给出了内核地址空间共享的示意,下面将根据该示意说明:为何基于页表读写属性的保护机制,不能完全阻止悬挂指针所带来的破坏。

图2给出了进程a和进程b共享内核地址空间的情况。在linux操作系统中,每个进程都有自己的pgd表。在一个进程被创建时,它会从swapper_pg_dir指向的pgd表中,复制所有属于内核地址部分的pgd表项到自己的pgd表中(实际上在出现缺页时,也会从swapper_pg_dir指向的pgd表中复制表项)。这样一来,所有进程pgd表内核地址部分的表项,都会指向若干相同的pud表。例如图2,假设在映射持久性内存时,在swapper_pg_dir指向的pgd表中选择了表项m。而当进程a和进程b在创建时,会将表项m的内容,分别复制到进程a和进程b的pgd表的表项m中。如此,swapper_pg_dir指向的pgd表表项m、进程a和进程b的pgd表表项m,指向了同一个pud表。由此可见,内核地址部分所用到的后三级页表pud表、pmd表和pt表,在各个进程之间都是共享的。

假设进程a要对持久性内存进行写。进程a会首先进入内核,然后将要写的持久性内存页对应的r/w位设置为1。如果此时进程b也陷入内核,并执行一段质量不高的内核代码。而这段内核代码存在悬挂指针,且正好指向进程a要写的持久性内存页。由于后三级页表是共享的,进程a对r/w位修改,显然对进程b也是有效的。由于此时r/w位被设置为了1,进程b上下文所运行的内核代码,通过上述悬挂指针就能破坏持久性内存页上的数据。

(2)该机制存在因悬挂指针而导致数据泄露的可能

如图2所示,所有进程都共享后三级内核页表,即pud表、pmd表和pt表。基于页表读写属性的持久性内存保护机制,在内核地址空间映射持久性内存页后,由于上述内核页表共享,因此,运行在任意cpu上的内核代码,都能读取被映射的持久性内存页。假设进程a要对某持久性内存页进行读操作,它会陷入内核然后按照相应流程读取。另一进程b在其他cpu上运行,并执行了一段存在悬挂指针的内核代码,而该悬挂指针正好指向持久性内存页。由于内核页表共享,进程b有可能通过该悬挂指针从持久性内存页中读出数据。而上述场景的本意,只是让进程a读取数据,而非进程b。因此,基于页表读写属性的持久性内存保护机制,无法阻止进程b因悬挂指针而读出持久性内存页数据。显然,这增加了持久性内存数据泄露的风险。



技术实现要素:

针对现有技术中的上述不足,本发明提供的工作于内核态的进程间持久性内存保护方法解决了现有的持久性内存保护方法中,存在于内核代码的悬挂指针可能破坏和泄露持久性内存中的数据的问题。

为了达到上述发明目的,本发明采用的技术方案为:一种工作于内核态的进程间持久性内存保护方法,包括以下步骤:

s1、初始化阶段:在内核地址空间占据内核pdg表的若干空闲表项,并构建映射到持久性内存的后三级页表;

s2、保护阶段:当用户进程需要读写持久性内存时,修改该进程的pgd表项n,使其指向初始化阶段构建的后三级页表,从而实现进程间持久性内存的保护;

其中,当初始化阶段仅占据一个pgd表项时,该表项索引即为n。

进一步地,所述步骤s1具体为;

s11、确定整个持久性内存的大小;

s12、在内核数据结构中查找大于等于持久性内存大小且满足地址范围要求的内核线性地址区域;

s13、向管理内核线性地址区域的数据结构插入元素,以占据步骤s12中查找到的内核线性地址区域;

s14、计算完成到持久性内存映射所需的后三级页表的页数;

其中,后三级页表依次为pud表、pmd表和pt表;

s15、根据所需的pud表、pmd表和pt表的页数,向内核申请对应数量的页框,并根据映射关系填写后三级页表,完成映射到持久性内存的后三级页表的构建。

进一步地,在所述后三级页表中,所有持久性页面的读写属性均设置为可读可写状态。

进一步地,所述步骤s12中的地址范围要求包括该地址范围是连续且空闲的,以及在内核页表中该地址范围对应的所有pgd表项均为0。

进一步地,所述步骤s12中,内核数据结构为链表vmap_area_list和红黑树vmap_area_root。

进一步地,所述步骤s13中,管理内核线性区域地址的数据结构包括链表vmap_area_list和红黑树vmap_area_root。

进一步地,所述步骤s2具体为:

s21、关闭中断,修改用户进程的pgd表项n,使其指向初始化阶段构建的映射到持久性内存的后三级页表,建立到持久性内存的映射;

s22、在用户进程上下文对持久性内存进行读写操作;

s23、当读写操作完成后,将当前用户进程的pgd表项n的值修改为0,解除其到持久性内存的映射;

s24、根据当前用户进程所读写的持久性内存地址,刷新tlb条目,并开启中断,从而实现进程间持久性内存的保护。

本发明的有益效果为:

(1)当没有进程要读写持久性内存时,内核代码中存在的悬挂指针无法破坏和泄露持久性内存中的数据。

(2)当某个进程在读写持久性内存时,在其他进程上下文中运行的内核代码中的悬挂指针,无法破坏和泄露持久性内存中的数据。

(3)本发明是基于页表机制,而该机制普遍存在于现代处理器和操作系统之中。因此,本发明方法具有普适性强的特点。

附图说明

图1为本发明背景技术中持久性内存映射到内核地址空间示意图。

图2为本发明背景技术中内核地址空间共享示意图。

图3为本发明中工作于内核态的进程间持久性内存保护方法流程图。

图4为本发明中初始化阶段构建映射到持久性内存的后三级页表的方法流程图。

图5为本发明中用户进程需要读写持久性内存时的方法流程图。

图6为本发明方法提供的实施例中初始化阶段建立的持久性内存页表映射示意图。

图7为本发明提供的实施例中进程读写持久性内存时页表映射关系示意图。

具体实施方式

下面对本发明的具体实施方式进行描述,以便于本技术领域的技术人员理解本发明,但应该清楚,本发明不限于具体实施方式的范围,对本技术领域的普通技术人员来讲,只要各种变化在所附的权利要求限定和确定的本发明的精神和范围内,这些变化是显而易见的,一切利用本发明构思的发明创造均在保护之列。

如背景技术中的内容所述,现有的持久性内存保护方法并不能阻止悬挂指针的访问,其根本原因在于如图2所示的内核地址空间的共享机制。实际上从图2中可以看出,内核地址部分只有后三级页表才能被进程共同拥有,而每个进程都有自己独立的pgd表。基于这一事实,本发明在要访问持久性内存的进程的pgd表上,单独建立到持久性内存的页表映射,绕开内核地址空间共享机制,从而完全阻止悬挂指针读写持久性内存。

因此,本发明提供了如图3所示的工作于内核态的进程间持久性内存保护方法,包括以下步骤:

s1、初始化阶段:在内核地址空间占据内核pdg表的若干空闲表项,并构建映射到持久性内存的后三级页表;

s2、保护阶段:当用户进程需要读写持久性内存时,修改该进程的pgd表项n,使其指向初始化阶段构建的后三级页表,从而实现进程间持久性内存的保护;

其中,为了简化描述,假设初始化阶段仅占据一个pgd表项时,该表项索引即为n。

如图4所示,上述步骤s1具体为;

s11、确定整个持久性内存的大小;

s12、在内核数据结构中查找大于等于持久性内存大小且满足地址范围要求的内核线性地址区域;

其中的地址范围要求包括该地址范围是连续且空闲的,即未被其他内核代码占用,以及在内核页表中该地址范围对应的所有pgd表项均为0。

上述步骤s12中,在linux内核中,内核数据结构为链表vmap_area_list和红黑树vmap_area_root。

s13、向管理内核线性地址区域的数据结构插入元素,以占据步骤s12中查找到的内核线性地址区域;

所述步骤s13中,linux内核中管理内核线性区域地址的数据结构包括链表vmap_area_list和红黑树vmap_area_root。

s14、计算完成到持久性内存映射所需的后三级页表的页数;

其中,后三级页表依次为pud表、pmd表和pt表;

s15、根据所需的pud表、pmd表和pt表的页数,向内核申请对应数量的页框,并根据映射关系填写后三级页表,完成映射到持久性内存的后三级页表的构建。

上述后三级页表中,所有持久性页面的读写属性均设置为可读可写状态。

如图5所示,步骤s2具体为:

s21、关闭中断,修改用户进程的pgd表项n,使其指向初始化阶段构建的映射到持久性内存的后三级页表,建立到持久性内存的映射;

其中关闭中断的目的是防止进程a被换出。

s22、在用户进程上下文对持久性内存进行读写操作;

s23、当读写操作完成后,将当前用户进程的pgd表项n的值修改为0,解除其到持久性内存的映射;

s24、根据当前用户进程所读写的持久性内存地址,刷新tlb条目,并开启中断,从而实现进程间持久性内存的保护。

其中刷新tlb条目原因在于,之前对持久性内存进行了读写操作,因此tlb中会缓存到持久性内存的地址映射,为防止之后该缓存用于访问持久性内存,因此需要根据进程a读写的持久性内存地址,刷新tlb条目。

在本发明的一个实施例中,为了便于对本发明方案的理解,提供初始化阶段中建立的到持久性内存的页表映射示意结构(如图6)和进程读写持久性内存时页表的映射关系示意(如图7)。

如前所述,本发明在初始化阶段会首先查找大于等于持久性内存大小,且对应的内核页表pgd表项为0的线性地址区域。在图6中,内核页表swapper_pg_dir的pgd表项n,就是查找到的线性地址区域所对应的pgd表项。为了便于理解本发明方案,这里假设了只需要一个pgd表项即可完成到持久性内存的映射;对于需要多个pgd表项的情况,处理方法类似。由于并不会实际将后三级页表映射到表项n,因此表项n的值依然为0。鉴于此,在图6中以虚线表示了这种映射关系。在映射的后三级页表中,所有持久性页面的读写属性均被设置为了可读可写。另外,为了便于对比,在图6中也给出了普通内存的映射示意,即内核页表swapper_pg_dir的pgd表项m所指向的后三级页表。

初始化阶段处理完毕后,映射到持久性内存的后三级页表被构建出来(图6),并占据内核pgd表的某个或某些表项,如图6中的表项n。但表项n的值依然为0,并未指向构建出来的后三级页表。因此,当某个进程需要访问持久性内存时,必须进行一些特殊处理才能正常读写。在图7给出的例子中,假设进程a需要访问持久性内存。此时,会将进程a的pgd表项n,指向在初始化阶段构建的映射到持久性内存的后三级页表。这里的n,即图6所示的在初始化阶段所占据的pgd表项。由于每个进程都有自己的pgd表,而本发明只修改要读写持久性内存的进程的pgd表,因此在图7中,内核页表swapper_pg_dir的pgd表项n、进程b的pgd表项n不会被修改依然为0。显然,此时只有需要读写持久性内存的进程a,才完成了到持久性内存的页表映射。即只有进程a才能读写持久性内存,而其他进程如进程b,一旦访问持久性内存就会产生页错误。由此实现进程间持久性内存的保护。

本发明适用的场景是持久性内存接入处理器内存子系统,而应用程序使用文件操作接口陷入内核对其进行访问。在这种场景下,内核代码中存在的悬挂指针可能破坏和泄露持久性内存中的数据,而本发明能有效阻止这种情况的发生。因此,本发明的有益效果为:

(1)当没有进程要读写持久性内存时,内核代码中存在的悬挂指针无法破坏和泄露持久性内存中的数据。

在图6中本发明在初始化阶段虽然建立了映射到持久性内存的后三级页表,但所占据的内核页表swapper_pg_dir的pgd表项n为0,即并未建立完到持久性内存的映射。显然,这种情况下内核代码中存在的悬挂指针是不可能访问持久性内存的,也即无法破坏和泄露其上数据。

(2)当某个进程在读写持久性内存时,在其他进程上下文运行的内核代码中的悬挂指针无法破坏和泄露持久性内存中的数据。

当某个进程,如进程a,在对持久性内存进行读写时,本发明会按照图7所示的方式,在进程a的pgd表项n上,建立完整的到持久性内存的映射。这样,进程a能正常读写持久性内存。但是,由于每个进程都有自己的pgd表,而本发明只修改了进程a的pgd表,因此其他进程,如图7中的进程b,其pgd表项n依然为0,即没有建立起到持久性内存的映射。假设在进程a读写持久性内存期间,进程b也陷入到内核,并在其他核上执行了存在悬挂指针的代码。由于进程b的pgd表项n依然为0,所以它是无法访问持久性内存的。其中存在的悬挂指针,也就无法破坏和泄露持久性内存上的数据。

(3)本发明不依赖于特定硬件,具有普适性。

本发明是基于页表机制,而该机制普遍存在于现代处理器和操作系统之中。因此,本发明方法具有普适性强的特点。

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