1. 前言
我們可以使用BPF對(duì)Linux內(nèi)核進(jìn)行跟蹤,收集我們想要的內(nèi)核數(shù)據(jù),從而對(duì)Linux中的程序進(jìn)行分析和調(diào)試。與其它的跟蹤技術(shù)相比,使用BPF的主要優(yōu)點(diǎn)是幾乎可以訪問(wèn)Linux內(nèi)核和應(yīng)用程序的任何信息,同時(shí),BPF對(duì)系統(tǒng)性能影響很小,執(zhí)行效率很高,而且開(kāi)發(fā)人員不需要因?yàn)槭占瘮?shù)據(jù)而修改程序。
本文將介紹保證BPF程序安全的BPF驗(yàn)證器,然后以BPF程序的工具集BCC為例,分享kprobes和tracepoints類型的BPF程序的使用及程序編寫示例。
2. BPF驗(yàn)證器
BPF借助跟蹤探針收集信息并進(jìn)行調(diào)試和分析,與其它依賴于重新編譯內(nèi)核的工具相比,BPF程序的安全性更高。重新編譯內(nèi)核引入外部模塊的方式,可能會(huì)因?yàn)槌绦虻腻e(cuò)誤而產(chǎn)生系統(tǒng)奔潰。BPF程序的驗(yàn)證器會(huì)在BPF程序加載到內(nèi)核之前分析程序,消除這種風(fēng)險(xiǎn)。
BPF驗(yàn)證器執(zhí)行的第一項(xiàng)檢查是對(duì)BPF虛擬機(jī)加載的代碼進(jìn)行靜態(tài)分析,目的是確保程序能夠按照預(yù)期結(jié)束。驗(yàn)證器在進(jìn)行第一項(xiàng)檢查時(shí)所做工作為:
程序不包含控制循環(huán);
程序不會(huì)執(zhí)行超過(guò)內(nèi)核允許的最大指令數(shù);
程序不包含任何無(wú)法到達(dá)的指令;
程序不會(huì)超出程序界限。
BPF驗(yàn)證器執(zhí)行的第二項(xiàng)檢查是對(duì)BPF程序進(jìn)行預(yù)運(yùn)行,所做工作為:
分析BPF程序執(zhí)行的每條指令,確保不會(huì)執(zhí)行無(wú)效指令;
檢查所有內(nèi)存指針是否可以正確訪問(wèn)和引用;
預(yù)運(yùn)行將程序控制流的執(zhí)行結(jié)果通知驗(yàn)證器,確保BPF程序最終都會(huì)執(zhí)行BPF_EXIT指令。
3. 內(nèi)核探針 kprobes
內(nèi)核探針可以跟蹤大多數(shù)內(nèi)核函數(shù),并且系統(tǒng)損耗最小。當(dāng)跟蹤的內(nèi)核函數(shù)被調(diào)用時(shí),附加到探針的BPF代碼將被執(zhí)行,之后內(nèi)核將恢復(fù)正常模式。
3.1 kprobes類BPF程序的優(yōu)缺點(diǎn)
優(yōu)點(diǎn) 動(dòng)態(tài)跟蹤內(nèi)核,可跟蹤的內(nèi)核函數(shù)眾多,能夠提取內(nèi)核絕大部分信息。
缺點(diǎn) 沒(méi)有穩(wěn)定的應(yīng)用程序二進(jìn)制接口,可能隨著內(nèi)核版本的演進(jìn)而更改。
3.2 kprobes
kprobe程序允許在執(zhí)行內(nèi)核函數(shù)之前插入BPF程序。當(dāng)內(nèi)核執(zhí)行到kprobe掛載的內(nèi)核函數(shù)時(shí),先運(yùn)行BPF程序,BPF程序運(yùn)行結(jié)束后,返回繼續(xù)開(kāi)始執(zhí)行內(nèi)核函數(shù)。下面是一個(gè)使用kprobe的bcc程序示例,功能是監(jiān)控內(nèi)核函數(shù)kfree_skb函數(shù),當(dāng)此函數(shù)觸發(fā)時(shí),記錄觸發(fā)它的進(jìn)程pid,進(jìn)程名字和觸發(fā)次數(shù),并打印出觸發(fā)此函數(shù)的進(jìn)程pid,進(jìn)程名字和觸發(fā)次數(shù):
#!/usr/bin/python3
# coding=utf-8
from __future__ import print_function
from bcc import BPF
from time import sleep
# define BPF program
bpf_program = “”“
#include 《uapi/linux/ptrace.h》
struct key_t{
u64 pid;
};
BPF_HASH(counts, struct key_t);
int trace_kfree_skb(struct pt_regs *ctx) {
u64 zero = 0, *val, pid;
pid = bpf_get_current_pid_tgid() 》》 32;
struct key_t key = {};
key.pid = pid;
val = counts.lookup_or_try_init(&key, &zero);
if (val) {
(*val)++;
}
return 0;
}
”“”
def pid_to_comm(pid):
try:
comm = open(“/proc/%s/comm” % pid, “r”).read().rstrip()
return comm
except IOError:
return str(pid)
# load BPF
b = BPF(text=bpf_program)
b.attach_kprobe(event=“kfree_skb”, fn_name=“trace_kfree_skb”)
# header
print(“Tracing kfree_skb.。. Ctrl-C to end.”)
print(“%-10s %-12s %-10s” % (“PID”, “COMM”, “DROP_COUNTS”))
while 1:
sleep(1)
for k, v in sorted(b[“counts”].items(),key = lambda counts: counts[1].value):
print(“%-10d %-12s %-10d” % (k.pid, pid_to_comm(k.pid), v.value))
該bcc程序主要包括兩個(gè)部分,一部分是python語(yǔ)言,一部分是c語(yǔ)言。python部分主要做的工作是BPF程序的加載和操作BPF程序的map,并進(jìn)行數(shù)據(jù)處理。c部分會(huì)被llvm編譯器編譯為BPF字節(jié)碼,經(jīng)過(guò)BPF驗(yàn)證器驗(yàn)證安全后,加載到內(nèi)核中執(zhí)行。python和c中出現(xiàn)的陌生函數(shù)可以查下面這兩個(gè)手冊(cè),在此不再贅述:
python部分遇到的陌生函數(shù)可以查這個(gè)手冊(cè): 點(diǎn)此跳轉(zhuǎn)
c部分中遇到的陌生函數(shù)可以查這個(gè)手冊(cè): 點(diǎn)此跳轉(zhuǎn)
需要說(shuō)明的是,該BPF程序類型是kprobe,它是在這里進(jìn)行程序類型定義的:
b.attach_kprobe(event=“kfree_skb”, fn_name=“trace_kfree_skb”)
b.attach_kprobe()指定了該BPF程序類型為kprobe;
event=“kfree_skb”指定了kprobe掛載的內(nèi)核函數(shù)為kfree_skb;
fn_name=“trace_kfree_skb”指定了當(dāng)檢測(cè)到內(nèi)核函數(shù)kfree_skb時(shí),執(zhí)行程序中的trace_kfree_skb函數(shù);
BPF程序的第一個(gè)參數(shù)總為ctx,該參數(shù)稱為上下文,提供了訪問(wèn)內(nèi)核正在處理的信息,依賴于正在運(yùn)行的BPF程序的類型。CPU將內(nèi)核正在執(zhí)行任務(wù)的不同信息保存在寄存器中,借助內(nèi)核提供的宏可以訪問(wèn)這些寄存器,如PT_REGS_RC。
程序運(yùn)行結(jié)果如下:
3.3 kretprobes
相比于內(nèi)核探針kprobe程序,kretprobe程序是在內(nèi)核函數(shù)有返回值時(shí)插入BPF程序。當(dāng)內(nèi)核執(zhí)行到kretprobe掛載的內(nèi)核函數(shù)時(shí),先執(zhí)行內(nèi)核函數(shù),當(dāng)內(nèi)核函數(shù)返回時(shí)執(zhí)行BPF程序,運(yùn)行結(jié)束后返回。
以上面的BPF程序?yàn)槔粢褂胟retprobe,可以這樣修改:
b.attach_kretprobe(event=“kfree_skb”, fn_name=“trace_kfree_skb”)
b.attach_kretprobe()指定了該BPF程序類型為kretprobe,kretprobe類型的BPF程序?qū)⒃诟櫟膬?nèi)核函數(shù)有返回值時(shí)執(zhí)行BPF程序;
event=“kfree_skb”指定了kretprobe掛載的內(nèi)核函數(shù)為kfree_skb;
fn_name=“trace_kfree_skb”指定了當(dāng)內(nèi)核函數(shù)kfree_skb有返回值時(shí),執(zhí)行程序中的trace_kfree_skb函數(shù);
4. 內(nèi)核靜態(tài)跟蹤點(diǎn) tracepoint
tracepoint是內(nèi)核靜態(tài)跟蹤點(diǎn),它與kprobe類程序的主要區(qū)別在于tracepoint由內(nèi)核開(kāi)發(fā)人員在內(nèi)核中編寫和修改。
4.1 tracepoint 程序的優(yōu)缺點(diǎn)
優(yōu)點(diǎn) 跟蹤點(diǎn)是靜態(tài)的,ABI更穩(wěn)定,不隨內(nèi)核版本的變化而致不可用。
缺點(diǎn) 跟蹤點(diǎn)是內(nèi)核人員添加的,不會(huì)全面涵蓋內(nèi)核的所有子系統(tǒng)。
4.2 tracepoint 可用跟蹤點(diǎn)
系統(tǒng)中所有的跟蹤點(diǎn)都定義在/sys/kernel/debug/traceing/events目錄中:
使用命令perf list 也可以列出可使用的tracepoint點(diǎn):
對(duì)于bcc程序來(lái)說(shuō),以監(jiān)控kfree_skb為例,tracepoint程序可以這樣寫:
b.attach_tracepoint(tp=“skb:kfree_skb”, fn_name=“trace_kfree_skb”)
bcc遵循tracepoint命名約定,首先是指定要跟蹤的子系統(tǒng),這里是“skb:”,然后是子系統(tǒng)中的跟蹤點(diǎn)“kfree_skb”:
5. 總結(jié)
本文主要介紹了保證BPF程序安全的BPF驗(yàn)證器,然后以BPF程序的工具集BCC為例,分享了kprobes和tracepoints類型的BPF程序的使用及程序編寫示例。本文分享的是內(nèi)核跟蹤,那么用戶空間程序該如何跟蹤呢,這將在后面的文章中逐步分享,感謝閱讀。
原文標(biāo)題:梁金榮:使用eBPF追蹤LINUX內(nèi)核
文章出處:【微信公眾號(hào):Linuxer】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
責(zé)任編輯:haq
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1380瀏覽量
40359 -
Linux
+關(guān)注
關(guān)注
87文章
11336瀏覽量
210095
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
利用西門子EDA工具進(jìn)行SafeSPI功能安全驗(yàn)證
![利用西門子EDA工具進(jìn)行SafeSPI功能<b class='flag-5'>安全</b><b class='flag-5'>驗(yàn)證</b>](https://file1.elecfans.com/web3/M00/06/5F/wKgZPGeKCaaAGfXnAAAOij9ptiQ569.png)
如何進(jìn)行電子連接器的測(cè)試與驗(yàn)證
智能安全配電裝置在臨時(shí)展會(huì)場(chǎng)所中如何保證用電安全
![智能<b class='flag-5'>安全</b>配電裝置在臨時(shí)展會(huì)場(chǎng)所中如何<b class='flag-5'>保證</b>用電<b class='flag-5'>安全</b>](https://file1.elecfans.com//web3/M00/01/F5/wKgZPGdaObOANFB6AAA1fLMIQFA428.jpg)
電子設(shè)備濾波器的種類 影響水質(zhì)的濾波器類型
Parker派克防爆電機(jī)在實(shí)際應(yīng)用中的安全性能如何保證?
![Parker派克防爆電機(jī)在實(shí)際應(yīng)用中的<b class='flag-5'>安全</b>性能如何<b class='flag-5'>保證</b>?](https://file1.elecfans.com/web2/M00/0C/F4/wKgaomc-k26AOmP8AAB6uhl1X5U700.png)
是德科技助力三星電子驗(yàn)證FiRa 2.0安全測(cè)距測(cè)試用例
AWR1843 DMM接口介紹和驗(yàn)證測(cè)試
![AWR1843 DMM接口<b class='flag-5'>介紹</b>和<b class='flag-5'>驗(yàn)證</b>測(cè)試](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
濾波電路的四種類型是什么
西門子推出Solido IP驗(yàn)證套件,為下一代IC設(shè)計(jì)提供端到端的芯片質(zhì)量保證
請(qǐng)問(wèn)NFC數(shù)據(jù)傳輸如何保證數(shù)據(jù)安全?
奇瑞汽車股份有限公司發(fā)布“數(shù)據(jù)驗(yàn)證方法、設(shè)備、服務(wù)器及存儲(chǔ)介質(zhì)”
![奇瑞汽車股份有限公司發(fā)布“數(shù)據(jù)<b class='flag-5'>驗(yàn)證</b>方法、設(shè)備、服務(wù)<b class='flag-5'>器</b>及存儲(chǔ)介質(zhì)”](https://file1.elecfans.com/web2/M00/C5/EB/wKgaomX5Ul2AIWWkAADfXuxlQl4802.png)
評(píng)論