Terry1234's blog

我們終會抵達各自的終點

0%

Maglev Inlining and CVE-2025-8011

前陣子看到跟 Maglev Function Inline 有關的漏洞 CVE-2025-8011,所以順便追一下 Maglev 是怎麼處理 Function Inline 的

Maglev Function Inline

MaglevGraphBuilder::TryBuildInlineCall()

[1] -> 要有 feedback vector
[2] -> 看可不可以 Inline
[3] -> 根據 SharedFunctionInfo / CallArgument 決定要不要用 Eager Inline
[4] -> 看起來跟 user 自訂的選項有關
[5] -> 如果 Maglev 判斷這個 Function 不值得馬上 Inline,會把它放進 inlineable_call_ 裡面
後續會由 MaglevInliner 判斷要不要做 Inline
可能是這些較小、值得被展開的 Function 有助於建立 Maglev IR Graph 時的優化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
MaybeReduceResult MaglevGraphBuilder::TryBuildInlineCall(
ValueNode* context, ValueNode* function, ValueNode* new_target,
#ifdef V8_ENABLE_LEAPTIERING
JSDispatchHandle dispatch_handle,
#endif
compiler::SharedFunctionInfoRef shared,
compiler::FeedbackCellRef feedback_cell, CallArguments& args,
const compiler::FeedbackSource& feedback_source) {
DCHECK_EQ(args.mode(), CallArguments::kDefault);
if (!feedback_cell.feedback_vector(broker())) { // [1]
// TODO(verwaest): Soft deopt instead?
TRACE_CANNOT_INLINE("it has not been compiled/run with feedback yet");
return {};
}

float feedback_frequency = 0.0f;
if (feedback_source.IsValid()) {
compiler::ProcessedFeedback const& feedback =
broker()->GetFeedbackForCall(feedback_source);
feedback_frequency =
feedback.IsInsufficient() ? 0.0f : feedback.AsCall().frequency();
}
float call_frequency = feedback_frequency * GetCurrentCallFrequency();

if (!CanInlineCall(shared, call_frequency)) return {}; // [2]
if (ShouldEagerInlineCall(shared, args)) {// [3]
return BuildEagerInlineCall(context, function, new_target, shared,
feedback_cell, args, call_frequency);
}

// Should we inline call?
if (inlining_depth() > max_inline_depth()) {
TRACE_CANNOT_INLINE("inlining depth (" << inlining_depth()
<< ") >= max-depth ("
<< max_inline_depth() << ")");
return {};
}

compiler::BytecodeArrayRef bytecode = shared.GetBytecodeArray(broker());
if (!is_non_eager_inlining_enabled()) { // [4]
graph()->add_inlined_bytecode_size(bytecode.length());
return BuildEagerInlineCall(context, function, new_target, shared,
feedback_cell, args, call_frequency);
}

TRACE_INLINING(" considering " << shared << " for inlining");
auto arguments = GetArgumentsAsArrayOfValueNodes(shared, args);
auto generic_call = BuildCallKnownJSFunction(context, function, new_target,
#ifdef V8_ENABLE_LEAPTIERING
dispatch_handle,
#endif
shared, arguments);

// Note: We point to the generic call exception handler instead of
// jump_targets_ because the former contains a BasicBlockRef that is
// guaranteed to be updated correctly upon exception block creation.
// BuildLoopForPeeling might reset the BasicBlockRef in jump_targets_. If this
// happens, inlined calls within the peeled loop would incorrectly point to
// the loop's exception handler instead of the original call's.
CatchBlockDetails catch_details = GetTryCatchBlockForNonEagerInlining(
generic_call->exception_handler_info());
catch_details.deopt_frame_distance++;
float score = call_frequency / bytecode.length();
MaglevCallSiteInfo* call_site = zone()->New<MaglevCallSiteInfo>(
MaglevCallerDetails{
arguments, &generic_call->lazy_deopt_info()->top_frame(),
known_node_aspects().Clone(zone()), loop_effects_,
unobserved_context_slot_stores_, catch_details, IsInsideLoop(),
/* is_eager_inline */ false, call_frequency},
generic_call, feedback_cell, score);
graph()->inlineable_calls().push(call_site); // [5]
return generic_call;
}

ShouldEagerInlineCall()

  1. 看 bytecode 長度夠不夠短 (len < 27)
  2. 如果有開 –turbolev 的話看 len < 75 和一些 flag,接著檢查參數的 type,如果有的話就 return true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
bool MaglevGraphBuilder::ShouldEagerInlineCall(
compiler::SharedFunctionInfoRef shared, CallArguments& args) {
compiler::BytecodeArrayRef bytecode = shared.GetBytecodeArray(broker());
if (bytecode.length() < max_inlined_bytecode_size_small()) {// 27
TRACE_INLINING(" greedy inlining "
<< shared << ": small function, skipping max-depth");
return true;
}
// TODO(victorgomes): Evaluate why this is not worth for Maglev, it regresses
// crypto benchmarks.
if (is_turbolev() && inlining_depth() <= max_inline_depth() &&
bytecode.length() <
max_inlined_bytecode_size_small_with_heapnum_in_out() &&
args.mode() == CallArguments::kDefault) {// 75
bool has_float_arg = false;
for (size_t i = 1; i < args.count_with_receiver(); i++) {
if (args[i] &&
(args[i]->value_representation() == ValueRepresentation::kFloat64 ||
args[i]->value_representation() ==
ValueRepresentation::kHoleyFloat64)) {
has_float_arg = true;
break;
}
}
if (has_float_arg) {
TRACE_INLINING(" greedy inlining "
<< shared << ": small function with heap number inputs");
return true;
}
}
return false;
}

CVE-2025-8011 Infomation

(CVE-2025-8011)[430572435][maglev]Type Confusion
https://chromium-review.googlesource.com/c/v8/v8/+/6732846
https://chromereleases.googleblog.com/2025/07/stable-channel-update-for-desktop_22.html

Reported by Shaheen Fazim(@shaheenfazim)

Issue 目前不公開,但有 Patch 可以看

Patch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
From f22ca7b61a92d3cd2b856485a55a1519cb11b627 Mon Sep 17 00:00:00 2001
From: Toon Verwaest <verwaest@chromium.org>
Date: Mon, 14 Jul 2025 17:01:40 +0200
Subject: [PATCH] [maglev] Cap inlining at MaxInliningId

Bug: 430572435
Change-Id: I4f20bad6c99e9d3d5a959cb801485dfb117e9884
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6732846
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Auto-Submit: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Olivier Flückiger <olivf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#101423}
---

diff --git a/src/codegen/source-position.h b/src/codegen/source-position.h
index 85dcd96..3b0ff0e 100644
--- a/src/codegen/source-position.h
+++ b/src/codegen/source-position.h
@@ -116,6 +116,8 @@
value_ = InliningIdField::update(value_, inlining_id + 1);
}

+ static constexpr int MaxInliningId() { return InliningIdField::kMax; }
+
static const int kNotInlined = -1;
static_assert(kNoSourcePosition == -1);

diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
index 861d64b..3d5a3a3 100644
--- a/src/maglev/maglev-graph-builder.cc
+++ b/src/maglev/maglev-graph-builder.cc
@@ -8002,6 +8002,13 @@

bool MaglevGraphBuilder::CanInlineCall(compiler::SharedFunctionInfoRef shared,
float call_frequency) {
+ if (static_cast<int>(graph()->inlined_functions().size()) >=
+ SourcePosition::MaxInliningId()) {
+ compilation_unit_->info()->set_could_not_inline_all_candidates();
+ TRACE_CANNOT_INLINE("maximum inlining ids");
+ return false;
+ }
+
if (graph()->total_inlined_bytecode_size() >
max_inlined_bytecode_size_cumulative()) {
compilation_unit_->info()->set_could_not_inline_all_candidates();

看到這裡我想到 CVE-2024-2887,它是一個 WasmType ID 超出最大值導致使用了 general Type 來表示 Wasm Struct 的 Type Confusion 漏洞
但 Maglev Inline ID 沒找到類似的情境
所以猜測可能是 integer overflow 導致這裡拿到了錯的 SharedFunctionInfo
等 Issue 或 PoC 公開後會拿 gdb 追一遍,順便研究怎麼打

1
2
3
4
5
6
7
8
9
10
11
12
std::vector<SourcePositionInfo> SourcePosition::InliningStack(
Isolate* isolate, OptimizedCompilationInfo* cinfo) const {
SourcePosition pos = *this;
std::vector<SourcePositionInfo> stack;
while (pos.isInlined()) {
const auto& inl = cinfo->inlined_functions()[pos.InliningId()];
stack.push_back(SourcePositionInfo(isolate, pos, inl.shared_info));
pos = inl.position.position;
}
stack.push_back(SourcePositionInfo(isolate, pos, cinfo->shared_info()));
return stack;
}