UbuntuとUEFIセキュアブート
「Ubuntu」と「UEFIセキュアブート」に関するお話です。ちなみに「Ubuntu」は「UEFIセキュアブート」に対応しています。
UEFIセキュアブート
「UEFIセキュアブート」は「UEFI」が持つ機能の1つで、ファームウェア(UEFI BIOS)によって実行されるコードが信頼されたコードであるかどうかを検証する仕組みです。検証の結果、信頼されていないソフトウェアは実行を拒否されます。
「UEFIセキュアブート」を適切に運用するには、OS起動時に読み込まれる各バイナリーがファームウェアに格納されている鍵に対し検証可能でなければなりません。
ファームウェアにはMicrosoftの鍵が格納されている
多くのPC(x86)では、ファームウェアに予め「Microsoft」の鍵が格納されています。この鍵を利用してOS起動時に実行されるソフトウェアを検証します。
世の中で販売されている多くのPCがサポートしているOSは「Windows」のみであり、PCメーカーが「Microsoft」の鍵のみを予めファームウェアに格納しておくことは、ごく自然なことです。
(ここではARMに関する話題は飛ばします。)
UbuntuはWindowsではない
しかし「Ubuntu」は「Windows」ではありません。このままでは「UEFIセキュアブート」環境で「Ubuntu」を起動することはできません。
「Ubuntu」をこのようなPCで簡単に起動できるようにするには、「Microsoft」の鍵で「Ubuntu」のソフトウェアを検証できるようにしなければなりません。
このような環境でLinuxを簡単に起動するための仕組みが導入されていますが、多くのLinuxディストリビューションでは、ファームウェアに予め「Microsoft」の鍵が格納されているという前提に強く依存しています。
Microsoftに署名してもらおう
「Ubuntu」のソフトウェアを「Microsoft」に署名してもらえば、「Microsoft」の鍵で「Ubuntu」のソフトウェアを検証できるようになります。ということで「Ubuntu」では、OSローダーである「shim」バイナリーを「Microsoft」に署名してもらっています。
加えてその後起動する「grub」バイナリーは、「Canonical」が署名しています。
つまり「Microsoft」と「Canonical」による署名でセキュアブートが実現されています。
これらのソフトウェアは、「shim-signed」パッケージや「grub-efi-amd64-signed」パッケージで提供されています。
shim-signedの説明
「shim-signed」パッケージの説明は、以下のようになっています。
セキュアブートチェインローディングブートローダ (Microsoft 署名つきバイナリ)
本パッケージは他の UEFI バイナリの署名を Secure Boot DB/DBX またはビルトイン署名データベースを使って検証することのできる最低限のブートローダを提供します。
その目的は頻繁に変更されない小さなバイナリにUEFI CAによる署名を施し、 OSディストリビュータがCAと独立にメインのブートローダを改訂できるようにすることです。
本パッケージにはMicrosoft UEFI CAにより署名された版のブートローダバイナリが含まれます。
本パッケージは他の UEFI バイナリの署名を Secure Boot DB/DBX またはビルトイン署名データベースを使って検証することのできる最低限のブートローダを提供します。
その目的は頻繁に変更されない小さなバイナリにUEFI CAによる署名を施し、 OSディストリビュータがCAと独立にメインのブートローダを改訂できるようにすることです。
本パッケージにはMicrosoft UEFI CAにより署名された版のブートローダバイナリが含まれます。
grub-efi-amd64-signedの説明
「grub-efi-amd64-signed」パッケージの説明は、以下のようになっています。
GRand Unified Bootloader, version 2 (EFI-AMD64 version, signed)
GRUB は移植可能で強力なブートローダです。
(中略)
This package contains a version of GRUB built for use with the EFI-AMD64 architecture, signed with Canonical's UEFI signing key.
GRUB は移植可能で強力なブートローダです。
(中略)
This package contains a version of GRUB built for use with the EFI-AMD64 architecture, signed with Canonical's UEFI signing key.
Ubuntuのセキュアブート対応
「Ubuntu」のセキュアブート対応を紹介します。1.Ubuntuのインストール時やGRUBのインストール時
「Ubuntu」をインストールする時や「GRUB」をインストール(アップデート)する時、「Ubuntu」はファームウェアの「BootEntry」に「Ubuntu」を起動するためのエントリーを追加し、デフォルトで「Ubuntu」が起動するように設定を行います。この時「shim」バイナリーはすでに「Microsoft」によって署名されているバイナリーであり、ファームウェアは自身が格納している「Microsoft」の鍵で「shim」バイナリーを検証し、そして正当なバイナリーであることが分かるため、ファームウェアは「Ubuntu」による設定を受け入れます。
2.PCが起動すると
PCが起動すると、ファームウェアは自身の「BootEntry」変数で指定されている「shim」バイナリーを読み込みます。上記で紹介したように「shim」バイナリーは正当なバイナリーであるため、ファームウェアはこの「shim」バイナリーを実行します。
「Microsoft」の署名関連の話はここで一段落付きます。
さて起動した「shim」バイナリーは、通常は「grub」を起動します。
もしファームウェア変数で鍵管理を行うように設定されていれば、「MokManager」を起動します。
後者の設定は通常、以前起動していたシステム(OS)により、設定されるものです。
3.MokManagerが起動すると
鍵管理を行うように設定されている場合、「MokManager(mm*.efi)」バイナリーが読み込まれます。このバイナリーは「shim」によって一時的な鍵により署名され、その署名により信頼されるバイナリーです。
ただし「shim」による署名は「shim」のビルド時に共にビルドされた「MokManager」に対してのみ有効です。
これにより悪意あるバイナリーの実行を制限しています。
「MokManager」では、鍵の登録や削除、信頼するバイナリーハッシュの登録、「shim」による署名検証の有効・無効の切り替えなどを実行できます。
ただしこれらの作業では、事前に設定したパスワードの入力が必要になります。
このパスワードは一時的なものであり、作業が完了もしくはキャンセルされれば、即座にパスワードが削除されます。
またこれとは別に「MokManager」自身のパスワード設定も可能です。
4.grubが起動すると
「Ubuntu」では「initrd」イメージを除き、「Ubuntu」の起動に必要なすべてのバイナリーは「Canonical」によって署名されています。「Canonical」の鍵は「Microsoft」によって署名された「shim」バイナリーに埋め込まれており、「Canonical」の署名は暗黙的に信頼されるようになっています。
「grub(grub*.efi)」バイナリーが読み込まれ検証が実行されますが、「grub」バイナリーは「Canonical」によって署名されているため、検証に成功し起動プロセスを続行できます。
「grub」は「ESP(EFI System Partition)」から設定ファイルを読み込み、その設定ファイルに指定されているもう一つの設定ファイルを読み込みます。
もう一つの設定ファイルは、root(/)もしくはbootパーティションに配置されています。
そしてその設定ファイルには、読み込むべきカーネルイメージが指定されており、指定されたカーネルイメージを読み込み起動処理を続行します。
この一連の流れにおいてEFIアプリケーションは、ファームウェア変数の設定などファームウェアに対して完全なアクセスが可能です。
そのためロードする「Linux kernel」は、信用データベースに対し検証可能であり検証に成功しなければなりません。
「Ubuntu」が提供する「Linux kernel」は「Canonical」によって署名されており、検証に成功します。
その後「Linux kernel」に処理が委譲されます。
ただし「initrd」イメージは署名されておらず、「initrd」イメージの検証は行われません。
5.検証に失敗すると
「Ubuntu」の起動に必要ないずれかのソフトウェアの検証に失敗した場合、「Ubuntu」は起動に失敗します。またサードパーティー製のドライバーなど検証に成功する署名が為されていないカーネルモジュールは、「Linux kernel」で読み込めません。
「Linux kernel」はそのようなカーネルモジュールを拒否します。
例えば「insmod」や「modprobe」でカーネルモジュールを読み込もうとしても失敗し、エラーメッセージが出力されます。
ユーザーによる署名とMOK
さて署名がないカーネルモジュールをUEFIセキュアブート環境で読み込めるようにするには、検証可能な署名が必要になります。だからと言って「Canonical」に署名してもらうわけには行きません。
MOK
そこで登場するのが「MOK(Machine Owner Key)」です。名称の通りマシン(PC)の所有者(ユーザー)が所持する鍵です。
この鍵を利用してカーネルモジュールに署名します。
MOKの生成と登録
「MOK」は「UEFI」環境で「Ubuntu」をインストールもしくはアップグレードしていれば、自動的に生成されます。インストール時もしくはアップグレード時に生成される「MOK」はそのPC固有の「MOK」であり、「shim」や「Linux kernel」によりカーネルモジュールに署名するためだけに利用できる鍵です。
「MOK」には「KeyUsage OID(1.3.6.1.4.1.2312.16.1.2)」が指定されており、利用用途が制限されています。
また「Ubuntu」インストール時にUEFIセキュアブート環境でユーザーが指示すれば、インストール完了後に初めて「Ubuntu」を起動した時に、ユーザーによる「MOK」の登録作業を行えます。
この辺の話は後述します。
MOKを登録するには
さてUEFIセキュアブート環境で「MOK」の登録を行っていない場合、自動的に生成された「MOK」を「shim」に登録するには、以下のコマンドを実行します。
sudo update-secureboot-policy --enroll-key
すでに「MOK」が登録されている場合、このコマンドは何も行いません。
「MOK」が登録されていなかった場合、「MOK」登録作業時に入力するパスワードを入力するように促されます。
パスワード設定後にPCを再起動すれば、「MokManager」が起動し「MOK」登録作業を行えるようになります。
この時パスワードの入力が求められるので、上記コマンド実行時に入力したパスワードを入力します。
MOKを生成するには
自動的に生成された「MOK」が存在していない場合、「MOK」が見つからないとのエラーメッセージが出力されます。その時は以下のコマンドで「MOK」を生成できます。
sudo update-secureboot-policy --new-key
「MOK」生成後、再度上記で紹介したコマンドを実行し「MOK」を登録してください。
カーネルモジュールに署名
後は「kmodsign」コマンドを実行し、「MOK」でカーネルモジュールに署名するだけです。MOKの自動生成と自動署名
上記でも紹介したように「MOK」は「UEFI」環境で「Ubuntu」をインストールもしくはアップグレードしていれば、自動的に生成されます。この流れを具体的に見てみましょう。
UEFI環境でUbuntuをインストールしていない場合
「UEFI」環境で「Ubuntu」をインストールしていない場合、「MOK」の自動生成やカーネルモジュールへの自動署名は行われません。このような環境ではUEFIセキュアブートの仕組みが存在せず、そもそも鍵の登録もできません。
UEFI環境でUbuntuをインストールする場合
「UEFI」環境で「Ubuntu」をインストールする場合、「MOK」の自動生成やカーネルモジュールへの自動署名が行われます。UEFIセキュアブートが無効になっていても「MOK」の自動生成や自動署名が行われます。
これは後からユーザーがUEFIセキュアブートを有効にする場合に備えるためです。
さて「UEFI」環境で「Ubuntu」をクリーンインストールする場合と、アップグレードする場合で、その過程が少し異なります。
Ubuntuをクリーンインストールする場合
「Ubuntu」を「UEFI」環境でクリーンインストールする場合、インストールの準備画面でサードパーティー製のソフトウェアをインストールするオプションを選択できます。このオプションを選択すると、署名が必要なサードパーティー製のソフトウェアが存在する場合、「MOK」を登録するためのパスワード入力画面が表示されます。
また署名が必要なサードパーティー製のソフトウェア(カーネルモジュール)は、自動的に「MOK」による署名が行われます。
「MOK」の登録作業は「Ubuntu」インストール完了後に初めて「Ubuntu」を起動した時に、ユーザーによる「MOK」の登録作業を行います。
Ubuntuをアップグレードする場合
「UEFI」環境でインストールした「Ubuntu」をアップグレードする場合、「shim-signed」パッケージのアップグレード時に「MOK」が生成されます。また「MOK」を登録するためのパスワード入力画面が表示されます。
また署名が必要なサードパーティー製のソフトウェア(カーネルモジュール)は、自動的に「MOK」による署名が行われます。
「MOK」の登録作業は「Ubuntu」アップグレード完了後に初めて「Ubuntu」を起動した時に、ユーザーによる「MOK」の登録作業を行います。
またこの時セキュアブートによる検証が無効になっている場合は、再度検証を有効にするように促されます。
DKMSによる自動署名
クリーンインストールする場合でもアップグレードする場合でも、その後サードパーティーのカーネルモジュールをアップデートする場合でも、「DKMS」による「MOK」の自動署名が行われます。つまり「DKMS」でサードパーティーのカーネルモジュールをビルドしている場合は、ユーザーは何もしなくてもシステム側で面倒を見てくれるというわけです。
というわけで
特にカジュアルなユーザーにとってUEFIセキュアブートは分かりにくく、自分でビルドしたドライバーが認識しない等のトラブルに対し、原因の追求や対処は時間がかかる作業となります。このような状況では、UEFIセキュアブートを無効にして現象を確認するのも一つの方法かと思います。