跳轉到

1.3 為何需要虛擬機(隔離、可攜性、安全性)#

從資源共享到多重動機#

虛擬機最初的動機非常單純:1960 年代的大型主機太貴,必須讓多人共用。但六十多年來,驅動虛擬機技術演進的動機不斷擴張,歸納起來可分為三大支柱:隔離、可攜性與安全性。這三者看似不同,其實共享同一個核心思想——在系統中插入一個間接層,把「程式寫死的假設」與「實際執行的環境」解耦。David Wheeler 的名言「電腦科學中的任何問題都可以靠增加一層間接層解決(除了間接層太多的問題)」,正是虛擬機的最佳註腳。

一、隔離(Isolation)#

在沒有虛擬機的世界裡,一台機器 = 一個作業系統 = 一組共享全部資源的程序。任何隔離都只能依賴作業系統的保護機制(分頁、權限位元、檔案權限),而 OS 本身的漏洞會使所有隔離一起失效。虛擬機提供的是更強的邊界:

  • 系統 VM 的隔離:每個虛擬機有獨立的客座核心、獨立的位址空間、獨立的設備模型。一個 VM 內的核心 panic 不會影響鄰居。這讓 1990 年代末的研究者得以在同一台伺服器上做「怪獸實驗」:修改核心、測試新作業系統、重現攻擊環境,而不必维护多台實體機。
  • 程序 VM 的隔離:JVM、.NET CLR 提供了比 Unix 程序更細的隔離——同位址空間內的多個程式(如瀏覽器中的多個 applet、App Engine 上的多租戶程式碼)被位元碼驗證器與安全模型限制彼此的存取。
  • 雲端的經濟學:AWS(2006 年上線)之所以可能,正是因為 EC2 能把一台實體機器切成數十個互不信任的租戶 VM。隔離直接轉換為商業模式:你租的不是「機器時間」,而是「一台虛構的、完全屬於你的機器」。

隔離也重塑了開發與維運流程:快照(snapshot)、檢查點(checkpoint)、遷移(live migration,2005 年前後在 Xen 上成熟)讓系統狀態可以被凍結、複製、搬移——這些都是實體機器做不到的操作。

二、可攜性(Portability)#

1960 年代的程式設計師面對的殘酷現實是:每家廠商、甚至同一廠商的每個機型,都有不同的字長、字元編碼與指令集,軟體幾乎無法跨機搬移。兩條路線先後解決了這個問題:

  1. 高階語言路線:編譯器把原始碼翻譯到各平台。問題是每個平台都要移植一個編譯器後端,且編譯出的二進位檔仍不可攜。
  2. 位元碼路線:只翻譯到一個虛構的中間 ISA,再為每個平台實作一次「小小的」虛擬機。Unix 的 BCPL 曾用 O-code(1960 年代末,Martin Richards)、Pascal 用 P-code(1973 年由 Kesley 及 Wirth 團隊推廣),而 1995 年的 Java 把這條路線推到極致:「Write Once, Run Anywhere」。
原始碼 ──編譯器(一次)──> 位元碼(.class/.jar/.pyc)
                            │
        ┌───────────────────┼───────────────────┐
      x86 VM             ARM VM            SPARC VM
   (每平台只需 VM)

可攜性的價值在網際網路時代被放大:伺服器架構五花八門,若應用程式發行的是 x86 機器碼,發行者必須為每種平台各自建置;發行位元碼則只需一份構建產物。Java 的成功使位元碼發行成為行動與企業軟體的標準做法,Android 的 Dalvik(2008)與微軟的 CIL(2002)皆承襲此思路。C 語言世界的相對應方案則是原始碼層可攜(靠 #ifdef 與 autoconf),但代價是建置矩陣的組合爆炸——虛擬機方案以「每平台一份 VM」的線性成本,換掉了「每平台 × 每應用」的乘積成本。

三、安全性(Security)#

虛擬機的安全性貢獻有三個層次:

  1. 防禦惡意與錯誤的客座程式:位元碼驗證(見 2.3 節)在載入時靜態證明程式不會偽造指標、不會跳到任意位址、不會繞過型別系統。1995 年 Java applet 能在瀏覽器中執行不可信程式,靠的正是這套機制;今日 JavaScript 的 sandbox、Android 的應用沙箱,皆是同一思想的後裔。
  2. 縮小信任基礎(TCB):hypervisor 的程式碼量遠小於一般作業系統核心(Xen 的 hypervisor 約十萬行,Linux 核心數千萬行),攻擊面因此大幅縮小。2000 年代以降,「把關鍵服務放在專屬 VM 中」成為標準的安全架構。
  3. 惡意程式分析與蜜罐:分析師在 VM 中執行可疑樣本,崩潰與感染被限制在快照之內;反之,惡意程式也學會偵測 VM(紅旗:特定hypervisor 字串、時間漂移),攻防兩端共同演進。

當然,虛擬機不是銀彈:VM escape(從客座突破到 hypervisor)的漏洞(如 2008 年公開的 VMware 問題、歷年 Pwn2Own 競賽的 escape 案例)顯示隔離層本身也是軟體;側通道攻擊(如 2018 年的 Spectre/Meltdown 對雲端租戶隔離的衝擊)則提醒我們微架構狀態可能跨 VM 洩漏。

小結#

隔離讓一變多、讓資源可分割與可逆;可攜性讓程式與平台脫鉤、讓發行從矩陣變成直線;安全性讓不可信程式碼得以在受控環境中執行。這三大動機分別支撐了雲端基礎設施(第 5 章)、位元碼生態系(第 2、3 章)與語言執行時期的驗證/GC 基礎建設(2.3、3.3 節)。當讀者在後續章節鑽研指令集設計或 JIT 細節時,應不時回到本節的問題意識:這個技術究竟是為了把什麼與什麼解耦?