姜文,劉立康
?
基于Linux環(huán)境的C/C++軟件重量級靜態(tài)檢查
姜文,劉立康
摘 要:為了保證基于Linux環(huán)境的C/C++軟件代碼的質量,對軟件源代碼進行靜態(tài)檢查非常重要。以SVN作為配臵管理工具,將重量級靜態(tài)檢查工具Coverity和Fortify集成到持續(xù)集成工具ICP-CI上,對C/C++源代碼進行靜態(tài)檢查。詳細敘述了Linux環(huán)境下配臵管理工具SVN客戶端安裝、SVN版本庫的代碼更新、Coverity和Fortify編譯器的配臵、ICP-CI的任務管理頁面上配臵檢查任務。分析了檢查過程中出現(xiàn)各種問題的原因并給出相應的解決方案。最后介紹了一個應用重量級靜態(tài)檢查的案例。工作實踐表明靜態(tài)檢查有助于及時發(fā)現(xiàn)并解決C/C++軟件源代碼的各種缺陷,從而提高軟件質量和安全性。關鍵詞:Linux操作系統(tǒng);靜態(tài)檢查;持續(xù)集成;安全漏洞
Linux操作系統(tǒng)[1-3]是開源免費軟件,是一個基于多用戶、多任務、支持多線程和多CPU的操作系統(tǒng),廣泛應用于各類軟件開發(fā)。Linux系統(tǒng)本身是網(wǎng)絡的產(chǎn)物,在網(wǎng)絡編程中占有重要地位。作為Linux系統(tǒng)的開發(fā)語言,C語言在Linux編程開發(fā)中扮演著重要的角色。C語言是一種通用的、過程式的編程語言,廣泛用于系統(tǒng)與應用軟件開發(fā)。C語言具有高效、靈活、功能豐富、表達力強和較高的移植性等特點。嵌入式C++(含C)也是嵌入式領域中最具有競爭力的編程語言。
Linux環(huán)境下流行的開發(fā)工具是GNU Tools,GNU Tools是免費、使用廣泛,技術支持好的開發(fā)套件。gcc是GUN C的編譯器,g++ 是GUN C++的編譯器,而EGCS(Enhanced GNU Compiler Suite)可以認為是gcc的改進版。GDB即GNU的調試器,它是GCC附帶的一個性能優(yōu)質的調試器。軟件工程工具make用于協(xié)助多人開發(fā)大型軟件項目管理,make使用的重點和難點是編寫Makefile文件。通常采用編輯器(emacs, vim) 來編輯程序。
為了保證基于Linux操作系統(tǒng)的軟件代碼質量,檢測軟件源代碼中存在的各種缺陷和安全漏洞非常重要。本文采用CodeCC(Code Check Center)工具壓縮包開展檢測工作。工具壓縮包中包括靜態(tài)檢查工具Coverity和Fortify,采用靜態(tài)檢查方法檢測源代碼,將檢查結果反饋給開發(fā)人員及時處理,從而提高軟件的質量和安全性。
通常把Coverity[4.5]和Fortify[6.7]稱為重量級的靜態(tài)檢查工具。
1.1 Coverity Prevent
Coverity Prevent是一款高性能靜態(tài)檢查軟件,提供最先進的和可配置的用于檢測軟件缺陷和安全隱患的靜態(tài)源代碼分析解決方案。Coverity Prevent是第一個能夠快速、準確分析當今大規(guī)模(幾百萬、甚至幾千萬行的代碼)、高復雜度代碼的工具。
首先Coverity Prevent的編譯器在通過配置器命令處理后,編譯處理C/C++源文件,解析代碼后在中間目錄中生成代碼的模型;然后分析引擎讀取中間目錄,分析源代碼,生成缺陷報告;最后將報告提交到缺陷管理數(shù)據(jù)庫,供分析人員處理。
Coverity Prevent可以解決影響源代碼分析有效性的很多關鍵問題:構建集成、編譯兼容性、高誤報率、有效的錯誤根源分析等。Coverity Prevent主要功能包括源代碼分析、缺陷管理、擴展工具(Coverity extend)、繪制軟件DNA圖譜。Coverity Prevent是檢測和解決C/C++源代碼中嚴重缺陷的領先自動化方法。
1.2 Fortify SCA
靜態(tài)代碼分析器Fortify SCA(Static Code Analyzer)是一款軟件源代碼缺陷靜態(tài)測試工具。它內置五大分析模塊:數(shù)據(jù)流分析模塊、語義分析模塊、結構分析模塊、控制流分析模塊與配置流模塊。Fortify首先通過調用語言的編譯器或者解釋器把源代碼轉換成一種中間媒體文件*.nst (Normal Syntax Tree)。通過分析引擎和Fortify SCA分析規(guī)則庫提供的分析規(guī)則對中間媒體文件進行靜態(tài)分析,從而將源代碼中存在的缺陷和安全漏洞掃描出來,并給予整理報告。掃描的結果中不但包括詳細的缺陷和安全漏洞的信息,還會有相關的安全知識的說明,同時提供修復意見。
Fortify SCA支持的編程語言多達17種,包括C、C+、C#、JAVA等,基本上涵蓋了絕大多數(shù)編程語言。
為了保證軟件源代碼質量,每周至少對合入版本庫的源代碼進行2-3次Coverity和Fortify檢查。持續(xù)集成[8]工具可以提供方便的集成平臺,可以設置定時任務,使Coverity和Fortify檢查任務能夠充分利用非工作時間完成編譯和結果分析等比較耗時的執(zhí)行過程,保證及時得到分析結果,方便開發(fā)人員根據(jù)檢查報告處理軟件源代碼缺陷。
本文中采用的軟件配置管理工具是SVN,持續(xù)集成工具是ICP-CI。由于使用的編譯環(huán)境是Linux,代理服務器上需要安裝ICP_CI_Linux_Agent。由于Linux操縱系統(tǒng)是64位,首先將集成了Coverity和Fortify工具的CodeCC (Code Check Center)工具的壓縮包CodeCC_Linux64.zip拷貝到持續(xù)集成主控服務器與代理服務器的plugin目錄下解壓,再分別對Coverity和Fortify工具進行相關的編譯器配置,然后完成搭建構建工程。構建工程命名為:“產(chǎn)品名_版本號_CodeCheck”。檢測過程如圖1所示:

圖1 CodeCC檢測流程
2.1 Linux環(huán)境下的SVN客戶端安裝
執(zhí)行編譯的操作系統(tǒng)是Linux,需要在代理服務器上安裝SVN工具。安裝的SVN客戶端版本為1.7.5,安裝包為subversion-1.7.5.tar.bz2,安裝步驟如下:
將安裝包subversion-1.7.5.tar.bz2拷貝到/opt/software路徑下;
執(zhí)行tar xvfj subversion-1.7.5.tar.bz2,完成安裝包解壓;執(zhí)行cd subversion-1.7.5,進入安裝包路徑;
執(zhí)行chmod +x get-deps.sh,給獲取依賴的腳本添加執(zhí)行權限;
執(zhí)行./get-deps.sh,獲取依賴;
執(zhí)行./configure,完成安裝前的配置;
分別執(zhí)行make與make install完成SVN客戶端的安裝;執(zhí)行svn help,確認客戶端安裝成功。
如果在SVN客戶端在安裝配置過程中報這個錯:“configure: error: in `/root/subversion-1.7.5':”,則需要執(zhí)行“yum install gcc”,安裝gcc編譯器;如果在配置過程中報這個錯:“configure: error: We require OpenSSL; try --w ith-openssl”,則需要執(zhí)行“yum install openssl”和“yum install openssl-devel”安裝OpenSSL之后繼續(xù)安裝SVN客戶端。
2.2 SVN版本庫的代碼更新
持續(xù)集成工具ICP-CI需要在版本庫鎖庫之后完成源代碼更新,然后進行Coverity和Fortify檢查。ICP-CI工具執(zhí)行代碼更新時,需要編寫代碼更新的Shell腳本CodeUpdate.sh,把代碼更新的腳本配置在任務中。更新代碼的批處理腳本內容如下:
VIEWPATH=usr1/Code/Product_Code tmplogfile="/tmp/svn_log.log"
svn update $VIEWPATH >> $tmplogfile
2.3 Coverity編譯器配置
軟件產(chǎn)品模塊進行Coverity檢查時,需要在模塊源代碼進行編譯的時候調用Coverity工具中的cov_configure命令。為了成功調用cov_configure命令,需要在CodeCC工具的tqeconfig.ini文件中完成編譯器的配置。
對于基于Linux操作系統(tǒng)的軟件產(chǎn)品,在tqeconfig.ini文件中編譯器的配置內容如下:
gcc=/usr/bin/gcc
完成編譯器配置后,執(zhí)行tqeconfig.sh文件,該文件如果執(zhí)行成功則將生成相應的配置文件保存在CodeCC oolcoverityconfig目錄下。在配置編譯器時需要注意tqeconfig.sh腳本的執(zhí)行結果,當執(zhí)行窗口中提示執(zhí)行成功,配置的編譯器才能在CodeCC oolcoverityconfig目錄下生成對應編譯器的配置文件。
代理服務器上安裝的Linux操作系統(tǒng)是64位,而產(chǎn)品編譯生成的進程文件包含32位和64位,因此在安裝64位的Linux操作系統(tǒng)上對32位的進程文件進行CodeCC檢查,需要采取如下措施:
在環(huán)境變量里面添加export COVERITY_UNSUPPOR TED=1;
進入cov-configure路徑(在/CodeCC/tool/coverity/bin下),
執(zhí)行./cov-configure -co gcc -- -m32;
完成編譯器配置后,需要將持續(xù)集成主控服務器和代理服務器上的coverity工具路徑:
pluginCodeCC oolcoverityin路徑添加到環(huán)境變量path中。
Coverity任務配置到ICP-CI上之后,通常由主控服務器將任務下發(fā)至代理服務器上執(zhí)行。執(zhí)行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操作系統(tǒng)的編譯器,需要配置到fortify的配置文件中。為了Fortify工具可以識別和使用這些編譯器,需要修改Fortify的配置文件,將Linux操作系統(tǒng)的編譯器配置到CodeCC oolfortifycoreconfig目錄下的fortify-sca. properties文件中。配置內容如下所示:
com.fortify.sca.compilers.gcc=com.fortify.sca.util.compil ers.GccCompiler
編譯器配置完成之后,需要將持續(xù)集成主控服務器與代理服務器上的fortify工具路徑:pluginCodeCC oolfor tifyin添加到環(huán)境變量path中。
2.4.2 在編譯腳本中嵌入fortify命令
進行代碼編譯時,需要將以前編譯生成的*.obj目標文件全部刪除。Fortify工具通過跟蹤編譯器生成中間文件*.nst,如果編譯過程中以前的*.obj目標文件沒有刪除,F(xiàn)ortify工具無法跟蹤編譯器生成正確的*.nst文件。
為了使Fortify工具通過跟蹤的方式編譯生成中間文件*.nst,需要根據(jù)軟件模塊重新編寫編譯腳本和makefile文件。在編譯過程中需要調用鉤子函數(shù)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工具的執(zhí)行命令主體;build_id表示Fortify的工程名(不能與Fortify的關鍵字相同)。
Fortify任務配置到ICP-CI上之后,通常由主控服務器將任務下發(fā)至代理服務器上執(zhí)行。需要將原來的編譯腳本如上改造之后更名為*_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的執(zhí)行窗口顯示CodeCC任務成功并處于等待分析結果狀態(tài)。等待分析結果的時間長短取決于生成的中間文件的大小以及分析服務器的忙碌程度。
對于無法搭建大型分析服務器的情況,可以采用以下方法來獲取Coverity和Fortify的檢查結果。對于Coverity檢查,可以使用cov-analyze對Coverity編譯生成的中間文件進行分析,將分析結果使用cov-commit-defects提交到“缺陷管理數(shù)據(jù)庫”,使用cov-start-gui啟動GUI之后,打開瀏覽器查看Coverity的分析結果。
對于Fortify檢查,可以執(zhí)行sourceanalyzer -b build_id -XssLM -scan -f result_dir esult.fpr,對生成的中間文件進行分析,分析結果報告會生成在result_dir目錄下。
2.6 檢查結果的處理
當分析服務器分析完畢,將模塊的分析結果回傳到ICP-CI工具,在ICP-CI工具的頁面上可以看到Coverity 和Fortify工具各自的檢查結果。檢查結果包括模塊的缺陷數(shù)以及總缺陷數(shù),缺陷級別。缺陷級別分為高、中、低3個級別。各級別的顯示結果用“/”分隔。同時也會根據(jù)檢查模塊任務配置的郵件主送人和抄送人,給這些人發(fā)送郵件。郵件的發(fā)送人是CodeCC。郵件內容為該檢查模塊的Coverity和Fortify檢查日志與檢查結果下載路徑。
開發(fā)人員下載檢查結果文件,分析檢查結果。確認是源代碼問題,修改源代碼后重新合入版本庫,進行新的CodeCC檢查,根據(jù)新的檢查結果確認代碼缺陷是否已經(jīng)被解決,已經(jīng)解決的缺陷呈現(xiàn)的狀態(tài)為“Fixed”,呈現(xiàn)狀態(tài)為“new”,缺陷數(shù)量減少。確認是誤報的缺陷,在顯示的Coverity和Fortify檢查結果頁面的“Ignore defects”鏈接進入由分析服務器指定的缺陷庫,完成誤報缺陷的屏蔽,屏蔽之后的缺陷呈現(xiàn)為“Dismissed”狀態(tài)。
進行CodeCC檢查時,難免會出現(xiàn)失敗的情況。CodeCC檢查失敗需及時發(fā)現(xiàn)處理,根據(jù)失敗的模塊、構建工程頁面上提示失敗的信息和構建工程的詳細日志文件來確定CodeCC檢查失敗的原因。CodeCC檢查失敗通常有以下3類:
3.1 Coverity或Fortify檢查在編譯階段出錯
在編譯階段出錯,查看對應的編譯日志可以發(fā)現(xiàn)各種問題(編譯器配置問題、編譯腳本問題或源代碼編譯錯誤等),導致在編譯階段檢查報錯。
解決方法如下:
在tqeconfig.ini中配置相應編譯器,并執(zhí)行tqeconfig.sh文件完成配置,或在fortify-sca.properties文件中完成配置。
根據(jù)日志所報編譯問題,重新編寫編譯模塊的編譯腳本。
開發(fā)工程師定位、處理模塊編譯錯誤,新的源代碼合入版本庫之后重新執(zhí)行模塊的CodeCC檢查任務。
Coverity或Fortify檢查在分析階段出錯
在分析階段出錯,查看對應的分析日志可以發(fā)現(xiàn)大部分是分析服務器問題導致的執(zhí)行失敗,通常表現(xiàn)為上傳中間文件壓縮包失敗、分析結果回傳失敗等。根據(jù)分析日志發(fā)現(xiàn)此類問題,需要聯(lián)系相關人員解決分析服務器問題。3.3 CodeCC檢查文件的比例問題
查看檢查的編譯日志文件build.log文件,查看模塊編譯檢查文件的百分比,如果模塊需要編譯的文件都完成檢查,百分比應該是100%。如果這個百分比值不是100%,需要在日志文件里分析查找錯誤。通常這些錯誤不是產(chǎn)品模塊的代碼編譯錯誤,而是由于產(chǎn)品模塊源代碼生成中間文件過程中與編譯器沖突導致的。為了提高檢查的文件比例,需要開發(fā)工程師與系統(tǒng)工程師共同研究分析,盡可能通過修改源代碼提高檢查文件的比例。
某公司的有一個軟、硬件結合的中型開發(fā)項目,總的代碼量為300萬行。Linux環(huán)境下采用C/C++進行軟件開發(fā);采用的軟件配置管理工具為SVN;持續(xù)集成工具為ICP-CI。集成到ICP-CI工具后,使用Shell腳本和ANT腳本完成對軟件模塊的Coverity檢查和Fortify檢查。以db模塊為例,對該模塊進行檢查的掃描結果如下表1所示:

表1 對db模塊進行Coverity檢查和Fortify檢查的掃描結果
同時在檢查結果報告中詳細列舉了缺陷的類型與種類,db模塊的開發(fā)工程師下載檢查結果報告后,對產(chǎn)品源代碼進行分析,對于存在的缺陷根據(jù)檢查報告進行代碼優(yōu)化與重構。對于檢查中誤報的源代碼缺陷,開發(fā)工程師進入對模塊代碼進行檢查的缺陷庫,根據(jù)告警ID號查找對應的缺陷,認真填寫屏蔽原因之后,對告警進行屏蔽。經(jīng)過對db模塊的代碼優(yōu)化、重構以及誤報告警屏蔽,最終將db模塊的告警數(shù)目清零。通過對db模塊的Coverity檢查和Fortify檢查,將有助于提升db模塊的源代碼質量。
工作實踐表明CodeCC檢查有助于及時發(fā)現(xiàn)并解決C/C++源代碼的各種缺陷和安全漏洞,便于產(chǎn)品主管了解工作進度和解決存在的問題,進一步提升產(chǎn)品質量。
長期的工作實踐表明CodeCC檢查在C/C++程序開發(fā)過程中發(fā)揮了重要的作用。檢查工具集成到持續(xù)集成工具ICP-CI,可以自動完成CodeCC檢查,快速地向軟件開發(fā)人員反饋檢查結果,使軟件開發(fā)人員能夠及時修復源代碼的缺陷和安全漏洞,同時也給項目管理提供了很好的保證。軟件開發(fā)過程中CodeCC檢查工作做好了,有助于提高產(chǎn)品的質量,降低軟件開發(fā)的的成本。
參考文獻
[1] 秦攀科,Linux C 程序設計基礎[M].北京:清華大學出版社,2011.
[2] 莊嚴,王驍,湯建敏,嵌入式C/C++系統(tǒng)工程師實訓教程[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,F(xiàn)ortify SCA Performance Guide[R].Fortify Software Inc, June 2014.
[8] 羅時飛,敏捷持續(xù)集成 : CruiseControl版 : 高效硏發(fā)之道[M].北京:電子工業(yè)出版社,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‘a(chǎn)n 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-),男,西安人,西安電子科技大學,通信工程學院,副教授,研究方向:數(shù)字通信,圖像處理,嵌入式應用技術;西安 710071
收稿日期:(2015.11.02)