Ubuntu Weekly Recipe

第695回 入門BPF CO-RE

この記事を読むのに必要な時間:およそ 10.5 分

第694回ではポータブルなBPFバイナリを作成できる,BPF CO-REのビルド方法を紹介しました。今回はより実践的なコードを使って,いろいろなツールを作ってみましょう。

BPF CO-REの基本と事前準備

BPF CO-RE(Compile Once - Run Everywhere)については第694回でも言及しましたが,簡単に言うとeBPFとは「カーネルやプロセスの挙動を,それらを再コンパイルすることなく調べるためのツール」であり,BPF CO-RE「移植性のあるeBPFバイナリを作成するための仕組み」になります。

また,カーネル内部で動くBPFオブジェクトは,libbpfによってカーネルにロードされます。よってユーザーランド側のツールは,libbpfを通してBPFオブジェクトをカーネルに渡し,BPFオブジェクトが生成したデータを収集しなくてはなりません。

BPFオブジェクト自体はClangを使ってビルドし,ユーザーランドツールは好みのコンパイラを使うのが一般的です。今回はどちらもC言語で記述しますが,ユーザーランド側のツールはRustなどを使うケースもあるようです。

第694回で作成したプログラムは,単にカーネル内部で出力した文字列をトレースバッファーを経由して表示するだけのツールでした。今回はさらに発展して,ユーザーランドとカーネルの間でデータのやり取りができるようにしましょう。

BPF CO-REは比較的最近の仕組みであることから,今回もUbuntu 21.10ベースで話を進めます。あらかじめ次のパッケージをインストールしておいてください。

$ sudo apt install build-essential libbpf-dev clang llvm linux-tools-generic

また第694回で作成した次のファイルを準備しておきます。

  • Makefile:BPFバイナリとユーザーランドツールを作成するファイル
  • execsnoop.bpf.c:BPFオブジェクトを作るためのC言語のコード
  • execsnoop.c:BPFオブジェクトをロードするユーザーランドのコード

次の方法でgit cloneできるようにしておきました。

$ git clone https://gitlab.com/mtyshibata/bpf-core-sample.git
$ cd bpf-core-smaple
$ git checkout r694 v1.0

ちなみにmainブランチの最新の状態は,本記事での変更を反映したあとのものになっています。変更を反映する前,つまり前回第694回のものはv1.0タグを付けています。

このリポジトリは,makeコマンドだけでプログラムをビルドできるようになっています。

$ make
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
clang -g -O2 -Wall -target bpf -D__TARGET_ARCH_x86 -c execsnoop.bpf.c -o execsnoop.bpf.o
llvm-strip -g execsnoop.bpf.o
bpftool gen skeleton execsnoop.bpf.o > execsnoop.skel.h
libbpf: elf: skipping unrecognized data section(3) .rodata.str1.1
cc -g -O2 -Wall -c execsnoop.c -o execsnoop.o
cc -g -O2 -Wall execsnoop.o -lbpf -o execsnoop

実行には管理者権限が必要です。

$ sudo ./execsnoop

何がしかのプログラムがexecveされると,データが記録されます。この時点でのコードでは,カーネルのトレースバッファーからしかその記録は取得できません。

$ sudo cat /sys/kernel/debug/tracing/trace_pipe

    byobu-status-3782063 [002] d... 242751.308364: bpf_trace_printk: Hi, execve!

    byobu-status-3782064 [003] d... 242751.315108: bpf_trace_printk: Hi, execve!

    byobu-status-3782065 [003] d... 242751.334648: bpf_trace_printk: Hi, execve!

最低限の仕組みはできたので,ここからは第690回相当のスクリプトになるようカスタマイズしていきましょう。

ちなみに残念ながらlibbpfにはまだまともなAPIドキュメントがありません。このため何かやりたい場合は,libbpfのコードやBCC/libbpf-tools以下のコードを参照しながら記述することになります。また,manpagesパッケージから提供されるbpf-helpers(7)マニュアルも参考になるはずです。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。