1 eBPF簡介
eBPF(extended Berkeley Packet Filter)是一種革命性的內(nèi)核技術(shù),它允許開發(fā)人員編寫可動態(tài)加載到內(nèi)核中的自定義代碼,從而改變內(nèi)核的運行方式。(如果你對內(nèi)核還不太了解,不用擔心,本章很快就會講到)。
這使得新一代高性能網(wǎng)絡(luò)、可觀察性和安全工具成為可能。而且,正如你將看到的,如果你想用這些基于eBPF的工具來檢測應(yīng)用程序,你不需要以任何方式修改或重新配置應(yīng)用程序,這要歸功于eBPF在內(nèi)核中的有利位置。
使用 eBPF 可以做的事情包括
- 對系統(tǒng)的幾乎所有方面進行性能跟蹤
- 具有內(nèi)置可見性的高性能網(wǎng)絡(luò)
- 檢測和(可選)預(yù)防惡意活動
1.1 eBPF的起源:伯克利數(shù)據(jù)包過濾器
我們今天所說的"eBPF"起源于BSD包過濾器,1993年由勞倫斯伯克利國家實驗室的Steven McCanne和Van Jacobson撰寫的一篇論文首次對其進行了描述。這篇論文討論了一種可以運行過濾器的偽機器,過濾器是為決定接受或拒絕網(wǎng)絡(luò)數(shù)據(jù)包而編寫的程序。這些程序是用BPF指令集編寫的,這是一套32位指令的通用指令集,與匯編語言非常相似。下面是直接摘自該論文的一個示例:
ldh [12]
jeq #ETHERTYPE IP, L1, L2
L1: ret #TRUE
L2: ret #0
這一小段代碼過濾掉了不是互聯(lián)網(wǎng)協(xié)議(IP)數(shù)據(jù)包的數(shù)據(jù)包。該過濾器的輸入是一個以太網(wǎng)數(shù)據(jù)包,第一條指令 (ldh) 從數(shù)據(jù)包的第12個字節(jié)開始加載一個2字節(jié)的值。在下一條指令(jeq)中,該值與代表IP數(shù)據(jù)包的值進行比較。如果匹配,執(zhí)行將跳轉(zhuǎn)到標有L1的指令,并通過返回非零值(此處標識為 #TRUE)來接受數(shù)據(jù)包。如果不匹配,則該數(shù)據(jù)包不是IP數(shù)據(jù)包,會被拒絕,返回0。
你可以根據(jù)數(shù)據(jù)包的其他方面做出更復雜的決定,你也可以在論文中找到更復雜的過濾程序的例子。重要的是,過濾器的作者可以編寫自己的定制程序在內(nèi)核中執(zhí)行,這就是eBPF的核心功能。
BPF是"伯克利數(shù)據(jù)包過濾器"(Berkeley Packet Filter)的縮寫,于1997年首次引入Linux,內(nèi)核版本為2.1.75,當時它被用在tcpdump工具中,作為捕獲要追蹤的數(shù)據(jù)包的有效方法。
2012年,內(nèi)核3.5版本引入了seccomp-bpf。這使得BPF程序可以決定是否允許或拒絕用戶空間應(yīng)用程序進行系統(tǒng)調(diào)用。我們將在第10章對此進行更詳細的探討。這是BPF從狹義的數(shù)據(jù)包過濾發(fā)展到今天的通用平臺的第一步。從這時起,BPF名稱中的 "包過濾 "一詞就不再那么有意義了!
1.2 從BPF到eBPF
從2014年內(nèi)核3.18版開始,BPF演進為我們所說的"擴展BPF"。這涉及幾個重大變化:
- 為了在64位機器上更高效,BPF指令集進行了全面修改,解釋器也完全重寫。
- 引入了eBPF映射,這是一種數(shù)據(jù)結(jié)構(gòu),BPF程序和用戶空間應(yīng)用程序都可以訪問,從而可以在它們之間共享信息。你將在第2章了解映射。
- 增加了bpf()系統(tǒng)調(diào)用,這樣用戶空間程序就可以與內(nèi)核中的eBPF程序交互。
- 添加了幾個 BPF 輔助函數(shù)。
- 添加了eBPF校驗器,以確保eBPF程序可以安全運行
這為eBPF奠定了基礎(chǔ),但開發(fā)工作并未因此放緩!從那時起,eBPF有了長足的發(fā)展。
1.3 eBPF向生產(chǎn)系統(tǒng)的演進
自2005年以來,Linux內(nèi)核中就存在一種名為kprobes(內(nèi)核探測)的功能,允許在內(nèi)核代碼中的幾乎所有指令上設(shè)置陷阱。開發(fā)人員可以編寫內(nèi)核模塊,將函數(shù)附加到kprobes上,用于調(diào)試或性能測量。
2015年,kprobes增加了附加eBPF程序的功能,這是Linux系統(tǒng)追蹤方式革命的起點。與此同時,內(nèi)核網(wǎng)絡(luò)堆棧中開始添加鉤子,允許eBPF程序處理網(wǎng)絡(luò)功能的更多方面。
到2016年,基于eBPF的工具已被用于生產(chǎn)系統(tǒng)。布蘭登-格雷格(Brendan Gregg)在Netflix的跟蹤工作在基礎(chǔ)設(shè)施和運營圈廣為人知,他關(guān)于eBPF"為Linux帶來超級能力"的說法也廣為人知。同年Cilium項目發(fā)布,這是首個在容器環(huán)境中使用eBPF替換整個數(shù)據(jù)路徑的網(wǎng)絡(luò)項目。
次年Facebook(現(xiàn)為 Meta將Katran列為開源項目。Katran作為第4層負載平衡器,滿足了Facebook對高度可擴展和快速解決方案的需求。自2017年以來,F(xiàn)acebook.com的每一個數(shù)據(jù)包都經(jīng)過eBPF/XDP.4。
2018年,eBPF成為Linux內(nèi)核中的一個獨立子系統(tǒng),其維護者是來自Isovalent的Daniel Borkmann和來自Meta的Alexei Starovoitov(后來,同樣來自Meta的Andrii Nakryiko也加入了他們的行列)。同年BPF類型格式(BTF BPF Type Format)問世,它使eBPF程序更具可移植性。
2020年,LSM BPF正式推出,eBPF程序可以連接到Linux 安全模塊(LSM Linux Security Module)內(nèi)核接口。這表明 eBPF的第三個主要用例已經(jīng)確定:很明顯,除了網(wǎng)絡(luò)和可觀察性之外,eBPF還是安全工具的絕佳平臺。
多年來,由于300多名內(nèi)核開發(fā)人員以及相關(guān)用戶空間工具(如 bpftool,我們將在第 3 章中介紹)、編譯器和編程語言庫的眾多貢獻者的努力,eBPF的能力得到了大幅提升。程序曾被限制在4,096條指令以內(nèi),但現(xiàn)在這一限制已增加到100萬條驗證指令,而且由于支持尾調(diào)用和函數(shù)調(diào)用,這一限制實際上已變得無關(guān)緊要。
阿列克謝-斯塔羅沃伊托夫(Alexei Starovoitov)從軟件定義網(wǎng)絡(luò)(SDN)的根源出發(fā),對BPF的歷史進行了精彩的介紹。在這次演講中,他討論了讓內(nèi)核接受早期eBPF補丁所使用的策略,并透露eBPF的正式生日是2014年9月26日,這一天標志著第一套涵蓋驗證器、BPF系統(tǒng)調(diào)用和地圖的補丁被接受。
Daniel Borkmann還討論了BPF的歷史及其支持聯(lián)網(wǎng)和跟蹤功能的演變。我強烈推薦他的演講"eBPF和Kubernetes: 擴展微服務(wù)的小助手",其中充滿了有趣的信息。
1.4 命名很難
eBPF的應(yīng)用范圍遠遠超出了數(shù)據(jù)包過濾的范疇,以至于這個縮寫現(xiàn)在基本上毫無意義,它已經(jīng)成為一個獨立的術(shù)語。由于目前廣泛使用的Linux內(nèi)核都支持"擴展"部分,eBPF和BPF這兩個術(shù)語在很大程度上可以互換使用。在內(nèi)核源代碼和eBPF編程中,常用術(shù)語是BPF。例如,我們將在第4章中看到,與eBPF交互的系統(tǒng)調(diào)用是bpf(),輔助函數(shù)以bpf_開頭,不同類型的(e)BPF 程序以BPF_PROG_TYPE 開頭。在內(nèi)核社區(qū)之外,"eBPF"這個名字似乎已經(jīng)深入人心,例如社區(qū)網(wǎng)站ebpf.io和eBPF基金會的名稱。
1.5 Linux內(nèi)核
要理解eBPF,你需要牢固掌握Linux內(nèi)核和用戶空間之間的區(qū)別。我在"什么是 eBPF?"報告中對此進行了闡述,并在接下來的幾段中對部分內(nèi)容進行了改編。
Linux內(nèi)核是應(yīng)用程序與運行硬件之間的軟件層。應(yīng)用程序運行在稱為用戶空間的非特權(quán)層中,不能直接訪問硬件。相反,應(yīng)用程序會使用系統(tǒng)調(diào)用(syscall)接口發(fā)出請求,要求內(nèi)核代表它采取行動。硬件訪問可能涉及讀寫文件、發(fā)送或接收網(wǎng)絡(luò)流量,甚至只是訪問內(nèi)存。內(nèi)核還負責協(xié)調(diào)并發(fā)進程,使許多應(yīng)用程序能同時運行。如圖所示。
作為應(yīng)用程序開發(fā)人員,我們通常不會直接使用系統(tǒng)調(diào)用接口,因為編程語言為我們提供了更容易編程的高級抽象和標準庫接口。因此,很多人都不知道內(nèi)核在我們程序運行時做了多少工作。如果你想了解內(nèi)核被調(diào)用的頻率,可以使用strace工具來顯示應(yīng)用程序進行的所有系統(tǒng)調(diào)用。
$ strace -c echo "hello"
hello
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 1 read
0.00 0.000000 0 1 write
0.00 0.000000 0 5 close
0.00 0.000000 0 9 mmap
0.00 0.000000 0 3 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 3 brk
0.00 0.000000 0 4 pread64
0.00 0.000000 0 1 1 access
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 1 arch_prctl
0.00 0.000000 0 1 set_tid_address
0.00 0.000000 0 3 openat
0.00 0.000000 0 4 newfstatat
0.00 0.000000 0 1 set_robust_list
0.00 0.000000 0 1 prlimit64
0.00 0.000000 0 1 getrandom
0.00 0.000000 0 1 rseq
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 0 43 2 total
由于應(yīng)用程序?qū)?nèi)核的依賴程度如此之高,這意味著如果我們能觀察到應(yīng)用程序與內(nèi)核的交互,就能了解到應(yīng)用程序的行為方式。有了eBPF,我們就可以在內(nèi)核中添加儀器,從而獲得這些信息。
例如如果能攔截打開文件的系統(tǒng)調(diào)用,就能準確了解應(yīng)用程序訪問了哪些文件。但如何進行攔截呢?讓我們考慮一下,如果我們想修改內(nèi)核,添加新代碼,以便在調(diào)用系統(tǒng)調(diào)用時創(chuàng)建某種輸出,會涉及到哪些問題。
1.6 為內(nèi)核添加新功能
對任何代碼庫進行修改都需要對現(xiàn)有代碼有一定程度的熟悉,所以除非你已經(jīng)是內(nèi)核開發(fā)人員,否則這很可能是一個挑戰(zhàn)。
此外,如果你想把你的改動貢獻給上游,你將面臨一個不純粹是技術(shù)上的挑戰(zhàn)。Linux是一種通用操作系統(tǒng),可用于各種環(huán)境和情況。這意味著,如果你想讓你的改動成為Linux正式版本的一部分,就不僅僅是寫出能正常運行的代碼那么簡單了。這些代碼必須得到社區(qū)(更具體地說是Linux的創(chuàng)建者和主要開發(fā)者Linus Torvalds)的認可,被認為是對所有人都有利的改變。這并不是必然的,在提交的內(nèi)核補丁中,只有三分之一被接受。
假設(shè)你已經(jīng)找到了攔截打開文件的系統(tǒng)調(diào)用的好技術(shù)方法。經(jīng)過幾個月的討論和艱苦的開發(fā)工作,我們假設(shè)內(nèi)核接受了這一修改。好極了!但要多久才能在每個人的機器上實現(xiàn)呢?
Linux內(nèi)核每兩三個月就會發(fā)布一個新版本,但即使某項改動已被納入其中一個版本,它距離在大多數(shù)人的生產(chǎn)環(huán)境中使用仍有一段時間。這是因為我們大多數(shù)人并不直接使用Linux內(nèi)核,而是使用Debian、Red Hat、Alpine和Ubuntu等Linux發(fā)行版,這些發(fā)行版將Linux內(nèi)核與其他各種組件打包在一起。你很可能會發(fā)現(xiàn),你最喜歡的發(fā)行版使用的內(nèi)核已經(jīng)是幾年前的版本了。
參考資料
- 軟件測試精品書籍文檔下載持續(xù)更新 https://github.com/china-testing/python-testing-examples 請點贊,謝謝!
- 本文涉及的python測試開發(fā)庫 謝謝點贊! https://github.com/china-testing/python_cn_resouce
- python精品書籍下載 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- Linux精品書籍下載 https://www.cnblogs.com/testing-/p/17438558.html
1.7 內(nèi)核模塊
如果你不想等上好幾年才能把你的改動加入內(nèi)核,還有另一種選擇。Linux內(nèi)核是為接受內(nèi)核模塊而設(shè)計的,內(nèi)核模塊可以按需加載和卸載。如果你想改變或擴展內(nèi)核行為,編寫模塊無疑是一種方法。內(nèi)核模塊可以獨立于Linux內(nèi)核的正式版本發(fā)布,供其他人使用,因此不必被上游的主要代碼庫所接受。
這里最大的挑戰(zhàn)在于,這仍然是完全的內(nèi)核編程。用戶在使用內(nèi)核模塊時歷來非常謹慎,原因很簡單:如果內(nèi)核代碼崩潰,就會導致機器及其上運行的所有程序癱瘓。用戶如何確信內(nèi)核模塊可以安全運行?
安全運行"并不僅僅意味著不會崩潰--用戶想知道內(nèi)核模塊從安全角度來看是否安全。它是否包含攻擊者可能利用的漏洞?我們是否相信模塊作者不會在模塊中加入惡意代碼?由于內(nèi)核是特權(quán)代碼,它可以訪問機器上的一切,包括所有數(shù)據(jù),因此內(nèi)核中的惡意代碼會引起嚴重關(guān)切。這一點也適用于內(nèi)核模塊。
內(nèi)核的安全性是Linux發(fā)行版需要很長時間才能發(fā)布新版本的一個重要原因。如果其他人已經(jīng)在各種環(huán)境下運行了數(shù)月或數(shù)年的內(nèi)核版本,那么問題應(yīng)該已經(jīng)被清除了。發(fā)行版的維護者就可以確信,他們提供給用戶/客戶的內(nèi)核是經(jīng)過加固的,也就是說,運行起來是安全的。
eBPF提供了一種非常不同的安全方法:eBPF校驗器,它可以確保只有在運行安全的情況下才加載eBPF程序--它不會讓機器崩潰或鎖定在硬循環(huán)中,也不會讓數(shù)據(jù)泄露。
1.7 動態(tài)加載eBPF程序
eBPF程序可以動態(tài)加載到內(nèi)核或從內(nèi)核中移除。一旦程序被附加到事件中,無論事件發(fā)生的原因是什么,它們都會被該事件觸發(fā)。例如,如果將一個程序附加到打開文件的系統(tǒng)調(diào)用上,那么只要有進程試圖打開文件,該程序就會被觸發(fā)。至于程序加載時該進程是否已在運行,則無關(guān)緊要。與升級內(nèi)核,然后必須重啟機器才能使用新功能相比,這是一個巨大的優(yōu)勢。
這也是使用eBPF的可觀察性或安全工具的一大優(yōu)勢--它可以立即查看機器上發(fā)生的一切。在運行容器的環(huán)境中,這包括對容器內(nèi)以及主機上運行的所有進程的可見性。本章稍后我將深入探討這對云原生部署的影響。
此外,如圖所示,人們可以通過eBPF快速創(chuàng)建新的內(nèi)核功能,而不需要其他所有Linux用戶都接受相同的更改。
1.8 eBPF程序的高性能
eBPF程序是一種非常高效的添加方式。一旦加載并經(jīng)過JIT編譯,程序就能以本地機器指令的形式在CPU上運行。此外,處理每個事件都無需在內(nèi)核和用戶空間之間轉(zhuǎn)換(這是一項昂貴的操作)。
2018年的論文介紹了eXpress Data Path(XDP),其中包括eBPF在網(wǎng)絡(luò)中實現(xiàn)性能改進的一些示例。例如,與普通Linux 內(nèi)核實現(xiàn)相比,在XDP中實施路由"可將性能提高2.5倍",而在負載平衡方面,"XDP比IPVS的性能提高了4.3倍"。
在性能跟蹤和安全可觀察性方面,eBPF的另一個優(yōu)勢是可以在內(nèi)核中過濾相關(guān)事件,然后再將其發(fā)送到用戶空間。畢竟,只過濾某些網(wǎng)絡(luò)數(shù)據(jù)包才是最初BPF實現(xiàn)的重點。如今eBPF程序可以收集系統(tǒng)中各種事件的信息,并可以使用復雜、定制的程序過濾器,只向用戶空間發(fā)送相關(guān)的信息子集。
1.9 云原生環(huán)境中的eBPF
如今許多企業(yè)都不選擇直接在服務(wù)器上執(zhí)行程序來運行應(yīng)用程序。取而代之的是,許多組織使用云原生方法:容器、Kubernetes或ECS等編排器,或Lambda、云函數(shù)、Fargate等無服務(wù)器方法。這些方法都使用自動化來選擇每個工作負載運行的服務(wù)器;在無服務(wù)器中,我們甚至不知道每個工作負載運行的服務(wù)器是什么。
盡管如此,還是有服務(wù)器參與其中,而且每臺服務(wù)器(無論是虛擬機還是裸機)都運行著內(nèi)核。在容器中運行應(yīng)用時,如果它們運行在同一臺(虛擬)機器上,就會共享同一個內(nèi)核。在Kubernetes環(huán)境中,這意味著某個節(jié)點上所有pod中的所有容器都在使用同一個內(nèi)核。當我們在內(nèi)核中加入eBPF程序時,該節(jié)點上的所有容器化工作負載對這些eBPF程序都是可見的,如圖所示。
節(jié)點上所有進程的可見性,再加上動態(tài)加載eBPF程序的能力,讓我們在云原生計算中真正擁有了基于eBPF工具的超強能力:
- 我們不需要改變應(yīng)用程序,甚至不需要改變它們的配置方式,就能使用eBPF工具對它們進行檢測。
- 只要將其加載到內(nèi)核并附加到事件中,eBPF 程序就可以開始觀察已有的應(yīng)用程序進程。
這與側(cè)卡(sidecar)模式形成了鮮明對比,后者被用于在Kubernetes應(yīng)用程序中添加日志、跟蹤、安全和服務(wù)網(wǎng)格功能等功能。在"側(cè)卡"方法中,儀器以容器的形式運行,并被"注入"到每個應(yīng)用程序pod中。這一過程包括修改定義應(yīng)用程序pod的 YAML,并添加側(cè)卡容器的定義。這種方法當然比在應(yīng)用程序pod更方便。
sidecar方法也有一些缺點:
- 必須重新啟動應(yīng)用程序 pod 才能添加側(cè)載。
- 必須修改應(yīng)用程序 YAML。這通常是一個自動化流程,但如果出了差錯,側(cè)卡就不會被添加,這意味著pod不會被檢測到。例如,一個部署可能會被注釋為表明接納控制器應(yīng)將邊卡YAML添加到該部署的pod規(guī)范中。但是,如果部署沒有正確標注,側(cè)卡就不會被添加,因此儀器也就無法看到它。
- 當pod中有多個容器時,它們可能會在不同時間達到就緒狀態(tài),其順序可能無法預(yù)測。Pod的啟動時間可能會因注入側(cè)車而大大減慢,更有甚者,可能會導致競賽條件或其他不穩(wěn)定因素。例如,Open Service Mesh文檔描述了應(yīng)用容器在Envoy代理容器準備就緒之前,如何避免所有流量被丟棄。當服務(wù)網(wǎng)格等網(wǎng)絡(luò)功能作為側(cè)載實現(xiàn)時,必然意味著進出應(yīng)用容器的所有流量都必須通過內(nèi)核中的網(wǎng)絡(luò)堆棧才能到達網(wǎng)絡(luò)代理容器,從而增加了流量的延遲;如圖所示。
所有這些問題都是旁路模型的固有問題。幸運的是,現(xiàn)在有了eBPF作為平臺,我們就有了可以避免這些問題的新模式。此外,由于基于eBPF的工具可以看到(虛擬)機器上發(fā)生的一切,因此壞人更難躲避。例如,如果攻擊者設(shè)法在您的一臺主機上部署了加密貨幣挖礦應(yīng)用程序,他們可能不會使用您在應(yīng)用程序工作負載上使用的側(cè)卡對其進行檢測。如果你依賴基于邊卡的安全工具來防止應(yīng)用程序進行意外的網(wǎng)絡(luò)連接,那么如果沒有注入邊卡,該工具是不會發(fā)現(xiàn)挖礦應(yīng)用程序連接到其礦池的。相比之下,eBPF實現(xiàn)的網(wǎng)絡(luò)安全功能可以監(jiān)控主機上的所有流量,因此可以輕松阻止這種加密貨幣挖礦操作。出于安全原因丟棄網(wǎng)絡(luò)數(shù)據(jù)包的功能。
1.10 小結(jié)
希望本章能讓你了解eBPF作為平臺如此強大的原因。它允許我們改變內(nèi)核的行為,為我們提供了構(gòu)建定制工具或自定義策略的靈活性?;趀BPF的工具可以觀察內(nèi)核中的任何事件,從而觀察(虛擬)機器上運行的所有應(yīng)用程序,無論它們是否被容器化。
到目前為止,我們已經(jīng)在相對概念化的層面上討論了eBPF。在下一章中,我們將更具體地探討基于eBPF的應(yīng)用程序的各個組成部分。
9 值得慶幸的是,對現(xiàn)有功能的安全補丁提供得更快。文章來源:http://www.zghlxwxcb.cn/news/detail-710762.html
10 H?iland-J?rgensen T、Brouer JD、Borkmann D 等:《eXpress 數(shù)據(jù)路徑:操作系統(tǒng)內(nèi)核中的快速可編程數(shù)據(jù)包處理》。第 14 屆新興網(wǎng)絡(luò)實驗與技術(shù)國際會議(CoNEXT '18)論文集》。計算機械協(xié)會;2018:54-66.文章來源地址http://www.zghlxwxcb.cn/news/detail-710762.html
到了這里,關(guān)于eBPF(Linux內(nèi)核安全方案)教程1簡介的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!