Android 系統中的 eBPF 探索

摘要:本文主要記錄了筆者在 Android Studio Emulator 中測試高版本 Android Kernel 對基於 libbpf 的 CO-RE 技術支持程度的探索過程、結果和遇到的問題。測試採用的方式是在 Android Shell 環境下構建 Debian 環境,並基於此嘗試構建 eunomia-bpf 工具鏈、運行其測試用例。

背景

截至目前(2023-04),Android 還未對 eBPF 程序的動態加載做出較好的支持,無論是以 bcc 爲代表的帶編譯器分發方案,還是基於 btf 和 libbpf 的 CO-RE 方案,都在較大程度上離不開 Linux 環境的支持,無法在 Android 系統上很好地運行。

雖然如此,在 Android 平臺上嘗試 eBPF 也已經有了一些成功案例,除谷歌官方提供的修改 Android.bp 以將 eBPF 程序隨整個系統一同構建並掛載的方案,也有人提出基於 Android 內核構建 Linux 環境進而運行 eBPF 工具鏈的思路,並開發了相關工具。

目前已有的資料,大多基於 adeb/eadb 在 Android 內核基礎上構建 Linux 沙箱,並對 bcc 和 bpftrace 相關工具鏈進行測試,而對 CO-RE 方案的測試工作較少。在 Android 上使用 bcc 工具目前有較多參考資料,如:

其主要思路是利用 chroot 在 Android 內核上運行一個 Debian 鏡像,並在其中構建整個 bcc 工具鏈,從而使用 eBPF 工具。如果想要使用 bpftrace,原理也是類似的。

事實上,高版本的 Android 內核已支持 btf 選項,這意味着 eBPF 領域中新興的 CO-RE 技術也應當能夠運用到基於 Android 內核的 Linux 系統中。本文將基於此對 eunomia-bpf 在模擬器環境下進行測試運行。

eunomia-bpf 是一個結合了 libbpf 和 WebAssembly 技術的開源項目,旨在簡化 eBPF 程序的編寫、編譯和部署。該項目可被視作 CO-RE 的一種實踐方式,其核心依賴是 libbpf,相信對 eunomia-bpf 的測試工作能夠爲其他 CO-RE 方案提供參考。

測試環境

環境搭建

  1. 從 eadb 倉庫 的 releases 頁面獲取 debianfs-amd64-full.tar.gz 作爲 Linux 環境的 rootfs,同時還需要獲取該項目的 assets 目錄來構建環境;

  2. 從 Android Studio 的 Device Manager 配置並啓動 Android Virtual Device;

  3. 通過 Android Studio SDK 的 adb 工具將 debianfs-amd64-full.tar.gzassets 目錄推送到 AVD 中:

  1. 通過 adb 進入 Android shell 環境並獲取 root 權限:
  1. 在 Android shell 中構建並進入 debian 環境:

至此,測試 eBPF 所需的 Linux 環境已經構建完畢。此外,在 Android shell 中(未進入 debian 時)可以通過 zcat /proc/config.gz 並配合 grep 查看內核編譯選項。

目前,eadb 打包的 debian 環境存在 libc 版本低,缺少的工具依賴較多等情況;並且由於內核編譯選項不同,一些 eBPF 功能可能也無法使用。

工具構建

在 debian 環境中將 eunomia-bpf 倉庫 clone 到本地,具體的構建過程,可以參考倉庫的 build.md。在本次測試中,筆者選用了 ecc 編譯生成 package.json 的方式,該工具的構建和使用方式請參考倉庫頁面。

在構建過程中,可能需要自行安裝包括但不限於 curlpkg-configlibssl-dev 等工具。

測試結果

成功案例

bootstrap

運行輸出如下:

TIME     PID     PPID    EXIT_CODE  DURATION_NS  COMM    FILENAME  EXIT_EVENT
09:09:19  10217  479     0          0            sh      /system/bin/sh 0
09:09:19  10217  479     0          0            ps      /system/bin/ps 0
09:09:19  10217  479     0          54352100     ps                1
09:09:21  10219  479     0          0            sh      /system/bin/sh 0
09:09:21  10219  479     0          0            ps      /system/bin/ps 0
09:09:21  10219  479     0          44260900     ps                1

tcpstates

開始監測後在 Linux 環境中通過 wget 下載 Web 頁面:

TIME     SADDR   DADDR   SKADDR  TS_US   DELTA_US  PID     OLDSTATE  NEWSTATE  FAMILY  SPORT   DPORT   TASK
09:07:46  0x4007000200005000000000000f02000a 0x5000000000000f02000a8bc53f77 18446635827774444352 3315344998 0 10115 7 2 2 0 80 wget
09:07:46  0x40020002d98e50003d99f8090f02000a 0xd98e50003d99f8090f02000a8bc53f77 18446635827774444352 3315465870 120872 0 2 1 2 55694 80 swapper/0
09:07:46  0x40010002d98e50003d99f8090f02000a 0xd98e50003d99f8090f02000a8bc53f77 18446635827774444352 3315668799 202929 10115 1 4 2 55694 80 wget
09:07:46  0x40040002d98e50003d99f8090f02000a 0xd98e50003d99f8090f02000a8bc53f77 18446635827774444352 3315670037 1237 0 4 5 2 55694 80 swapper/0
09:07:46  0x40050002000050003d99f8090f02000a 0x50003d99f8090f02000a8bc53f77 18446635827774444352 3315670225 188 0 5 7 2 55694 80 swapper/0
09:07:47  0x400200020000bb01565811650f02000a 0xbb01565811650f02000a6aa0d9ac 18446635828348806592 3316433261 0 2546 2 7 2 49970 443 ChromiumNet
09:07:47  0x400200020000bb01db794a690f02000a 0xbb01db794a690f02000aea2afb8e 18446635827774427776 3316535591 0 1469 2 7 2 37386 443 ChromiumNet

開始檢測後在 Android Studio 模擬界面打開 Chrome 瀏覽器並訪問百度頁面:

TIME     SADDR   DADDR   SKADDR  TS_US   DELTA_US  PID     OLDSTATE  NEWSTATE  FAMILY  SPORT   DPORT   TASK
07:46:58  0x400700020000bb01000000000f02000a 0xbb01000000000f02000aeb6f2270 18446631020066638144 192874641 0 3305 7 2 2 0 443 NetworkService
07:46:58  0x40020002d28abb01494b6ebe0f02000a 0xd28abb01494b6ebe0f02000aeb6f2270 18446631020066638144 192921938 47297 3305 2 1 2 53898 443 NetworkService
07:46:58  0x400700020000bb01000000000f02000a 0xbb01000000000f02000ae7e7e8b7 18446631020132433920 193111426 0 3305 7 2 2 0 443 NetworkService
07:46:58  0x40020002b4a0bb0179ff85e80f02000a 0xb4a0bb0179ff85e80f02000ae7e7e8b7 18446631020132433920 193124670 13244 3305 2 1 2 46240 443 NetworkService
07:46:58  0x40010002b4a0bb0179ff85e80f02000a 0xb4a0bb0179ff85e80f02000ae7e7e8b7 18446631020132433920 193185397 60727 3305 1 4 2 46240 443 NetworkService
07:46:58  0x40040002b4a0bb0179ff85e80f02000a 0xb4a0bb0179ff85e80f02000ae7e7e8b7 18446631020132433920 193186122 724 3305 4 5 2 46240 443 NetworkService
07:46:58  0x400500020000bb0179ff85e80f02000a 0xbb0179ff85e80f02000ae7e7e8b7 18446631020132433920 193186244 122 3305 5 7 2 46240 443 NetworkService
07:46:59  0x40010002d01ebb01d0c52f5c0f02000a 0xd01ebb01d0c52f5c0f02000a51449c27 18446631020103553856 194110884 0 5130 1 8 2 53278 443 ThreadPoolForeg
07:46:59  0x400800020000bb01d0c52f5c0f02000a 0xbb01d0c52f5c0f02000a51449c27 18446631020103553856 194121000 10116 3305 8 7 2 53278 443 NetworkService
07:46:59  0x400700020000bb01000000000f02000a 0xbb01000000000f02000aeb6f2270 18446631020099513920 194603677 0 3305 7 2 2 0 443 NetworkService
07:46:59  0x40020002d28ebb0182dd92990f02000a 0xd28ebb0182dd92990f02000aeb6f2270 18446631020099513920 194649313 45635 12 2 1 2 53902 443 ksoftirqd/0
07:47:00  0x400700020000bb01000000000f02000a 0xbb01000000000f02000a26f6e878 18446631020132433920 195193350 0 3305 7 2 2 0 443 NetworkService
07:47:00  0x40020002ba32bb01e0e09e3a0f02000a 0xba32bb01e0e09e3a0f02000a26f6e878 18446631020132433920 195206992 13642 0 2 1 2 47666 443 swapper/0
07:47:00  0x400700020000bb01000000000f02000a 0xbb01000000000f02000ae7e7e8b7 18446631020132448128 195233125 0 3305 7 2 2 0 443 NetworkService
07:47:00  0x40020002b4a8bb0136cac8dd0f02000a 0xb4a8bb0136cac8dd0f02000ae7e7e8b7 18446631020132448128 195246569 13444 3305 2 1 2 46248 443 NetworkService
07:47:00  0xf02000affff00000000000000000000 0x1aca06cffff00000000000000000000 18446631019225912320 195383897 0 947 7 2 10 0 80 Thread-11
07:47:00  0x40010002b4a8bb0136cac8dd0f02000a 0xb4a8bb0136cac8dd0f02000ae7e7e8b7 18446631020132448128 195421584 175014 3305 1 4 2 46248 443 NetworkService
07:47:00  0x40040002b4a8bb0136cac8dd0f02000a 0xb4a8bb0136cac8dd0f02000ae7e7e8b7 18446631020132448128 195422361 777 3305 4 5 2 46248 443 NetworkService
07:47:00  0x400500020000bb0136cac8dd0f02000a 0xbb0136cac8dd0f02000ae7e7e8b7 18446631020132448128 195422450 88 3305 5 7 2 46248 443 NetworkService
07:47:01  0x400700020000bb01000000000f02000a 0xbb01000000000f02000aea2afb8e 18446631020099528128 196321556 0 1315 7 2 2 0 443 ChromiumNet

一些可能的報錯原因

opensnoop

例如 opensnoop 工具,可以在 Android 上成功構建,但運行報錯:

libbpf: failed to determine tracepoint 'syscalls/sys_enter_open' perf event ID: No such file or directory
libbpf: prog 'tracepoint__syscalls__sys_enter_open': failed to create tracepoint 'syscalls/sys_enter_open' perf event: No such file or directory
libbpf: prog 'tracepoint__syscalls__sys_enter_open': failed to auto-attach: -2
failed to attach skeleton
Error: BpfError("load and attach ebpf program failed")

後經查看發現內核未開啓 CONFIG_FTRACE_SYSCALLS 選項,導致無法使用 syscalls 的 tracepoint。

總結

在 Android shell 中查看內核編譯選項可以發現  CONFIG_DEBUG_INFO_BTF 默認是打開的,在此基礎上 eunomia-bpf 項目提供的 example 已有一些能夠成功運行的案例,例如可以監測 exec 族函數的執行和 tcp 連接的狀態。

對於無法運行的一些,原因主要是以下兩個方面:

  1. 內核編譯選項未支持相關 eBPF 功能;

  2. eadb 打包的 Linux 環境較弱,缺乏必須依賴;

目前在 Android 系統中使用 eBPF 工具基本上仍然需要構建完整的 Linux 運行環境,但 Android 內核本身對 eBPF 的支持已較爲全面,本次測試證明較高版本的 Android 內核支持 BTF 調試信息和依賴 CO-RE 的 eBPF 程序的運行。

Android 系統 eBPF 工具的發展需要官方新特性的加入,目前看來通過 Android APP 直接使用 eBPF 工具需要的工作量較大,同時由於 eBPF 工具需要 root 權限,普通 Android 用戶的使用會面臨較多困難。

參考

1.https://source.android.google.cn/docs/core/architecture/kernel/bpf

2.https://mp.weixin.qq.com/s/mul4n5D3nXThjxuHV7GpMA

3.https://blog.seeflower.dev/archives/138/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Zxj0Oy_p4HIXx1A3qI1kZQ