Berkeley Packet FilterBPF)は、特定のコンピューターのオペレーティングシステム上で特にネットワークトラフィックの解析に必要なプログラムで使われる技術である。

Berkeley Packet Filter
開発元 Steven McCanne,
Van Jacobson
初版 1992年12月19日 (31年前) (1992-12-19)
対応OS Unix-likeWindows
テンプレートを表示

概要 編集

BPFデータリンク層へのrawインターフェイスを提供し、生のリンク層パケットの送信と受信を可能にする[1]

それに加えて、ネットワークインタフェース向けのドライバーがプロミスキャス・モードをサポートしている場合には、インターフェイスをそのモードに切り替えて、他のホスト向けのパケットも含むネットワーク上のすべてのパケットを受信できるようにすることができる。

BPFはパケットのフィルタリングをサポートしているため、ユーザー空間プロセスは受信したいパケットを指定するフィルタープログラムを実装できる。たとえば、tcpdumpプロセスは、TCP接続を開始するパケットのみを受信する必要があることがある。BPFはプロセスが提供するフィルターを通過したパケットのみを返せるため、この機能を利用することで、オペレーティングシステムカーネルからプロセスへの不要なパケットのコピーが回避され、パフォーマンスが大幅に向上する。

BPFは、インターフェイス全体ではなく、BPFのフィルタリングメカニズムだけを指す場合がある。LinuxTru64 UNIXなどの一部のシステムは、BPFのrawインターフェイス以外にデータリンク層へのrawインターフェイスを提供するが、そのrawインターフェイスにはBPFのフィルタリングメカニズムを使用する。

また、eBPFLinuxカーネル内で実行される拡張された(extended)BPFのJIT仮想マシンである。

BPFはほとんどのUnix系オペレーティングシステムで利用でき、eBPFにはLinuxおよびMicrosoft Windows向けのものがある[2]

rawインターフェース 編集

BPFは、ネットワークインターフェイスにバインドできる疑似デバイスを提供する。疑似デバイスからの読み取りは、ネットワークインターフェイスで受信したパケットが保持されたバッファーの読み取りになり、疑似デバイスへの書き込みは、ネットワークインターフェイスへのパケットの挿入になる。

2007年、 Robert WatsonとChristian Peronは、FreeBSDオペレーティングシステムのBPF実装にゼロコピー・バッファ英語版拡張を追加した[3]。これにより、デバイスドライバの割り込みハンドラーのカーネルパケットキャプチャが、要件を回避するためにユーザープロセスメモリに直接書き込むことができるようになった。これは、BPFデバイスを介して受信したすべてのパケットデータに対して2つのコピーが必要になるのを回避するためである。1つのコピーがユーザープロセスの受信パスに残るが、これにより、さまざまなBPFデバイスコンシューマーの独立性が維持され、完全なパケットデータをコピーするのではなく、ヘッダーをBPFバッファーにパッキングできるようになる[4]

フィルタリング 編集

BPFのフィルタリング機能は、BPF仮想マシン向けの機械語のインタープリターとして実装されている。BPF仮想マシンは32ビットのマシンであり、固定長の命令、1つのアキュムレータ、1つのインデックスレジスタを備えている。この言語で書かれたプログラムでは、パケットからのデータのフェッチ、パケットのデータに対する算術演算の実行、結果に対する定数・パケット内のデータ・結果内のテストビットとの比較を行い、その結果に基づいてパケットをacceptまたはrejectすることができる。

BPFは、しばしばロード(ld)とストア(str)命令を「オーバーロード」することで拡張される。

伝統的なUnix系のBPF実装はカーネル空間用に記述されているが、ユーザー空間で使用できる。この仕組みは、プリプロセッサの条件分岐を使用して実現されている。

拡張と最適化 編集

一部のプロジェクトでは、オリジナルとは異なるBPF命令セットや実行手法を使用している。

FreeBSDNetBSDWinPcapなどの一部のプラットフォームでは、パフォーマンスを向上させるために、JITコンパイラを使用してBPF命令をネイティブコードに変換している。LinuxにはBPF JITコンパイラが含まれているが、デフォルトでは無効になっている。

同じ仮想マシン言語のカーネルモードのインタープリターは、Tru64 Unixなどの他のオペレーティングシステムの生のデータリンク層の内部や、Linuxカーネルのソケットフィルター、WinPcapやNpcapのパケットキャプチャの内部で使用される。

バージョン3.18以降のLinux カーネルには、extended BPFeBPF)と呼ばれる10個の64ビットレジスタを備えたeBPFの仮想マシンが含まれている。eBPFプログラムをさまざまなTracepointにアタッチする用途など、ネットワーク以外の目的でも使用できる[5][6][7]

カーネルバージョン3.19以降では、eBPFフィルターはソケット英語版にアタッチすることができ[8][9]、カーネルバージョン4.1以降は、ingressおよびegressネットワークデータパスのトラフィック制御英語版分類器にアタッチできる[10][11]。元の古いバージョンは、遡及的にclassic BPFcBPF)に名前が変更された。現在、LinuxカーネルはeBPFのみを実行しており、ロードされたcBPFのバイトコードは、プログラムの実行前にカーネル内で透過的にeBPF表現に変換されるようになっている[12]。DoS攻撃を防ぐために、実行前にすべてのバイトコードが検証される。Linux 5.3までは、verifierはループの使用を禁止していた。

BPFのユーザーモードのインタープリターは、pcap APIのlibpcap/WinPcap/Npcapの各実装で提供されるため、特定のフィルタリングメカニズムに対するカーネルモードのサポートがないシステムでパケットをキャプチャする場合、パケットをユーザーモードでフィルタリングできる。ただし、pcap APIを使用するコードは両方のタイプのシステムで機能するが、ユーザーモードでフィルタリングが行われるシステムでは、フィルターで除外されるものを含むすべてのパケットがカーネルからユーザー空間にコピーされる。このインタープリターは、pcapを使用してキャプチャされたパケットを含むファイルを読み取るときにも使用できえる。

もう1つのユーザーモードインタープリターは、JITとeBPFをサポートするuBPFである。そのコードは、Linux 以外のシステムでeBPFサポートを提供するために再利用されている[13]。Microsoftの「eBPF on Windows」は、uBPFとPREVAIL形式の検証ツールを基に構築されている[14]

歴史 編集

オリジナルの論文は、1992年にローレンス・バークレー国立研究所に所属していたSteven McCanne英語版ヴァン・ジェイコブソンによって書かれた[1][15]

2003年8月、SCO Groupは、Linuxカーネルが所有するUnixコードを侵害していると公に主張した[16]。プログラマーはすぐに、挙げられた例の1つがBerkeley Packet Filterであることに気付いた。実際にはSCOはBPFを所有したことない[17]。SCOはその間違いを弁明することなく訴訟を続け、SCO・Linux論争を引き起こした[18]

セキュリティ上の懸念 編集

Spectre攻撃により、LinuxカーネルのeBPF JITコンパイラを利用して、他のカーネルプロセスからデータを抽出し、ユーザー空間でそのデータを読み取れるようになる可能性がある[19]

関連項目 編集

出典 編集

  1. ^ a b McCanne (1992年12月19日). “The BSD Packet Filter: A New Architecture for User-level Packet Capture”. 2022年5月14日閲覧。
  2. ^ Microsoft embraces Linux kernel's eBPF super-tool, extends it for Windows”. The Register (2011年5月11日). 2022年5月14日閲覧。
  3. ^ bpf(4) Berkeley Packet Filter”. FreeBSD (2010年6月15日). 2022年5月14日閲覧。
  4. ^ Watson (2007年3月9日). “Zero-Copy BPF”. 2022年5月14日閲覧。
  5. ^ Linux kernel 3.18, Section 1.3. bpf() syscall for eBFP virtual machine programs”. kernelnewbies.org (2014年12月7日). 2019年9月6日閲覧。
  6. ^ Jonathan Corbet (2014年9月24日). “The BPF system call API, version 14”. LWN.net. 2015年1月19日閲覧。
  7. ^ Jonathan Corbet (2014年7月2日). “Extending extended BPF”. LWN.net. 2015年1月19日閲覧。
  8. ^ Linux kernel 3.19, Section 11. Networking”. kernelnewbies.org (2015年2月8日). 2015年2月13日閲覧。
  9. ^ Jonathan Corbet (2014年12月10日). “Attaching eBPF programs to sockets”. LWN.net. 2015年2月13日閲覧。
  10. ^ Linux kernel 4.1, Section 11. Networking”. kernelnewbies.org (2015年6月21日). 2015年10月17日閲覧。
  11. ^ BPF and XDP Reference Guide”. cilium.readthedocs.io (2017年4月24日). 2018年4月23日閲覧。
  12. ^ BPF and XDP Reference Guide — Cilium 1.6.5 documentation”. docs.cilium.io. 2019年12月18日閲覧。
  13. ^ generic-ebpf/generic-ebpf” (英語). GitHub. 2022年5月14日閲覧。
  14. ^ microsoft/ebpf-for-windows: eBPF implementation that runs on top of Windows”. GitHub. Microsoft (2021年5月11日). 2022年5月14日閲覧。
  15. ^ McCanne (1993年1月). “The BSD Packet Filter: A New Architecture for User-level Packet Capture”. USENIX. 2022年5月14日閲覧。
  16. ^ SCOsource update”. 2003年8月25日時点のオリジナルよりアーカイブ。2019年9月5日閲覧。
  17. ^ Bruce Perens. “Analysis of SCO's Las Vegas Slide Show”. 2009年2月17日時点のオリジナルよりアーカイブ。2022年5月14日閲覧。
  18. ^ Moglen (2003年11月24日). “SCO: Without Fear and Without Research”. GNU Operating System. The Free Software Foundation. 2019年9月5日閲覧。
  19. ^ Reading privileged memory with a side-channel”. Project Zero team at Google (2018年1月3日). 2018年1月20日閲覧。

参考文献 編集

外部リンク 編集