fbpx

vmlinux.hとは何か。なぜeBPFプログラムにとって重要なのか。 #aqua #セキュリティ #eBPF

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

本ブログは「Aqua Security」社の技術ブログで2021年3月30日に公開された「 What is vmlinux.h and Why is It Important for Your eBPF Programs? 」の日本語翻訳です。

vmlinux.hとは何か。なぜeBPFプログラムにとって重要なのか。


eBPF は、開発者が Linux カーネルの戦略的なポイントにカスタムコードを追加し、簡単な C 言語や Go 言語のプログラムを書くことでカーネルとのやりとりができる、強力かつ興味深い技術です。開発者が書いて実行した eBPF プログラムは、アタッチしたプロセスのメモリ内のデータを検査できます。しかし、そのためには eBPF プログラムがどのようなデータ構造を扱っているかを知る必要があります。そのためには、次の1行が必要です。それは、「#include "vmlinux.h"」です。このブログでは、vmlinux.h とは何か、なぜ eBPF のプログラムを書くときに vmlinux.h を使うべきなのかを説明します。

vmlinux.hの簡単な説明

vmlinux.h は生成されたコードです。これには、実行中の Linux カーネルが自身のソースコードで使用するすべての型定義が含まれています。Linux をビルドしたときの成果物の1つが、 vmlinux というファイルです。これは、主要なディストリビューションに普通は含まれているファイルで、コンパイルされた起動可能なカーネルを内部に含む ELF バイナリです。

Linux リポジトリの mainline には、bpftool という名前のツールがあります。このツールは、vmlinux オブジェクトファイルを読み込んで、vmlinux.h ファイルを生成する機能を持っています。vmlinux.h ファイルには、インストールされたカーネルが使用するすべての型定義が含まれているため、非常に大きなヘッダーファイルとなります。

実際のコマンドは以下となります。

The actual command is: 
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

このヘッダファイルをインポートすると、bpf プログラムはメモリを読みとることができ、どのバイトが構造体のどのフィールドに対応しているかを知ることができます。

例えば、linux ではプロセスの概念を task_struct という型で表現しています。bpf プログラムから task_struct の値を検査したい場合、その定義を知る必要があります。

一度のコンパイルでどこでも実行可能

vmlinux.h ファイルは、インストールされているカーネルから生成されています。異なるバージョンのカーネルを実行している別マシンでは、再コンパイルせずに bpf プログラムを実行すると、プログラムが壊れる可能性があります。これは、linux のソースコードの中で、バージョンごとに内部構造体の定義が変わるためです。

しかし、libbpf を使うと、一度のコンパイルでどこでも実行できます。libbpf には BPF_CORE_READ などのマクロが定義されており、vmlinux.h で定義されている型の中のどのフィールドにアクセスしようとしているかを分析します。したがって、自分のカーネルから生成した vmlinux.h ファイルで bpf プログラムをコンパイルして、別のカーネルで実行しても問題ありません。

まとめ


すべての Linux カーネルタイプを含む独自の vmlinux.h ヘッダを生成することで、eBPF プログラムを書く際にカーネルヘッダへの依存をなくすことができます。次回の記事では、vmlinux.h の利便性、libbpf の柔軟性、Go 言語の安全性の両方を活用した bpf プログラムの書き方を紹介する予定です。

New call-to-action

新規CTA