近日看到B站up"硬核空间JAVA"在线修fastjson 的Bug,感到收益匪浅,所以自己按照他的思路重新也修一遍bug

(已提供可复现的源码,求fix)fastjson无法反序列化超出某种限制的类 · Issue #2779 · alibaba/fastjson​github.com
bc931e84e5148e8b935ecdafe65f4fd3.png

大家可以围观一下这个issuses,然后我们来复盘一下整个过程。

因为bug已经修复,我们可以下载完代码切到bug修复之前

d7544ca55c1136336afef21472be10c2.png

然后我们按照描述去复现这个bug,但是代码中用了lombok 插件,不想下载该插件的话我们可以用set()、get() 方法代替 ,然后运行代码,果然出现了所描述的错误(下图)

9dc7add2e919dc065cfea166c4c54753.png

看到这个错误,我们首先按照控制台的错误提示找到ASMDeserializerFactory这个类的83行,断点打在这一行。然后debug,运行如下:

9d54326dd50de368e3c9fb52790e9d9d.png

现在我们可以看下这个类的字节码,这里用到了我们不经常使用Evaluate,在上图中选中code右击,然后点击Evaluate Expression

0fe049ac0c301c4b7cb22248dd32998e.png

然后,我们需要将code 写成class 文件,为了操作方便我们选择google的Files去写

c752626f688b4246608e79f4acac4c9d.png

然后去执行,操作完毕后,我们去找到bad.class。idea中关于读字节码的插件有很多,像ASM等,这里我们要介绍另外一种好用的工具classpy,该作者写过《自己动手写Java虚拟机》。我们按照classpy的操作,打开bad.class文件(如下)

61261ce81175dd6999e1483379c38197.png

到了这一步,我们仍然没有任何头绪。

此时我们回到开始报错的时候,发现“Illegal target of jump or branch”这个错误仍然不是很明显,所以我们去下载jdk 源码,看下jdk里是怎么写的。这里我们直接去官方下载即可,我下载的是openJDK9,至于为什么是jdk9?jdk8 可以吗?我们卖个关子。全局搜索后,我们果然找到了两处

7aa93f810a069f032610861fd8821f71.png

acaf9043f3516537940e0f7cb19d95a1.png

现在我们需要改些东西

9d978c822162ddeb58c76c8fdfb426d8.png

这样我们可以清楚的定位到什么位置出的错误。

改完代码后,我们需要编译,因为windows上的编译有些麻烦,我又买不起mac,所以只能在centos系统上进行编译。把openjdk 整个文件上传到centos上,然后我们运行这一行命令

yum install libfreetype6-dev libcups2-dev libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev libasound2-dev libffi-dev autoconf gcc clang libfontconfig1-dev

先把环境准备好,文件上传完毕后,进入openjdk 文件夹

69bb04cf59592fc042eaddd5b611e6d7.png

我们可以看到这些文件,然后可以运行 sh configure 命令 查看还需要什么软件,直到看到

e3fd2c7fc054db37ae4eb9292b45f3fd.png

就可以进行编译啦!因为编译jdk需要上个版本的jdk,原来装了jdk8 ,所以这次选择的是jdk9编译命令 make images,这个时候可以休息一会等待编译完成。然而到了一半出了错 : collect2: error: ld terminated with signal 9 [Killed]

原来是swap文件太小了,增大swap文件之后,继续编译。这次很顺利的成功了。

接下来,我们开始用jdk9运行AbcDTO.java 文件,centos上的命令和windows上不同,下面展示的centos的命令:

编译命令

 /root/openjdk/build/linux-x86_64-normal-server-release/jdk/bin/javac -cp fastjson-1.2.47.jar  AbcDTO.java

运行命令

 /root/openjdk/build/linux-x86_64-normal-server-release/jdk/bin/java -cp fastjson-1.2.47.jar: AbcDTO

运行完后,我们可以看到

2b80fe0a249049ff09eb327b346840b9.png

原来的错误提示变成了这样 “ Illegal target of jump or branch 50 -32405”,此时我们再打开classpy,根据报错信息找到deserialze 这个方法,寻找第50行

a3c601f18b7808e328fd3e35a5cc61fa.png

这里我们可以看出来是越界了,然后找到这一块代码,ifeq上面的方法是isEnabled,下面的是aload

46556b6066c126cebc1014e4c86be445.png

找到这个后,查看visitJumpInsn这个方法

a1565fd8aeb50c9d43fde2db2db80344.png

我们可以查出这个方法是ASM(这是一个 Java 字节码操控框架)的方法,我们去下载源码看下

public 

我们看以看出经过几年的发展,asm现在的源码已经增加了很多,只需按照这个思路改下fastjson 源码即可,我试着把fastjson 都换成最新的asm代码,但涉及的有些多,水平不够,还需努力学习。整个过程抽丝剥茧,让我耳目一新,所以记下来。另外ASM是一个优秀的框架,很值得学习。最后fastjson 正在投票,喜欢fastjson的可以投票https://www.oschina.net/project/top_cn_2019。

一些知识点介绍的仍不是很仔细,我具体参考的资料如下,大家可以看下

B站视频,全文就是按照这个复现的 :https://www.bilibili.com/video/av77302131?from=search&seid=8954886140096434686

字节码: https://en.wikipedia.org/wiki/Java_bytecode
linux增大swap空间:https://www.cnblogs.com/cc11001100/p/7803583.html

java 一些数据类型的范围。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐