1、Fuchsia 設計解讀重德智能 多年的 Android,ChromeOS 開發經驗一方面讓 Google 在操作系統方面積累了足夠多的人才和組件,另一方面也充分認識到了 Linux kernel 很多的局限性 Fuchsia 是一個全新的操作系統的統稱。Google 挑選了一系列它認為合適的技術和組件進入這個操作系統,比如:微內核,基于能力的訪問控制,Vulkan 圖形接口,3D 桌面渲染 Scenic,Flutter 應用開發框架。目前支持的編程語言是:C/C+,Go,Rust,Dart Google 2016 年中放出了所有的代碼,但是沒有正式宣布這個項目的目標,開發社區目前有一個 IR
2、C 頻道進行交流 支持的架構是 X86-64 和 ARM 64,支持的設備從 IoT 到服務器Fuchsia 的基本情況為什么不在 Android 上改進,塞入各種新技術https:/spectrum.ieee.org/aerospace/aviation/how-the-boeing-737-max-disaster-looks-to-a-software-developer 737 的問題:機翼下空間太小,放不下大引擎。改動機翼相當于重新設計一架飛機 所以,改變發動機位置強行放進去,后果是改變了空氣動力學特性,機頭容易上揚 解決方案是通過修改飛控軟件來彌補,飛控認為飛機在上揚,強行下壓,造
3、成失控 當總體設計出現問題的時候,用再多的技巧去彌補,也只會造成最終的災難Google 為什么要從頭設計全新的操作系統 上游硬件廠商 下游應用開發者 設備友商 用戶 黑客現代通用、開放 OS 需要面對的方面 原生進程沙箱,解決應用安全和分發問題(黑客)Linux:Namespace,Control group,Unionfs=Docker 穩定的驅動接口,硬件廠商可獨立維護硬件驅動(硬件)系統模塊化,分層,設備廠商可以靈活定制專有系統(友商)基于 Vulkan 和物理渲染的純 3D UI,全局光照(用戶)Flutter 應用開發框架(開發者)Fuchsia 解決現代 OS 痛點 全局文件系統
4、用戶 進程的創建 系統調用Fuchsia 重新思考四個 Unix 的基礎抽象機制 在 Unix 里,存在一個全局的根文件系統 它是每個進程共享的基礎資源 文件系統涵蓋了非文件資源:/proc,/sys,網絡是例外 在 Fuchsia 里,沒有全局根文件系統 文件和文件系統成為一個局部概念(局限在每個文件系統進程里),從而在進程內核數據結構里沒有 file 用 namespace 來定義一個進程能夠訪問的資源每個 name(路徑)對應一個資源進程 channel 的 handle“/“-root vfs service handle,“/dev”-dev fs service handle,“/
5、net/dns”-DNS service handle全局文件系統 在 Unix 中,User 本來是用作不同的用戶登錄共享服務器的機制 User 是真正的用戶 后來主要用作權限控制,弱化的沙箱機制 在 Fuchsia 中,在底層(Zircon,Garnet)沒有用戶的概念 用 namespace 來控制進程能夠訪問的資源 Capability-based access control 從而在進程里沒有 uidUser 在 Unix 中,新的進程由老的進程 fork 而來 新的進程繼承父進程的全部資源 一種偷懶的設計 Andrew Baumann,A fork()in the road,ACM
6、 Hot Topics in OS,May 2019 在 Fuchsia 中,新進程的創建需要從頭開始 創建 process,thread 父進程建立初始的 namespace 到資源 channel handle 的映射 調用 process_start 顯式地告訴內核新的進程可以跑了 在 Fuchsia 內核的 process 數據結構里,沒有 file 和 uid進程的創建Unix/Linux 里,通過中斷調用內核服務:int 0 x80,syscall,sysenter 系統調用的方式是確定的,直接的內核接口不能變可以被任意注入的代碼調用Zircon 里系統調用通過 vDSO 進行,意
7、圖是防止用戶代碼直接通過固定的中斷代碼調用system call,達到內核詳細接口的隔離。保持 C 層面的接口穩定:名字+參數。而不是內核入口匯編指令層面的穩定注入的代碼無法直接調用 vDSO 里的接口,雖然加載地址固定,但是計算出入口地址很難,如果不是不可能的話內核會驗證調用指令的地址,而 vDSO 的加載地址是固定的。并且在編譯的時候會驗證有限的入口符號,這些符號在編譯時唯一生成,防止用戶進程繞過 vDSO這里主要的目的是隔離 system call 的調用方式,不是絕對意義上的不可注入調用https:/ 典型的漏洞利用步驟通過系統調用 fork()/exec()直接創建反向 shell繼
8、承 uid(或者通過獲得 root uid 進行提權)獲得泛在授權訪問全局文件系統 在 Fuchsia 里,以上機制全都不存在沒有固定的系統調用入口,必須動態鏈接創建進程時顯式建立 root namespace沒有 user,從而沒有 ambient authority(DAC/MAC)Capability-based access control能訪問的資源是父進程賦予的 namespace看不到初始 namespace 之外的任何資源仿佛是專門針對漏洞利用作出的設計Kernel 的本質是什么 管理硬件 執行特權指令 引導啟動過程 處理中斷Kernel 的本質不是:不同進程唯一共享內存地址空
9、間的場合 切換地址空間是進入內核的標志 不同的進程通過共享內核地址空間來交換信息 切換地址空間是切換進程的關鍵步驟Kernel 的本質是:地址空間切換 虛擬內存和物理內存管理VMO:Virtual Memory Object:包含物理頁 進程和線程管理 進程間通信channelZircon 主要內核態功能 Virtual Memory Object(VMO)代表一個內存對象,懶分配 VMO 通過向 channel 發送 handle 在進程之間傳遞進程拿到 VMO handle,把 VMO 重新映射到自己的地址空間里 Unix 是以文件為中心的設計以內存為中心的設計channel 是進程間通信
10、的(唯一)機制一個 channel 有 2 個 handle,h1,h2,從一頭寫入消息,從另一頭讀出消息一個進程在創建時有一些初始 channel handle要與一個服務x建立通信,進程創建一個 channel,自己拿 h1,把 h2 通過已有的channel(root_svc)發送給相應的服務,服務拿到 h2,將其放到自己的事件監聽循環里 示意 API:connectToService(root_svc,“x”,h2)比如 open(),在 Linux 里會在進程的內核數據結構里增加打開的文件描述符,不涉及到其他進程;在Fuchsia 里則是創建一個 channel,把遠端發送給相應的服
11、務,建立通信通道channel_write()把消息寫到另一個進程能看到的地方。進程間是不共享內存地址空間的。只有內核的地址空間是進程共享的。所以 channel_write()必須是一個系統調用,切換到內核地址空間里進行消息寫入。一旦切換到內核地址空間里,就能看到另一個 handle 了。寫到那個handle 的消息隊列里,等另外一個進程切換到內核地址空間里,就能看到消息了channelchannel 的實現Process AProcess BKernelhandle 1peer handlemsg listhandleIndex1handleIndex 2handle 2peer hand
12、lemsg list 內核映像還嵌入了一個 vDSO,包含了系統調用入口 這個 vDSO 被映射到每個進程的內存地址空間里 它本身是 ELF shared object 文件格式,但是又不是以文件形態存在,所以叫做vDSO Linux kernel 也用這種方式實現了一些簡單的系統調用,比如 getdaytime()。但是Zircon 并不是為了避免切換內核態,而是把系統調用的接口用 vDSO 進行隔離系統調用 vDSOvDSO 最大的優勢在于保證二進制接口(ABI)兼容性的同時,不干擾升級系統調用的實現。Linux 的系統調用 ABI 是基于處理器中斷的,每個系統調用都有自己的系統調用編號,
13、這么多年來除了 syscall/sysenter 并沒有本質上的升級。這是因為相當多的預編譯好的程序會不管三七二十一去調用中斷。一旦 Linux 不再支持基于中斷的系統調用接口,那這些現有的應用程序除非返回源代碼重新編譯,否則無法正常運行。Fuchsia 非常重視 ABI 兼容性,但同時也不希望放棄將來優化系統調用的機會。這類問題可以通過多加一層間接調用來解決(Fundamental theorem of software engineering)。Fuchsia 里所有的系統調用都必須由 vDSO 發起。用戶代碼要想調用系統函數就要先動態鏈接上 vDSO,再呼叫 vDSO 中的某個函數,再由
14、那個函數去調用系統。這樣一來用戶程序跟內核接口完全解耦。下一版,Fuchsia 無論是要改變系統調用的寄存器順序,還是改換效率更高的調用約定,都可以通過更新 vDSO 來無縫兼容現有的一切應用。另外,在 Linux 里遇到緩沖區溢出 bug,攻擊者能夠注射一段調用系統函數的代碼,從而拿到 shell。但是在 Fuchsia 里因為系統調用來源強制限制為 vDSO,而 vDSO 所在的內存頁面永遠是只讀頁面,注入的代碼并不能調用任何系統函數,形成了 0-day 漏洞前方的最后一道防線(內核會檢查入口指令的地址,而vDSO映射的地址是固定的)。vDSO 的好處 Linus vs Tanenbaum
15、 的論戰 Tanenbaum:Linux 是七十年代的技術。在 1991 年寫宏內核是錯誤的。爭論早就結束了,微內核已經贏了。我是教授,Minix 只是我的 hobby,所以別拿 Minix 說事。Linus:Linux 比你寫的 Minix 強多了。微內核只是你們學術界的玩具,我看過所有的關于微內核效率優化的論文,它們實際上只是在重復宏內核早就用過的技巧。Mach,Hurd Performance overhead Context switching(user space kernel space)Thread scheduling微內核 Monolithic CPU0Context swi
16、tching:2 Micro CPU0Context switching:8Thread scheduling:4Overhead:single core caseCPU0CPU0CUP1CUP2CUP3 Monolithic CPU0Context switching:2Overhead:multicore case Micro CPU0Context switching:2 CPU1Context switching:2 CPU2Context switching:2 CPU3Context switching:2Fuchsia 架構HardwareKernel(process,IPC,m
17、m)Flutter Frameworkdevmgr(/dev)devhostdevhost(/dev/x)devhostdevhost(gpu driver)appmgr(/hub)sysmgrscenic(Vulkan)Applicationsfshost(/)svchost(/svc)在服務器平臺上,原生的進程沙箱機制將帶來新的安全特性和容器機制 在桌面平臺上,類似于游戲 3D 引擎 pipeline 的圖形棧以及毫無遺產負擔的實現將使電子娛樂應用變得更為高效;無縫兼容龐大的 Android 生態 在移動平臺上,系統的模塊化方便第三方設備廠商的全面定制,驅動框架方便硬件廠商編寫和維護私有驅
18、動Fuchsia 在各個平臺上的可能的優勢Ubuntu 18.10 很精致,X+OpenGL/Vulkan+QT 比較穩定可靠了X Window 誕生于 1984 年,越來越多的功能被加入到 X stack 里隨著技術的發展,越來越多的功能從X中移到內核或者是其他專門的庫中:kms,cairo,opengl/vulkan DRI2,fontconfig/freetypeX 的問題:window manager 也作為一個 client,導致效率低,容易出 bug,如果不遵循 ICCCM 的話Wayland 是一個融合了 compositor 的 display server,去掉了 X 里的過
19、時功能,比如繪制但是 Nvidia 和其余廠商還沒有就 Wayland 里的 buffer 管理達成一致,導致 nv 還不支持 wayland注:在 X 里,OpenGL/Vulkan 是嵌在 Window 里的;在 Fuchsia 里,整個桌面的繪制是交給 Vulkan 的Linux 桌面的現狀 Fuchsia 是一個像 Lego 玩具一樣組裝起來的操作系統 谷歌在設計時已經考慮了其他廠商可能會深度定制適配自己產品的操作系統,所以模塊化做得比 Android 徹底很多 廠商的深度定制可以從以下任意一層開始 Zircon:微內核,基礎服務進程(設備管理器,核心設備驅動,libc,進程間通信接口
20、庫fidl)Garnet:設備層面的系統服務:軟件安裝,通信,媒體,圖形,包管理,更新系統等 Peridot:用戶體驗的基礎設施層:模塊,用戶,存儲服務,等等 Topaz:系統的基礎應用,Web,Dart,Flutter 這些名字來自于 Steven UniverseFuchsia 分層Fuchsia 啟動流程設置各種控制寄存器,進入 EL1設置內核頁表,打開虛擬內存為當前執行軌跡初始化為線程結構之后進入C 的世界用 psci smccall 啟動副cpu進行一系列初始化,包括各種設備構造第一個用戶態線程userboot,內核線程進入 idleUserboot 從bootfs 中加載第一個文件
21、進程 devmgrdevmgr=svchost,fshost,devhost,appmgr=sysmgrZircon 內核線程比較少,主要是 dpc thread(deferred procedure call)之前的微內核一般需要實現一個基本的文件系統加載功能在內核里,然后加載第一個用戶進程文件,之后就不再使用內核里的文件系統功能 Zircon 把第一個用戶態進程的 ELF 文件嵌入進內核映像里,這樣就不需要從文件系統里加載了第一個用戶態進程的創建 devmgr,devhost,svchost,fshost Appmgr Sysmgr Fuchsia 定義了一套穩定的 DDK 接口,硬件廠商
22、開發自己的閉源驅動的方便性大大提高了。因為 Linux kernel 是拒絕提供穩定的內核內部驅動接口的。要想被官方維護,就得放進內核里,否則只能自己跟著內核去改接口 內核不提供 POSIX 支持,用戶層可以模擬一部分 POSIX 接口Zircon 用戶態 ELF 的加載位置是隨機的,并不是遵守 ELF program header 里規定的 v_addr 會在加載時對符號地址進行修正Kernel Address Space Layout Randomization Qemu最方便的環境,沒有 GUI Intel NUC目前最好的測試環境,有 GUI Khadas Vim2Google 內部開
23、發用的板子Fuchsia 目前的運行環境 在 Qemu 中可以直接運行 Booloader 加載到 0 x40080000 內核加載到 0 x40090000 Ramdisk 加載到 0 x48000000 0 x40000000-0 x40080000 之間是 FDT flattened device treeQemu 開發機啟動 paving 服務,會將整個 Fuchsia 操作系統刷到 NUC 上 啟動 Zircon 到 zedboot 模式,會直接連接開發機Intel NUC Amlogic S912 SoC Quad Core A53 Mali-T450MP5 GPU 3G DDR4
24、 64G eMMC storage HDMI,USB-C,USB 2.0,TF Card,Ethernet,WiFi,BluetoothKhadas Vim2 開發板 Arm Trusted Firmware:BL1 in ROM Custom u-boot:BL2+BL30+BL31+BL32+u-boot(BL33)其中 bl2,bl30,bl31,bl32 都是 amlogic 提供的 binary Bl33 從 emmc offset 0 x50200 處開始,加載到內存 16MB 處執行 使用 fastboot 協議可以用 usb-c 將 zircon kernel 寫入 boot
25、分區 https:/ 的啟動 系統軟件與應用軟件不同 有大量的緘默知識,長期積累的 know-how 工具鏈:gcc,ld,as,clang,ELF,微處理器:X86,ARM,周邊設備:UEFI,ACPI,APIC,PCIE,USB,SATA,AHCI,GPU 知識存在于代碼中,沒有系統化的 know-how 文檔,硬件標準文檔一般都是 1000+頁 寫玩具系統容易,產品級的設計非常困難:支持海量的設備,應用,負載 要經過以下四個階段 模仿 理解 掌握 創新系統軟件研發能力的獲得 Fuchsia 重新思考了操作系統設計的各個方面,是一次難得的從頭開始的機會 在未來 Fuchsia 會成為一個非
26、常重要的操作系統總結 https:/ News 上的討論IRC 上 Fuchsia 開發者的反饋 https:/ 老邁龍鐘,歷史負擔太重,微軟自己的創新 Midori 胎死腹中,因為無法承受在新的框架中重新實現一遍 Windows 的全部功能,只能在原地進行重構Linux 里大部分開發人員只關心服務器的世界,就像一個專注于在甲板下面鍋爐房里干活的鍋爐工MacOS,iOS 封閉在蘋果的硬件生態里Android 為了彌補 Linux 的缺點打上了一個厚厚的中間層,不斷在做著妥協GNU Hurd 作為 GNU 項目“最后的組件”一直未能產品化,原因是“微內核消息傳遞機制 debug 太困難”?Unix 的后繼者 Plan 9 于 2002 年發布了最后一個版本,它的余熱隨著作者融入了 Go世界需要新的操作系統