漏洞实现过程
如果要继续,则需要构建V8版本8.5.51(提交64cadfcf4a56c0b3b9d3b5cc00905483850d6559),建议使用完整符号进行构建(修改args.gn并添加symbol_level = 2行)。
在x64.release目录中,你可以使用以下命令以零编译器优化来编译发行版本:
- find . -type f -exec grep '-O3' -l {} ";" -exec sed -i 's/-O3/-O0/' {} ";" -ls
如果你想继续阅读本博文中的一些代码示例,我仍然建议你构建普通发行版(启用编译器优化)。如果不进行优化,某些示例将花费非常长的时间才能运行。
从上面链接的bugtracker中获取概念证明。
2017年之前的V8
在2017年之前,许多JavaScript内置函数(Array.prototype.concat,Array.prototype.map等)都是用JavaScript本身编写的,尽管这些函数使用了TurboFan(V8的推测性优化编译器,稍后将进行详细说明)。为了最大限度地发挥性能,它们的运行速度根本没有使用本机代码编写的速度快。
对于最常见的内置函数,开发人员将以手写汇编形式编写非常优化的版本。之所以可行,因为ECMAScript规范(点击查看示例)中对这些内置函数的描述非常详细。但是,它有一个很大的缺点:V8针对大量平台和体系结构,这意味着V8开发人员必须为每个体系结构编写和重写所有这些优化的内置函数。随着ECMAScript标准的不断发展和新语言函数的不断标准化,维护所有这些手写程序集变得非常繁琐且容易出错。
遇到此问题后,开发人员开始寻找更好的解决方案。直到TurboFan引入V8才找到解决方案。
CODESTUBASSEMBLER
TurboFan为低层指令带来了跨平台的中间表示(IR),V8团队决定在TurboFan之上构建一个新的前端,他们将其称为CodeStubAssembler。 CodeStubAssembler定义了一种可移植的汇编语言,开发人员可以使用该语言来实现优化的内置函数。最重要的是,可移植汇编语言的跨平台性质意味着开发人员只需编写一次内置函数即可。所有支持的平台和体系结构的实际本机代码都由TurboFan进行编译,你可以在此处阅读有关CSA的更多信息。
尽管这是一个很大的改进,但仍然存在一些问题。使用CodeStubAssembler的语言编写最佳代码需要开发人员积累很多专业知识。即使掌握了所有这些知识,仍然存在很多容易导致安全漏洞的非常规漏洞,这导致V8团队最终编写了一个称为Torque的新组件。
Torque
Torque是基于CodeStubAssembler构建的语言前端,它具有类似TypeScript的语法,强大的类型系统和强大的漏洞检查函数,所有这些使得它成为V8开发人员编写内置函数的理想选择。Torque编译器使用CodeStubAssembler将Torque代码转换为有效的汇编代码,它极大地减少了安全漏洞的数量,你可以在此处阅读更多有关Torque的信息。
漏洞发生的原因
由于Torque仍相对较新,因此仍然需要重新实现大量的CSA代码。其中包括用于处理创建新的FixedArray和FixedDoubleArray对象的CSA代码,它们是V8中的“快”数组(“快”数组具有连续的数组后备存储,而“慢”数组具有基于字典的后备存储)。