BPF的理解
當我需要使用 擷取一些數據包
tcpdump
時,我使用如下命令:tcpdump -i eth0 "dst host 192.168.1.0"
我一直認為dst 主機 192.168.1.0部分稱為 BPF,Berkeley Packet Filter。對我來說,這是一種過濾網路數據包的簡單語言。但是今天我的室友告訴我,BPF 可以用來擷取性能資訊。根據他的描述,它就像
perfmon
Windows上的工具。這是真的嗎?它與我在問題開頭提到的 BPF 相同嗎?
什麼是 BPF?
BPF(或更常見的擴展版本,eBPF)是一種最初專門用於過濾數據包的語言,但它的功能遠不止於此。正如您所指出的,在 Linux 上,它可以用於許多其他事情,包括用於安全性的系統呼叫過濾器和性能監控。雖然 Windows 確實添加了 eBPF 支持,但這不是 Windows
perfmon
實用程序使用的。Windows 僅添加了對依賴於作業系統對 eBPF 支持的非 Windows 實用程序的兼容性支持。eBPF 程序不在使用者空間中執行。相反,應用程序創建一個 eBPF 程序並將其發送到核心,核心將執行它。它實際上是以解釋器的形式在核心中實現的虛擬處理器的機器程式碼,儘管它也可以使用JIT 編譯來顯著提高性能。該程序可以訪問核心中的一些基本介面,包括與性能和網路相關的介面。eBPF 程序然後與核心通信以向其提供計算結果(例如丟棄數據包)。
eBPF 程序的限制
為了防止拒絕服務攻擊或意外崩潰,核心在編譯之前首先驗證程式碼。在執行之前,程式碼需要經過幾個重要的檢查:
結果是驗證者必須能夠證明 eBPF 程序停止。當然,它還沒有找到解決停止問題的方法,這就是為什麼它只接受它知道會停止的程序的原因。為此,它將程序表示為有向無環圖。除此之外,它還試圖通過防止指針的實際值被洩露,同時仍然允許對其執行有限的操作來防止資訊洩漏和越界記憶體訪問:
- 指針不能作為可檢查的值進行比較、儲存或返回。
- 指針運算只能針對標量(不是從指針派生的值)進行。
- 沒有指針算法可以導致指向指定的記憶體映射之外。
驗證器相當複雜,而且做得更多,儘管它本身就是嚴重 安全 漏洞的根源,至少在沒有為非特權使用者禁用
bpf(2)
系統呼叫的情況下。查看程式碼
您的
dst host 192.168.1.0
命令組件不是 BPF。這只是tcpdump
. 但是,您給它的命令用於生成 BPF 程序,然後將其發送到核心。請注意,在這種情況下使用的不是 eBPF,而是較舊的 cBPF。兩者之間有幾個重要的區別。該-d
標誌可用於查看 cBPF 程式碼:# tcpdump -i eth0 "dst host 192.168.1.0" -d (000) ldh [12] (001) jeq #0x800 jt 2 jf 4 (002) ld [30] (003) jeq #0xc0a80100 jt 8 jf 9 (004) jeq #0x806 jt 6 jf 5 (005) jeq #0x8035 jt 6 jf 9 (006) ld [38] (007) jeq #0xc0a80100 jt 8 jf 9 (008) ret #262144 (009) ret #0
更複雜的過濾器會導致更複雜的字節碼。嘗試手冊頁中的一些範例並附加
-d
標誌以查看將哪些字節碼載入到核心中。為了了解如何閱讀反彙編,請查看BPF 過濾器文件。如果你正在閱讀 eBPF 程序,你應該看看虛擬 CPU 的eBPF 指令集。我強烈建議您閱讀這篇文章以了解如何
tcpdump
使用 cBPF。讀完之後,請閱讀這篇關於如何
tcpdump
將表達式轉換為字節碼的說明。如果您想了解有關它的所有內容,可以隨時查看原始碼!