0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

教你們?nèi)绾问褂胑BPF追蹤LINUX內(nèi)核

Linux閱碼場 ? 來源:Linux內(nèi)核之旅 ? 作者:梁金榮 ? 2021-04-20 11:26 ? 次閱讀

1. 前言

我們可以使用BPF對Linux內(nèi)核進行跟蹤,收集我們想要的內(nèi)核數(shù)據(jù),從而對Linux中的程序進行分析和調(diào)試。與其它的跟蹤技術相比,使用BPF的主要優(yōu)點是幾乎可以訪問Linux內(nèi)核和應用程序的任何信息,同時,BPF對系統(tǒng)性能影響很小,執(zhí)行效率很高,而且開發(fā)人員不需要因為收集數(shù)據(jù)而修改程序。

本文將介紹保證BPF程序安全的BPF驗證器,然后以BPF程序的工具集BCC為例,分享kprobes和tracepoints類型的BPF程序的使用及程序編寫示例。

2. BPF驗證器

BPF借助跟蹤探針收集信息并進行調(diào)試和分析,與其它依賴于重新編譯內(nèi)核的工具相比,BPF程序的安全性更高。重新編譯內(nèi)核引入外部模塊的方式,可能會因為程序的錯誤而產(chǎn)生系統(tǒng)奔潰。BPF程序的驗證器會在BPF程序加載到內(nèi)核之前分析程序,消除這種風險。

BPF驗證器執(zhí)行的第一項檢查是對BPF虛擬機加載的代碼進行靜態(tài)分析,目的是確保程序能夠按照預期結束。驗證器在進行第一項檢查時所做工作為:

程序不包含控制循環(huán);

程序不會執(zhí)行超過內(nèi)核允許的最大指令數(shù);

程序不包含任何無法到達的指令;

程序不會超出程序界限。

BPF驗證器執(zhí)行的第二項檢查是對BPF程序進行預運行,所做工作為:

分析BPF程序執(zhí)行的每條指令,確保不會執(zhí)行無效指令;

檢查所有內(nèi)存指針是否可以正確訪問和引用;

預運行將程序控制流的執(zhí)行結果通知驗證器,確保BPF程序最終都會執(zhí)行BPF_EXIT指令。

3. 內(nèi)核探針 kprobes

內(nèi)核探針可以跟蹤大多數(shù)內(nèi)核函數(shù),并且系統(tǒng)損耗最小。當跟蹤的內(nèi)核函數(shù)被調(diào)用時,附加到探針的BPF代碼將被執(zhí)行,之后內(nèi)核將恢復正常模式。

3.1 kprobes類BPF程序的優(yōu)缺點

優(yōu)點 動態(tài)跟蹤內(nèi)核,可跟蹤的內(nèi)核函數(shù)眾多,能夠提取內(nèi)核絕大部分信息。

缺點 沒有穩(wěn)定的應用程序二進制接口,可能隨著內(nèi)核版本的演進而更改。

3.2 kprobes

kprobe程序允許在執(zhí)行內(nèi)核函數(shù)之前插入BPF程序。當內(nèi)核執(zhí)行到kprobe掛載的內(nèi)核函數(shù)時,先運行BPF程序,BPF程序運行結束后,返回繼續(xù)開始執(zhí)行內(nèi)核函數(shù)。下面是一個使用kprobe的bcc程序示例,功能是監(jiān)控內(nèi)核函數(shù)kfree_skb函數(shù),當此函數(shù)觸發(fā)時,記錄觸發(fā)它的進程pid,進程名字和觸發(fā)次數(shù),并打印出觸發(fā)此函數(shù)的進程pid,進程名字和觸發(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程序主要包括兩個部分,一部分是python語言,一部分是c語言。python部分主要做的工作是BPF程序的加載和操作BPF程序的map,并進行數(shù)據(jù)處理。c部分會被llvm編譯器編譯為BPF字節(jié)碼,經(jīng)過BPF驗證器驗證安全后,加載到內(nèi)核中執(zhí)行。python和c中出現(xiàn)的陌生函數(shù)可以查下面這兩個手冊,在此不再贅述:

python部分遇到的陌生函數(shù)可以查這個手冊: 點此跳轉(zhuǎn)

c部分中遇到的陌生函數(shù)可以查這個手冊: 點此跳轉(zhuǎn)

需要說明的是,該BPF程序類型是kprobe,它是在這里進行程序類型定義的:

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”指定了當檢測到內(nèi)核函數(shù)kfree_skb時,執(zhí)行程序中的trace_kfree_skb函數(shù);

BPF程序的第一個參數(shù)總為ctx,該參數(shù)稱為上下文,提供了訪問內(nèi)核正在處理的信息,依賴于正在運行的BPF程序的類型。CPU將內(nèi)核正在執(zhí)行任務的不同信息保存在寄存器中,借助內(nèi)核提供的宏可以訪問這些寄存器,如PT_REGS_RC。

程序運行結果如下:

e2411330-a100-11eb-8b86-12bb97331649.png

3.3 kretprobes

相比于內(nèi)核探針kprobe程序,kretprobe程序是在內(nèi)核函數(shù)有返回值時插入BPF程序。當內(nèi)核執(zhí)行到kretprobe掛載的內(nèi)核函數(shù)時,先執(zhí)行內(nèi)核函數(shù),當內(nèi)核函數(shù)返回時執(zhí)行BPF程序,運行結束后返回。

以上面的BPF程序為例,若要使用kretprobe,可以這樣修改:

b.attach_kretprobe(event=“kfree_skb”, fn_name=“trace_kfree_skb”)

b.attach_kretprobe()指定了該BPF程序類型為kretprobe,kretprobe類型的BPF程序?qū)⒃诟櫟膬?nèi)核函數(shù)有返回值時執(zhí)行BPF程序;

event=“kfree_skb”指定了kretprobe掛載的內(nèi)核函數(shù)為kfree_skb;

fn_name=“trace_kfree_skb”指定了當內(nèi)核函數(shù)kfree_skb有返回值時,執(zhí)行程序中的trace_kfree_skb函數(shù);

4. 內(nèi)核靜態(tài)跟蹤點 tracepoint

tracepoint是內(nèi)核靜態(tài)跟蹤點,它與kprobe類程序的主要區(qū)別在于tracepoint由內(nèi)核開發(fā)人員在內(nèi)核中編寫和修改。

4.1 tracepoint 程序的優(yōu)缺點

優(yōu)點 跟蹤點是靜態(tài)的,ABI更穩(wěn)定,不隨內(nèi)核版本的變化而致不可用。

缺點 跟蹤點是內(nèi)核人員添加的,不會全面涵蓋內(nèi)核的所有子系統(tǒng)。

4.2 tracepoint 可用跟蹤點

系統(tǒng)中所有的跟蹤點都定義在/sys/kernel/debug/traceing/events目錄中:

e24d14fa-a100-11eb-8b86-12bb97331649.png

使用命令perf list 也可以列出可使用的tracepoint點:

e2629bc2-a100-11eb-8b86-12bb97331649.png

對于bcc程序來說,以監(jiān)控kfree_skb為例,tracepoint程序可以這樣寫:

b.attach_tracepoint(tp=“skb:kfree_skb”, fn_name=“trace_kfree_skb”)

bcc遵循tracepoint命名約定,首先是指定要跟蹤的子系統(tǒng),這里是“skb:”,然后是子系統(tǒng)中的跟蹤點“kfree_skb”:

e29048b0-a100-11eb-8b86-12bb97331649.png

5. 總結

本文主要介紹了保證BPF程序安全的BPF驗證器,然后以BPF程序的工具集BCC為例,分享了kprobes和tracepoints類型的BPF程序的使用及程序編寫示例。本文分享的是內(nèi)核跟蹤,那么用戶空間程序該如何跟蹤呢,這將在后面的文章中逐步分享,感謝閱讀。

參考資料

若未安裝bcc,請參考下方網(wǎng)址進行安裝;

https://github.com/iovisor/bcc/blob/master/INSTALL.md

bcc程序編寫指導手冊

https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md

參考書《Linux內(nèi)核觀測技術 BPF》

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 虛擬機
    +關注

    關注

    1

    文章

    917

    瀏覽量

    28223
  • python
    +關注

    關注

    56

    文章

    4797

    瀏覽量

    84729
  • BCC
    BCC
    +關注

    關注

    0

    文章

    10

    瀏覽量

    7539
  • BPF
    BPF
    +關注

    關注

    0

    文章

    25

    瀏覽量

    4007

原文標題:梁金榮:使用eBPF追蹤LINUX內(nèi)核

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    騰訊云內(nèi)核團隊修復Linux關鍵Bug

    騰訊云操作系統(tǒng)(Tencent OS)內(nèi)核團隊近日在Linux社區(qū)取得了顯著成果。他們提交的兩項改進方案,成功解決了自2021年以來一直困擾眾多一線廠商,并在近期讓多個Linux頂級
    的頭像 發(fā)表于 12-31 10:58 ?159次閱讀

    deepin社區(qū)亮相第19屆中國Linux內(nèi)核開發(fā)者大會

    中國 Linux 內(nèi)核開發(fā)者大會,作為中國 Linux 內(nèi)核領域最具影響力的峰會之一,一直以來都備受矚目。
    的頭像 發(fā)表于 10-29 16:35 ?515次閱讀

    詳解linux內(nèi)核的uevent機制

    linux內(nèi)核中,uevent機制是一種內(nèi)核和用戶空間通信的機制,用于通知用戶空間應用程序各種硬件更改或其他事件,比如插入或移除硬件設備(如USB驅(qū)動器或網(wǎng)絡接口)。uevent表示“用戶空間
    的頭像 發(fā)表于 09-29 17:01 ?716次閱讀

    linux驅(qū)動程序如何加載進內(nèi)核

    Linux系統(tǒng)中,驅(qū)動程序是內(nèi)核與硬件設備之間的橋梁。它們允許內(nèi)核與硬件設備進行通信,從而實現(xiàn)對硬件設備的控制和管理。 驅(qū)動程序的編寫 驅(qū)動程序的編寫是Linux驅(qū)動開發(fā)的基礎。在編
    的頭像 發(fā)表于 08-30 15:02 ?487次閱讀

    Linux內(nèi)核測試技術

    Linux 內(nèi)核Linux操作系統(tǒng)的核心部分,負責管理硬件資源和提供系統(tǒng)調(diào)用接口。隨著 Linux 內(nèi)核的不斷發(fā)展和更新,其復雜性和代碼規(guī)
    的頭像 發(fā)表于 08-13 13:42 ?508次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>測試技術

    Linux內(nèi)核中的頁面分配機制

    Linux內(nèi)核中是如何分配出頁面的,如果我們站在CPU的角度去看這個問題,CPU能分配出來的頁面是以物理頁面為單位的。也就是我們計算機中常講的分頁機制。本文就看下Linux內(nèi)核是如何管
    的頭像 發(fā)表于 08-07 15:51 ?299次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>中的頁面分配機制

    歡創(chuàng)播報 華為宣布鴻蒙內(nèi)核已超越Linux內(nèi)核

    1 華為宣布鴻蒙內(nèi)核已超越Linux內(nèi)核 ? 6月21日,在華為開發(fā)者大會上, HarmonyOS NEXT(鴻蒙NEXT)——真正獨立于安卓和iOS的鴻蒙操作系統(tǒng),正式登場。這是HarmonyOS
    的頭像 發(fā)表于 06-27 11:30 ?849次閱讀

    使用 PREEMPT_RT 在 Ubuntu 中構建實時 Linux 內(nèi)核

    盟通技術干貨構建實時Linux內(nèi)核簡介盟通技術干貨Motrotech如果需要在Linux中實現(xiàn)實時計算性能,進而有效地將Linux轉(zhuǎn)變?yōu)镽TOS,那么大多數(shù)發(fā)行版都可以打上名為PREE
    的頭像 發(fā)表于 04-12 08:36 ?2540次閱讀
    使用 PREEMPT_RT 在 Ubuntu 中構建實時 <b class='flag-5'>Linux</b> <b class='flag-5'>內(nèi)核</b>

    eBPF動手實踐系列三:基于原生libbpf庫的eBPF編程改進方案簡析

    在上一篇文章《eBPF動手實踐系列二:構建基于純C語言的eBPF項目》中,我們初步實現(xiàn)了脫離內(nèi)核源碼進行純C語言eBPF項目的構建。libbpf庫在早期和
    的頭像 發(fā)表于 03-19 14:19 ?851次閱讀
    <b class='flag-5'>eBPF</b>動手實踐系列三:基于原生libbpf庫的<b class='flag-5'>eBPF</b>編程改進方案簡析

    C++在Linux內(nèi)核開發(fā)中從爭議到成熟

    Linux 內(nèi)核郵件列表中一篇已有六年歷史的老帖近日再次引發(fā)激烈討論 —— 主題是建議將 Linux 內(nèi)核的開發(fā)語言從 C 轉(zhuǎn)換為更現(xiàn)代的 C++。
    的頭像 發(fā)表于 01-31 14:11 ?638次閱讀
    C++在<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>開發(fā)中從爭議到成熟

    Ubuntu 24.04 LTS選用Linux 6.8為默認內(nèi)核

    關于Ubuntu 24.04 LTS使用何種內(nèi)核版本,一直備受關注。Canonical工程師Andrea Righi昨日宣布,Ubuntu 24.04將默認搭載Linux 6.8內(nèi)核
    的頭像 發(fā)表于 01-29 11:27 ?1128次閱讀

    探索aarch64架構上使用ftrace的BPF LSM

    筆者在MacBook M2上搭建Linux虛擬機上開發(fā)eBPF程序時,遇到一些LSM eBPF類型程序無法運行的問題,哪怕是5.15內(nèi)核的ubuntu server,依舊無法正常運行。
    的頭像 發(fā)表于 01-25 09:30 ?755次閱讀

    linux內(nèi)核主要由哪幾個部分組成,作用是什么

    Linux內(nèi)核主要由以下幾個部分組成: 進程管理:Linux內(nèi)核負責管理和調(diào)度系統(tǒng)中的進程。它通過進程調(diào)度算法來決定哪個進程在什么時間運行以及如何分配系統(tǒng)資源。 內(nèi)存管理:
    的頭像 發(fā)表于 01-22 14:34 ?2705次閱讀

    rk3399移植Linux內(nèi)核

    RK3399是一款由中國廠商瑞芯微推出的高性能處理器芯片,被廣泛用于嵌入式系統(tǒng)開發(fā)。在進行應用程序開發(fā)之前,我們需要將Linux內(nèi)核移植到RK3399上,以支持硬件的驅(qū)動和功能。本文將詳細介紹如何將
    的頭像 發(fā)表于 01-08 09:56 ?1156次閱讀

    RZ/G2L Linux系統(tǒng)如何添加新的內(nèi)核模塊

    RZ/G2L Linux系統(tǒng)的鏡像基于yocto構建,本篇介紹如何添加新的內(nèi)核模塊。
    的頭像 發(fā)表于 01-04 12:19 ?1793次閱讀
    RZ/G2L <b class='flag-5'>Linux</b>系統(tǒng)如何添加新的<b class='flag-5'>內(nèi)核</b>模塊