日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

【eBPF-01】初见:基于 BCC 框架的第一个 eBPF 程序

發(fā)布時(shí)間:2023/12/29 windows 40 coder
生活随笔 收集整理的這篇文章主要介紹了 【eBPF-01】初见:基于 BCC 框架的第一个 eBPF 程序 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

閑言少敘,本文記錄了如何零基礎(chǔ)通過(guò) BCC 框架,入門(mén) eBPF 程序的開(kāi)發(fā),并實(shí)現(xiàn)幾個(gè)簡(jiǎn)易的程序。

有關(guān) eBPF 的介紹,網(wǎng)絡(luò)上的資料有很多,本文暫且先不深入討論,后面會(huì)再出一篇文章詳細(xì)分析其原理和功能。

我們目前只需要知道,eBPF 實(shí)際上是一種過(guò)濾器,這種過(guò)濾器幾乎可以插入內(nèi)核源碼的任意的流程和環(huán)節(jié)中,實(shí)現(xiàn)自定義的邏輯。由于 eBPF 自身的若干限制,使它最常見(jiàn)的用法是,附著在內(nèi)核某些關(guān)鍵流程上,抓取一些關(guān)鍵數(shù)據(jù),用于監(jiān)控、統(tǒng)計(jì)和分析。

1 一個(gè)簡(jiǎn)單的例子

下面是一個(gè)簡(jiǎn)單的例子,我想實(shí)現(xiàn)一個(gè)程序,用來(lái)實(shí)時(shí)監(jiān)控內(nèi)核可執(zhí)行文件(ELF)的加載。這個(gè)程序運(yùn)行如下:

如圖所示,每當(dāng)有一個(gè) ELF 文件被加載時(shí),可以顯示這個(gè) ELF 加載時(shí)的一些內(nèi)核信息,如:加載時(shí)間、加載進(jìn)程名、加載進(jìn)程 PID、以及被加載的 ELF 文件名。

這個(gè)程序就是基于 eBPF 實(shí)現(xiàn)的。接下來(lái),我們就逐步了解一下,如何通過(guò) BCC 框架,成功編寫(xiě)運(yùn)行這個(gè) eBPF 程序。

2 BCC 框架

進(jìn)行 eBPF 編程,有很多種方式。例如:

1)libbpf:使用原生的 C 語(yǔ)言,基于 libbpf 庫(kù),編寫(xiě)用戶態(tài)程序和 BPF 程序的加載;

2)libbpf-bootstrap:使用 libbpf-bootstrap 腳手架,輕而易舉地編寫(xiě) BPF 程序;

3)BCC:使用 BCC 框架,基于 python/Lua 腳本,實(shí)現(xiàn) BPF 和用戶態(tài)程序,上手容易,簡(jiǎn)化了 BPF 的開(kāi)發(fā);

4)Bpftrace:一種用于eBPF的高級(jí)跟蹤語(yǔ)言,使用LLVM作為后端,將腳本編譯為BPF字節(jié)碼;

5)eunomia-bpf:較新的基于 libbpf 的 CO-RE 輕量級(jí)框架,簡(jiǎn)化了 eBPF 程序的開(kāi)發(fā)、構(gòu)建、分發(fā)、運(yùn)行

選擇 BCC 框架作為第一個(gè)學(xué)習(xí)的框架的原因是,BCC 封裝較好,上手容易,用戶態(tài)和內(nèi)核態(tài)的區(qū)分明顯,用戶態(tài)支持 Python,易于理解。

安裝過(guò)程很簡(jiǎn)單,直接通過(guò)對(duì)應(yīng)軟件包管理器安裝即可。

本文的實(shí)驗(yàn)環(huán)境是 REHL 8(x86),因此,執(zhí)行 yum 命令來(lái)安裝。

yum install -y python3-bcc.x86_64

2.1 編寫(xiě) hello world

安裝好 Python BCC 依賴包后,在工作目錄中創(chuàng)建一個(gè) py 腳本文件,輸入以下代碼:

#!/bin/python3
from bcc import BPF

bpf_code = '''
int kprobe__sys_clone(void *ctx) {
    bpf_trace_printk("Hello world!\\n");
    return 0;
}
'''

b = BPF(text=bpf_code)
b.trace_print()

運(yùn)行這個(gè) py 腳本,當(dāng)有進(jìn)程被創(chuàng)建時(shí),打印一條 Hello world 記錄。

這就是一個(gè)最簡(jiǎn)單的 eBPF 程序。

3 擴(kuò)展這個(gè) Hello world

上面給出的這個(gè)程序結(jié)構(gòu)很清晰,分為兩個(gè)部分:以 C 編寫(xiě)的 eBPF 內(nèi)核態(tài)程序,和以 Python 編寫(xiě)的用戶態(tài)控制程序。eBPF 內(nèi)核態(tài)程序被 BCC 框架編譯到內(nèi)核中,等待預(yù)設(shè)的觸發(fā)條件,——這里是 sys_clone 即進(jìn)程創(chuàng)建的系統(tǒng)調(diào)用,eBPF 被執(zhí)行時(shí),將會(huì)返回?cái)?shù)據(jù)給用戶態(tài)控制程序。

流程可以描述如下:

接下來(lái)我們對(duì)這個(gè)程序進(jìn)行億點(diǎn)點(diǎn)擴(kuò)展,讓它變得規(guī)范一些,代碼如下:

#!/bin/python3
from bcc import BPF
from bcc.utils import printb

# define BPF program
prog = """
int hello(void *ctx) {
    bpf_trace_printk("Hello, World!\\n");
    return 0;
}
"""

# load BPF program
b = BPF(text=prog)
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="hello")

# header
print("%-18s %-16s %-6s %s" % ("TIME(s)", "COMM", "PID", "MESSAGE"))

# format output
while 1:
    try:
        (task, pid, cpu, flags, ts, msg) = b.trace_fields()
    except ValueError:
        continue
    except KeyboardInterrupt:
        exit()
    printb(b"%-18.9f %-16s %-6d %s" % (ts, task, pid, msg))

在這段程序中,我們做出了以下幾點(diǎn)變動(dòng):

1)使用 event=b.get_syscall_fnname("clone") 來(lái)綁定內(nèi)核中的系統(tǒng)調(diào)用監(jiān)視點(diǎn),這里綁定了 clone 進(jìn)程創(chuàng)建調(diào)用;使用 fn_name="hello" 綁定了 eBPF 程序中的自定義檢查邏輯;使用 b.attach_kprobe() 函數(shù)將 eBPF 程序加載到內(nèi)核中。

2)使用 b.trace_fields() 函數(shù)按字段的形式,接收內(nèi)核 eBPF 程序傳出的輸出信息;其中,msgbpf_trace_printk() 的打印信息。

3)通過(guò)無(wú)限循環(huán),監(jiān)測(cè) clone 系統(tǒng)調(diào)用的執(zhí)行;增加了異常輸出。

這段程序運(yùn)行后,輸出結(jié)果如下:

4 進(jìn)一步擴(kuò)展,監(jiān)視 do_execve

第 3 節(jié)的代碼,輸出內(nèi)核字段的方式是 bpf_trace_printk() + trace_fields(),比較靈活,但性能較差。實(shí)際上,還有一種比較常見(jiàn)的輸出方式,那就是通過(guò)一段共享內(nèi)存 Ring buffer 來(lái)實(shí)現(xiàn)。

此外,這次我們更換一個(gè)內(nèi)核監(jiān)視點(diǎn),不再關(guān)注進(jìn)程的創(chuàng)建,而關(guān)注進(jìn)程的執(zhí)行。

接下來(lái),對(duì)上面的代碼進(jìn)行大刀闊斧的修改吧。

文件拆分:

// do_execve.c
#include <uapi/linux/limits.h>		// #define NAME_MAX		255
#include <linux/fs.h>			// struct filename;
#include <linux/sched.h>		// #define TASK_COMM_LEN	16

// 定義 Buffer 中的數(shù)據(jù)結(jié)構(gòu),用于內(nèi)核態(tài)和用戶態(tài)的數(shù)據(jù)交換
struct data_t {
	u32     pid;
	char    comm[TASK_COMM_LEN];
	char    fname[NAME_MAX];
};
BPF_PERF_OUTPUT(events);
// 自定義 hook 函數(shù)
int check_do_execve(struct pt_regs *ctx, struct filename *filename,
                                const char __user *const __user *__argv,
                                const char __user *const __user *__envp) {
	truct data_t data = { };
	
	data.pid = bpf_get_current_pid_tgid();
	bpf_get_current_comm(&data.comm, sizeof(data.comm));
	bpf_probe_read_kernel_str(&data.fname, sizeof(data.fname), (void *)filename->name);
	// 提交 buffer 數(shù)據(jù)
	events.perf_submit(ctx, &data, sizeof(data));
	return 0;
}
# do_execve.py
#!/bin/python3
from bcc import BPF
from bcc.utils import printb
# 指定 eBPF 源碼文件
b = BPF(src_file="do_execve.c")
# 以內(nèi)核函數(shù)的方式綁定 eBPF 探針
b.attach_kprobe(event="do_execve", fn_name="check_do_execve")

print("%-6s %-16s %-16s" % ("PID", "COMM", "FILE"))
# 自定義回調(diào)函數(shù)
def print_event(cpu, data, size):
	event = b["events"].event(data)
	printb(b"%-6d %-16s %-16s" % (event.pid, event.comm, event.fname))

# 指定 buffer 名稱(chēng),為 buffer 的修改添加回調(diào)函數(shù)
b["events"].open_perf_buffer(print_event)
while 1:
	try:
		# 循環(huán)監(jiān)聽(tīng)
		b.perf_buffer_poll()
	except KeyboardInterrupt:
		exit()

這一次,我們又進(jìn)行了億點(diǎn)點(diǎn)修改:

1)首先,對(duì) eBPF BCC 程序的用戶態(tài)和內(nèi)核態(tài)代碼進(jìn)行拆分,并在用戶態(tài)程序中,通過(guò) b = BPF(src_file="do_execve.c") 對(duì)內(nèi)核態(tài)源碼文件進(jìn)行綁定。

2)以內(nèi)核函數(shù)的方式綁定 eBPF 程序,綁定點(diǎn)為 do_execve(),自定義處理函數(shù)為 check_do_execve()

注意:

可以看到,check_do_execve() 函數(shù)的參數(shù)分為兩部分:

① struct pt_regs *ctx;
② struct filename *filename, const char __user *const __user *__argv, const char __user *const __user *__envp

這是因?yàn)椋谒淼模莾?nèi)核 do_execve()函數(shù)的參數(shù)。do_execve()函數(shù)簽名如下:

// fs/exec.c
int do_execve(struct filename *filename, const char __user *const __user *__argv, const char __user *const __user *__envp) {...}

是的,通過(guò)這種方式,幾乎可以監(jiān)控任意一個(gè)內(nèi)核中的函數(shù)

3)內(nèi)核態(tài)程序中,使用了一些 eBPF Helper 函數(shù)來(lái)進(jìn)行一些基礎(chǔ)的操作和數(shù)據(jù)獲取,例如:

bpf_get_current_pid_tgid()								// 獲取當(dāng)前進(jìn)程 pid
bpf_get_current_comm(&data.comm, sizeof(data.comm));					// 獲取當(dāng)前進(jìn)程名 comm
bpf_probe_read_kernel_str(&data.fname, sizeof(data.fname), (void *)filename->name);	// 將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間

4)內(nèi)核態(tài)程序中,使用 BPF_PERF_OUTPUT(events) 聲明 buffer 中的共享變量;使用 events.perf_submit(ctx, &data, sizeof(data)) 提交數(shù)據(jù)。
用戶態(tài)程序中,使用 b["events"].open_perf_buffer(print_event) 指定 buffer 名稱(chēng),為 buffer 的修改添加回調(diào)函數(shù) print_event

運(yùn)行這段程序,輸出如下:

可以看到,這段程序可以實(shí)時(shí)監(jiān)控內(nèi)核進(jìn)程執(zhí)行,并輸出執(zhí)行的進(jìn)程和被執(zhí)行的文件名。

5 總結(jié)

本文通過(guò)幾個(gè)程序 demo,簡(jiǎn)單介紹了 eBPF BCC 框架的編程方法,并最終實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的進(jìn)程執(zhí)行的監(jiān)視工具,可以實(shí)時(shí)打印被執(zhí)行的進(jìn)程信息。

本文開(kāi)篇所引出的實(shí)時(shí)監(jiān)控內(nèi)核可執(zhí)行文件(ELF)的加載程序,也就沒(méi)那個(gè)高深莫測(cè)了。

總結(jié)

以上是生活随笔為你收集整理的【eBPF-01】初见:基于 BCC 框架的第一个 eBPF 程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 在线观看一二三区 | 高h乱l高辣h文短篇h | 丰满熟妇肥白一区二区在线 | 99精品视频国产 | 久久黄色影视 | 91黄在线观看 | 最近中文字幕mv免费高清在线 | 中文在线字幕观看 | 亚洲经典一区二区 | 久久99在线 | 欧美日韩精品二区 | www.一起操| 中国毛片网 | 精品久久久久久久久久岛国gif | 成 人 免费 黄 色 | 操批网站 | 亚洲熟女综合一区二区三区 | 亚洲高清网站 | 欧美在线91 | www.日本在线观看 | 天堂中文在线视频 | 国产乱欲视频 | 另一种灿烂生活 | 东方成人av在线 | 先锋资源国产 | 国产精品白嫩极品美女 | 黄色av免费在线 | 亚洲无码精品在线播放 | www.色图 | 久久综合亚洲色hezyo国产 | 日本熟妇成熟毛茸茸 | 丁香婷婷成人 | 亚洲男人天堂2018 | 乱子伦一区二区三区 | 久久香蕉影院 | 538国产精品视频一区二区 | 姑娘第5集在线观看免费 | 成人免费版欧美州 | 欧美日韩国产电影 | 91在线日韩 | 欧美夫妻性生活视频 | 国产一级视频在线播放 | 欧亚乱熟女一区二区在线 | 老子影院午夜伦不卡大全 | 欧美绿帽交换xxx | 亚洲一区二区三区在线 | 欧美性猛交xxxx黑人交 | 色天天天| 成人国产免费视频 | 一区二区三区黄色录像 | 欧美一级一区二区 | 在线观看日本一区 | 激情国产在线 | 色中文网 | 色老板av | 日韩免费中文字幕 | 理论视频在线观看 | 91极品蜜桃臀 | 天天摸夜夜操 | 91麻豆蜜桃一区二区三区 | 国产又爽又黄无码无遮挡在线观看 | 亚洲天堂久| 中文字幕一二三四区 | 天天操天天干天天操 | av手机天堂| 性xxxx视频播放免费 | 狠狠天天 | 青青草自拍偷拍 | 性三级视频 | 综合图区亚洲 | 日韩欧美国产中文字幕 | 国产天堂av在线 | 国产99久久久国产精品成人免费 | 91视频免费 | 果冻传媒18禁免费视频 | 先锋影音制服丝袜 | 禁漫天堂黄漫画无遮挡观看 | 黄色私人影院 | 香蕉久久久 | 黄色私人影院 | 国产超碰av | 爱情岛亚洲首页论坛 | 亚洲精品无人区 | 婷婷亚洲天堂 | 一级黄色录相 | 欧美性受xxxx白人性爽 | 四虎少妇做爰免费视频网站四 | 香蕉视频官网在线观看 | 亚洲 欧美 激情 小说 另类 | 夜色资源网 | 亚洲精品久久久狠狠狠爱 | 国产精品片 | 国内外成人免费视频 | a极毛片| 国产欧美一级片 | 杨幂国产精品一区二区 | 精品在线视频播放 | 日韩精品在线观看中文字幕 | 国产精品久久婷婷六月丁香 |