動態控制eBPF程序加載:檢查 Tracepoint、Kprobe是否存在

前言

在 eBPF 程序開發中,確保程序能夠在各種不同的系統配置中兼容運行是至關重要的。本文將詳細介紹一個方案,通過動態檢查Tracepoint、Kprobe是否存在,并結合libbpf的API接口控制 eBPF 程序的加載。這種方法不僅可以提升程序的靈活性,還能提高其在不同內核版本和系統配置中的兼容性。

方案概述

本方案包括以下步驟:

  1. 檢查指定的 Tracepoint 是否存在;
  2. 檢查指定的 Kprobe 是否存在;
  3. 若不存在,則通過API函數bpf_object__find_program_by_name查找到 eBPF 程序,再使用 API函數bpf_program__set_autoload 動態設置 eBPF 程序的autoload屬性使其不加載。

檢查Tracepoint掛載點是否存在

Tracepoint是內核提供的一種跟蹤機制,通過訪問特定目錄可以檢查其是否存在。不同的Linux系統,查找的目錄不同,當前有以下兩種路徑:

  1. /sys/kernel/debug/tracing/events
  2. /sys/kernel/tracing/events

設計思路是順序地在這兩個路徑下使用access系統調用檢查是否存在某tracepoint文件,任意一個路徑下檢查到了,結果就是存在;兩個路徑下都沒檢查到,則結果是不存在。
注:這兩個路徑一般需要root權限,普通用戶無法訪問。

示例代碼

#include <iostream>
#include <unistd.h>bool tracepoint_exists(const char* tp_category, const char* tp_name)
{char path[256];snprintf(path, sizeof(path), "/sys/kernel/debug/tracing/events/%s/%s",tp_category, tp_name);auto ret = access(path, F_OK);if (ret == 0) {return true;}snprintf(path, sizeof(path), "/sys/kernel/tracing/events/%s/%s", tp_category, tp_name);ret = access(path, F_OK);if (ret == 0) {return true;}return false;
}int main(int argc, char** argv)
{if (argc != 3) {std::cout << "Usage: ./test category tracepoint_name" << std::endl;return -1;}auto ret = tracepoint_exists(argv[1], argv[2]);if (ret) {std::cout << "Tracepoint tp/" << argv[1] << "/" << argv[2]<< " exists!"<< std::endl;return 0;}std::cout << "Tracepoint tp/" << argv[1] << "/" << argv[2]<< " does not exist!"<< std::endl;return -1;
}

測試結果

使用以上程序檢測syscalls:sys_enter_read是否存在。

[root@VM-8-2-centos check_tracepoint_kprobe_uprobe]# ./test syscalls sys_enter_read
Tracepoint tp/syscalls/sys_enter_read exists!

再檢測一個不存在的,syscalls:sys_enter_readd。

[root@VM-8-2-centos check_tracepoint_kprobe_uprobe]# ./test syscalls sys_enter_readd
Tracepoint tp/syscalls/sys_enter_readd does not exist!

通過測試結果可知,功能符合預期。

檢查Kprobe掛載點是否存在

Kprobes允許動態掛載內核函數進行調試,通過讀取以下系統文件可以檢查特定的 Kprobe 是否存在。

  1. /sys/kernel/debug/tracing/available_filter_functions
  2. /sys/kernel/tracing/available_filter_functions

注:這兩個文件一般需要root權限,普通用戶無法訪問。

示例代碼

#include <iostream>
#include <stdio.h>
#include <string.h>bool kprobe_exists(const char *kprobe_name)
{FILE* file = fopen("/sys/kernel/debug/tracing/available_filter_functions", "r");if (!file) {file = fopen("/sys/kernel/tracing/available_filter_functions", "r");if (!file) {return false;}}char line[256];while (fgets(line, sizeof(line), file)) {line[strcspn(line, "\n")] = 0;if (strcmp(line, kprobe_name) == 0) {return true;}}return false;
}int main(int argc, char** argv)
{if (argc != 2) {std::cout << "Usage: ./test kprobe_name" << std::endl;return -1;}auto ret = kprobe_exists(argv[1]);if (ret) {std::cout << "kprobe " << argv[1] << " exists!"<< std::endl;return 0;}std::cout << "kprobe " << argv[1] << " does not exist!"<< std::endl;return -1;
}

測試結果

使用以上程序檢測__alloc_pages_direct_compact這個kprobe掛載點是否存在。

[root@VM-8-2-centos check_kprobe]# ./test __alloc_pages_direct_compact
kprobe __alloc_pages_direct_compact exists!

再檢測一個不存在的,__alloc_pages_direct_compact_abcdefg。

[root@VM-8-2-centos check_kprobe]# ./test __alloc_pages_direct_compact_abcdefg
kprobe __alloc_pages_direct_compact_abcdefg does not exist!

通過測試結果可知,功能符合預期。

動態設置 eBPF 程序的 autoload 屬性

當我們以libbpf-bootstrap為參考寫ebpf程序時,可以使用前文的方法提前判斷函數掛載點是否存在,若不存在,則使用libbpf的API將eBPF 程序的 autoload 屬性設置為false。使用到的API如下:

bpf_object__find_program_by_name

bpf_object__find_program_by_name接口是一個用于在 eBPF 對象中查找特定 eBPF 程序的函數,在bpf/libbpf.h頭文件中。
函數功能
在 eBPF 項目中,一個 BPF 對象可能包含多個 eBPF 程序(如一個bpf c語言源文件中有多個SEC),每個程序都可以有一個唯一的名稱。bpf_object__find_program_by_name接口的主要功能是根據給定的程序名稱,從 BPF 對象中查找并返回相應的 eBPF 程序。如果找到匹配的程序,則返回指向該程序的指針;否則,返回 NULL。
在前文中,我們能夠通過程序動態判斷是否支持某Tracepoint或Kprobe的掛載點,若不存在,需要使用這個API查找到對應的ebpf程序(struct bpf_program *),以便后續設置其autoload屬性。
函數原型

struct bpf_program * bpf_object__find_program_by_name(const struct bpf_object *obj, const char *name);

參數說明

  1. obj: 指向 BPF 對象的指針。該對象通常是通過加載 BPF ELF 文件生成的,包含多個 eBPF 程序。在libbpf-bootstrap框架中,可以通過skel->obj來獲取。
  2. name: 要查找的 eBPF 程序的名稱。名稱是一個字符串,應與 BPF 程序在源代碼中的定義名稱相匹配。

返回值
成功時,返回指向找到的 eBPF 程序的指針(struct bpf_program *);
如果未找到匹配的程序,則失敗,返回 NULL。

bpf_program__set_autoload

bpf_program__set_autoload接口定義在bpf/libbpf.h頭文件中,用于設置 eBPF 程序在加載 BPF 對象時是否自動加載。這在需要根據運行時條件動態控制 eBPF 程序的加載和執行時非常有用。
函數功能
bpf_program__set_autoload 接口的主要功能是啟用或禁用特定 eBPF 程序的自動加載。通過調用此函數,開發者可以決定某個 eBPF 程序在調用 bpf_object__load 時是否應被加載到內核中。
函數原型

int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);

參數說明

  1. prog: 指向要設置自動加載屬性的 eBPF 程序的指針(struct bpf_program *)。
  2. autoload: 一個布爾值,指示是否應自動加載該程序。設為 true 表示啟用自動加載,設為 false 表示禁用自動加載。

返回值
成功時返回 0;
失敗時返回一個負值的錯誤碼。

代碼示例

以下代碼展示了如何使用前文的兩個API實現動態禁用某ebpf程序的功能。

void disable_autoload(struct bpf_object *obj, const char *prog_name) {struct bpf_program *prog = bpf_object__find_program_by_name(obj, prog_name);if (!prog) {fprintf(stderr, "Program %s not found in object\n", prog_name);return;}if (bpf_program__set_autoload(prog, false) != 0) {fprintf(stderr, "Failed to disable autoload for program %s\n", prog_name);} else {printf("Autoload disabled for program %s\n", prog_name);}
}

完整的動態禁用eBPF程序autoload屬性的小demo可免費下載資源《禁用某eBPF程序源代碼 》。Demo中在eBPF程序的open和load之間調用了disable_autoload,將不存在的tracepoint禁用了。

結束語

通過本文的學習,在開發eBPF程序時可以實現對 eBPF 程序加載的動態控制,確保其在不同的系統配置和內核版本中都能正常運行。我們詳細探討了如何檢查 Tracepoint、Kprobe是否存在,并結合 bpf_program__set_autoload 和 bpf_object__find_program_by_name 控制 eBPF 程序的加載。這不僅提升了 eBPF 程序的靈活性,還增強了系統兼容性。希望本文的內容能為 eBPF 程序開發提供有價值的指導,幫助讀者更有效地利用 eBPF 技術實現內核級監控和調試。
后續會對Uprobe和USDT的檢測進行研究,歡迎關注和訂閱。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21207.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21207.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

jwt 實現用戶登錄完整java

登錄校驗邏輯 用戶登錄的校驗邏輯分為三個主要步驟&#xff0c;分別是校驗驗證碼&#xff0c;校驗用戶狀態和校驗密碼&#xff0c;具體邏輯如下 前端發送username、password、captchaKey、captchaCode請求登錄。判斷captchaCode是否為空&#xff0c;若為空&#xff0c;則直接…

AWS聯網和內容分發服務

概況 VPC Amazon Virtual Private Cloud (Amazon VPC) 讓您能夠全面地控制自己的虛擬網絡環境&#xff0c;包括資源放置、連接性和安全性。首先在 AWS 服務控制臺中設置 VPC。然后&#xff0c;向其中添加資源&#xff0c;例如 Amazon Elastic Compute Cloud (EC2) 和 Amazon …

數據分析必備:一步步教你如何用Pandas做數據分析(15)

1、Pandas 數據丟失 Pandas 數據丟失的操作實例 在現實生活中&#xff0c;數據丟失始終是一個問題。機器學習和數據挖掘等領域在模型預測的準確性方面面臨嚴重問題&#xff0c;因為缺少值會導致數據質量較差。在這些領域中&#xff0c;缺失值處理是使模型更準確和有效的主要重…

定個小目標之每天刷LeetCode熱題(7)

今天這道題是道簡單題&#xff0c;使用雙指針進行迭代即可&#xff0c;畫了下草圖如下 代碼如下 class Solution {public ListNode reverseList(ListNode head) {if (head null || head.next null) {return head;}ListNode p head, q head.next, temp null;while (q ! nu…

【Python如何將EXCEL拆分】

文章目錄 Python將一個EXCEL表拆分多個excel表Python將一個EXCEL表中一個sheet拆分多個sheet表 Python將一個EXCEL表拆分多個excel表 在Python中&#xff0c;你可以使用pandas庫來讀取Excel文件&#xff0c;并將一個大的Excel表格&#xff08;工作表&#xff09;拆分成多個單獨…

Writerside生成在線幫助文檔或用戶手冊軟件基礎使用教程

Writerside是JetBrains出的一個技術文檔工具&#xff0c;既能用在JetBrains IDE上&#xff0c;也能單獨用。它能幫你輕松寫、建、測、發技術文檔&#xff0c;像產品說明、API參考、開發指南等都能搞定。 特點&#xff1a; 文檔即代碼&#xff1a;它讓你像管代碼一樣管文檔&…

【大數據Spark】常見面試題(萬字!建議收藏)

文章目錄 入門級中等難度中高級難度數據傾斜解決方法 入門級 什么是Apache Spark&#xff1f;它與傳統的MapReduce有何不同&#xff1f; Apache Spark是一個開源的分布式計算系統&#xff0c;它提供了高效的數據處理和分析能力。與傳統的MapReduce相比&#xff0c;Spark具有更快…

海光CPU:國產信創的“芯“動力解讀

國產信創CPU-海光CPU CPU&#xff1a;信創根基&#xff0c;國之重器 國產CPU形成三大陣營&#xff1a;自主架構、x86及ARM。自主陣營中&#xff0c;龍芯和申威以LoongArch和SW-64為基石&#xff1b;ARM陣營由鯤鵬、飛騰主導&#xff0c;依托ARM授權研發處理器&#xff1b;x86陣…

紅帽練習 之邏輯卷 pv lv gv

邏輯卷習題 1 在/dev/sdb 存儲設備上創建物理設備分區 創建2個大小各為256MB的分區 并設置為linux lvm類型 使用first 和second 作為這些分區的名稱 parted /dev/sdb mklabel gpt parted /dev/sdb primary mkpart first 1M 256M parted /dev/sdb set 1 …

【Linux|數據恢復】extundelete和ext4magic數據恢復工具使用

環境&#xff1a;Centos7.6_x86 一、extundelete工具 1、extundelete介紹 Extundelete 是一個數據恢復工具&#xff0c;用于從 ext3 或 ext4 分區中恢復刪除文件。根據官網0.2.4版本介紹是支持ext4&#xff0c;但實際上使用發現ext4格式有些問題&#xff0c;會報以下錯誤&…

動態SQL IF語句

IF語句學習 第一種寫法(標準) 我們先來看以下標準寫法: select * from .. <where> <if test""> and ....... <if test""> and ....... <where> 我們用了一個where標簽 , 內嵌if語句 第二種寫法: 這是第二種寫法:不用where標…

大降分!重郵計算機專碩復試線大降50分!重慶郵電計算機考研考情分析!

重慶郵電大學&#xff08;Chongqing University of Posts and Telecommunications&#xff09;簡稱重郵&#xff0c;坐落于中國重慶市主城區南山風景區內&#xff0c;是中華人民共和國工業和信息化部與重慶市人民政府共建的教學研究型大學&#xff0c;入選國家“中西部高校基礎…

一篇文章搞懂Go語言切片底層原理(圖文并茂+舉例講解)

1. 切片和數組的底層關系 Go語言切片的數據結構是一個結構體&#xff1a; type slice struct {array unsafe.Pointerlen intcap int }Go語言中切片的內部結構包含地址、大小和容量。將數組比喻成一個蛋糕&#xff0c;那么切片就是需要切的那一塊&#xff0c;而那一塊的的…

c++學生管理系統

想要實現的功能 1&#xff0c;可以增加學生的信息&#xff0c;包括&#xff08;姓名&#xff0c;學號,c成績&#xff0c;高數成績&#xff0c;英語成績&#xff09; 2&#xff0c;可以刪除學生信息 3&#xff0c;修改學生信息 4&#xff0c;顯示所有學生信息 5&#xff0c…

支持AMD GPU的llm.c

anthonix/llm.c: LLM training in simple, raw C/HIP for AMD GPUs (github.com) llm.c for AMD devices This is a fork of Andrej Karpathys llm.c with support for AMD devices. 性能 在單個7900 XTX顯卡上使用默認設置&#xff0c;目前的訓練步驟耗時約為79毫秒&#x…

Docker的安裝、啟動和配置鏡像加速

前言&#xff1a; Docker 分為 CE 和 EE 兩大版本。CE 即社區版&#xff08;免費&#xff0c;支持周期 7 個月&#xff09;&#xff0c;EE 即企業版&#xff0c;強調安全&#xff0c;付費使用&#xff0c;支持周期 24 個月。 而企業部署一般都是采用Linux操作系統&#xff0c;而…

【軟件設計師】2022年上半年真題解析

??馮諾依曼計算機體系結構的基本特點是&#xff1a; A. 程序指令和數據都采用二進制表示 - 這是正確的&#xff0c;因為馮諾依曼架構下的計算機使用二進制形式來表示和處理所有信息&#xff0c;包括指令和數據。 B. 程序指令總是存儲在主存中&#xff0c;而數據則存儲在高速…

Java基礎語法詳解——入門學習教程

Java 基礎 目錄 一、數據類型 基本類型包裝類型緩存池 二、String 概覽不可變的好處String, StringBuffer and StringBuilder String Poolnew String(“abc”) 三、運算 參數傳遞float 與 double隱式類型轉換switch 四、關鍵字 finalstatic 五、Object 通用方法 概覽equals()ha…

深入解析 MongoDB Map-Reduce:強大數據聚合與分析的利器

Map-Reduce 是一種用于處理和生成大數據集的方法&#xff0c;MongoDB 支持 Map-Reduce 操作以執行復雜的數據聚合任務。Map-Reduce 操作由兩個階段組成&#xff1a;Map 階段和 Reduce 階段。 基本語法 在 MongoDB 中&#xff0c;可以使用 db.collection.mapReduce() 方法執行…

IsoBench:多模態基礎模型性能的基準測試與優化

隨著多模態基礎模型的快速發展&#xff0c;如何準確評估這些模型在不同輸入模態下的性能成為了一個重要課題。本文提出了IsoBench&#xff0c;一個基準數據集&#xff0c;旨在通過提供多種同構&#xff08;isomorphic&#xff09;表示形式的問題&#xff0c;來測試和評估多模態…