電子情報学特論:
Chromium のアーキテクチャを解き明かす
〜 EEIC の授業が生きるプロダクトの世界〜
Kentaro Hara
2024 May
(๑>ᴗ<๑)
*
*
*
*
自己紹介
理科 I 類
EEIC
田浦研
プログラミングをはじめる
卒論と修論
Chrome
チーム
教養〜EEIC 時代
田浦研時代
Google へ
趣味:日本料理を極めること
道場六三郎さんの YouTube チャンネルで料理してきた
第8回ジビエ料理コンテストのお店部門で「全国日本調理技能士会連合会会長賞」受賞
本題:Chromiumの話
*
*
*
*
Chromium と Chrome
Chromium
Google Chrome
Chromium と Chrome
「4 つの S」
S....
S....
S....
S....
「4 つの S」
Speed
Simplicity
Security
Stability
今日のお話の中心
今日のお話
プロセスモデル
*
*
*
*
プロセス vs. スレッド
クイズ:違いは何だっけ? (๑˃̵ᴗ˂̵)و
プロセス vs. スレッド
プロセス vs. スレッド
マルチプロセスアーキテクチャ
マルチプロセスアーキテクチャ
Browser process
Browser process
Browser process
Renderer process
(sandbox)
IPC
しかし話は終わらない (╹◡╹✿)
インターネット黎明期に Web を成功へ導いたもの
Embeddability
<html><body>
こんにちは!ようこそ私のホームページへ!
あなたは 1206 番目の訪問者です(◍•ᴗ•◍)
<iframe src="https://maps.google.com/..."></iframe>
<iframe src="https://facebook.com/..."></iframe>
<iframe src="https://g.doubleclick.net/..."></iframe>
</body></html>
Embeddability
Spectre とは
Spectreの原理
// こういうArray構造体があるとする
struct Array {
char at(int i) {
if (i < length)
return buffer[i];
else
return -1;
}
int length;
char* buffer;
};
// 以下のコードで攻撃する
int data[2000];
// 狙ったアドレスを指定
char v = array->at(12345678);
if (v == -1) { return; }
else if (v & 1) { data[0]; }
else { data[1000]; }
投機的実行がなければ の部分が実行される
Spectreの原理
// こういうArray構造体があるとする
struct Array {
char at(int i) {
if (i < length)
return buffer[i];
else
return -1;
}
int length;
char* buffer;
};
// 以下のコードで攻撃する
int data[2000];
// 狙ったアドレスを指定
char v = array->at(12345678);
if (v == -1) { return; }
else if (v & 1) { data[0]; }
else { data[1000]; }
投機的実行があると、(あとで外れることが判明する)分岐予測によって return buffer[i]; が実行されて、buffer[12345678]の値によって、 data[0] とdata[1000] のどっちかがキャッシュに読み込まれる
Spectreの原理
// こういうArray構造体があるとする
struct Array {
char at(int i) {
if (i < length)
return buffer[i];
else
return -1;
}
int length;
char* buffer;
};
// 以下のコードで攻撃する
int data[2000];
// 狙ったアドレスを指定
char v = array->at(12345678);
if (v == -1) { return; }
else if (v & 1) { data[0]; }
else { data[1000]; }
分岐が外れたとわかった時点で投機的実行の結果は捨てられて の部分がやり直されるのだが・・・ data[0] と data[1000] のどっちかがキャッシュに残ってしまう
ということは data[0] と data[1000] のアクセス速度を調べれば、buffer[12345678]の中身を確定できるじゃん!! => Web広告からcitibank.comのパスワードが読めるかも
解決策:Site Isolation
main frame (site A)
iframe (site B)
iframe (site C)
iframe (site C)
process 1
process 2
process 3
Chrome のタブ
ところで、
Chromeってメモリ使いすぎじゃない??
メモリ使いすぎ問題
意外なことが判明する・・・
参考:Jevons paradox
より多くのことをできるようになっている
メモリモデル
*
*
*
*
クイズ
ちなみに Linux カーネルが2800万行
クイズ
クイズ
検証してみた
結論:どっちもおいしかった
C++という選択
Security 上の懸念をどう補っていくか?
Use-after-free
Object* obj =
malloc(sizeof(Object));
free(obj);
obj->Foo(); // Use-after-free
// もう少し現実的な例
class A {
A(B* b) : b_(b) { }
void Foo() {
b_->Bar(); // この時点でb_が生きていることはどう保証されるのか...?
}
B* b_; //生ポインタは常に危険を伴う
};
Use-after-free の何が問題なのか
class A {
A(B* b) : b_(b) { }
void Foo() {
b_->Bar();
}
B* b_;
};
注:実際に行うには Heap spraying などの高度な手法が必要
最も美しく正しい解決策:GC
GCの基本:マーク & スイープ
A
B
E
F
C
G
D
H
I
root
root
GCの基本:マーク & スイープ
A
B
E
F
C
G
D
H
I
root
root
✔
✔
✔
✔
✔
GCの基本:マーク & スイープ
A
B
C
D
E
F
H
I
G
ヒープ
✔
✔
✔
✔
✔
GCの基本:マーク & スイープ
A
B
C
D
E
F
H
I
G
ヒープ
✔
✔
✔
✔
✔
走査
しかし話は終わらない (╹◡╹✿)
問題点:GC の停止時間が致命的
時刻t
Mark & sweep
この時点までスクロールに反応できない
問題点:JavaScript と C++ の言語境界
JavaScript のヒープ
C++ のヒープ
GC できたよ!!
これで Use-after-free がゼロになる!!
(◍>◡<◍)
というほど、
この世界は単純ではない
GC が抱える問題点
GC が抱える問題点
class A : public GC {
};
class B : public GC {
~B() {
a_->Clear(); // デストラクタの順序次第で a_ はもう解放されてるかもしれない
}
GCedPointer<A> a_;
};
現実的な落としどころ
Chromiumのオブジェクト全体
GC 化されている
オブジェクト
(主に JavaScript と
接続している C++ 部分)
GC 化されていない
オブジェクト
現実的な落としどころ
Chromiumのオブジェクト全体
GC 化されている
オブジェクト
(主に JavaScript と
接続している C++ 部分)
GC 化されていない
オブジェクト
スマートポインタ(unique_ptr や scoped_refptr)は当然使っているが、
それで生ポインタがなくなるわけではない
(全部に使ったら参照サイクルが起きる)
ここに残った生ポインタをどうするか???
ちょっと深いところに入ります
MiraclePtr(みらくる☆ぽいんた)の話
生ポインタの安全性をどう保証するか?
class A {
A(B* b) : b_(b) { }
void Foo() {
b_->Bar();
}
B* b_; //生ポインタは常に危険を伴う
};
// 別のコード
std::unique_ptr<B> b = new B();
A* a = new A(b.get());
...
b = nullptr; // b を free
a->Foo(); // use-after-free!
生ポインタの安全性をどう保証するか?
MiraclePtr<>のコンストラクタで参照カウント++
MiraclePtr<>のデストラクタで参照カウント--
参照カウントが0になるまで free を遅延させる
class A {
A(B* b) : b_(b) { }
void Foo() {
b_->Bar();
}
MiraclePtr<B> b_;
};
// 別のコード
std::unique_ptr<B> b = new B();
A* a = new A(b.get());
...
b = nullptr;
a->Foo(); // use-after-freeが起きない
生ポインタの安全性をどう保証するか?
use-after-free を検出して治す努力
use-after-free を検出して治す努力
レンダリングモデル
*
*
*
*
レンダリングエンジン
レンダリングエンジン
?
クイズ
これを実現するために
いろんな工夫がいる
全体像
<html>
...
</html>
HTML
pixels
中間データ構造
Stage
Stage
Stage
ステージ1:Parsing
<html>
<body>
<p>aaa</p>
<p>bbb</p>
</body>
</html>
"<" "html" ">"
"<" "body" ">"
"<" "p" ">"
"aaa"
"<" "/p" ">"
"<" "p" ">"
"bbb"
"<" "/p" ">"
"<" "/body" ">"
"<" "/html" ">"
HTMLファイル
字句解析
構文解析
(構文木)
html
body
p
p
text
text
ステージ1:Parsing
<html>
<body>
<p>aaa</p>
<p>bbb</p>
</body>
</html>
HTMLファイル
DOM tree
html
body
p
p
text
text
Parsing
ステージ2:Style
html
body
p
p
text
text
/* every p has red text*/
p { color : red }
hello
font-weight: bold;
margin-left: 2cm;
hello
outline: dashed blue;
hello
transform: rotate(20deg);
hello
ステージ2:Style
html
body
p
p
text
text
html
body
p
p
text
text
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle {
fontWeight = ...
marginLeft = ...
background = ...
}
Style
ステージ3:Layout
div
Layout {
x = 183
y = 250
width = 600
height = 140
}
ステージ3:Layout
Is this a pen? No, it is a dog.
リガチャ
改行
ステージ3:Layout
html
body
p
p
text
text
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle
ComputedStyle
Layout
Layout
Layout
Layout
Layout
Layout
Layout tree
Layout
ステージ4:Layering
iframe A
iframe B
iframe C
別レイヤーで描画可能
アニメーションする部分を
別レイヤーで動かす
ステージ4:Layering
Layout
Layout
Layout
Layout
Layout
Layout
Layout tree
Layout
Layout
Layout
Layout
Layout
Layout
Layering
ステージ5:Raster
Raster
Layout
Layout
Layout
Layout
Layout
Layout
全体像を振りかえる
<html>
<body>
<p>aaa</p>
<p>bbb</p>
</body>
</html>
html
body
p
p
text
text
html
body
p
p
text
text
Layout
Layout
Layout
Layout
Layout
Layout
Layout
Layout
Layout
Layout
Layout
Layout
CS
CS
CS
CS
CS
CS
HTMLファイル
DOM tree
スタイル情報付きDOM tree
Layout tree
bitmap
Layer
Parsing
Style
Layout
Raster
Layering
なぜ「ステージ」から「ステージ」へ
中間データ構造を渡していくのか?
ステージングする理由1
Texのレンダリング | Webのレンダリング |
静的 | 動的 |
レンダリングが完了して DVI ファイルができたらおわり | JavaScript が DOM を変更する JavaScript が CSS を変更する ユーザが画面をスクロールする アニメーション |
ステージングする理由1
Parsing
Style
Layout
Layering
Raster
html
body
p
p
text
text
CS
CS
CS
CS
CS
CS
この <p> の色が変更されたときは、その部分木のみ invalidation すればよい
ステージングする理由1
アニメーションの Layer のみ
Raster しなおせばよい
Parsing
Style
Layout
Layering
Raster
ステージングする理由2
時刻t
ページロード
ユーザインタラクション
(タッチ、スクロール、入力)
ユーザが見たいであろうコンテンツを最速で描画できるよう最適化
ユーザインタラクションに最速で反応できるよう最適化
最短化
60 frames per second
ステージングする理由2
時刻t
JavaScript
この時点までスクロール
に反応できない
メインスレッド
ステージングする理由2
Parsing
Style
Layout
Layering
Raster
メインスレッド
描画スレッド
Layout
Layout
Layout
Layout
Layout
Layout
ステージングする理由2
時刻t
JavaScript
メインスレッド
描画スレッド
Raster
Raster
Raster
まとめ
*
*
*
*
ブラウザ = ただのブラウザアプリ
ではなく、もはや
ブラウザ = Web の OS
古典的な OS との決定的な違い = Embeddability
Web 上に転がっているいろんな人や組織が作った
(よって信用を仮定できない)アプリをセキュアにホストする
(twitter.com はそれがどのページにどう埋め込まれようと、
twitter.com は twitter.com のデータにしかアクセスできないし、
twitter.com のデータは twitter.com にしかアクセスされないことを保証)
古典的な OS との決定的な違い = Embeddability
Web 上に転がっているいろんな人や組織が作った
(よって信用を仮定できない)アプリをセキュアにホストする
(twitter.com はそれがどのページにどう埋め込まれようと、
twitter.com は twitter.com のデータにしかアクセスできないし、
twitter.com のデータは twitter.com にしかアクセスされないことを保証)
システム屋には
たまらなくおもしろい!
より深く学びたい人へ
レポート課題
*
*
*
*
レポート課題
Google のミッション:
世界中の情報を整理し、
世界中の人々がアクセスできて
使えるようにすること
レポート課題
レポート課題
Q&A
*
*
*
*