eBPF(一)—— eBPF介绍&内核编译

admin 2024年11月15日16:15:43评论15 views字数 5391阅读17分58秒阅读模式
eBPF(一)—— eBPF介绍&内核编译
eBPF(一)—— eBPF介绍&内核编译

eBPF(一)—— eBPF介绍&内核编译

eBPF(一)—— eBPF介绍&内核编译
目录

eBPF介绍

○ eBPF基础

    ◇ 代码验证

    ◇ 即时编译

○ eBPF开发工具

    ◇ BCC

    ◇ bpftrace

    ◇ libbpf C/C++库

    ◇ eBPF Go库

○ 内核编译

    ◇ 查看内核版本

    ◇ 下载内核源码

    ◇ 安装依赖项

    ◇ 安装最新版llvm和clang

    ◇ 配置内核

    ◇ 编译内核BPF示例程序

    ◇ 常见问题

○ 第一个eBPF程序

    ◇ hello_kern.c

    ◇ hello_user.c

    ◇ Makefile

    ◇ 编译

    ◇ 运行

○ 声明

eBPF介绍

eBPF(一)—— eBPF介绍&内核编译

NO.1

BPF(Berkeley Packet Filter,拓展的伯克利报文过滤器)是类Unix系统上数据链路层的一种原始接口,提供原始链路层封包的收发。

除此之外,如果网卡驱动支持混杂模式,那么它可以让网卡处于此种模式,这样可以收到网络上的所有包,不管他们的目的地是不是所在主机,目前被称为cBPF(classical BPF)。

从3.18版本开始,Linux 内核提供了一种扩展的BPF虚拟机,名为“extended BPF”,简称为eBPF。它能够被用于非网络相关的功能,比如附在不同的tracepoints上,从而获取当前内核运行的许多信息。

eBPF现在主要被应用于网络、跟踪、内核优化、硬件建模等领域。

eBPF(一)—— eBPF介绍&内核编译

eBPF基础

eBPF(一)—— eBPF介绍&内核编译

NO.2

eBPF 程序是事件驱动的,能将代码加载进内核中的eBPF虚拟机,并在内核或应用程序通过某个挂钩点时运行。预定义的钩子包括系统调用、函数进入/退出、内核跟踪点、网络事件等。

eBPF(一)—— eBPF介绍&内核编译

eBPF(一)—— eBPF介绍&内核编译

如果不存在用于特定需求的预定义挂钩,则可以创建内核探针 (kprobe) 或用户探针 (uprobe) 以在内核或用户应用程序的几乎任何位置附加 eBPF 程序。

eBPF(一)—— eBPF介绍&内核编译

当程序加载到 Linux 内核中时,它在附加到请求的钩子之前要经过两个步骤:

    1.代码验证

    2.即时编译(Just In Time,JIT)

代码验证

验证步骤确保 eBPF 程序可以安全运行。它验证程序是否满足几个条件,例如:

    1.加载 eBPF 程序的进程拥有所需的能力(特权)。除非启用非特权 eBPF,否则只有特权进程才能加载 eBPF 程序。

    2.该程序不会崩溃或以其他方式损害系统。

    3.程序总是运行到完成(即程序不会永远处于循环中,阻止进一步的处理)。

即时编译

即时 (JIT) 编译步骤将程序的通用字节码转换为机器特定的指令集,以优化程序的执行速度,这使得 eBPF 程序可以像本地编译的内核代码或作为内核模块加载的代码一样高效地运行。

eBPF开发工具

eBPF(一)—— eBPF介绍&内核编译

NO.3

目前eBPF存在几个开发工具链来协助 eBPF 程序的开发和管理,用于满足用户的不同需求:

    1.BCC

    2.bpftrace

    3.libbpf C/C++库

    4.eBPF Go库

BCC

BCC 是一个框架,使用户能够编写带有嵌入其中的 eBPF 程序的 python 程序。该框架主要针对涉及应用程序和系统分析/跟踪的用例,其中 eBPF 程序用于收集统计信息或生成事件,而用户空间中的对应物收集数据并以人类可读的形式显示。运行 python 程序将生成 eBPF 字节码并将其加载到内核中。

eBPF(一)—— eBPF介绍&内核编译

bpftrace

bpftrace 是 Linux eBPF 的高级跟踪语言,可用于最新的 Linux 内核。bpftrace 使用 LLVM 作为后端将脚本编译为 eBPF 字节码,并利用 BCC 与 Linux eBPF 子系统以及现有的 Linux 跟踪功能进行交互:内核动态跟踪 (kprobes)、用户级动态跟踪 (uprobes) 和跟踪点。bpftrace 语言的灵感来自 awk、C 和前身跟踪器,例如 DTrace 和 SystemTap。

libbpf C/C++库

libbpf 库是一个基于 C/C++ 的通用 eBPF 库,它有助于将由 clang/LLVM 编译器生成的 eBPF 目标文件加载到内核中,并且通常通过提供易于使用的库 API 来抽象与 BPF 系统调用的交互应用程序。

eBPF(一)—— eBPF介绍&内核编译

eBPF Go库

eBPF Go 库提供了一个通用的 eBPF 库,它将获取 eBPF 字节码的过程与 eBPF 程序的加载和管理分离。eBPF 程序通常是通过编写高级语言创建的,然后使用 clang/LLVM 编译器编译为 eBPF 字节码。

eBPF(一)—— eBPF介绍&内核编译

内核编译

eBPF(一)—— eBPF介绍&内核编译

NO.4

查看内核版本

root@ubuntu:~# uname -r5.15.0-52-generic

下载内核源码

https://github.com/torvalds/linux/tags

下载与当前系统内核版本一致的内核源码,并解压到/usr/src目录中:

root@ubuntu:/usr/src# lslinux-5.15

安装依赖项

apt install libncurses5-dev flex bison libelf-dev binutils-dev libssl-dev libcap-dev

安装最新版llvm和clang

1)备份源文件

cp /etc/apt/sources.list /etc/apt/sources.list.bak

2)编辑/etc/apt/sources.list,在末尾加入以下内容,保存

deb http://apt.llvm.org/focal/ llvm-toolchain-focal maindeb-src http://apt.llvm.org/focal/ llvm-toolchain-focal maindeb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 maindeb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-12 maindeb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 maindeb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main

3)更新源

apt update

4)安装llvm

apt install llvm

5)安装clang

apt install clang

更新源的时候可能会出现这个错误:

eBPF(一)—— eBPF介绍&内核编译

使用以下命令解决:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 15CF4D18AF4F7421

配置内核

1)进入内核源码目录,后续操作都在源码根目录进行:

cd linux-5.15

2)生成内核头文件

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

3)在内核源码根目录下生成.config文件

make defconfig

编译内核BPF示例程序

1)关联内核头文件

make headers_install

2)编译

make M=samples/bpf

如果出现以下警告,不影响编译:

eBPF(一)—— eBPF介绍&内核编译

常见问题

问题一:libbpf: map ‘rx_cnt’: unexpected def kind var.

eBPF(一)—— eBPF介绍&内核编译

解决方法:升级llvm和clang至最新版即可

问题二:/bin/sh: 1: scripts/mod/modpost: not found

解决方法:

make modules_prepare

第一个eBPF程序

eBPF(一)—— eBPF介绍&内核编译

NO.5

文件目录:/usr/src/linux-5.15/samples/bpf

注意:自Linux内核5.11版本开始,移除了bpf_load.h等头文件,部分函数和宏不再适用,因此在代码的写法上也有不同,网上的demo大多是基于5.10版本以下的,不适用于新版内核,本篇在这里提供新版本写法

hello_kern.c

#include <bpf/bpf_helpers.h>#define SEC(NAME) __attribute__((section(NAME), used))SEC("tracepoint/syscalls/sys_enter_execve")    //触发的事件类型/系统调用int bpf_prog(void *ctx)              //触发事件时调用的函数{  char msg[] = "Hello BPF World!";  bpf_trace_printk(msg, sizeof(msg));      //将信息写入管道,等待用户态读取  return 0;}char _license[] SEC("license") = "GPL";

hello_user.c

#include <stdio.h>#include "trace_helpers.h"int main(int ac, char **argv){  struct bpf_link *link = NULL;  struct bpf_program *prog;  struct bpf_object *obj;  char filename[256];  snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);  //只有当运行的程序名为hello时才能读到hello_kern.o  obj = bpf_object__open_file(filename, NULL);  if (libbpf_get_error(obj)) {    fprintf(stderr, "ERROR: opening BPF object file failedn");    return 0;  }  prog = bpf_object__find_program_by_name(obj, "bpf_prog");  if (!prog) {    fprintf(stderr, "ERROR: finding a prog in obj file failedn");    goto cleanup;  }  /* load BPF program */  if (bpf_object__load(obj)) {    fprintf(stderr, "ERROR: loading BPF object file failedn");    goto cleanup;  }  link = bpf_program__attach(prog);  if (libbpf_get_error(link)) {    fprintf(stderr, "ERROR: bpf_program__attach failedn");    link = NULL;    goto cleanup;  }  read_trace_pipe();cleanup:  bpf_link__destroy(link);  bpf_object__close(obj);  return 0;}

Makefile

编辑samples/bpf目录中的Makefile文件,在下方标红位置添加内容:

tprogs-y += xdp_redirect_maptprogs-y += xdp_redirecttprogs-y += xdp_monitortprogs-y += helloxdp_redirect_map-objs := xdp_redirect_map_user.o $(XDP_SAMPLE)xdp_redirect-objs := xdp_redirect_user.o $(XDP_SAMPLE)xdp_monitor-objs := xdp_monitor_user.o $(XDP_SAMPLE)hello-objs := hello_user.o $(TRACE_HELPERS)always-y += hbm_out_kern.oalways-y += hbm_edt_kern.oalways-y += xdpsock_kern.oalways-y += hello_kern.o

编译

回到内核源码根目录,再次运行以下命令:

make M=samples/bpf

如果出现如下图红框中的内容,不影响编译:

eBPF(一)—— eBPF介绍&内核编译

查看是否编译成功:

ls | grep "hello*"

eBPF(一)—— eBPF介绍&内核编译

运行

1)运行前线新起一个终端,用于测试:

eBPF(一)—— eBPF介绍&内核编译

2)在终端1中运行编译好的程序:

eBPF(一)—— eBPF介绍&内核编译

3)在终端2中执行任意命令,在终端1查看程序是否能够监测到,如果成功监测到新进程运行便会输出一条"Hello BPF World"

eBPF(一)—— eBPF介绍&内核编译

声明

eBPF(一)—— eBPF介绍&内核编译

NO.6

本文作者:lzyddf

本文编辑:Yusa

感谢lzyddf师傅 (๑•̀ㅂ•́)و✧

原文链接:

https://blog.csdn.net/qq_41988448/article/details/127784863?spm=1001.2014.3001.5501

参考文档:

https://ebpf.io/what-is-ebpf/

https://www.bilibili.com/video/BV1LX4y157Gp/?spm_id_from=333.999.0.0

https://www.bilibili.com/video/BV1f54y1h74r/?spm_id_from=333.999.0.0

https://zhuanlan.zhihu.com/p/496990553

https://www.ebpf.top/post/ubuntu_2104_bpf_env/

往期回顾

eBPF(一)—— eBPF介绍&内核编译

鼠标指针文件格式解析——Windows(三)

eBPF(一)—— eBPF介绍&内核编译

鼠标指针文件格式解析——Windows(二)

eBPF(一)—— eBPF介绍&内核编译

中间件常见漏洞之Tomcat

eBPF(一)—— eBPF介绍&内核编译
eBPF(一)—— eBPF介绍&内核编译

扫码关注我们

天虞实验室为赛宁网安旗下专业技术团队,重点攻关公司业务相关信息安全前沿技术。

原文始发于微信公众号(天虞实验室):eBPF(一)—— eBPF介绍&内核编译

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月15日16:15:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   eBPF(一)—— eBPF介绍&内核编译https://cn-sec.com/archives/1626011.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息