基于Linux环境的C/C++软件重量级静态检查
2016-07-07姜文刘立康
姜文,刘立康
基于Linux环境的C/C++软件重量级静态检查
姜文,刘立康
摘 要:为了保证基于Linux环境的C/C++软件代码的质量,对软件源代码进行静态检查非常重要。以SVN作为配臵管理工具,将重量级静态检查工具Coverity和Fortify集成到持续集成工具ICP-CI上,对C/C++源代码进行静态检查。详细叙述了Linux环境下配臵管理工具SVN客户端安装、SVN版本库的代码更新、Coverity和Fortify编译器的配臵、ICP-CI的任务管理页面上配臵检查任务。分析了检查过程中出现各种问题的原因并给出相应的解决方案。最后介绍了一个应用重量级静态检查的案例。工作实践表明静态检查有助于及时发现并解决C/C++软件源代码的各种缺陷,从而提高软件质量和安全性。关键词:Linux操作系统;静态检查;持续集成;安全漏洞
0 引言
Linux操作系统[1-3]是开源免费软件,是一个基于多用户、多任务、支持多线程和多CPU的操作系统,广泛应用于各类软件开发。Linux系统本身是网络的产物,在网络编程中占有重要地位。作为Linux系统的开发语言,C语言在Linux编程开发中扮演着重要的角色。C语言是一种通用的、过程式的编程语言,广泛用于系统与应用软件开发。C语言具有高效、灵活、功能丰富、表达力强和较高的移植性等特点。嵌入式C++(含C)也是嵌入式领域中最具有竞争力的编程语言。
Linux环境下流行的开发工具是GNU Tools,GNU Tools是免费、使用广泛,技术支持好的开发套件。gcc是GUN C的编译器,g++ 是GUN C++的编译器,而EGCS(Enhanced GNU Compiler Suite)可以认为是gcc的改进版。GDB即GNU的调试器,它是GCC附带的一个性能优质的调试器。软件工程工具make用于协助多人开发大型软件项目管理,make使用的重点和难点是编写Makefile文件。通常采用编辑器(emacs, vim) 来编辑程序。
为了保证基于Linux操作系统的软件代码质量,检测软件源代码中存在的各种缺陷和安全漏洞非常重要。本文采用CodeCC(Code Check Center)工具压缩包开展检测工作。工具压缩包中包括静态检查工具Coverity和Fortify,采用静态检查方法检测源代码,将检查结果反馈给开发人员及时处理,从而提高软件的质量和安全性。
1 重量级静态检查工具
通常把Coverity[4.5]和Fortify[6.7]称为重量级的静态检查工具。
1.1 Coverity Prevent
Coverity Prevent是一款高性能静态检查软件,提供最先进的和可配置的用于检测软件缺陷和安全隐患的静态源代码分析解决方案。Coverity Prevent是第一个能够快速、准确分析当今大规模(几百万、甚至几千万行的代码)、高复杂度代码的工具。
首先Coverity Prevent的编译器在通过配置器命令处理后,编译处理C/C++源文件,解析代码后在中间目录中生成代码的模型;然后分析引擎读取中间目录,分析源代码,生成缺陷报告;最后将报告提交到缺陷管理数据库,供分析人员处理。
Coverity Prevent可以解决影响源代码分析有效性的很多关键问题:构建集成、编译兼容性、高误报率、有效的错误根源分析等。Coverity Prevent主要功能包括源代码分析、缺陷管理、扩展工具(Coverity extend)、绘制软件DNA图谱。Coverity Prevent是检测和解决C/C++源代码中严重缺陷的领先自动化方法。
1.2 Fortify SCA
静态代码分析器Fortify SCA(Static Code Analyzer)是一款软件源代码缺陷静态测试工具。它内置五大分析模块:数据流分析模块、语义分析模块、结构分析模块、控制流分析模块与配置流模块。Fortify首先通过调用语言的编译器或者解释器把源代码转换成一种中间媒体文件*.nst (Normal Syntax Tree)。通过分析引擎和Fortify SCA分析规则库提供的分析规则对中间媒体文件进行静态分析,从而将源代码中存在的缺陷和安全漏洞扫描出来,并给予整理报告。扫描的结果中不但包括详细的缺陷和安全漏洞的信息,还会有相关的安全知识的说明,同时提供修复意见。
Fortify SCA支持的编程语言多达17种,包括C、C+、C#、JAVA等,基本上涵盖了绝大多数编程语言。
2 检查工具集成到持续集成工具ICP-CI
为了保证软件源代码质量,每周至少对合入版本库的源代码进行2-3次Coverity和Fortify检查。持续集成[8]工具可以提供方便的集成平台,可以设置定时任务,使Coverity和Fortify检查任务能够充分利用非工作时间完成编译和结果分析等比较耗时的执行过程,保证及时得到分析结果,方便开发人员根据检查报告处理软件源代码缺陷。
本文中采用的软件配置管理工具是SVN,持续集成工具是ICP-CI。由于使用的编译环境是Linux,代理服务器上需要安装ICP_CI_Linux_Agent。由于Linux操纵系统是64位,首先将集成了Coverity和Fortify工具的CodeCC (Code Check Center)工具的压缩包CodeCC_Linux64.zip拷贝到持续集成主控服务器与代理服务器的plugin目录下解压,再分别对Coverity和Fortify工具进行相关的编译器配置,然后完成搭建构建工程。构建工程命名为:“产品名_版本号_CodeCheck”。检测过程如图1所示:
图1 CodeCC检测流程
2.1 Linux环境下的SVN客户端安装
执行编译的操作系统是Linux,需要在代理服务器上安装SVN工具。安装的SVN客户端版本为1.7.5,安装包为subversion-1.7.5.tar.bz2,安装步骤如下:
将安装包subversion-1.7.5.tar.bz2拷贝到/opt/software路径下;
执行tar xvfj subversion-1.7.5.tar.bz2,完成安装包解压;执行cd subversion-1.7.5,进入安装包路径;
执行chmod +x get-deps.sh,给获取依赖的脚本添加执行权限;
执行./get-deps.sh,获取依赖;
执行./configure,完成安装前的配置;
分别执行make与make install完成SVN客户端的安装;执行svn help,确认客户端安装成功。
如果在SVN客户端在安装配置过程中报这个错:“configure: error: in `/root/subversion-1.7.5':”,则需要执行“yum install gcc”,安装gcc编译器;如果在配置过程中报这个错:“configure: error: We require OpenSSL; try --w ith-openssl”,则需要执行“yum install openssl”和“yum install openssl-devel”安装OpenSSL之后继续安装SVN客户端。
2.2 SVN版本库的代码更新
持续集成工具ICP-CI需要在版本库锁库之后完成源代码更新,然后进行Coverity和Fortify检查。ICP-CI工具执行代码更新时,需要编写代码更新的Shell脚本CodeUpdate.sh,把代码更新的脚本配置在任务中。更新代码的批处理脚本内容如下:
VIEWPATH=usr1/Code/Product_Code tmplogfile="/tmp/svn_log.log"
svn update $VIEWPATH >> $tmplogfile
2.3 Coverity编译器配置
软件产品模块进行Coverity检查时,需要在模块源代码进行编译的时候调用Coverity工具中的cov_configure命令。为了成功调用cov_configure命令,需要在CodeCC工具的tqeconfig.ini文件中完成编译器的配置。
对于基于Linux操作系统的软件产品,在tqeconfig.ini文件中编译器的配置内容如下:
gcc=/usr/bin/gcc
完成编译器配置后,执行tqeconfig.sh文件,该文件如果执行成功则将生成相应的配置文件保存在CodeCC oolcoverityconfig目录下。在配置编译器时需要注意tqeconfig.sh脚本的执行结果,当执行窗口中提示执行成功,配置的编译器才能在CodeCC oolcoverityconfig目录下生成对应编译器的配置文件。
代理服务器上安装的Linux操作系统是64位,而产品编译生成的进程文件包含32位和64位,因此在安装64位的Linux操作系统上对32位的进程文件进行CodeCC检查,需要采取如下措施:
在环境变量里面添加export COVERITY_UNSUPPOR TED=1;
进入cov-configure路径(在/CodeCC/tool/coverity/bin下),
执行./cov-configure -co gcc -- -m32;
完成编译器配置后,需要将持续集成主控服务器和代理服务器上的coverity工具路径:
pluginCodeCC oolcoverityin路径添加到环境变量path中。
Coverity任务配置到ICP-CI上之后,通常由主控服务器将任务下发至代理服务器上执行。执行Coverity任务时,需要改造原来的编译脚本,使其能够调用cov-configure。具体脚本内容如下:
CUR_SH_PATH='pwd' export
PATH=/usr1/ICP_CI_Linux_Agent/plugin/CodeCC/tool/cover ity/bin:$PATH
CODE_ROOT_PATH=${CUR_SH_PATH}/../
echo “change attribute:$CODE_ROOT_PATH”
chmod -R 775 $CODE_ROOT_PATH
./ims_make.sh ghy3100 db mcca clean
echo “begin compiling coverity db”
./ims_make.sh ghy3100 db mcca
2.4 Fortify编译器配置
2.4.1 编译文件配置
基于Linux操作系统的编译器,需要配置到fortify的配置文件中。为了Fortify工具可以识别和使用这些编译器,需要修改Fortify的配置文件,将Linux操作系统的编译器配置到CodeCC oolfortifycoreconfig目录下的fortify-sca. properties文件中。配置内容如下所示:
com.fortify.sca.compilers.gcc=com.fortify.sca.util.compil ers.GccCompiler
编译器配置完成之后,需要将持续集成主控服务器与代理服务器上的fortify工具路径:pluginCodeCC oolfor tifyin添加到环境变量path中。
2.4.2 在编译脚本中嵌入fortify命令
进行代码编译时,需要将以前编译生成的*.obj目标文件全部删除。Fortify工具通过跟踪编译器生成中间文件*.nst,如果编译过程中以前的*.obj目标文件没有删除,Fortify工具无法跟踪编译器生成正确的*.nst文件。
为了使Fortify工具通过跟踪的方式编译生成中间文件*.nst,需要根据软件模块重新编写编译脚本和makefile文件。在编译过程中需要调用钩子函数sourceanalyzer.exe文件,将编译器和链接器都挂在钩子上,从而生成中间文件*.nst。编译脚本如下所示:
CUR_SH_PATH='pwd'
echo “fortify,change attribute:$CODE_ROOT_PATH”
chmod -R 775 $CODE_ROOT_PATH
export
PATH=/usr1/ICP_CI_Linux_Agent/plugin/CodeCC/tool/fortif y/bin:$PATH
cd $CODE_ROOT_PATH/build
echo “begin compiling db”
bash ./ims_make.sh ghy3100 db mcca clean
sourceanalyzer -b fortify_db
sourceanalyzer -b fortify_db touchless bash ./make_ ghy_db.sh
其中,sourceanalyzer表示Fortify工具的执行命令主体;build_id表示Fortify的工程名(不能与Fortify的关键字相同)。
Fortify任务配置到ICP-CI上之后,通常由主控服务器将任务下发至代理服务器上执行。需要将原来的编译脚本如上改造之后更名为*_fortify.sh。
2.5 ICP-CI的任务管理页面上配置检查任务
在ICP-CI的任务管理页面的构建工程上配置CodeCC检查任务,通常Coverity任务和Fortify任务同时配置。以软件模块db为例来描述集成过程。配置db模块的CodeCC任务时,在任务栏上选择“CodeCC”任务。对于Coverity任务,将db模块的编译脚本make_ghy_db_con.sh脚本和db模块编译脚本路径配置到CodeCC任务类型页面下的编译脚本编译路径中,选择编译类型为gcc,并在任务选项栏添加“Coverity”任务。
对于Fortify任务,将db模块的Fortify编译脚本make_ghy_db_fortify.sh脚本以及db模块编译脚本路径配置到CodeCC任务的fortifyexecutable这个配置项中。最后在任务类型中再添加“Fortify”任务。
使用工具ICP-CI做Coverity和Fortify检查时,通常先对模块做Coverity检查,生成的中间文件压缩包上传到指定的分析服务器;接着对模块做Fortify检查,同样将生成的中间文件压缩包上传到同一个分析服务器。此时ICP-CI的执行窗口显示CodeCC任务成功并处于等待分析结果状态。等待分析结果的时间长短取决于生成的中间文件的大小以及分析服务器的忙碌程度。
对于无法搭建大型分析服务器的情况,可以采用以下方法来获取Coverity和Fortify的检查结果。对于Coverity检查,可以使用cov-analyze对Coverity编译生成的中间文件进行分析,将分析结果使用cov-commit-defects提交到“缺陷管理数据库”,使用cov-start-gui启动GUI之后,打开浏览器查看Coverity的分析结果。
对于Fortify检查,可以执行sourceanalyzer -b build_id -XssLM -scan -f result_dir esult.fpr,对生成的中间文件进行分析,分析结果报告会生成在result_dir目录下。
2.6 检查结果的处理
当分析服务器分析完毕,将模块的分析结果回传到ICP-CI工具,在ICP-CI工具的页面上可以看到Coverity 和Fortify工具各自的检查结果。检查结果包括模块的缺陷数以及总缺陷数,缺陷级别。缺陷级别分为高、中、低3个级别。各级别的显示结果用“/”分隔。同时也会根据检查模块任务配置的邮件主送人和抄送人,给这些人发送邮件。邮件的发送人是CodeCC。邮件内容为该检查模块的Coverity和Fortify检查日志与检查结果下载路径。
3 CodeCC检查出现问题的分析和处理
开发人员下载检查结果文件,分析检查结果。确认是源代码问题,修改源代码后重新合入版本库,进行新的CodeCC检查,根据新的检查结果确认代码缺陷是否已经被解决,已经解决的缺陷呈现的状态为“Fixed”,呈现状态为“new”,缺陷数量减少。确认是误报的缺陷,在显示的Coverity和Fortify检查结果页面的“Ignore defects”链接进入由分析服务器指定的缺陷库,完成误报缺陷的屏蔽,屏蔽之后的缺陷呈现为“Dismissed”状态。
进行CodeCC检查时,难免会出现失败的情况。CodeCC检查失败需及时发现处理,根据失败的模块、构建工程页面上提示失败的信息和构建工程的详细日志文件来确定CodeCC检查失败的原因。CodeCC检查失败通常有以下3类:
3.1 Coverity或Fortify检查在编译阶段出错
在编译阶段出错,查看对应的编译日志可以发现各种问题(编译器配置问题、编译脚本问题或源代码编译错误等),导致在编译阶段检查报错。
解决方法如下:
在tqeconfig.ini中配置相应编译器,并执行tqeconfig.sh文件完成配置,或在fortify-sca.properties文件中完成配置。
根据日志所报编译问题,重新编写编译模块的编译脚本。
开发工程师定位、处理模块编译错误,新的源代码合入版本库之后重新执行模块的CodeCC检查任务。
Coverity或Fortify检查在分析阶段出错
在分析阶段出错,查看对应的分析日志可以发现大部分是分析服务器问题导致的执行失败,通常表现为上传中间文件压缩包失败、分析结果回传失败等。根据分析日志发现此类问题,需要联系相关人员解决分析服务器问题。3.3 CodeCC检查文件的比例问题
查看检查的编译日志文件build.log文件,查看模块编译检查文件的百分比,如果模块需要编译的文件都完成检查,百分比应该是100%。如果这个百分比值不是100%,需要在日志文件里分析查找错误。通常这些错误不是产品模块的代码编译错误,而是由于产品模块源代码生成中间文件过程中与编译器冲突导致的。为了提高检查的文件比例,需要开发工程师与系统工程师共同研究分析,尽可能通过修改源代码提高检查文件的比例。
4 典型案例
某公司的有一个软、硬件结合的中型开发项目,总的代码量为300万行。Linux环境下采用C/C++进行软件开发;采用的软件配置管理工具为SVN;持续集成工具为ICP-CI。集成到ICP-CI工具后,使用Shell脚本和ANT脚本完成对软件模块的Coverity检查和Fortify检查。以db模块为例,对该模块进行检查的扫描结果如下表1所示:
表1 对db模块进行Coverity检查和Fortify检查的扫描结果
同时在检查结果报告中详细列举了缺陷的类型与种类,db模块的开发工程师下载检查结果报告后,对产品源代码进行分析,对于存在的缺陷根据检查报告进行代码优化与重构。对于检查中误报的源代码缺陷,开发工程师进入对模块代码进行检查的缺陷库,根据告警ID号查找对应的缺陷,认真填写屏蔽原因之后,对告警进行屏蔽。经过对db模块的代码优化、重构以及误报告警屏蔽,最终将db模块的告警数目清零。通过对db模块的Coverity检查和Fortify检查,将有助于提升db模块的源代码质量。
工作实践表明CodeCC检查有助于及时发现并解决C/C++源代码的各种缺陷和安全漏洞,便于产品主管了解工作进度和解决存在的问题,进一步提升产品质量。
5 总结
长期的工作实践表明CodeCC检查在C/C++程序开发过程中发挥了重要的作用。检查工具集成到持续集成工具ICP-CI,可以自动完成CodeCC检查,快速地向软件开发人员反馈检查结果,使软件开发人员能够及时修复源代码的缺陷和安全漏洞,同时也给项目管理提供了很好的保证。软件开发过程中CodeCC检查工作做好了,有助于提高产品的质量,降低软件开发的的成本。
参考文献
[1] 秦攀科,Linux C 程序设计基础[M].北京:清华大学出版社,2011.
[2] 庄严,王骁,汤建敏,嵌入式C/C++系统工程师实训教程[M].北京:清华大学出版社,2011.
[3] 吴世忠,郭涛,董国伟,张普含, 软件漏洞分析技术[M].北京:科学出版社,2014.
[4] Ali Almossaw i,Kelvin Lim,Tanmay,Analysis Tool Evaluation:Coverity Prevent [R]. SinhaCarnegie Mellon University, May , 2006.
[5] Coverity® Scan:2013 Open Source Report [R].Coverity,Inc,2014.
[6] Fortify SCA User Guide Fortify 360 Version 2.6[R].For -tify Software Inc,May 2010.
[7] Peter Blay,Simon Corlett,Fortify SCA Performance Guide[R].Fortify Software Inc, June 2014.
[8] 罗时飞,敏捷持续集成 : CruiseControl版 : 高效硏发之道[M].北京:电子工业出版社,2008.
Heavy-weight Static Checking of C/C++ Software Based on Linux Operation System
Jiang Wen, Liu Likang
(School of Telecommunication Engineering, Xidian University, Xi‘an 710071,China)
Abstract:In order to ensure the quality of code in language C/C++ based on Linux environment, it is very important to do the static checking of the software code. With SVN as configuration management tool, the heavy-weight static checking tools Coverity and Fortify are integrated into continuous integration tool ICP-CI, for static checking. The SVN client installation under Linux environment, the code update of the SVN repository, the Coverity and Fortify compiler configuration, the inspection tasks configuration on ICP-CI task management page are described in detail. Analyze causes of problems appearing in the process of checking and the corresponding solutions are given. Finally the heavy-weight static checking applied in a case is introduced. Practice shows that the static checking conduces to discover and solve all kinds of flaws of the C/C++ code timely, to improve software quality and safety.
Key words:Linux Operating System; Static Checking; Continuous Integration; Security Vulnerabilities
中图分类号:TP311.56
文献标志码:B
文章编号:1007-757X(2016)05-0012-04
基金项目:国家部委基础科研计划:国防预研基金项目 (A1120110007)
作者简介:姜 文(1986-),女,西安人,西安电子科技大学,CCF会员(E200032324M),研究方向:图像处理,软件工程;西安 710075刘立康(1962-),男,西安人,西安电子科技大学,通信工程学院,副教授,研究方向:数字通信,图像处理,嵌入式应用技术;西安 710071
收稿日期:(2015.11.02)