Open11

crosvmについて調べる

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ
  • crosvmがどういうアーキテクチャでChromiumでどのように使われていて、普通のVMMと何が違っているか
  • Firecrackerはcrosvmから着想を得ているが、どのような違いがあり、どのような要件から実装に至り、AWSの中でどのように使われているか
    を調べると師匠に寿司を奢ってもらえるので調べる

追記
まとめました
https://zenn.dev/usaneko_xlarge/articles/2a1cfa883a2806

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

https://crosvm.dev/book/introduction.html

Book of crosvm を読む。

Introduction

  • hosted VMM (Hyper Visor の下にホストOSがあるタイプ)
    • QEMU-KVM や Virtual Box と同じ
  • Rustで書かれている
  • Runtime Sandbox システム が特徴
  • 仮想デバイスは minijail サンドボックス の中で動き、隔離されている
  • syscall security policy に基づき、侵害されたデバイスが不必要なシステムコールを行うことを防ぐ
  • 動かすのに必要なのは OS イメージ(root file system + kernel)
  • hypervisor を使ってそれを動かす

疑問の解消

  • まず、この文脈でのVMM (virtual machine monitor) と Hypervisor ってなに?
    VMM は Hypervisor のことを指すこともあるが、この文脈では "crosvm will run it through the platform's hypervisor" とあるので、違いそう
    Firecracker の論文の図を見てみた
    https://www.usenix.org/system/files/nsdi20-paper-agache.pdf
    Figure 1 の説明部分

コンテナの場合は、seccompなどで制限はされているもののコンテナがホストkernel を直接呼び出す。virtualization ではゲストkernelへのフルアクセスを許可するが、ホストから見てゲストkernelは信頼されていない。

crosvm は QEMU-KVMと同じらしいので Figure1 の KVM の部分をさしてそう?でも Firecracker (crossvmをもとにしているらしい)が VMM って言われてそうなので VMM の部分なのかな

https://blog.inductor.me/entry/2020/02/20/014025
師匠のブログ

FirecrackerではKVMを使い続ける選択をしましたが、QEMUを完全に置き換えて、MicroVMを管理および構成するための新しい仮想マシンモニター(VMM)、デバイスモデル、およびAPIを構築しました。

とあるので、QEMU のほうが VMM っぽい。ので、 Figure1 の VMM の部分(host kernel と guest kernel の間)が crosvm にあたるのかな。
じゃあ Hypervisor ってなに?
https://crosvm.dev/book/hypervisors.html
ここを見ると KVM/WHPX/HAXM などがそれにあたるらしい。
つまり Figure1 の、host kernel の一部がそれに当たるのかな。

図的にはそうだけど、結局 Figure1 の VMM/KVM(=HyperVisor)が何をしているかというと、
https://www.linkedin.com/pulse/qemu-vs-kvm-quick-comparison-raja-nagori-

  • KVM は CPU の仮想化を行っている
  • VMM はハードウェアデバイス(プロセッサ/メモリ/ストレージ/ネットワークインターフェイス)などのエミュレートを行う
    みたいです。

まとめると、crosvm では、CPU仮想化を行う部分は KVM などのハイパーバイザーにまかせて、ハードウェアデバイスのエミュレートを行う部分を実装しているということでしょう。

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

疑問解決その2 : Runtime Sandbox システムとは?
https://crosvm.dev/book/appendix/sandboxing.html

crosvm では、仮想化されたデバイスをプロセスとして隔離することでサンドボックス化を実現している。そのプロセスは他の仮想化環境とは別のアドレス空間に隔離されている(図の crosvm Process)。

これは、普通の VMM とは違うのか?まず普通の VMM がなんなのかわからない
→この部分については一般的?(KVM/QEMUとか)なものとおなじっぽい?

別師匠の話を聞いたまとめ

(一般的に)VMM は、ゲスト kernel が CPU で直接実行できない/したらホスト OS に影響が出るような命令(デバイス IO/特権非特権の切り替え)などを行おうとしたとき、それをホスト kernel に影響が出ないような形で処理するような働きをする。(crosvm だとプロセスっぽい)
KVM は、CPU で実行できるような命令をゴリゴリ実行するとき、ゲスト kernel と CPU が紐付いていないといけないので、紐付け用にレジスタなどの値を持っておき、複数 CPU があるように見せる働きをする。

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

疑問解決その3 : minijail サンドボックス とは?
https://crosvm.dev/book/appendix/minijail.html

デバイスをサンドボックス化するために使っているライブラリ(クレート)。Google が作っていて ChromeOS や Android で使われている。
https://google.github.io/minijail/

https://github.com/google/crosvm/blob/main/jail/src/helpers.rs
ここにかんたんな crosvm の minijail 使用部分の実装がある。たとえば、create_sandbox_minijail関数の実装を見ると、jail ライブラリを使って

  • change uid/gid をしたり
  • uid/gid map を変更して jail の中で current user を root として扱ったり
  • namespace を作ったり
  • 権限を新たに得ることを禁止したり
  • seccomp を設定していたり
    しそう。コンテナ作るみたいな感じだなあ。

https://docs.google.com/presentation/d/e/2PACX-1vRBqpin5xR9sng6lIBPjG0XQtu-uWWgr0ds-M3zW13XpDO-bTcMERLwoHUEB9078p1yqr9L-su9n5dk/pub?slide=id.g116613332a_0_643

Minijail : Android, Chrome OS and Brillo's containment helper.

って書いてあるので、その感想で正しそう。
普通にコンテナ作るのをかんたんにしてくれる Rust Wrapper みたいなイメージ?

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

疑問解決 4 : syscall security policy とは?
Seccomp については学習済み。プロセスが利用できるシステムコールを絞ってくれるみたいなイメージ。

The form of seccomp used by crosvm (SECCOMP_SET_MODE_FILTER) allows for a BPF program to be used.

crosvm で使われている seccomp だと、 BPF プログラムが使われることを許可している らしい。

BPF(eBPF) ってなんだっけ
https://atmarkit.itmedia.co.jp/ait/articles/1811/21/news010.html
https://caddi.tech/archives/3880

  • もともカーネル内部でパケットフィルタリングをするために考えられ、仮想的なレジスタマシンを持ち、それ用の BPF プログラムなるものを実行することだった。
  • 今は、eBPF プログラムというバイトコードを渡して、カーネル内で検証して実際に動作するマシンコードにコンパイルしたあとにカーネルに組み込む という機構全般のこと

要するに、 crosvm は、(x86_64などのアーキテクチャごとに作られた)デバイスごとにどのsyscallたちを使うかのポリシーを記述したものを渡されると、そのファイルをeBPF バイトコードに変換し、crosvm の実行ファイルに組み込む。これによりなにができるんだ?seccompなのでシステムコールがフィルタリングできていそう。じゃあ、なんでわざわざBPFプログラムを使っているんだ?

https://mmi.hatenablog.com/entry/2016/08/01/044000

こうしてみると,確かにBPFを使ってシステムコールのフィルタリングができていることが分かります.これだけならあまり BPFを使う理由はないように思うかもしれませんが,ある特定の引数だけ許可したいとなると,確かにBPFのプログラムで効率的 に処理できるような気がしてきたりしないでしょうか. また,seccomp_dataにはinstruction_pointerがあり,これと/proc/pid/mapsを組み合わせれば特定の関数からのみ システムコールを許可するといったことも可能になります.

BPF 元祖の目的であるパケットフィルタリングを応用してシステムコールのフィルタリングをやっているということか。

一般的にこの方法をseccomp mode 2というらしいです。

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

師匠「minijailの背景にはそもそもUNIXのjailがあるのでそれを調べよう」

OSレベル仮想化機構実装の一つらしい。
https://atmarkit.itmedia.co.jp/ait/articles/1207/20/news153_2.html
chroot と似たように隔離された環境で動かしたプロセスがそれ以上の階層のディレクトリにアクセスできないようにするが、それだけでなくPIDなども分離する。ネットワークNameSpace とかも分けられていそう。

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

crosvm とはなにか、どういうアーキテクチャなのか

https://github.com/google/crosvm

crosvm is currently used to run Linux/Android guests on ChromeOS devices.

ホスト OS (のカーネル)の上でゲスト OS を動かす際に、Virtual Macine Monitor (VMM) と Hypervisor の 2 つを利用する。

VMM は、ハードウェアデバイス(プロセッサ/メモリ/ストレージ/ネットワークインターフェイス)などのエミュレートを行う。もっと詳しく言うと、ゲスト kernel が CPU で直接実行できない、またはそうしたらホスト OS に影響が出るような命令(デバイス IO/特権非特権の切り替え)などを行おうとしたとき、VMEXITというイベントが起こってVMMに実行が委ねられ、VMMはそれをホスト kernel に影響が出ないような形で処理するような働きをする。

Hypervisor は、CPU の仮想化を行っている。もっと詳しく言うと、CPU で実行できるような命令をゴリゴリ実行するとき、ゲスト kernel と CPU が紐付いていないといけないので、紐付け用にレジスタなどの値を持っておき、複数 CPU があるように見せる働きをする。

crosvm は VMM の一種であり、Chrome OS (Linuxのディストリビューション)のカーネルの上で Linux や Android のゲスト OS を動かすのに使われている。crosvm と互換性がある Hypervisor に、KVM/WHPX/HAXM/Geniezone/Gunyah などがある。

一般的な VMM と違うところは最後に詳しく述べるが、かんたんには以下のような特徴がある。

  • Rust で書かれており、メモリ安全性が高い
  • seccomp mode2 (eBPF によりシステムコールのフィルタリングを行う仕組み)を使っている。
  • OSレベル仮想化機構実装の一つである jail の機能を使えるようにした Rust のラッパーである minijail を利用している

Chromiumでどのように使われているのか

https://qiita.com/kizitorashiro/items/ccec4d02c2550832214f

Chrome OS において、Linux/Android のゲスト OS を動かすのに使われている。

普通のVMMと何が違っているか

https://chromium.googlesource.com/chromiumos/platform/crosvm/+/master/README.md

What makes crosvm unique is a focus on safety within the programming language and a sandbox around the virtual devices to protect the kernel from attack in case of an exploit in the devices.

https://github.com/google/crosvm

crosvm is a virtual machine monitor (VMM) based on Linux’s KVM hypervisor, with a focus on simplicity, security, and speed. crosvm is intended to run Linux guests, originally as a security boundary for running native applications on the ChromeOS platform. Compared to QEMU, crosvm doesn’t emulate architectures or real hardware, instead concentrating on paravirtualized devices, such as the virtio standard.

https://prilik.com/blog/post/crosvm-paravirt/
このブログは実装にまで踏み込んでいてわかりやすいです(crosvmの開発に関わったインターン生のブログらしい)
ただしこのブログは、私の言うVMMをType2-Hypervisor、HypervisorをType1-Hypervisor と呼称しているが、あまりしない言い方なので注意

crosvm の特徴として、主に以下の点が挙げられる

  • Rust が使われている。QEMU や kvmtool など KVM ベースの VMM は C 言語で書かれており、crosvm はより Rust のメモリ安全性が生かされている
  • QEMU や VirtualBox にくらべて、Linux VM を動かす機能に絞って開発されており、他のOSイメージは動かない。
  • crosvm はハードウェアをエミュレートするのではなく、vitro standard のようにデバイスを仮想化(paravirtualized)することに力を入れている。paravirtualize により、VMとデバイスドライバが直接働きあうことで、ファイルアクセスやネットワーク、画像処理などIOが重いワークロードにおいてベアメタルに近いスピードを出すことができる。

最後の点について詳しく話そう。
VMEXIT は非常に重い動作である。なぜなら、Memory Mapped IO (MMIO、CPUのメモリの一部がデバイスのレジスタと結びついていることでデバイスを操作する仕組み)を通して vCPU がデバイスを操作しようとし、その操作でアクセス権の欠如が起こることを把握した Hypervisor が vCPU を止め、crosvm に実行を委ね、crosvm がデバイス操作が成功したかのようにエミュレートする、といったような CPU のコンテキストスイッチが含まれた一連の動作が行われているからである。
paravirtualization では、一般的な仮想化と異なり、ゲストは VM の中で動いていることを知ることができる。これにより、VMEXIT をできるだけ避けるような paravirtualized driver というものを実装できる。これを実装する方法の一つとして、virtio がある。

エミュレータを使った場合と、virtio を使った場合の違いについて述べよう。
たとえば、ループの内部で毎回デバイスを参照するようなプログラムがあったとする。この場合 単純なエミュレータを利用すると、VMEXIT のオーバーヘッドがパフォーマンスに影響を与えてしまう。virtioを使うと、以下のようにすることで読み書きが非同期になり、 VMEXIT しなくて済む。

  • VMEXIT しなくても読み書きできる場所に virtqueues という キューを置く。
  • ゲスト OS はデバイスから読み書きしたいときにバッファへのポインタをそのキューにおく
  • crosvm はキューを監視し、新しいバッファが現れたら、そこにデバイスからの結果を置く
  • バッファが埋められたら通知する
    https://syuu1228.github.io/howto_implement_hypervisor/part11.html

(参考)
Rust の安全性については以下
https://qiita.com/Cowsisland/items/71248bdd081089b7ba09

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

https://www.usenix.org/system/files/nsdi20-paper-agache.pdf

https://tech.gunosy.io/entry/read-firecracker

Firecracker とは

Firecracker は KVM を用いた VMM で、 microVM と呼ばれるものを作ったり管理したりするのに使う。

Firecrackerと crosvm の違い

  • Firecracker ではコードが半分以下になっている
  • USBやGPUなどのデバイスドライバを削除し、9P ファイルシステムプロトコルをサポートしている

Firecracker はどのような要件から実装に至り、AWSの中でどのように使われているか

https://firecracker-microvm.github.io/

Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

論文本編の内容を以下に要約していきます。

どのような要件から実装に至ったか
Firecracker 以前の Lambda は、アカウントごとに VM を用意して、その中でワークロードごとに別のコンテナを動かしていました。
しかし、コンテナではセキュリティを担保しながらコードの互換性を保つことができないことや、ワークロードのコンテナを VM の中に無駄なく配置することが難しいことに不満がありました。
そのため、以下の要件を満たすような別の方法を考える必要があり、Firecracker の実装に至りました。

  • 同じハードウェア上で複数のワークロードを動かすが、特権昇格や情報の開示、隠れチャネルなどのリスクから守られている
  • 同じハードウェア上で最小限の無駄で何千ものワークロードを動かせる
  • ネイティブに実行したときと同じパフォーマンスで動かせる
  • 同じハードウェア上で隣接するワークロードたちのふるまいにかかわらず一定のパフォーマンスで動かせる
  • ワークロードに含まれている Linux バイナリやライブラリを修正や再コンパイルせず動かせる
  • ワークロードの開始と終了を高速に行える
  • CPU やメモリなどのリソースをオーバーコミットできる
  • 権限のあるリソースを無為に消費するのではなく必要とするリソースだけを消費する
Usaneko Large うさねこらーじUsaneko Large うさねこらーじ

crosvm とどのような違いがあるか
crosvm にくらべて USB や GPU などのデバイスドライバを削除することでコードを半分程度に減らしました。(アーキテクチャがシンプルになり、爆発半径が小さくなる)

AWS の中でどのように使われているか
AWS Lambda というサービスで使われています。
AWS Lambda では様々な言語のランタイムを提供しており、ワークロードをコードスニペットで提供することができます。また、HTTP/REST API もサポートしているため、この中身をあらゆる言語で開発し、言語実装とともにバイナリやバンドルとして提供することもできます。
Lambda ワークロードは sandbox 環境の中で実行されます。最初にメモリの制約やイベントを処理する際の最大実行時間を設定します。イベントは、API コールや HTTP リクエスト、ほかのAWS サービスなどによって作られます。

具体的に Firecracker がどこで使われているかというと、Frontend でイベントをトリガーする命令を受け付け、ワーカーマネージャーがワーカーにそれをわりふるのですが、このワーカーにおいて使われています。
どのように使われているかというと、

ワーカーの中では何千もの MicroVM が実行されており、これはそれぞれひとつの Firecracker によって作成管理されているものです。Frontend とこの MicroVM の中は、 TCP/IP を介して情報をやり取りします。
Firecracker の起動時間が短いことで、プールされている MicroVM のスロットが少なくても済みます。