CodeQL
CodeQL
是一個代碼檢查工具,會根據開發者編寫的代碼生成數據庫,之后開發者通過編寫ql腳本
查找代碼中的問題。原本似乎是semmle(?)
的產品,后來被github
收購了,所以現在實際上應該算是github
官方的東西(但是github
現在又是微軟的了...)。
以C++為例,雖然gcc編譯器本身就會對代碼做語法檢查,保證代碼沒有錯誤,但是在每個項目中可能會有一些約定俗成的規則,比如在某個函數中不能調用某個函數這樣的規則,此時就可以通過ql腳本制定一個自定義規則,codeql會篩查出來符合規則的代碼。並且可以輸出為csv文件。
CodeQL支持vscode編輯器,網上幾乎所有的使用教程都是使用VSCode編輯器運行CodeQL的,但是我的使用環境是服務器,使用vim開發,並不能使用VSCode,所以研究了一下怎么直接在命令行中使用CodeQL對代碼進行檢查。
相關參考:
- CodeQL documentation (github.com) (官方文檔,最權威的文檔,但是更新似乎比較緩慢)
- 代碼分析平台 CodeQL 學習手記(十三) - GeekMeta 極客元素 - 區塊鏈技術及應用分享社區 ql腳本的學習文章,出處是哪里不太清楚
- https://lgtm.com/query 這里可以直接運行ql腳本,可以對你自己github項目進行檢查。為了方便學習它也提供了一些生成好的數據庫
- 代碼分析引擎 CodeQL 初體驗 (seebug.org)
建議先通過vscode配置好一個codeql方便學習語法,然后再命令行中使用。
概述
codeql分成兩部分,一部分是CodeQL CLI,另一部分就是它自帶的qll庫了 可以理解為,前者是解釋器控制台(編譯器),后者是庫文件,相當於C語言中stdio.h的存在,提供一些常用的類和方法
Getting started with the CodeQL CLI — CodeQL (github.com)
大體使用過程分為兩步,首先生成數據庫,之后編寫ql腳本對數據庫進行查詢。
在生成數據庫這一步分為需要區別解釋型語言和編譯型語言,解釋型語言可以解析直接生成數據庫,而編譯型語言codeql需要監控編譯過程。
安裝
直接使用在線查詢(lgtm)
不過這個網站訪問比較玄學,科學或者魔法你總得會一個。國內直連訪問不太穩定,經常打不開,所以建議學習的時候使用vscode
vscode使用codeql
這也是網絡上最常用的使用方式,不過根據網上的操作方式給我弄得很懵逼,如果會英文的話,直接看官方文檔比較好。
Setting up CodeQL in Visual Studio Code — CodeQL (github.com)
下載
在vscode里面安裝插件
然后點擊這個測試,新版會問你要不要安裝CLI,點擊YES之后就會自動開始下載 (我第一次使用的時候是沒有提示下載的,如果沒有提示需要自己下載,參考網上別的教程,唯一需要注意的就是需要把庫文件給放到CLI
目錄(codeql
命令所在目錄)里,改名。否則運行腳本的時候會提示找不到庫文件)
到此CLI就安裝好了 它自己安裝的路徑C:\Users\用戶名\AppData\Roaming\Code\User\globalStorage\github.vscode-codeql\distribution1\codeql
庫文件
(通過vscode自動安裝就不需要手動下載庫文件了)
然后下載庫文件,github/codeql: CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security (code scanning), LGTM.com, and LGTM Enterprise
或者把這個倉庫克隆下來也行 (我給放到了 D:/codeql/codeql_repo
)
測試
下載現成的數據庫,用來測試環境是不是正常的,數據庫位置無所謂,解壓出來
vscode打開文件夾 D:/codeql/codeql_repo
然后選擇 From a folder
選擇到剛才解壓的數據庫
然后在vscode的資源管理器里面打開路徑 cpp/ql/src/
這里面都是一些例子代碼,比如下面我運行了 Likely Bugs/ReturnConstType.ql
只需要在ql文件里面右鍵選擇 CodeQL: Run Query
linux控制台運行
這里使用的版本是 2.6.3版本,經過測試centos6.8及以下是不能直接運行的 (但是你可以安裝docker
然后在centos7.9
的容器中運行)
下載
通過Releases · github/codeql-cli-binaries下載,linux
下載codeql-linux64.zip
解壓到~/codeql/codeql
放到 ~/codeql/codeqlrepo
這里需要注意的是,庫文件必須在cli
的同級目錄或者子目錄 否則會找不到包
安裝
可以建立一個軟鏈到/usr/bin/
然后執行 codeql --version
沒有問題就好了
創建數據庫
相關的官方說明:Creating CodeQL databases — CodeQL (github.com)
對於C++
來說,命令如下
codeql database create testdb/ --language=cpp --command="g++ c.cpp"
--command
參數指定了正常編譯的時候需要執行的命令,可以是make -j20
這樣的命令
--language
參數指定了需要生成數據庫的語言,具體可以是什么參看上面相關官方說明的連接里面
如果修改了代碼想要重復生成數據庫,可以添加--overwrite
參數覆蓋數據庫
所以,生成C++
數據的命令可以是codeql database create testdb/ --overwrite --language=cpp --command="make -j20"
[st@local ~]$ codeql database create testdb/ --language=cpp --command="g++ c.cpp"
Initializing database at /home/st/testdb.
Running build command: [g++, c.cpp]
Finalizing database at /home/st/testdb.
Successfully created database at /home/st/testdb.
命令執行完成之后可以看到當前目錄下面有一個testdb
文件夾,這個就是codeql
的數據庫
編寫QL查詢數據庫
相關官方說明:database analyze — CLI manual (github.com)
建議在~/codeql/codeqlrepo/cpp/ql/src/
創建一個文件夾比如work
,在這個文件夾中編寫自己的ql代碼
一個簡單的例子
/**
* @name AllFunction
* @kind problem
* @id cpp-test
*/
import cpp
from Function f
select f, "name: " + f.getName()
這個ql腳本會把所有的函數列舉出來,
運行這個腳本使用命令如下
codeql database analyze testdb --rerun --format=csv --output=c.csv ./codeql_repo/cpp/ql/src/work/allfun.ql
--rerun
表示重復查詢,默認情況下codeql
會直接使用數據庫中緩存的結果,會導致修改ql腳本之后再運行的結果不正確,所以強烈建議加上這個參數
--format=csv
表示指定輸出結果文件的格式,一般控制台的話輸出csv
格式就好了,還有其他格式參考上面給出的相關官方說明
--output=c.csv
把結果輸出到c.csv
文件里面
完整參數解釋database analyze — CLI manual (github.com)
運行結果
簡單解釋
首先貼出來對於ql文件的官方說明: About CodeQL queries — CodeQL (github.com)
注釋風格是C/C++的風格,上面代碼中注釋的部分被稱之為query metadata
,相關說明: Metadata for CodeQL queries — CodeQL (github.com)
不過需要注意的是,文檔比較老舊,所以只能作為參考,比如文檔說@kind
是可選項,但是經過測試,腳本在控制台下執行的時候,是必須的,否則運行不起來(vscode
里面跑的時候確實是可選的)。此外,雖然說文檔里說@kind
類型只有problem
和path-problem
兩個,但是我看例子代碼里面還有table
,所以說,最好是文檔配合位於codeql庫文件/cpp/ql/src/
里面的例子代碼一起看比較好。
import cpp
表示導入C++
相關的庫文件
from Function f
按照C++
的思想來說就是聲明一個變量,如果類比sql
語句,就相當於選定了一張表,可以理解為f
是一個集合,里面是數據庫中所有的函數。
select
輸出結果,如果上面是@kind problem
,那么select
就必須是兩個參數。否則會報錯