操作系统实验三:基于BPF机制的系统跟踪与探测

  • 实验内容

学习BPF机制,了解BCC(BPF Compiler Collection)和bpftarce的实现原理,利用BPF工具实现对系统的跟踪和探测,如跟踪新创建的进程,统计线程占用CPU的时间,统计某内核函数的调用次数,跟踪系统中的内存调用和页错误,跟踪文件打开信息等。

  • 实验目的

通过实验,让学生了解BPF机制,掌握利用BPF工具对系统进行跟踪与探测的方法。

  • 设计思路和流程图
  1. 认识BCC:

BCC 是一个用于创建高效内核跟踪和操作程序的工具包,包括几个有用的工具和示例。它利用了扩展的 BPF(Berkeley Packet Filters),正式名称为 eBPF,这是首次添加到 Linux 3.15 的新功能。BCC 使用的大部分内容都需要 Linux 4.1 及更高版本。

BCC 使 BPF 程序更易于编写,使用 C 中的内核工具(并包括围绕 LLVM 的 C 包装器),以及 Python 和 lua 中的前端。它适用于许多任务,包括性能分析和网络流量控制。

BCC 是 eBPF 的一个工具集,是 eBPF 提取数据的上层封装,它的形式是

python 等程序中嵌套 bpf 程序。python 部分的作用是为用户提供友好的使

用 eBPF 的上层接口,也用于数据处理。bpf 程序会注入内核,提取数据。

当 bpf 程序运行时,通过 LLVM 将 bpf 程序编译得到 bpf 指令集的 elf 文

件,从 elf 文件中解析出可以注入内核的部分,用 bpf_load_program()方

法完成注入。注入程序 bpf_load_program()加入了更复杂的 verifier 机

制,在运行注入程序之前,先进行一系列的安全检查,最大限度的保证系统

的安全。

  1. 了解BPF

BPF,及伯克利包过滤器Berkeley Packet Filter,最初构想提出于 1992 年,其目的是为了提供一种过滤包的方法,并且要避免从内核空间到用户空间的无用的数据包复制行为。它最初是由从用户空间注入到内核的一个简单的字节码构成,它在那个位置利用一个校验器进行检查 —— 以避免内核崩溃或者安全问题 —— 并附着到一个套接字上,接着在每个接收到的包上运行。几年后它被移植到 Linux 上,并且应用于一小部分应用程序上(例如,tcpdump)。其简化的语言以及存在于内核中的即时编译器(JIT),使 BPF 成为一个性能卓越的工具。

在 2013 年,Alexei Starovoitov 对 BPF 进行彻底地改造,并增加了新的功能,改善了它的性能。这个新版本被命名为 eBPF (意思是 “extended BPF”),与此同时,将以前的 BPF 变成 cBPF(意思是 “classic” BPF)。新版本出现了如映射和尾调用tail call这样的新特性,并且 JIT 编译器也被重写了。新的语言比 cBPF 更接近于原生机器语言。并且,在内核中创建了新的附着点。

用Linux Kernel Module来做一个类比说明eBPF诞生的目的。

Kernel Module的主要目的就是让用户可以通过这种机制,实现对内核的“赋能”,动态添加一些内核本身不支持的功能,比如硬件的驱动能力,新的文件系统或是系统调用。当然也可以融合到现有的内核处理流程中,比如在netfilter的某个hook点中添加包处理方法等。

Kernel Module的优点:

动态添加/删除,无需重新编译内核

减小内核体积

缺点:

一旦出现BUG可能导致内核直接崩溃

增加内核攻击面,影响内核安全

eBPF要做的事情也非常类似,但它想要克服Kernel Module的缺点,即确保执行的代码绝对安全。

为了达到这一目的,eBPF在内核中实现了一个虚拟机执行用户的指令。与Kernel Module直接在真实的物理硬件上执行用户的指令不同,eBPF提供给用户一个虚拟的RISC处理器,以及一组相关的指令。用户可以直接用这组指令编写程序。同时,程序在下发到该虚拟机之前也会经过eBPF的检查,比如会不会进入无限循环,会不会访问不合法的内存地址等等。只有在通过检查之后才可以进入执行的环节。

对eBPF来说,和Kernle Module一样,也是通过特定的Hook点监听内核中的特定事件,进而执行用户定义的处理。这些Hook点包括:

静态tracepoint

动态内核态探针(Dynamic Kernel probes)

动态用户态探针(Dynamic User Probes)

其他hook点

针对主要是监控、跟踪使用的eBPF应用来说,主要通过这种方式取得内核运行时的一些参数和统计信息。例如,系统调用的参数值、返回值,通过eBPF map将得到的信息送给用户态程序,进而在用户态完成后处理流程。

另外一类应用则直接在一些内核处理流程中加入自己的处理逻辑,例如XDP,就是在网卡驱动和内核协议栈之间插入了eBPF扩展的网包过滤、转发功能。

eBPF 是一个在内核中运行的虚拟机,它可以去运行用户。在用户态实现的这种 eBPF 的代码,在内核以本地代码的形式和速度去执行,它可以跟内核的 Trace 系统相结合,给我们提供了几乎无限的可观测性。

eBPF 的基本原理——它所有的接口都是通过 BPF 系统调用来跟内核进行交互,eBPF 程序通过 LVM 和 Cline 进行编译,产生 eBPF 的字节码,通过 BPF 系统调用,加载到内核,验证代码的安全性,从而通过 JIT 实时的转化成 Native 的 X86 的指令。

3. 了解 bpftrace:

bpftrace 是一个基于bcc和bpf的开源跟踪器

bpftrace 提供了一种快速利用 eBPF 实现动态追踪的方法,可以作为简

单的命令行工具或者入门级编程工具来使用。动态追踪是一种高级的内核调

试技术,通过探针机制,采集内核态或者用户态程序的运行信息,而不需要

修改内核和应用程序的代码。这种机制性能损耗小,不会对系统运行构成任

何危险。因此,能够以非常低的成本,在短时间内获得丰富的运行信息,进

而可以快速的分析、排查、发现系统运行中的问题。

  • 主要数据结构及其说明

  • 源程序并附上注释(关键部分)

有关安装相关代码:

sudo apt-get install -y bpftrace

安装依赖:

sudo apt-get -y install bison build-essential cmake flex git libedit-dev \

  libllvm6.0 llvm-6.0-dev libclang-6.0-dev python zlib1g-dev libelf-dev libfl-dev python3-distutils

sudo apt-get install python3-distutils

sudo apt-get install python3-pip

sudo apt-get install python3-setuptools

安装bcc:

tar zxvf bcc-src-with-submodule.tar.gz

cd bcc

mkdir build

cd build

cmake ..

make

sudo make install

cmake - DPYTHON_CMD = python3 .. #build python3 binding

pushd src/python/

make

sudo make install

popd

使用BCC构建一个Trace Point程序

#!/usr/bin/python

#

# urandomread  Example of instrumenting a kernel tracepoint.

#              For Linux, uses BCC, BPF. Embedded C.

#

# REQUIRES: Linux 4.7+ (BPF_PROG_TYPE_TRACEPOINT support).

#

# Test by running this, then in another shell, run:

#     dd if=/dev/urandom of=/dev/null bs=1k count=5

#

# Copyright 2016 Netflix, Inc.

# Licensed under the Apache License, Version 2.0 (the "License")

from __future__ import print_function

from bcc import BPF

from bcc.utils import printb

# load BPF program

b = BPF(text="""

TRACEPOINT_PROBE(random, urandom_read) {

    // args is from /sys/kernel/debug/tracing/events/random/urandom_read/format

    bpf_trace_printk("%d\\n", args->got_bits);

    return 0;

}

""")

# header

print("%-18s %-16s %-6s %s" % ("TIME(s)", "COMM", "PID", "GOTBITS"))

# 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))

TRACEPOINT_PROBE(random, urandom_read): 启动内核跟踪点。根据目录/random/urandom_read输入参数。

args->got_bits: 自动生成的参数,每个event的参数各有不同

  • 程序运行结果及分析

查看 TCP 会话的生命周期和吞吐量统计:

输入指令:sudo python tcplife.py:

跟踪 hit radio:

输入指令:sudo python cachestat.py:

追踪每个任务占用 CPU 时间:

输入指令:sudo python cpudist.py:

追踪新的进程:

输入指令:sudo python execsnoop.py:

追踪新创建的线程:

输入指令:sudo python threadsnoop.py:

内存泄露使用的是memleak.py文件,作用是统计从运行开始之后,内存的分配与释放情况,每隔一段时间,打印出分配了,但没有被释放的内存,信息包括分配的函数栈以及内存大小、个数:

输入指令:sudo python memleak.py:

使用cachetop.py文件,可以统计每个进程的缓存命中率,原理是在内核cache相关的几个函数上加了kprobe进行统计。

输入指令:sudo python cachetop.py:

biolatency 统计bio的耗时分布情况:

输入指令:sudo python biolatency.py:

biotop 统计每个进程的bio数据量大小:

输入指令:sudo python biotop.py:

biosnoop 统计每个bio的进程、大小、耗时等信息:

输入指令:sudo python biosnoop.py:

bitesize 统计每个进程的bio大小的分布情况:

输入指令:sudo python bitesize.py:

使用BCC构建一个Trace Point程序:

TRACEPOINT_PROBE(random, urandom_read): 启动内核跟踪点。根据目录/random/urandom_read输入参数。

args->got_bits: 自动生成的参数,每个event的参数各有不同,见下文

输入指令:sudo python3 hello.py:

urandomread的参数设置如下:

输入指令:

cat /sys/kernel/debug/tracing/events/random/urandom_read/format

结果:

从最后一行可以看到,可以输出go_bits,pool_left,input_left三个参数。

  • 实验体会

在网上查看有关 BCCeBPF bpftrace 的有关资料,令我对他们有了从一无所知到初步了解。在安装的时候曾经遇到过各种各样的问题,比如说由于安装bcc所需的版本必须在4.1以上,所以在老师所提供的环境下无法进行。在SEED上进行安装的时候,也出现了各种各样的问题,比如:

当时还一度打开了系统文件:

在向老师和助教询问之后,我最终发觉是版本与系统的不适应所导致的,最后下载了2021年九月份的bcc,最终得以将问题解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值