基于RISC-V与不可执行内存的缓冲区溢出攻击防御方法及系统转让专利

申请号 : CN202110806956.0

文献号 : CN113626805B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 刘畅赵琛武延军芮志清吴敬征

申请人 : 中国科学院软件研究所

摘要 :

本发明公开了一种基于RISC‑V与不可执行内存的缓冲区溢出攻击防御方法及系统,属于计算机技术领域,通过设置页表中的特定标志位,控制对应内存区域的可执行属性,防止堆栈代码意外执行。本发明可以在不改变程序控制流的情况下,消除被恶意篡改的返回地址的执行可能性,可以有效地阻止利用缓冲区溢出在堆栈空间强制执行代码的攻击,提高RISC‑V系统的安全性。

权利要求 :

1.一种基于RISC‑V与不可执行内存的缓冲区溢出攻击防御方法,其特征在于,步骤包括:

1)对程序源代码生成抽象语法树,根据该抽象语法树生成控制流图,该控制流图是有向图,表示为G=(V,E,nentry,nexit),其中V是节点的集合,每个节点对应程序中的一条语句或一个语句块;E是有向边的集合,每条边对应一条可能执行的控制流通路;nentry和nexit分别对应程序的入口节点和出口节点;

2)分析控制流图,确定待保护的涉及堆栈缓冲区的代码片段;确定待保护的涉及堆栈缓冲区的代码片段包括以下步骤:预先定义节点识别特征集合,包括用于识别起始节点的堆相关特征和栈相关特征,以及用于识别终止节点的识别特征;遍历控制流图,找出所有进入堆栈的节点,形成起始节点集合,以及找出所有从堆栈退出的节点,形成终止节点集合;

根据控制流图识别堆栈相关代码片段,如果该片段的起始节点属于上述起始节点集合,该片段的终止节点属于上述终止节点集合,且在该片段的起始节点和终止节点之间存在控制流通路,则确定该片段为待保护的涉及堆栈缓冲区的代码片段;

3)将待保护的涉及堆栈缓冲区的代码片段始末位置作为插桩点,插入开启/清除NX位标志的RISC‑V扩展指令;

4)执行程序,在当前控制流进入堆栈缓冲区之前开启NX位标志,使对应内存不可执行;

包括以下步骤:执行开启NX位标志的RISC‑V指令;根据开启NX位标志的RISC‑V指令自身的代码位置,计算出当前待保护的涉及堆栈缓冲区的代码片段的起始位置;根据上述起始位置,在当前进程页表项中找到对应的NX位,设置该标志,表示其对应的内存范围不可执行;

5)控制流离开堆栈缓冲区之后,清除NX位标志,恢复内存可执行状态。

2.如权利要求1所述的方法,其特征在于,步骤1)中根据抽象语法树生成控制流图,包括以下步骤:

在抽象语法树中找出所有表示语句和谓词的节点;

根据抽象语法树和节点集合,找出任意两个节点之间的控制流通路作为有向边;

根据抽象语法树,找出程序的入口节点和出口节点;

将上述步骤找出的节点、有向边、入口节点和出口节点进行组合,生成对应于程序源代码的控制流图。

3.如权利要求1或2所述的方法,其特征在于,为抽象语法树的每个节点赋予content属性,其属性值对应于节点所表示的代码语句;为每个节点赋予type属性,其属性值对应于对节点所表示代码的判断,从语句、谓语、不关心的代码中取值;在抽象语法树中根据节点的type属性,找出所有的语句和谓词节点。

4.如权利要求1所述的方法,其特征在于,步骤3)包括以下步骤:对于待保护的涉及堆栈缓冲区的代码片段,按当前控制流执行的次序,依次判断其起始节点之前是否已插入开启NX位标志的RISC‑V指令,其终止节点之后是否已插入清除NX位标志的RISC‑V指令;对于没有插入开启NX位标志的RISC‑V指令的,则在相应位置插入开启NX位标志的RISC‑V指令;

对于没有插入清除NX位标志的RISC‑V指令,则在相应位置插入清除NX位标志的RISC‑V指令。

5.如权利要求1所述的方法,其特征在于,步骤5)包括以下步骤:执行清除NX位标志的RISC‑V指令;

根据清除NX位标志的RISC‑V指令自身的代码位置,计算出当前正在保护的涉及堆栈缓冲区的代码片段的终止位置;

根据上述终止位置,在当前进程页表项中找到对应NX位,清除该标志,表示其对应的内存范围可执行。

6.一种基于RISC‑V与不可执行内存的缓冲区溢出攻击防御系统,其特征在于,包括存储器和处理器,在该存储器上存储有计算机程序,该处理器执行该程序时实现如权利要求

1‑5任一项所述方法的步骤。

7.一种计算机可读存储介质,其特征在于,存储有计算机程序,该程序被处理器执行时实现如权利要求1‑5任一项所述方法的步骤。

说明书 :

基于RISC‑V与不可执行内存的缓冲区溢出攻击防御方法及

系统

技术领域

[0001] 本发明属于计算机技术领域,涉及一种基于RISC‑V与不可执行内存的缓冲区溢出攻击防御方法及系统。

背景技术

[0002] 计算机系统在各行各业的数字化、信息化进程中扮演着举足轻重的角色,影响着包括经济、教育、医疗等各领域的发展和稳定。在计算机系统应用日益普及、深入生产生活
方方面面的今天,如何保证其功能的有效性、数据信息的真实性、行为的可靠性,使其免受
恶意攻击的影响,便成为了学术界和工业界共同关注的一大关键问题。这些恶意攻击中,缓
冲区溢出攻击是一种常见的攻击手段,它针对内存不安全语言所编写的源程序中缺失边界
检查等机制的漏洞,通过对缓冲区容量限制的突破,覆盖其它区域的数据内容,进而破坏程
序的完整性和正确性。由于其操作难度较低,实施较为便捷,这类攻击手段被广泛使用于程
序控制流劫持等攻击之中。
[0003] 为了能够对抗程序控制流劫持等攻击形式,使系统免受缓冲区溢出攻击的影响,学术界一直在研究行之有效的防御方法。鉴于缓冲区溢出攻击的主要目标之一,将控制流
引导到不在CFG(Control Flow Graph,控制流图)中的代码处执行,已有一些基于不可执行
内存的防御方法被提出。这些基于不可执行内存的防御方法通过将内存空间划分为具有不
同可执行性的区域,限制或消除易受攻击的堆栈区域的可执行权限,从而避免位于堆栈中
的CFG之外代码的执行。然而,目前存在的基于不可执行内存的防御方法对硬件环境和系统
特性的依赖较大,无法直接迁移到基于RISC‑V指令集架构实现的系统;且会造成对系统核
心的侵入式更改,使得在现有系统中的应用也受到限制。例如,Red Hat公司在2004年提出
了用于Linux系统的防御机制Exec Shield,并一直沿用至今。该防御机制通过“段限制方
法”(Segment Limit Approach)将进程的内存空间划分为可执行和不可执行的两段,将读
取与执行权限近似于分开,来确保返回地址只指向受信任的代码。但是由于“段限制方法”
属于Intel处理器中的一个模糊特性,因此Exec Shield机制也仅适用于基于Intel指令集
架构(如x86)的系统;其它现有系统需要对处理器功能或指令集架构进行针对性改变,才可
能达到与之近似的效果。在上述例子中,对硬件特性的依赖导致了技术方案的适用范围受
限、难以推广迁移至包括RISC‑V系统在内的其它现有系统中。

发明内容

[0004] 本发明的目的在于提供一种可应用于RISC‑V系统的基于不可执行内存的缓冲区攻击防御方法及系统。该方法通过设置页表中的特定标志位,控制对应内存区域的可执行
属性,防止堆栈代码意外执行。该方法可以在不改变程序控制流的情况下,消除被恶意篡改
的返回地址的执行可能性,可以有效地阻止利用缓冲区溢出在堆栈空间强制执行代码的攻
击,提高RISC‑V系统的安全性。
[0005] 为实现上述目的,本发明采用如下技术方案:
[0006] 一种基于RISC‑V与不可执行内存的缓冲区溢出攻击防御方法,其步骤包括:
[0007] 1)对程序源代码生成抽象语法树(Abstract Syntax Tree,AST),根据该抽象语法树生成控制流图(Control Flow Graph,CFG),该控制流图是有向图,表示为G=(V,E,
nentry,nexit),其中V是节点的集合,每个节点对应程序中的一条语句或一个语句块;E是
有向边的集合,每条边对应一条可能执行的控制流通路;nentry和nexit分别对应程序的入
口节点和出口节点;
[0008] 2)分析控制流图,确定待保护的涉及堆栈缓冲区的代码片段;
[0009] 3)将待保护的涉及堆栈缓冲区的代码片段始末位置作为插桩点,插入开启/清除NX位(no‑execute bit,非执行位)标志的RISC‑V扩展指令;
[0010] 4)执行程序,在当前控制流进入堆栈缓冲区之前开启NX位标志,使对应内存不可执行;
[0011] 5)控制流离开堆栈缓冲区之后,清除NX位标志,恢复内存可执行状态。
[0012] 进一步地,步骤1)中,包括以下步骤:
[0013] a)对程序源代码生成抽象语法树;
[0014] b)在抽象语法树中找出所有表示语句和谓词的节点;
[0015] c)根据抽象语法树和节点集合,找出任意两个节点之间的控制流通路作为有向边;
[0016] d)根据抽象语法树,找出程序的入口节点和出口节点;
[0017] e)将上述步骤找出的节点、有向边、入口节点和出口节点进行组合,生成对应于程序源代码的控制流图。
[0018] 进一步地,为抽象语法树的每个节点赋予content属性,其属性值对应于节点所表示的代码语句;为每个节点赋予type属性,其属性值对应于对节点所表示代码的判断,从语
句、谓语、不关心的代码中取值;在抽象语法树中根据节点的type属性,找出所有的语句和
谓词节点。
[0019] 进一步地,步骤2)中,包括以下步骤:
[0020] a)预先定义节点识别特征集合,包括用于识别起始节点的堆相关特征和栈相关特征,以及用于识别终止节点的识别特征;
[0021] b)遍历控制流图,找出所有进入堆栈的节点,形成起始节点集合,以及找出所有从堆栈退出的节点,形成终止节点集合;
[0022] c)根据控制流图识别堆栈相关代码片段,如果该片段的起始节点属于上述起始节点集合,该片段的终止节点属于上述终止节点集合,且在该片段的起始节点和终止节点之
间存在控制流通路,则确定该片段为待保护的涉及堆栈缓冲区的代码片段。
[0023] 进一步地,步骤3)中,包括以下步骤:对于待保护的涉及堆栈缓冲区的代码片段,按当前控制流执行的次序,依次判断其起始节点之前是否已插入开启NX位标志的RISC‑V指
令,其终止节点之后是否已插入清除NX位标志的RISC‑V指令;对于没有插入开启NX位标志
的RISC‑V指令的,则在相应位置插入开启NX位标志的RISC‑V指令;对于没有插入清除NX位
标志的RISC‑V指令,则在相应位置插入清除NX位标志的RISC‑V指令。
[0024] 进一步地,步骤4)中,包括以下步骤:
[0025] a)执行开启NX位标志的RISC‑V指令;
[0026] b)根据开启NX位标志的RISC‑V指令自身的代码位置,计算出当前待保护的涉及堆栈缓冲区的代码片段的起始位置;
[0027] c)根据上述起始位置,在当前进程页表项中找到对应的NX位,设置该标志,表示其对应的内存范围不可执行。
[0028] 进一步地,步骤5)中,包括以下步骤:
[0029] a)执行清除NX位标志的RISC‑V指令;
[0030] b)根据清除NX位标志的RISC‑V指令自身的代码位置,计算出当前正在保护的涉及堆栈缓冲区的代码片段的终止位置;
[0031] c)根据上述终止位置,在当前进程页表项中找到对应NX位,清除该标志,表示其对应的内存范围可执行。
[0032] 一种基于RISC‑V与不可执行内存的缓冲区溢出攻击防御系统,包括存储器和处理器,在该存储器上存储有计算机程序,该处理器执行该程序时实现上述方法的步骤。
[0033] 一种计算机可读存储介质,存储有计算机程序,该程序被处理器执行时实现上述方法的步骤。
[0034] 本发明取得的技术效果是:
[0035] 1、通过对进程页表项NX位进行设置,控制特定内存的可执行性。NX位作为已广泛存在于现代处理器架构的一种控制标志位,被多种计算机系统所支持,使本发明具有相当
程度的普遍适用价值。
[0036] 2、基于RISC‑V扩展指令集实现的实现方案,顺应了技术发展逐渐走向开放的时代趋势,将硬件纳入系统安全防御体系,实现了防御的软硬协同。围绕RISC‑V扩展指令集设计
的安全硬件有助于提供更佳的防御效果。
[0037] 3、通过仅仅限制特定内存的可执行性实现防御效果,而不直接改变程序控制流,可将对程序执行的影响降至最小。体现了本发明在维护系统生态与程序执行环境方面的优
越性。

附图说明

[0038] 图1是RISC‑V系统中基于不可执行内存的缓冲区溢出防御方法的流程图。
[0039] 图2是对程序源代码生成控制流图的流程图。
[0040] 图3是根据控制流图确定待保护代码片段的流程图。
[0041] 图4是向代码片段插入开启NX位标志指令的流程图。
[0042] 图5是向代码片段插入清除NX位标志指令的流程图。
[0043] 图6是进入缓冲区前/离开缓冲区后,开启/清除NX位标志的流程图。
[0044] 图7是用于设置NX位标志的RISC‑V扩展指令的指令格式设计示意图。

具体实施方式

[0045] 下面结合附图,对本发明做进一步的说明。
[0046] 本实施例基于RISC‑V与不可执行内存的缓冲区溢出攻击防御方法,其中总体流程如图1所示,主要包括以下步骤:
[0047] 1)对程序源代码生成控制流图,控制流图是一种反映程序执行过程的图状数据结构。具体地,控制流图G=(V,E,nentry,nexit)是一个有向图,其中V是节点的集合,每个节
点对应程序中的一条语句或一个语句块;E是有向边的集合,每条边对应一条可能执行的控
制流通路;nentry和nexit分别对应程序的入口节点和出口节点。其流程如图2所示,具体说
明如下:
[0048] 1a)对程序源代码生成抽象语法树,为抽象语法树的每个节点赋予content属性,其属性值对应于节点所表示的代码语句;为每个节点赋予type属性,其属性值对应于对节
点所表示代码的判断,取值范围{statement,predicate,others},分别表示语句、谓词、不
关心的代码,转到1b)。
[0049] 1b)在抽象语法树中根据节点的type属性,找出所有的语句和谓词节点,转到1c)。
[0050] 1c)根据抽象语法树和1b)中找出的节点,判断任意两个节点之间的控制流通路是否存在,并将存在的通路记录为有向边的集合,转到1d)。
[0051] 1d)根据抽象语法树,找出程序的入口节点和出口节点,转到1e)。
[0052] 1e)将1b)中找出的节点、1c)中找出的有向边、1d)中找出的入口节点和出口节点进行组合,生成对应于程序源代码的控制流图。
[0053] 2)分析CFG确定待保护的涉及堆栈缓冲区的代码片段,堆栈缓冲区分为堆缓冲区和栈缓冲区两类,在程序中各有其相对固定的用途和使用场景。堆缓冲区用于分配长期全
局变量,多依赖于malloc()等动态服务;栈缓冲区用于分配临时局部变量,如函数调用时
存储调用参数、返回地址等。需要保护的代码片段,以进入堆栈缓冲区为起始,到从堆栈缓
冲区退出返回为止。其流程如图3所示,具体说明如下:
[0054] 2a)根据防御目标、防御强度等实际需要,定义具体的节点识别特征集合,包括用于识别起始节点的堆相关特征和栈相关特征,以及用于识别终止节点的识别特征,具体方
式为,事先定义一个识别特征集合FS=(H,S),其中,H为堆相关节点的特征,如含有malloc
()语句;S为栈相关节点的特征,如含有system()语句。定义识别结果λS:V,FS→ΣV,其中识
别结果集ΣV={true,false}。所有使λS=true的节点V即形成具有堆栈相关节点特征的起
始节点集合VS。事先定义一个识别特征集合FE={F},其中,F为指定的节点特征,如含有
return()语句。定义识别结果λE:V,FE→ΣV,其中识别结果集ΣV={true,false}。所有使
λE=true的节点V即形成终止节点集合VE。转到2b)。
[0055] 2b)从控制流图中取当前控制流下一个尚未被取到的节点,转到2c)。
[0056] 2c)根据2a)中定义的节点识别特征集合,对2b)中取出的节点进行识别,判断其种类,转到2d)。
[0057] 2d)根据2c)中的识别结果,将节点加入相应的节点集合;若节点不属于起始节点或终止节点,则无任何操作,转到2e)。
[0058] 2e)判断当前控制流是否已无未被取到的节点,若是,转到2f);若不是,转到2b)
[0059] 继续对后续节点进行识别分析。
[0060] 2f)根据控制流图和2d)中得到的起始节点集合与终止节点集合,确定需要保护的涉及堆栈缓冲区的代码片段,具体方式为,假设一个堆栈相关代码片段P=(pentry,
pexit),其中片段起始节点pentry∈VS,片段结束节点pexit∈VE,且根据CFG,在pentry和
pexit之间存在控制流通路。则T={P};生成这些代码片段的集合。
[0061] 3)将待保护代码片段始末位置作为插桩点,插入开启/清除NX位标志的RISC‑V扩展指令,其流程分别如图4和图5所示。用于设置NX位的RISC‑V扩展指令的指令格式如图7所
示,具体说明如下:
[0062] 3a)取代码片段集合中的一个代码片段,转到3b)。
[0063] 3b)取3a)中代码片段的起始节点和终止节点,转到3c)。
[0064] 3c)按当前控制流执行的次序,判断3b)中的起始节点在其之前是否已插入开启NX位标志指令,若是,转到3e);若不是,转到3d)。
[0065] 3d)在3b)中的起始节点之前插入一条开启NX位标志的指令,具体方式为,遍历需要保护的代码片段集合T,对于其中的每个代码片段P={pentry,pexit},若片段起始节点
pentry前尚未插入开启NX位标志的指令,则插入一条开启指令;转到3e)。
[0066] 3e)按当前控制流执行的次序,判断3b)中的终止节点在其之后是否已插入清除NX位标志指令,若是,转到3g);若不是,转到3f)。
[0067] 3f)在3b)中的终止节点之后插入一条清除NX位标志的指令,具体方式为,遍历需要保护的代码片段集合T,对于其中的每个代码片段P={pentry,pexit},若片段结束节点
pexit后尚未插入清除NX位标志的指令,则插入一条清除指令;转到3g)。
[0068] 3g)判断代码片段集合中是否还存在未被取到的代码片段,若是,转到3a)继续对后续代码片段进行处理。
[0069] 4)执行代码,在进入堆栈缓冲区之前开启NX位标志,使对应内存不可执行,其流程如图6所示,具体说明如下:
[0070] 4a)在当前控制流转移至堆栈缓冲区之前,将首先遇到3)中插入的NX位标志开启指令,执行该指令,转到4b)。
[0071] 4b)根据指令自身的代码位置计算出下一条指令,即待保护的堆栈缓冲区相关代码片段的起始位置,转到4c)。
[0072] 4c)根据4b)中计算出的起始位置,在当前进程的页表项中找到对应的NX位,转到4d)。
[0073] 4d)将4c)中找到的NX位的值设置为1,表示其对应的内存范围不可执行。
[0074] 5)执行流离开堆栈缓冲区之后,清除NX位标志,恢复内存可执行状态,其流程如图6所示,具体说明如下:
[0075] 5a)在当前控制流从堆栈缓冲区移除之后,将遇到3)中插入的NX位标志清除指令,执行该指令,转到5b)。
[0076] 5b)根据指令自身的代码位置计算出上一条指令,即当前保护的堆栈缓冲区相关代码片段的终止位置,转到5c)。
[0077] 5c)根据5b)中计算出的终止位置,在当前进程的页表项中找到对应的NX位,转到5d)。
[0078] 5d)将5c)中找到的NX位的值设置为0,表示其对应的内存范围可执行。
[0079] 以上实施例仅用以说明本发明的技术方案而非对其进行限制,本领域的普通技术人员可以对本发明的技术方案进行修改或者等同替换,本发明的保护范围以权利要求所述
为准。