聚焦源代码安全,网罗国内外最新资讯!
本文共分五部分:
一、时间线
二、背景
三、漏洞及补丁分析
1、漏洞复现
四、漏洞利用分析
1、漏洞利用
2、内存读写
3、代码执行
五、参考资料
一、时间线
2021年4月4日 - tr0y4 在 Chromium issue tracker 中提交该漏洞;
2021年4月12日 - Chromium 修复该漏洞,除了补丁外还公开了相关的poc;
2021年4月14日 - 国内的研究员 frust93717815 公开了此漏洞的exp[1][2],影响未开沙箱的稳定版 Chrome 浏览器;
2021年4月20日 - Chrome发布更新及致谢,对应的CVE编号为 CVE-2021-21224。
二、背景
该漏洞发生在v8的优化编译器 TurboFan 中,具体发生在 JIT 的 Simplified-Lowering 阶段。关于TurboFan的介绍可以参考 ”Introduction to TurboFan”[3]。有关 Simplefied-Lowering 阶段的具体细节可以参考 CVE-2020-16040 的分析[4]。此外,本文使用Turbolizer 展示 TurboFan 不同优化阶段的 sea of nodes graph。
下面简单介绍一下sea of nodes,它是TurboFan运行时的程序表示形式。TurboFan在优化代码时,整个代码是以graph的形式存储的,每个节点就是一个node,包括数学运算、加载、存储、调用、常数等形式。每个node的具体信息如下:
class NodeInfo final {
public:
…
private:
enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
State state_ = kUnvisited;
MachineRepresentation representation_ =
MachineRepresentation::kNone; // Output representation.
Truncation truncation_ = Truncation::None(); // Information about uses.
Type restriction_type_ = Type::Any();
Type feedback_type_;
bool weakened_ = false;
};
每个 node 都有一个 restriction type 和一个 feedback type ,前者可以理解为节点初始化后的类型,后者则是在实际优化过程中反馈的真实类型。Node 的 representation 则表示节点的表示类型,具体如下:
enum class MachineRepresentation : uint8_t {
kNone,
kBit,
// Integral representations must be consecutive, in order of increasing order.
kWord8,
kWord16,
kWord32,
kWord64,
// (uncompressed) MapWord
// kMapWord is the representation of a map word, i.e. a map in the header
// of a HeapObject.
// If V8_MAP_PACKING is disabled, a map word is just the map itself. Hence
// kMapWord is equivalent to kTaggedPointer -- in fact it will be
// translated to kTaggedPointer during memory lowering.
// If V8_MAP_PACKING is enabled, a map word is a Smi-like encoding of a map
// and some meta data. Memory lowering of kMapWord loads/stores
// produces low-level kTagged loads/stores plus the necessary
// decode/encode operations.
// In either case, the kMapWord representation is not used after memory
// lowering.
kMapWord,
kTaggedSigned, // (uncompressed) Smi
kTaggedPointer, // (uncompressed) HeapObject
kTagged, // (uncompressed) Object (Smi or HeapObject)
kCompressedPointer, // (compressed) HeapObject
kCompressed, // (compressed) Object (Smi or HeapObject)
// FP and SIMD representations must be last, and in order of increasing size.
kFloat32,
kFloat64,
kSimd128,
kFirstFPRepresentation = kFloat32,
kLastRepresentation = kSimd128
};
三、漏洞及补丁分析
根据commit信息得知,漏洞发生在 RepresentationChanger:: GetWord32RepresentationFor 函数内。该函数的调用栈如图 1,对该函数的调用主要发生在 Simplified-Lowering 阶段: