董云卫, 张涵博, 李勇军
西北工业大学计算机学院, 西安 71012
软件定义的概念和技术的发展和应用,软件安全问题已经成为嵌入式系统乃至装备产品研制和运行维护的核心关注点.装备嵌入式系统的软件规模性和复杂性都在急剧增加,软件的安全性和可靠性问题日益突出.研究保障系统安全可信性的软件代码加固安全,提高系统运行管理的可信性显得尤为重要.
目前针对于保障软件代码的安全性,国内外众多研究者主要利用安全漏洞检测技术和安全漏洞修复手段来提高软件的安全性.安全漏洞检测技术可以分为静态检测技术和动态检测技术,其主要通过软件测试、代码分析、符号执行和模型检验等技术途径来实现[1].为此,涌现出了多个优秀工具,如SAGE[2]是基于二进制代码的重量级模糊测试工具,PEX[3]是微软将轻量级动态符号执行方法与单元测试领域结合起来设计出的工具,YOGI[4]是微软基于抽象解释和反例制导的求精方法的模型检验工具,KLEE[5]是基于轻量级动态符号执行的自动化白盒模糊测试方法工具.
WEILE等[6]实现的静态分析检测框架Marple,该工具通过对控制流图中的路径进行分析,把路径分为安全、漏洞、警告、不可达和未知这五类,通过自动检测分析将路径类型信息、漏洞根源信息与位置信息形成信息报告给用户.航空软件系统往往代码行数巨大,且对代码的质量要求极高,美国NASA的BRAT等[7]针对于航空航天软件系统利用了抽象解释构造了误报率较低的缓冲区溢出检测方法,并开发出检测框架IKOS,该框架也有助于开发既精确又可伸缩的静态分析工具.GAO等[8]提出利用控制流图和函数调用图,来执行污染传播分析和数据流分析的检测方法,并实现了静态分析工具Carraybound.也有研究者将静态分析技术与机器学习算法进行结合,BINDU等[9]利用易于提取的轻量级静态代码属性,实现了预测缓冲区溢出的输入验证检查,然后在静态代码属性上使用数据挖掘方法来预测应用程序中的缓冲区溢出漏洞.然而众多的软件安全检测技术与工具只是提供了检测报告,针对软件源代码安全性风险进行加固的技术没有进一步研究和相应的成果.
本文借助现有软件代码安全性检测技术,对装备嵌入式软件的漏洞行为和结构分析,形成装备嵌入式软件漏洞特征和系统不安全行为属性规约,通过对软件属性规约的逻辑演算,形成软件安全性加固需求,采用基于安全规约属性模板的漏洞加固代码生成方法,提出对软件代码中潜在的安全漏洞进行加固代码生成技术,对不安全性代码进行自动加固和代码补全.代码自动加固技术是一种面向安全需求软件合成技术,用于解决软件漏洞修复问题.软件合成技术最早可追溯到1932年,KOLMOGOROFF[10]提出在构造性数学中(constructive mathematics)可以通过编写小的子程序,然后将其组合起来构造成一个算法.微软的GULWANI等[11-12]定义了程序综合的3个维度,即用户需求、搜索空间和搜索技术,同时也是最早的将程序综合的方法用到实际的应用中去.BECKER等[13]提出一个机器学习生成软件程序的系统,该系统使用了遗传算法(GA)只需通过较少的人工指导能生成软件程序.微软的BALOG等[14]在所提出的Deepcoder中使用了深度神经网络来预测将要生成的程序的属性,有效缩减了枚举生成代码过程中的状态空间,使生成代码的过程变得更加快速准确.
由于软件合成技术尚不成熟,现代的软件代码自动生成大多借助于模板来实现代码生成的自动化.模板技术是建立在事物相似性和设计方法重用基础上的一种类似的基于案例分析的知识重用技术[15].ARNOLDUS等[16]从数学角度去讨论模板,以提高模板的使用.模板技术的核心是设计信息的重用和参数化的变化,本质上也是一种占位符的动态替换过程.模板技术需要有模板文件、元数据和模板引擎这几个关键概念,其中模板引擎是核心,主要读取模板文件和元数据,然后依据模板引擎内部的规则进行转换、变量的匹配替换等,最终形成目标代码[17].
本文基于现有的软件安全检测技术,进一步利用检测报告结合模板技术的思想提出一种自动安全加固方法对软件源代码进行加固.
一个完整的装备嵌入式软件自动安全加固和代码补全流程可分为如下5个阶段:
1)利用软件源代码解析工具如LLVM和ANTLR工具,提取源代码的中间表示包括抽象语法树和函数调用图.
2)分析源代码中间表示得到结构化的源代码信息,生成特征值属性逻辑表达式.
3)对源代码信息特征值属性表达式与规约库中的特征值规约进行演算,从而生成检测报告.
4)利用检测报告和安全防护库所提供的防护模板生成安全防护代码.
5)将安全防护代码和软件代码进行融合形成安全软件源代码.
为了支持装备嵌入式软件自动安全加固和代码补全,本文提出了一种嵌入式软件安全漏洞检测与代码加固框架,如图1所示.该框架由基于漏洞特征的软件安全特征分析、安全防护库的构建(漏洞特征、规约库和模板库)、加固代码生成和代码植入等四部分内容组成.
图1 嵌入式软件安全漏洞检测与代码加固技术路线Fig.1 Technical route of embedded software security vulnerability detection and code reinforcement
建立安全防护库的目的主要在于软件安全分析,并为代码生成方法提供支持,其内容主要包括漏洞特征与规约库、模板库的构建,特征与规约库的构建为模板的建立提供了依据.
漏洞特征提取和软件安全漏洞检测是软件安全加固的基础.为了提取嵌入式软件漏洞特征,设定漏洞特征值与构建漏洞检测规约库,用一个漏洞特征三元组(VC,VP,F)来表示.
其中,1)VC是漏洞特征变量集合,每一个变量刻画了一种漏洞特征形态;2)VP是漏洞特征值属性集合,它表示不同特征值的取值范围,漏洞的表现形态由特征值来刻画;3)F是定义在特征值变量的一种对漏洞安全属性规约的逻辑命题,用来检测软件中的满足某种漏洞特征值规约的漏洞是否存在.
例如针对于缓冲区溢出漏洞,该漏洞的特征之一是由脆弱函数所引起的缓冲区溢出,那些可能引起脆弱漏洞的API函数名称就是缓冲区溢出漏洞特征值,VC={strcpy,memcpy,strcat,wcscpy,…}.其中,特征变量strcpy的特征值属性包括了6个属性,即VP={name_arg1,name_arg2,vol_arg1,len_arg2,kind_arg1,kind_arg2}.其中name_arg1是指strcpy第1个参数变量的名称,name_arg2是指strcpy第2个参数变量的名称,vol_arg1是strcpy第1个参数所指向的内存空间容量,len_arg2是strcpy第2参数所指向的字符串长度,king_arg1是指第一个参数类型,kind_arg2是第2个参数类型.定义在strcpy特征值属性上的安全属性规约f:vol_arg1>len_arg2.
软件安全分析技术在工业界和学术界已经形成了众多的研究成果与工具,且对源代码具有强大的分析与处理能力,根据漏洞特征模型及其安全规约,可以利用ANTLR、Clang等工具对源代码进行处理生成源代码的中间表示包括抽象语法树、函数调用图等,进而得到被加固软件代码漏洞特征、特征值的属性及其安全属性规约,利用安全防护库的已有知识,检测代码中所有的漏洞安全规约是否满足已有的漏洞规约,进而生成加固需求报告.
加固需求报告采用JSON的文件格式进行描述,加固需求报告的内容描述如图2所示.其中FilePath标识的是被检测源代码文件路径位置信息.content标识的是被检测源代码文件中的所有加固需求信息.需求内容content里对每一个漏洞,用character表示漏洞特征值,Attribute表示漏洞的属性值信息,存在多个属性值信息时采用“@#@”特殊符号隔开描述,row和col分别表示漏洞的位置信息的行号与列号.
图2 加固需求报告内容描述Fig.2 Reinforcement requirements report content
模板库的构建主要是为加固代码生成提供支持,模板库中含有模板文件和搜索文件.安全加固模板是将安全特征相关软件结构规律予以固定化、标准化的成果,它体现的是安全加固代码结构形式的标准化.因此,不同的加固模板就是把同类软件加固代码中相同的软件特征描述出来,针对具体漏洞的加固需求进行适应性变化,从而形成满足修复需求新的加固代码.模板技术促进了加固模式和加固代码的复用.
模板形态是对模板结构信息的描述,与编程语言无关.模板实例是针对于需要对模板结构信息的实现,与编程语言相关.实例化是指把语言无关的模板形态转换成与语言相关的模板实例.如图3所示,产生模板实例的过程可以分为两步,第一步:产生模板形态,模板的形态需要人工以漏洞安全知识为背景来制定模板的形态.第二步:针对于每一种漏洞类型,本文依据每一种漏洞特征与安全属性规约进行实例化模板,最后得到具体的模板实例.具体实例化步骤如下:
1)依据安全规约,建立不同的模板;
2)为模板赋予漏洞特征值;
3)根据规约以及漏洞知识编写模板的代码模块、属性值接口、修复相对位置;
4)对模板进行命名.
图3 模板的实例化流程Fig.3 process of instantiating a template
通过对漏洞安全知识的研究与分析,提出生成加固代码的模板形态.通常基于模板的代码生成较少的包含除代码外其他的信息,为了保证针对安全需求的加固代码模板可靠性以及加固代码的植入,在设计模板形态时除考虑代码以外,还在模板形态中添加了部分必要的信息.提出的模板形态主要包括模板ID、漏洞特征值、属性规约命题、加固位置、属性值接口和代码模块,如表1所示.
表1 加固代码模板形态Tab.1 Forms of reinforced codes template
模板的精准搜索是可提高加固效率和复用水平的重要技术手段,加固模板搜索是以提高模板的搜索效率以及计算模板匹配度为目标.依据模板库建立搜索文件,包含模板特征表、倒排表和索引表.模板特征表是用来记录模板名称与模板特征值的对应关系,为初始化索引表以及计算模板匹配度提供数据支持.倒排表是用来记录特征值与所包含该特征值的模板名称的对应关系,并用于更新索引表及搜索模板.索引表是用来记录搜索特征与模板名称所对应的关系,用于搜索满足需求的模板.
如图4所示为模板特征表、倒排表和索引表之间的关系.通过获取模板特征表的信息来建立倒排表,并利用模板特征表来初始化索引表.利用模板特征表计算模板的匹配度,通过倒排表去更新索引表.
图4 3个搜索文件之间的关系Fig.4 Relationship of three search files
模板特征表用来记录模板名称与模板特征的对应关系,目的是为初始化索引表以及计算模板匹配度.包含两部分内容,第一部分内容是模板ID,第二部分内容是模板所使用的特征值.用集合S表示模板库中所使用的特征值集合,即S={s1,s2,…,sn}.集合S中的元素si(i=1,…,n)是一个特征值.令标识特征值为C,则C的格式表示为:C=c1|c2|…|cn;ci=si或ci=sj+sk,其中si,sj,sk∈S.在式ci=sj+sk中符号“+”表示该模板被sj和sk共同标识缺一不可,在式C=c1|c2|…|cn中符号“|”表示该模板既可以被c1标识,又可以被c2标识.
模板特征表建立步骤:通过遍历模板库中的每一个模板文件并解析模板文件,记录模板ID与模板文件中所描述的特征,最后形成模板特征表.
基于模板特征表建立倒排表,倒排表用于更新索引表和搜索模板.包含两部分内容,第一部分内容为模板的特征值该部分内容只能使用一个特征值,第二部分内容为模板ID,第二部分内容可以包含多个模板ID.
倒排表建立步骤:第一步,对模板特征表的第二部分内容的特征值以“+”和“|”为分隔符进行切分,形成单独的特征值序列.第二步,针对每个不同的特征值,并记录该特征所出现的模板名称.
基于模板特征表初始化索引表,并利用倒排表更新索引表.主要包含两部分内容,第一部分内容为模板特征值该部分内容作为索引,第二部分内容为模板ID及其匹配度.
索引表建立步骤:以每个模板特征值中的“|”进行切分,把切分后的每一个特征值表达式都分别作为一个索引内容并记录分割后的特征值所对应的模板ID,并按模板ID所对应的特征值个数进行分类,即可分为用一个特征值所标识的模板ID、用两个特征值所标识的模板ID等,这样有助于搜索时可根据特征值的个数从而减少搜索范围.最后,把所有模板的匹配度都置为100%.
匹配度的计算公式采用Jaccard系数的计算方式进行计算,如式(1)所示,对于两个集合A和集合B,用两集合的交集去除以两集合的并集.例如:模板的特征是特征1、特征2和特征3,所搜索的特征是特征1,本文认为该模板与所需求的模板匹配度为33%.当模板的特征是特征1,所要搜索的特征也是特征1,此时认为该模板与需求模板的匹配度为100%.
(1)
在嵌入式软件安全漏洞检测与代码加固技术路线中,通过建立模板库来为生成安全加固代码提供支持.利用软件安全检测技术生成的加固需求报告,根据加固需求报告中的漏洞信息搜索模板,将漏洞信息和搜索到的模板通过模板引擎加工生成植入代码.
加固需求报告是软件安全检测技术向代码生成与植入模块提供的数据文件,其内容主要包含软件源代码漏洞的描述信息.根据代码生成方法的需求,软件源代码漏洞的描述信息主要包含源代码文件名及其路径信息和漏洞内容信息,其中漏洞内容信息包含漏洞特征值、属性值和漏洞位置信息.
有了加固需求报告和安全防护库后,根据代码生成算法生成加固代码.
算法:加固代码的生成算法
首先第1~4行处理搜索文件和加固需求报告中的信息形成集合.将模板库TemLib中的索引表中的对象obs1……obsi,由obs构成集合OBIndex;将TemLib中的倒排表中的对象obd1……obdi,由obd构成集合OBInvert;将TemLib中的模板特征表中的对象obm1…obmi,由obm构成集合OBTem;将加固需求DefectReport中的对象ob1…obi,由ob构成集合OBDefect.由此进一步进行代码生成.第5行~22行,针对于加固报告中的每个被检测文件生成加固信息.其中第7~21行针对于被检测文件中的每个漏洞生成加固代码,第9行~13行表示如果在索引表中匹配到Chasub,将根据模板ID找到模板文件然后根据模板文件生成加固代码.第14行~19行表示如果不能在索引表中匹配到Chasub,则在倒排表中匹配Chasub,并根据模板特征表计匹配度提示需要修改模板.第22行表示将集合REINCODE中的信息组织成加固需求文件.
根据算法生成了加固代码文件中所包含的信息为加固代码和其所该植入的位置信息,其位置信息采用源代码文件行号信息进行描述.进一步,解析加固代码文件,获取加固代码和其所要植入的位置信息,然后对位置信息从大到小进行排序,最后依次插入到源代码文件中形成安全源代码.
本文所提出的软件安全保障方法工具实现结构图,分为3个层次,如图5所示:工具在Eclipse集成开发环境(第1层)上开发,第2层为工具的核心功能主要含有漏洞检测、安全防护库管理和代码生成与融合模块,漏洞检测模块与代码生成与融合模块之间通过加固需求报告进行数据传递;第3层主要与源代码相关的功能包括查看和高亮显示加固代码,第2层和第3层在第1层的支撑下进行图像化界面显示.
图5 本文所提出技术路线的工具结构图Fig.5 tool structure diagram of the technical route is proposed in this paper
结合CWE(Common Weakness Enumeration),针对于缓冲区溢出漏洞构造了漏洞特征规约库和模板库.图6为针对缓冲区溢出所构建的特征规约文件,图中只展示了脆弱函数strcpy的特征与规则,文件采用xml的方式描述.其中,标签
选取CWE测试集中CWE121 _Stack _Bas ed_Buffer_Overflow_src_char_declare_cpy_01.c文件作为测试用例.如图8所示,该例子描述了由于strcpy(dest,data)所造成的栈缓冲区溢出,主要步骤为首先初始化一个容量为100的字符串数组data,然后利用memset函数把字符串数组data的每一位填充为’A’,最后使用strcpy函数把data数组的全部内容复制给一个初始化容量为50的数组dest,从而导致dest数组溢出.
图6 缓冲区溢出strcpy函数特征规约Fig.6 strcpy function features rule for buffer overflows
图7 针对于缓冲区溢出构建的模板文件Fig.7 Template files built for buffer overflows
图8 缓冲区溢出的代码片段Fig.8 Buffer overflow code snippet
根据所构建的缓冲区溢出模板库,通过输入加固需求,生成的加固代码为if(50>strlen(data)),其中属性值50和data需由漏洞检测框架所提供,最后对如图9框中所生成的防护加固代码进行高亮显示.
通过工具实现和案例实验,针对本文所提出的通过构建安全防护库,对缓冲区溢出漏洞进行特征分析,基于安全规约属性模板的代码加固方法可有效的对缓冲区溢出漏洞进行安全加固,从而保护嵌入式软件源代码代码安全.
图9 生成的防护加固代码并进行高亮显示Fig.9 The generated reinforcement code is highlighted
本文针对嵌入式系统维护提出了一种软件源代码安全漏洞检测与代码加固技术,通过构建漏洞特征、规约库并借助工具提取特征进行规约演算得到检测报告,并进一步利用模板技术生成安全防护代码并植入到源代码中,最终得到安全的源代码.通过实践表明该方法具有可行性.此外,所提出的漏洞特征、规约库和模板库构建方法可扩展到绕过权限检测、未验证输入和不安全文件操作等漏洞类型,表明该方法具有高可扩展性.