1、前言
由于个人需求,想要使用CodeQL对JDK进行代码查询。
按照笔者平时的习惯,为了避免在目标代码库编译和生成CodeQL数据库上浪费时间,笔者多数情况下都会利用 lgtm 来搞定:
-
方式一:在lgtm上搜索现成的CodeQL数据库。
方式一用于直接获取代码库最新commit对应的CodeQL数据库。 -
方式二:如果想要生成代码库指定版本所对应的CodeQL数据库,则先在github上clone一份代码库,然后切换
git checkout <tag>
切换到指定版本,然后git push到自己的github远程仓库中。接着通过配置 让lgtm集成到你github代码库中,这样lgtm就会对你的代码库启用CodeQL扫描,lgtm扫描后便可在上面下载CodeQL数据库(当然咯,也可以直接在lgtm上面直接进行CodeQL查询,看个人习惯和需要)。如下图:
但是笔者在lgtm上并没有找到 https://github.com/openjdk/jdk8u 可用的CodeQL数据库,具体原因不清楚,可能是lgtm无法通过常规的Java工程编译方式去编译openjdk?暂不细究了。完成目标比较重要。
所以就只能把OpenJDK 8的代码clone下来,自个编译并生成CodeQL数据库。
2、编译OpenJDK 8
其实只要确保代码库编译是没问题的,CodeQL数据库的生成也就没问题了,一条命令的事。
笔者成功编译了OpenJDK 8u101
和8u322
两个版本。
2.1 编译过程
1、使用docker镜像 ubuntu:16.04
搭建环境。
2、通过apt
安装一些常用的命令行程序,以及编译时需要的依赖:
apt install -y build-essential gdb cmake openjdk-8-jdk cpio file unzip zip wget
&&
apt install -y --no-install-recommends libfontconfig1-dev libfreetype6-dev libcups2-dev libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev libasound2-dev libffi-dev autoconf
注:--no-install-recommends
选项:使apt
不要把推荐的软件作为安装的依赖。
3、上面的依赖安装完后,make
程序的版本是4.1
,由于该版本在编译OpenJDK 8u101
版本时会报各种错误,所以为了简单起见,就干脆都用较低的3.81
版本的make
。因此从make
官方下载3.81
版本进行编译安装:
wget http://ftp.gnu.org/gnu/make/make-3.81.tar.gz
&& tar -zxvf make-3.81.tar.gz
&& cd /make-3.81
&& bash configure -prefix=/usr
&& make
&& make install
安装完后如图:
4、进入OpenJDK源码目录,运行configure
进行编译配置和编译环境检查:
# bash configure --with-debug-level=fastdebug \
--with-jvm-variants=server \
--with-boot-jdk=/usr/lib/jvm/java-1.8.0-openjdk-amd64 \
--with-target-bits=64 \
--enable-debug-symbols \
--with-native-debug-symbols=internal
编译选项可参考官方文档(参考[1]
)。
简单说一下用到的几个:
--with-jvm-variants
:编译特定模式的Hotspot JVM虚拟机,这里选择server
模式;--with-boot-jdk
:这里指定一个已经编译好的JDK路径,这个JDK叫作Bootstrap JDK
,且版本至少为N-1
。这里我们要编译的是8
,所以至少要安装7
版本的JDK,不过用8
也是可以的,所以上面通过apt安装了openjdk-8-jdk
;--with-target-bits
:选择编译成32位还是64位;--with-native-debug-symbols
:符号信息的编译方式,我们选择internal
;--enable-debug-symbols
:启用调试符号信息。
检查通过后,如图:
5、执行make
命令开始编译OpenJDK 8。
make images JOBS=4
编译完成后如下图:
3、生成CodeQL数据库
既然OpenJDK编译没问题了,那么生成CodeQL肯定就没问题了。
下载codeql命令行工具(下载地址:https://github.com/github/codeql-cli-binaries/releases)后,在OpenJDK的源码目录下执行如下命令生成CodeQL数据库:
codeql database create openjdk8u322-db --language=java --command='make images JOBS=4'
注:其实codeql
生成数据库是在代码库编译的过程中进行的。上面我只是为了确保编译没问题,才先执行的编译。
4、QL查询 - 简单测试
笔者生成了OpenJDK 8u101
和8u322
两个版本的CodeQL数据库。
在VS Code上编写查询简单玩一下:
import java
class RegistryContext_decodeObject extends Method {
RegistryContext_decodeObject() {
this.getDeclaringType().hasQualifiedName("com.sun.jndi.rmi.registry", "RegistryContext") and
this.getName() = "decodeObject"
}
}
from RegistryContext_decodeObject m1
select m1
右键执行CodeQL: Run Query On Multiple Databases
,执行完成后,在左侧Query HISTORY
窗口便能选择查看在不同数据库的查询结果:
可以从com.sun.jndi.rmi.registry.RegistryContext#decodeObject()
方法看8u101
和8u322
版本代码的其中一个区别,没错,就是JDK高版本对JNDI注入的限制。
5、小结
版本稍低的JDK(比如这里的8u101
),编译的时候,笔者一开始用的ubuntu:18.04
,结果编译的时候各种报错,后来换成3.81
版本的make
还是不行。为了避免再继续浪费时间,索性用了更低版本的ubuntu,结果顺利进行了编译…
不禁想起不记得在哪里看到的一句话:
Never to wrestle with a pig. You get dirty, and the pig like it.
2022-01-23 更新:
编译好的数据库分享到网盘了:
链接: hxxps://pan.baidu.com/s/1fllcshUXhgHOjq1-edywlg
提取码: s4v8
参考
[1] http://hg.openjdk.java.net/jdk8/jdk8/raw-file/tip/README-builds.html
[2] https://github.com/openjdk/jdk8u
[3] https://github.com/fnmsd/OpenJDK8-BuildEnv-Docker