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
就必须是两个参数。否则会报错