TT Lab
はじめる
学ぶ 学習パス コース

閉域網へのGPUドライバ搬入と導入

閉域網で DKMS モジュールを本当にビルドする

TT Labで続きを見る

このラボは本物のVM上で動きます

Ubuntu 24.04のVM 1台です。カーネルをビルドしてモジュールを読み込むには、カーネルの権限が必要なので、PodではなくVMです。dkmsとビルドツールがインストールされていて、サンプルモジュールのソースが/opt/airgap-hello/(airgap_hello.c、Makefile)にあります。NVIDIAドライバーは再配布できないので、同じ経路(ヘッダーの持ち込み → DKMSビルド → modprobe)を、この20行のGPLモジュールでたどります。VMは、最初はインターネット(80/443)に届きます。ステップ2までが、接続された状態での持ち込み準備で、ステップ3で、外部への送信をふさぎます。採点は、外部からVMの8899ポートに入ってくるエージェントが行うので、すでに確立した接続をふさぐと、採点が切れます。

目標

実行中のカーネルと正確に同じヘッダーを持ち込んで、オフラインでインストールし、DKMSでモジュールをビルド・インストール・ロードしたあと、ヘッダーがずれたときのエラーを採取します。

なぜ重要なのか

エアギャップ環境でのドライバーのインストールで、最もよく壊れる場所は、ドライバーではなく、カーネルヘッダーです。DKMSは、実行中のカーネルのビルドツリー(/lib/modules/<커널>/build)で、モジュールをビルドしますが(プレースホルダーはカーネルです)、持ち込んだヘッダーが1バージョンでも違うと、ビルドが始まりすらしません。そして、カーネルの更新が入った瞬間に、同じことがもう一度起きます。このラボは、その経路を、本物のカーネルでたどります。

所要時間は50分ほどです。セッションが終わるとVMが消えるので、残したいファイルは、終了前に別に保管してください。

ステップ

  1. running=(実行中のカーネル)、headers_pkg=(そのカーネルのヘッダーのパッケージ名)、build_dir=(yesまたはno。今/lib/modules/<커널>/buildがあるか)を書いてください(ファイル: /root/dkms/kernel.txt)。プレースホルダーはカーネルです。
  2. 接続されている間に、そのカーネルのヘッダーのパッケージと、それが要求するヘッダーのパッケージを、インストールせずに/root/dkms/bundle/に取得して、その中でSHA256SUMSを作成してください(ファイル: /root/dkms/bundle/SHA256SUMS)。
  3. 再実行しても、ルールが1セットだけ残るスクリプトで、外部への送信をふさいでください(スクリプト: /root/dkms/egress.sh)。チェーンAIRGAP-EGRESSを使い、ループバックと確立済みの接続は通します。
  4. ハッシュを確認したあと、バンドルの.debでヘッダーをオフラインでインストールして、/lib/modules/<커널>/buildができるようにしてください(プレースホルダーはカーネルです)。
  5. モジュールのソースを/usr/src/airgap-hello-1.0/に置いて、dkms.confを書き(ファイル: /usr/src/airgap-hello-1.0/dkms.conf)、DKMSにaddしてください。
  6. 実行中のカーネルで、build・installして、dkms statusにinstalledが出るようにしてください。
  7. モジュールをsite=labでロードして、vermagic=・signer=(なければnone)・sb_state=(mokutil --sb-stateの結果1行)を書いてください(ファイル: /root/dkms/load.txt)。
  8. ヘッダーがないカーネルバージョン6.8.0-9999-genericでビルドさせて、DKMSが出すエラーを保存してください(保存先: /root/dkms/mismatch.txt)。

参考

実行中のカーネルと、必要なヘッダー

running=・headers_pkg=・build_dir=の3行を書いてください(ファイル: /root/dkms/kernel.txt)。

DKMSが使うビルドツリーは、/lib/modules/<カーネル>/buildです。Ubuntuのヘッダーのパッケージ名は、実行中のカーネル文字列を、そのまま付けたものです。今そのディレクトリがあるかを、確認してください。

ヘッダーをインストールせずに取得して、ハッシュの一覧を作成する

実行中のカーネルのヘッダーのパッケージと、それが要求するヘッダーのパッケージを、/root/dkms/bundle/に取得して、SHA256SUMSを作成してください(ファイル: /root/dkms/bundle/SHA256SUMS)。

apt-get downloadは、インストールせずに、.debだけを取得します。取得したヘッダーパッケージのDependsを見ると、一緒に必要な共通のヘッダーパッケージが出てきます。ハッシュの一覧は、バンドルのディレクトリの中で、相対パスで作成してください。

外部への送信をふさいで、エアギャップ環境にする

再実行しても、ルールが1セットだけ残るスクリプトで、外部への送信をふさいでください(スクリプト: /root/dkms/egress.sh)。

新しいチェーンを作って、OUTPUTの先頭からそこへ送り、ループバック・確立済みの接続・採点エージェントを先に通してから、残りをふさぎます。これ以降は、aptが外部から取得できません。

持ち込んだヘッダーをオフラインでインストールする

ハッシュを確認したあと、バンドルの.debでヘッダーをインストールして、/lib/modules/<커널>/buildができるようにしてください(プレースホルダーはカーネルです)。

バンドルのディレクトリで、ハッシュの一覧で先に検査します。dpkgに2つの.debを一緒に渡すと、お互いの依存を一度に解決します。インストール後、buildがどこを指すリンクなのかを、見てください。

dkms.confを書いてadd

モジュールのソースを/usr/src/airgap-hello-1.0/に置いて、dkms.confを書き(ファイル: /usr/src/airgap-hello-1.0/dkms.conf)、DKMSにaddしてください。

DKMSは、/usr/src/<名前>-<バージョン>でソースを探します。dkms.confには、パッケージ名とバージョン、作られるモジュール名(.koなし)、インストール先、新しいカーネルで自動的にもう一度ビルドするかを書きます。

実行中のカーネルでbuild・install

実行中のカーネルで、build・installして、dkms statusにinstalledが出るようにしてください。

buildは、/var/lib/dkmsの下でモジュールを作成し、installが、それを/lib/modules/<カーネル>/の下に移して、depmodを実行します。失敗すると、make.logのパスが、出力に出ます。

ロードして、vermagic・署名・Secure Bootを記録する

モジュールをsite=labでロードして、vermagic=・signer=・sb_state=を書いてください(ファイル: /root/dkms/load.txt)。

modprobeは、depmodが作成した一覧からモジュールを探して、依存まで読み込み、パラメータを、名前=値で受け取ります。modinfo -Fで、フィールド1つだけを取り出せます。Secure Bootの状態は、mokutilが教えてくれます(EFI変数がないVMなら、そう答えます)。

ヘッダーがないカーネルでビルドさせる

カーネルバージョン6.8.0-9999-genericでビルドさせて、DKMSが出すエラーを保存してください(保存先: /root/dkms/mismatch.txt)。

dkms buildには、対象のカーネルを選ぶオプションがあります。そのカーネルのビルドツリーがなければ、DKMSは、コンパイルを始める前に止まります。出力(標準エラー出力を含む)を、そのまま保存してください。