久しぶりにPCのモニターを新調したので、このタイミングでGRUB(GRand Unified Bootloader)を少しいじってみることにした。
GRUBにはたくさんの機能があり、かなりのことができるようになっているにもかかわらず、それは知識が足らなくて使えない。
一方で、使える解像度を調べたい、お気に入りのフォントを使いたいといった簡単なことが、かつてはできていたのにセキュアブートの制限でできないでいる。
この以前簡単にできたことを、セキュアブートの環境でできるようにする。
はじめに
やること
やることは以下。
- 使用したいコマンドやフォント・キーマップを内蔵したGRUBバイナリを作る。
- 自分専用の秘密鍵・証明書を作りShimの信頼データーベースに登録する。
- 自分専用の秘密鍵・証明書で、作成したGRUBバイナリに署名する。
これを実行するために調べたことを書き記しているので、記事はやたらと長くなっているが、実行すること自体はそれほど多くない。
結論からすると、この手順でVMwareではちゃんと動作するGRUBバイナリを作ることができる。
メインPCではat_keyboardが動作しないため、ソースからビルドしてだいたいOKなGRUBバイナリを作った。
環境
Windows 11 Pro と Ubuntu 20.04 LTS desktop のデュアルブート環境。
セキュアブートとTPM2.0に対応したシステム構成になっている。
Windows 11 Proが要求するのでセキュアブートを有効にしている。
そのために、Ubuntuもセキュアブートに対応させる必要がある。
デュアルブート環境の方は、こんな理由でUbuntuのセキュアブートを有効にしているのではなかろうか。
起動の仕組み
Ubuntuのセキュアブートについて教えてくれている。
Ubuntu wiki / SecureBoot
以下は、元記事の自分なりの理解+今回分かったことの表。
段階 | 起こること | Shim検証 | ファイル |
---|---|---|---|
1 | ファームウェアがブートエントリーで指定されたShimバイナリをロードする。 ShimバイナリはMicrosoftによって署名されているので、ファムウェアに承認される。 ShimバイナリはCanonicalの証明書と独自の信頼データーベースを持っている。 | - | shimx64.efi |
2 | ShimからGRUBバイナリがロードされる。 GRUBバイナリはCanonicalによって署名されているので、信頼される。 もし、鍵の管理が必要な場合は、GRUBの代わりにMokManagerが呼び出される。 MokManagerは後述の青い背景の画面で、鍵の設定が終わるorキャンセルされたリブートする。 | ○ | grubx64.efi mmx64.efi |
3 | GRUBが構成ファイルやモジュール、フォントをロードする。 GRUBバイナリに含まれるモジュールやフォントはロードできる。 GRUBの外にあるファイルの多くはセキュリティポリシーでロードできない。 (構成ファイルと背景画像はロードできる) | ? | (GRUB用) モジュール フォント キーマップ |
4 | GRUBがカーネルをロードする。 公式のUbuntuカーネルはCanonicalによって署名されているので、信頼される。 なお、initrd.imgは検証されない。 | ○ | vmlinuz |
5 | カーネルに制御が移ると、信頼変数へのアクセスは読み取り専用になる。 カーネルはモジュールを検証してからロードする。 Canonicalが配布するモジュールはCanonicalによって署名されレテいるので、信頼される。 | - | カーネルモジュール |
GRUBがモジュールやフォントのロード時に発生させるエラーは、単にポリシーによるものなのか、Shimにより拒否しているのか明確にできていない。
フォントに署名する方法は見つからなかったが、GRUBバイナリの中にそれらを含めればロードできることは分かった。
また、カーネルの検証で使われる証明書がなんなのかは読み取れなかったが、今回はGRUBの設定なので対象外としておく。
Ubuntuの場合、起動時に/boot/efiにESP(EFI System Partition)をマウントしており、GRUBバイナリ(grubx64.efi)は/boot/efi/EFI/ubuntuにある。
grubx64.efiの拡張子は、Extensible Firmware Interface(EFI)で、ファームウェアで実行できるプログラムであることを表している。
ブートローダー(または、ファームウェアによって直接ロードされるファイル=efi_binary)にはsbsignで署名できる。
今回はgrubx64.efiを生成するので、この手法で実際に署名している。
$ sbsign --cert path/to/MOK.pem --key path/to/MOK.priv --output path/t/outputfile.efi efi_binary.efi
カーネルモジュールにはkmodsignで署名できる。
$ kmodsign sha512 \ /var/lib/shim-signed/mok/MOK.priv \ /var/lib/shim-signed/mok/MOK.der \ module.ko
MOK.priv、MOK.pem、MOK.derはこの先で生成している。
今回はカーネルモジュールは触っていないので、/var/lib/shim-signed/mokには配置していないけれど、何か署名されていないドライバーを使いたいときには、この秘密鍵と証明書が使えるだろう。
結局どうするべきなのか
セキュアブート環境におけるGRUBのカスタマイズには、以下の4つの選択肢がある。
- [insecure]ファームウェアでセキュアブートを無効にする。
- [insecure]Shimによる検証を無効にする。
- [secure]必要なモジュールやフォント、キーマップを含めたGRUBバイナリを作り、Shimの検証が正常となるように仕掛ける。
- [secure]GRUBのカスタマイズを諦める。
選択肢1は、Windows 11に要求されているので適用できない。
仕方なく選択肢4だったのだが、これをどうにかしようと思い立った訳で…
選択肢2 or 3のいずれかを適用することになる(この先で手順を説明している)。
選択肢2、つまりShimを無効にすることついては色々な場所で議論されていると思うが、それはそれで1つの選択ではある。
でも、カーネルに何か悪いものが侵入した場合、それが巧妙に隠され、lsで見ることさえもできなくなってしまうかもしれない。そんなものは入ってこない!とは断言できないから、安全サイドに倒すのならば選択肢3を適用するのだろう。
今回は選択肢3、つまり、GRUBバイナリを作成し、Shimの検証が正常になる手順を整理したので、選択肢3を適用してみるか…
検証環境について
VMware playerでUbuntu 22.04 LTS serverの環境を立ち上げ、手順を確立することにした。
解像度に関してだけ、ちょっとやることがある。
Qiita / VMware WorkstationのLinux Serverコンソールを高解像度にする
/path/to/vmxfile/hoge.vmx
svga.guestBackedPrimaryAware = "FALSE"
※FALSEに設定を変更しておく。あるいは、この行を削除する。
※この設定は、ゲストを起動する度に"TRUE"に書き換えられる。再起動では問題ないが、シャットダウンしたら再度書き換える必要がある。
GRUBで使用できる解像度は、GRUBで調べる。
メニューが表示されている間に[c]キーを押し、コマンド入力画面でvideoinfoコマンドを実行する。
以下、VMware playerで実行した結果(抜粋)。
grub> set pager=1 grub> videoinfo List of supported video modes: Legend: mask/position=red/green/blue/reserved Adapter `Bochs PCI Video Driver': No info available Adapter `Cirrus CLGD 5446 PCI Video Driver': No info available Adapter `EFI GOP driver': 0x000 320 x 200 x 32 (1280) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 ... 0x003 1024 x 768 x 32 (4096) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 ... 0x016 1920 x 1080 x 32 (7680) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 ... 0x01c 1280 x 768 x 32 (5120) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 Adapter `EFI UGA driver': No info available grub> exit
テストでは1920x1080を使用している。
GRUBのカスタマイズ(Shimの検証をやめる)
前述のページに、Shimによる検証を無効にする方法が書かれている。
これによって安全性が失われ、起動時に「Booting in insecure mode」と安全でないことが表示される副作用もある。
でも、ファームウェアはセキュアブートのままだし、もちろんWindowsはセキュアブートが有効。
あくまでも、Ubuntuが起動中のShimによる検証を止めるだけ。
インストール済みのGRUBのコマンドはそのまま使えるし、フォントもキーマップも読み込むことができるようになる。
世の中にある多くのGRUBカスタマイズの記事をそのまま適用できるようになるのは、メリットといえるかもしれない。
Shimの検証を無効化
Shimの検証を無効化するには、以下を実行。
$ sudo mokutil --disable-validation password length: 8~16 input password: パスワードを入力[Enter] input password again: 同じパスワードを入力[Enter] $ sudo reboot
※パスワード 12345678 が楽かも。
再起動すると、MOKの確認画面が現れる。
パスワードの確認画面が現れる。
ここでは、パスワードの○文字目、○文字目、○文字目…と3回聞かれる。
パスワードの確認が終わると、セキュアブートを無効するかどうかを聞いてくるので、はいと回答し、再起動する。
これで、起動時のShimによる確認が行われなくなる。
元に戻すには、以下を実行。
$ sudo mokutil --enable-validation password length: 8~16 input password: パスワードを入力[Enter] input password again: 同じパスワードを入力[Enter] $ sudo reboot
比較的簡単に検証機能のオンオフができることが分かった。
解像度
解像度はGRUB_GFXMODEで設定する。
/etc/default/grub
GRUB_GFXMODE=1920x1080x32
GRUBの更新。
$ sudo update-grub
これで再起動したところ、設定通りの解像度になった。
なお、メインPCで4Kを試したところ、文字の描画にかなり時間が掛かるようになった。
使いやすいとはいえないので2Kに設定したが、これもだいぶもたつく。
モニターを新調したので解像度を上げて使いやすくしようとする試みだったので、ここでちょっと萎えたのは内緒。
フォント
解像度を大きくすると文字が小さくなってしまうと想像し、大きなフォントを使うことにした。
(実際にはモニターがまぁまぁ大きいので、デフォルトのままでも問題はなかったが)
検索してみたところ、ヒットしたのがこちら。
タイトルはアレな感じを出しつつ、中身はしっかりと書かれていて、最後に萌えで締まる秀逸な記事だった。
おのかちお's blog / PCのブートローダーを痛grubにする
grub-mkfontというコマンドで、お気に入りのフォントを作成できるそうだ。
$ sudo apt install fonts-noto-mono fonts-dejavu
インストールしたフォントは/usr/share/fontsあたりに入っている。
ここからGRUB用のフォントを作ってみた。
$ sudo grub-mkfont -s 32 -o /boot/grub/fonts/NotoSansMono-Regular.pf2 /usr/share/fonts/truetype/noto/NotoSansMono-Regular.ttf $ sudo grub-mkfont -s 32 -o /boot/grub/fonts/DejaVuSansMono.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf
あわせて、M+ FONTSを試してみる。
$ git clone https://github.com/coz-m/MPLUS_FONTS.git $ sudo grub-mkfont -s 32 -o /boot/grub/fonts/Mplus1Code-Regular.pf2 MPLUS_FONTS/fonts/ttf/Mplus1Code-Regular.ttf
フォントを読み込む設定をする。
/etc/default/grub
GRUB_FONT="/boot/grub/fonts/NotoSansMono-Regular.pf2" #GRUB_FONT="/boot/grub/fonts/DejaVuSansMono.pf2" #GRUB_FONT="/boot/grub/fonts/Mplus1Code-Regular.pf2"
※今回はフォントを3つ作ったが、どれか1つを読み込むように設定。
GRUBを更新して再起動。
$ sudo update-grub
それぞれのフォントで、このような表示がされた。
M+FONTで罫線と矢印が表示できないので探してみたところ、このような情報が見つかった。
Ask Ubuntu / Adding a GRUB2 background image and custom font
Ask Ubuntu / No box characters after changing the default Grub font
フォントのグリフ(glyphs)の順序が特定のものでないと、うまく表示ができないとのこと。
GIMPで編集という投稿もあったので、画像編集ソフトで開いて編集できるのかもしれないが、どんなものなのかは調べていない。
キーマップ
日本語キーボードなので、grubでの入力がちょっと大変。
ask ubuntu / How to change grub command-line (grub shell) keyboard layout?
キーマップを作成。
$ sudo grub-kbdcomp -o /boot/grub/japanese.gkb jp
これを読み込むために設定を入れる。
/etc/default/grub
GRUB_TERMINAL_INPUT="at_keyboard"
これだけだと作られない設定があるようで、grub.cfgを作成するスクリプトに2行を追加。
/etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
insmod keylayouts
keymap /boot/grub/japanese.gkb
GRUBを更新して再起動。
$ sudo update-grub
これで、日本語キーボードの表記通りに文字を入力することができるようになった。
背景画像の設定
背景画像の設定について、こちらで教えてくれている。
Ubuntu documentation / Community Help Wiki / Grub2/Displays
画像は8ビット(256色)のJPGが使えるけれど、PNGの方が良いでしょう、と教えてくれているので、海で撮った写真を適当に切り取ってPNGを作成した。
このPNGファイル、移動されると見えなくなる。
ユーザーディレクトリに置いておくよりは、どこかあんまり触らないところにおくのが良さそうだった。
$ sudo mkdir /usr/local/share/grub $ sudo cp beach.png /usr/local/share/grub
GRUBにこの画像を設定。
/etc/default/grub
GRUB_BACKGROUND="/usr/local/share/grub/beach.png"
GRUBを更新して、再起動。
$ sudo update-grub
再起動すると画像が表示される。
1920x1080(16:9)と1024x768(4:3)の2パターンで試したところ、画像が自動で伸縮される様子が見えた。
適用する解像度・縦横比に合わせた画像を用意すれば、いつも気分がよい映像が表示されることだろう。
GRUBのカスタマイズ(Shimの検証を通す)
安全性を保ち、起動時には「EFI stub: UEFI Secure Boot is enabled.」と安全であることが表示される。
(安全表示はメインPCでは行われなかった、余計なことは表示されず、スマートに起動している)
一定の手順を踏めば、セキュアブートの環境で、思い通りにGRUBを動作させることが可能になる。
世の中にあるGRUBのカスタマイズ記事を適用するには、相応のカスタマイズが必要ではある。
やること
Ubuntuで配布されているGRUBバイナリ(grubx64.efi)は、Canonicalによって署名されている。
このバイナリはコマンド(モジュール)やunicodeフォントを内蔵しており、これらは正常に読み込まれて動作する。
Shimを有効にしてGRUBバイナリを思い通りに動作させようという試みは、以下を実施することである。
- フォントやキーマップなど、読み込む必要があるファイルを入れたmemdiskを作成。
- 利用するモジュールを全て含み、かつ、memdiskを含むgrubx64.efiを生成。
- grubx64.efiに署名するための秘密鍵と証明書を生成。
- Shimに証明書を登録。
- 秘密鍵と証明書でgrubx64.efiに署名し、/boot/efi/EFI/ubuntu/grubx64.efiと差し替え。
GRUBのカスタマイズが大変なので、systemd-bootに移行したという書き込みもチラホラ見られた。
確かにまっすぐにやり方を教えてくれるところがなくて時間が掛かったが、最終的にはArchLinuxの解説ページ→Ubuntuのビルドスクリプトとたどって、手順を整理できた。
このような情報を見ておいてもいいかもしれない。
Ubuntu blog / How to sign things for Secure Boot
Ubuntu Wiki / Testing Secure Boot
Debian Wiki / SecureBoot
ArchLinux / Unified Extensible Firmware Interface/セキュアブート
セキュアブートで発生した問題
Shimによる検証を無効にしてGRUBをカスタマイズした後、Shimによる検証を有効にした。
この時に発生した問題を整理しておく。
ぱっと見で分かるのは解像度が変わらないこと、フォントが読み込まれないこと、罫線が表示されないこと。
上下の矢印も表示されていない。
ask Ubuntu / No box characters after changing the default Grub font
フォントは読み込みでエラーが発生している。
grub> loadfont /boot/grub/fonts/NotoSansMono-Regular.pf2 error: prohibited by secure boot policy.
※訳:セキュアブートのポリシーで禁止されている。
videoinfoを表示させようとしたが、こちらもエラーになっている。
grub> videoinfo error: Secure Boot forbids loading module from (hd0,gpt2)/boot/grub/x86_64-efi/videoinfo.mod.
※訳:セキュアブートは(hd0,gpt2)/boot/grub/x80_64-efi/videoinfo.modからのモジュールの読み込みを禁止している。
キーマップは英語キーボードのそれだった。
きっと、モジュールも読み込めないし、キーマップも読み込めないのだろう。
でも、背景画像は表示されている。読み込みは禁止されていない。
解像度が変わらないのは何故か。
構成ファイルを確認してみると、フォントの読み込みに失敗すると、解像度を変更しない作りになっていることが原因だった。
/boot/grub/grub.cfg
if loadfont $font ; then set gfxmode=1920x1080 load_video insmod gfxterm set locale_dir=$prefix/locale set lang=en_US insmod gettext fi terminal_output gfxterm
そこで、GRUBのコマンドラインで解像度の変更がされるのか試してみた。
UNIX & LINUX / Is it possible to set the screen resolution from inside the GRUB terminal?
grub> set gfxmode=1920x1080 grub> terminal_output console grub> terminal_output gfxterm
結果、解像度はちゃんと変化した。
解像度変更前の画像のサイズを測ってみたら、元々の解像度は1024x768だったことが分かる。
GRUBが自動的に最適と考えるサイズは1024x768ということのようだ。
発生した問題についての確認は、ザックリとはこんなところ。
とはいえ、表示が変なだけで動作はする。
でも、この先の手順で失敗すると「GRUBバイナリが起動できない=Ubuntuが起動できない」なんてこともあるので、回復の手段を用意しておく。
GRUBバイナリの回復手段
試行錯誤している間、それこそ「何度も何度も繰り返し実施」この回復をさせている。
問題発生時に実行できるようにリハーサルしておくべき。
カスタマイズしたGRUBバイナリ(grubx64.efi)を作り、元々あるgrubx64.efiと置き換える。
grubx64.efiに間違いがあると、その間違いの状態によって以下の致命的な問題が発生する。
- GRUBが起動しない(青画面=MokManagerが起動してOSを起動できない)
- GRUBは起動するが、メニューが表示されず、コマンドも実行できない。
- GRUBのメニューが表示されるが、カーネルをロードできない。
そこで、回復手段の1つとして、Ubuntu server 22.04 LTS のLiveCDを使用した回復を整理しておく。
LiveCDで起動して、シェルを起動する。
検証環境の場合、ディスクの状態は以下の通りになっていたので、
/dev/sda2 -> /
/dev/sda1 -> /boot/efi
以下のようにマウントすると、/mnt配下にディレクトリ構成が復元できる。
# mount /dev/sda2 /mnt # mount /dev/sda1 /mnt/boot/efi
メインPC(デュアルブート)の環境はこうだった。
# mount /dev/nvme0n1p5 /mnt # mount /dev/nvme0n1p1 /mnt/boot/efi
このように、マウントするデバイス・パーティションは、自分の環境に合わせて変える。
マウントしたら、Ubuntuで配布しているGRUBバイナリに書き戻す。
# cp /mnt/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed \ /mnt/boot/efi/EFI/ubuntu/grubx64.efi
※EFI/ubuntuディレクトリにバックアップを作っておいても良いかもしれない。
再起動。
# reboot
今回はgrub.cfgに無茶な変更を入れていないので、Ubuntuはこれで起動してくるだろう。
救援用のブートのエントリーを追加
これを先にやっておけば「回復手段」を使う回数はぐっと減ったはず。
後からこの手順を整理したので、効率が悪かった…
ファームウェアのブートメニューから、復旧ブートが選択できるようにする。
ここにCanonicalが署名したGRUBバイナリを入れておけば、セキュアブートのままでUbuntuを起動することができる。
EFIディレクトリにあるubuntuディレクトリがブートローダーの入ったディレクトリなので、これを複製する。
$ cd /boot/efi/EFI $ sudo cp -a ubuntu rescue
このままだと、ubuntuという名前が2つ見えるので、どちらがrescueなのかがはっきりしない。
そこで、以下のコマンドで名前を付ける。
kledgeb / efibootmgr その2 - UEFIブートマネージャーにブートローダーを登録する
$ sudo efibootmgr --create --disk /dev/sda1 --loader \\EFI\\rescue\\shimx64.efi --label rescue
メインPCでは、こんなパラメーターで追加することができた。
$ sudo efibootmgr --create --disk /dev/nvme0n1p1 --loader /EFI/rescue/shimx64.efi --label rescue
ディスクとパーティションは、以下で分かる。
$ df -h Filesystem Size Used Avail Use% Mounted on tmpfs 388M 1.5M 387M 1% /run /dev/sda2 19G 7.5G 11G 42% / tmpfs 1.9G 0 1.9G 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock /dev/sda1 952M 15M 937M 2% /boot/efi tmpfs 388M 4.0K 388M 1% /run/user/1000
VMware Playerの場合、起動直後にDELキーを押してあげると、どのブートローダーを読み込むのかを選択できる。
メインPCではF12キーだったりするので、そのあたりはPCやマザーボードについて調べておく。
これで、GRUBバイナリが何らかの理由で読み込めなかったとき、ファームウェアのブートメニューから rescue を起動すれば、OSが起動させられる。OSさえ起動できれば、後はどうにかなるだろう。
GRUBバイナリを構築する環境
GRUBバイナリ(grubx64.efi)の構築はなかなか難しく、適当なディレクトリで試行錯誤を繰り返し、とりあえず動くものが生成できるようになった。
ただ、GRUBバイナリができただけではダメ。
GRUBが更新されたときに、自動で再構築して差し替えられる、そんな仕掛けが必要だ。
それを仕掛けるなら、ちゃんと決まった場所にファイルを入れておきたい。
そこで、ディレクトリとファイルの構成を、以下の通りに整理した。
/usr/local/ |-- bin | `-- my-grub-mkimage *1 |-- lib | `-- grub | |-- grubx64.efi *2 | |-- grubx64.efi.signed *2 | |-- memdisk.squashfs *2 | `-- sbat.csv *2 `-- share `-- grub |-- memdisk | |-- fonts | | `-- unicode.pf2 *1 | `-- keylayouts | `-- japanese.gkb *1 `-- umi.png /var/lib/shim-signed/mok |-- MOK.der *1 |-- MOK.pem *1 `-- MOK.priv *1
*1 手で作成
*2 my-grub-mkimageが生成
ここで、以下のディレクトリを作っておく。
$ sudo mkdir /usr/local/{share,lib}/grub
なお、背景画像(この例だとbeach.png)はgrubx64.efiに含める必要はない。
読み込みが禁止されていないので、お好みの画像をフルパスでセットすればOK。
my-grub-mkimage
grubx64.efiの作り方を探していたところ、このような記事を見つけた。
おかげで、とりあえずgrubx64.efiが生成できるようになった。
ask ubuntu / Default embedded modules in bootx64.efi, grubx64.efi and mmx64.efi
もう少し探してみたところ、ArchLinuxが教えてくれた。困ったときにはArchLinux!
ArchLinux / GRUB
ビルドスクリプト, SBAT.CSV
おかげで、標準ではどんなモジュールが登録されていて、どんなパラメーターで作られているのかが分かった。
ソースコードをダウンロードしてきて、見よう見まねでGRUBバイナリを生成するスクリプトを作ってみる。
/usr/local/bin/my-grub-mkimage ※新規作成
#!/bin/bash DIR_LIB=/usr/local/lib/grub DIR_SHARE=/usr/local/share/grub DIR_MOK=/var/lib/shim-signed/mok if [ "$1" = "systemd" ]; then diff $DIR_LIB/grubx64.efi.signed /boot/efi/EFI/ubuntu/grubx64.efi if [ $? = 0 ]; then echo "not update" exit 0 fi fi SBAT_TMP=($(objdump -h /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed | grep \.sbat)) SBAT_POS=$((16#${SBAT_TMP[5]})) SBAT_SIZ=$((16#${SBAT_TMP[2]})) CD_MODULES=" all_video boot btrfs cat chain configfile echo efifwsetup efinet ext2 fat font gettext gfxmenu gfxterm gfxterm_background gzio halt help hfsplus iso9660 jpeg keystatus loadenv loopback linux ls lsefi lsefimmap lsefisystab lssal memdisk minicmd normal ntfs part_apple part_msdos part_gpt password_pbkdf2 png probe reboot regexp search search_fs_uuid search_fs_file search_label sleep smbios squash4 test true video xfs zfs zfscrypt zfsinfo " #serial #peimage CD_MODULES="$CD_MODULES cpuid linuxefi play tpm " GRUB_MODULES="$CD_MODULES cryptodisk gcry_arcfour gcry_blowfish gcry_camellia gcry_cast5 gcry_crc gcry_des gcry_dsa gcry_idea gcry_md4 gcry_md5 gcry_rfc2268 gcry_rijndael gcry_rmd160 gcry_rsa gcry_seed gcry_serpent gcry_sha1 gcry_sha256 gcry_sha512 gcry_tiger gcry_twofish gcry_whirlpool luks luks2 lvm mdraid09 mdraid1x raid5rec raid6rec " GRUB_MODULES="$GRUB_MODULES at_keyboard usb_keyboard keylayouts videoinfo " rm $DIR_LIB/memdisk.squashfs mksquashfs $DIR_SHARE/memdisk $DIR_LIB/memdisk.squashfs -comp xz if [ $(grub-mkimage --usage | grep -c sbat) == 1 ]; then # Ubuntu 22.04 tail -c +$SBAT_POS /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed \ | head -c $SBAT_SIZ \ | tr -d "\000" > $DIR_LIB/sbat.csv grub-mkimage \ -O x86_64-efi \ -o $DIR_LIB/grubx64.efi \ -m $DIR_LIB/memdisk.squashfs \ -p /EFI/ubuntu \ --sbat $DIR_LIB/sbat.csv \ $GRUB_MODULES else # Ubuntu 20.04 tail -c +$SBAT_POS /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed \ | head -c $SBAT_SIZ > $DIR_LIB/sbat.csv grub-mkimage \ -O x86_64-efi \ -o $DIR_LIB/grubx64.efi \ -m $DIR_LIB/memdisk.squashfs \ -p /EFI/ubuntu \ $GRUB_MODULES SBAT_INSTMP=($(objdump -h $DIR_LIB/grubx64.efi | grep \.reloc)) SBAT_INSPOS=$((16#${SBAT_INSTMP[5]})) SBAT_INSSIZ=$((16#${SBAT_INSTMP[2]})) objcopy --set-section-alignment '.sbat=4096' \ --add-section .sbat=$DIR_LIB/sbat.csv \ --adjust-section-vma .sbat=$(($SBAT_INSPOS+$SBAT_INSSIZ)) \ $DIR_LIB/grubx64.efi fi sbsign --key $DIR_MOK/MOK.priv --cert $DIR_MOK/MOK.pem \ --output $DIR_LIB/grubx64.efi.signed $DIR_LIB/grubx64.efi cp $DIR_LIB/grubx64.efi.signed /boot/efi/EFI/ubuntu/grubx64.efi
※Ubuntu 22.04と20.04で処理を分けた。20.04のgrub-mkimageで--sbatパラメーターが使えなかったため。
実行権を付けておく。
$ sudo chmod +x /usr/local/bin/my-grub-mkimage
スクリプトの中でobjdump,objcopyを使用しているので、パッケージをインストールしておく。
$ sudo apt install -y binutils
ArchLinuxの記事が教えてくれているように、sbat.csvがないとセキュアブート環境ではgrubx64.efiが起動しない。
ソースコードにあるsbat.ubuntu.csvを加工することを考えたが、2行目がgrub,1,...となっていて起動しない。
そこで、配布されているgrubx64.efi.signedから抜き出すことにした。
結果として、この日のGRUBバイナリからは、以下のファイルが抽出できる。
/usr/local/lib/grub/sbat.csv
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md grub,3,Free Software Foundation,grub,2.06,https://www.gnu.org/software/grub/ grub.ubuntu,1,Ubuntu,grub2,2.06-2ubuntu14.1,https://www.ubuntu.com/
スクリプトの実行には準備が必要なので、一旦ここまで。
フォント
フォントはgrubx64.efiに含めておく必要があり、かつ、unicodeというファイル名の場合に特別な読み込み処理が走るようだった。
そこで、作成したフォントをunicode.pf2として以下に保管。
ここではfonts-dejavuパッケージを使用している。
$ sudo apt install -y fonts-dejavu $ sudo mkdir -p /usr/local/share/grub/memdisk/fonts $ sudo grub-mkfont -s 32 -o /usr/local/share/grub/memdisk/fonts/unicode.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf
一応、DejaVuSansMono.pf2として登録してみたけれど、update-grubはフォントファイルの存在を確認しに行くため、grubx64.efiに内蔵するmemdiskを指定することができなかった。
- (memdisk)/fonts/DejaVuSansMono.pf2としても、そんなファイルはないと怒られる。
- /usr/local/share/grub/memdisk/fonts/DejaVuSansMono.pf2とすると、フォントを読み込む際にセキュアブートのポリシーエラーで怒られる。
どうしても、DejaVuSamsMono.pf2で読み込みたいのであれば、以下の近辺を触ることになると思われる。
色々な処理をコメント化してすっ飛ばし、GRUB_FONTに設定した値をそのまま設定するようにしているが、本当にやるならもうちょっとちゃんと考えた方が…。
/etc/grub.d/00_header
... : ' if [ "x$gfxterm" = x1 ]; then if [ -n "$GRUB_FONT" ] ; then # Make the font accessible prepare_grub_to_access_device `${grub_probe} --target=device "${GRUB_FONT}"` cat << EOF if loadfont `make_system_path_relative_to_its_root "${GRUB_FONT}"` ; then EOF else for dir in "${pkgdatadir}" "`echo '/boot/grub' | sed "s,//*,/,g"`" /usr/share/grub ; do for basename in unicode unifont ascii; do path="${dir}/${basename}.pf2" if is_path_readable_by_grub "${path}" > /dev/null ; then font_path="${path}" else continue fi break 2 done done if [ -n "${font_path}" ] ; then cat << EOF if [ x\$feature_default_font_path = xy ] ; then font=unicode else EOF # Make the font accessible prepare_grub_to_access_device `${grub_probe} --target=device "${font_path}"` cat << EOF font="`make_system_path_relative_to_its_root "${font_path}"`" fi if loadfont \$font ; then EOF else cat << EOF if loadfont unicode ; then EOF fi fi ' cat << EOF if loadfont ${GRUB_FONT} ; then EOF cat << EOF set gfxmode=${GRUB_GFXMODE} load_video insmod gfxterm EOF # Gettext variables and module if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "x" ]; then cat << EOF set locale_dir=\$prefix/locale set lang=${grub_lang} insmod gettext EOF #fi ...
その上で、以下。
/etc/default/grub
GRUB_FONT="(memdisk)/fonts/DejaVuSansMono.pf2"
ここまでやるくらいなら、unicode.pf2を差し替えた方が簡単だろうと思う。
キーマップ
キーマップもmemdiskに入れておく。
外に置いておくと、読み込みでセキュアブートのポリシーエラーが発生するため。
$ sudo mkdir -p /usr/local/share/grub/memdisk/keylayouts $ sudo grub-kbdcomp -o /usr/local/share/grub/memdisk/keylayouts/japanese.gkb jp Unknown keyboard scan identifier Meta_Tab Unknown keyboard scan identifier Meta_Tab Unknown keyboard scan code 0x54 Unknown keyboard scan code 0x65 Unknown keyboard scan code 0x7f
これで、(memdisk)/keylayouts/japanese.gkbとして読み込むことができる。
秘密鍵と証明書
RSA秘密鍵(MOK.priv)と証明書(MOK.der, MOK.pem)を生成する。
まずは、以下のディレクトリを確認。
/var/lib/shim-signed/mok/
メインPCでは、過去にGeForceのプロプライエタリドライバをインストールしていたことがあり、そのときに作成したMOK.privとMOK.derがあった。
この場合は、既に秘密鍵と証明書があるのだから、MOK.derからMOK.pemを生成するだけでOK。
あるいは、MOK2.{priv,der,pem}とでもしておいたら良いと思う。
ここでは、新しく秘密鍵を生成し、同時に証明書を生成する。
-subjのところは、発行先と発行元に使われるので、自分と分かる文字列を設定しておく。
$ cd <作業ディレクトリ>
$ openssl req -newkey rsa:4096 -nodes -new -x509 -sha256 -days 36500 -subj "/CN=ROHHIE" -keyout MOK.priv -outform DER -out MOK.der
$ openssl pkey -in MOK.priv -noout -text
Private-Key: (4096 bit, 2 primes)
modulus:
00:bb:bf:cd:50:2c:28:7b:f8:f8:80:a5:c8:d2:76:
58:d3:23:6c:6e:5d:42:b4:03:60:9c:c4:78:2c:9b:
15:db:9e:d9:ee:97:d1:d7:fa:61:e8:48:9b:9f:f8:
...
$ openssl x509 -in MOK.der -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
04:0e:1e:bd:9a:e0:08:a7:9b:ad:b9:5e:54:bf:75:19:4f:09:a0:93
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = ROHHIE
Validity
Not Before: Sep 9 13:26:25 2023 GMT
Not After : Aug 16 13:26:25 2123 GMT
Subject: CN = ROHHIE
...
※証明書は100年間有効、秘密鍵にパスフレーズはなかった。
DER形式の証明書を変換して、PEM形式の証明書を生成。
これは、grubx64.efiに署名するときに使用する。
$ openssl x509 -in MOK.der -inform DER -outform PEM -out MOK.pem
できあがった秘密鍵と証明書を所定の場所に格納する。
所定とは書いているが、自動化スクリプトが使用している場所だと思うので、別のところに決めて保管しても大丈夫。
my-grub-mkimageのDIR_MOKをそこに書き換えるだけ。
$ sudo cp MOK.* /var/lib/shim-signed/mok
ホームディレクトリにあるMOK.*は削除してもOK。
Shimに証明書を登録
DER形式の証明書を、Shimに登録する。
パスワードは、適当なものを付けておく(Shimに登録されるまで覚えていればOK)。
$ sudo mokutil --import /var/lib/shim-signed/mok/MOK.der input password: input password again:
再起動すると、MokManagerと呼ばれる画面が表示される。
そこで、このパスワードを利用して登録を完了させる。
$ sudo reboot
MOKに証明書が登録されたことを確認してみる。
$ mokutil --list-enrolled [key 1] SHA1 Fingerprint: 76:a0:92:06:58:00:bf:37:69:01:c3:72:cd:55:a9:0e:1f:de:d2:e0 Certificate: Data: ... [key 2] SHA1 Fingerprint: 4b:b9:2a:8b:b9:43:64:5f:36:fb:53:f2:fe:5f:a7:69:9e:96:13:58 Certificate: Data: Version: 3 (0x2) Serial Number: 04:0e:1e:bd:9a:e0:08:a7:9b:ad:b9:5e:54:bf:75:19:4f:09:a0:93 Signature Algorithm: sha256WithRSAEncryption Issuer: CN=ROHHIE Validity Not Before: Sep 9 13:26:25 2023 GMT Not After : Aug 16 13:26:25 2123 GMT Subject: CN=ROHHIE ...
ここでは、2つ目に登録されていることが確認できた。
GRUBバイナリの生成
準備ができたので、my-grub-mkimageを実行する。
$ ls -l /boot/efi/EFI/ubuntu/ -rwxr-xr-x 1 root root 108 Sep 16 07:18 BOOTX64.CSV -rwxr-xr-x 1 root root 126 Sep 16 07:18 grub.cfg -rwxr-xr-x 1 root root 2594696 Sep 9 05:41 grubx64.efi ※変更前 -rwxr-xr-x 1 root root 860824 Sep 16 07:18 mmx64.efi -rwxr-xr-x 1 root root 960472 Sep 16 07:18 shimx64.efi $ sudo my-grub-mkimage $ ls -l /boot/efi/EFI/ubuntu/ -rwxr-xr-x 1 root root 108 Sep 16 07:18 BOOTX64.CSV -rwxr-xr-x 1 root root 126 Sep 16 07:18 grub.cfg -rwxr-xr-x 1 root root 1898752 Sep 16 17:43 grubx64.efi ※変更後 -rwxr-xr-x 1 root root 860824 Sep 16 07:18 mmx64.efi -rwxr-xr-x 1 root root 960472 Sep 16 07:18 shimx64.efi $ ls -l /usr/local/lib/grub -rw-r--r-- 1 root root 1896448 Sep 16 17:43 grubx64.efi -rw-r--r-- 1 root root 1898752 Sep 16 17:43 grubx64.efi.signed ※署名したファイルと同じサイズ -rw-r--r-- 1 root root 69632 Sep 16 17:43 memdisk.squashfs -rw-r--r-- 1 root root 221 Sep 16 17:43 sbat.csv
grubx64.efiができあがっている。
memdiskの確認。
UNIX & LINUX / Mounting a squashfs filesystem in read-write
$ sudo mount -t squashfs /usr/local/lib/grub/memdisk.squashfs /mnt $ tree --charset=C /mnt /mnt |-- fonts | `-- unicode.pf2 `-- keylayouts `-- japanese.gkb 2 directories, 2 files $ sudo umount /mnt
※treeコマンドでなくても、中身が確認できればOK。
sbat.csvの確認。
$ objdump -j .sbat -s /boot/efi/EFI/ubuntu/grubx64.efi /boot/efi/EFI/ubuntu/grubx64.efi: file format pei-x86-64 Contents of section .sbat: 1cd000 73626174 2c312c53 42415420 56657273 sbat,1,SBAT Vers 1cd010 696f6e2c 73626174 2c312c68 74747073 ion,sbat,1,https 1cd020 3a2f2f67 69746875 622e636f 6d2f7268 ://github.com/rh 1cd030 626f6f74 2f736869 6d2f626c 6f622f6d boot/shim/blob/m 1cd040 61696e2f 53424154 2e6d640a 67727562 ain/SBAT.md.grub 1cd050 2c332c46 72656520 536f6674 77617265 ,3,Free Software 1cd060 20466f75 6e646174 696f6e2c 67727562 Foundation,grub 1cd070 2c322e30 362c6874 7470733a 2f2f7777 ,2.06,https://ww 1cd080 772e676e 752e6f72 672f736f 66747761 w.gnu.org/softwa 1cd090 72652f67 7275622f 0a677275 622e7562 re/grub/.grub.ub 1cd0a0 756e7475 2c312c55 62756e74 752c6772 untu,1,Ubuntu,gr 1cd0b0 7562322c 322e3036 2d327562 756e7475 ub2,2.06-2ubuntu 1cd0c0 31342e31 2c687474 70733a2f 2f777777 14.1,https://www 1cd0d0 2e756275 6e74752e 636f6d2f 0a000000 .ubuntu.com/.... 1cd0e0 00000000 00000000 00000000 00000000 ................ ...
作成した秘密鍵・証明書で署名されていることの確認。
$ sbverify --cert /var/lib/shim-signed/mok/MOK.pem /boot/efi/EFI/ubuntu/grubx64.efi Signature verification OK
grubx64.efiはうまくできあがったようだ。
あと一息。
GRUBの設定
あらためて、GRUBをカスタマイズ。
/etc/default/grub
GRUB_GFXMODE=1920x1080
#GRUB_FONT="/boot/grub/fonts/DejaVuSansMono.pf2"
GRUB_BACKGROUND="/usr/local/share/grub/beach.png"
GRUB_TERMINAL_INPUT="at_keyboard"
※フォントはgrubx64.efiに含まれるunicode.pf2を読み込むので、無指定にする。
キーマップを読み込むために、以下を追加する。
/etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
insmod keylayouts
keymap (memdisk)/keylayouts/japanese.gkb
※キーマップの読み込み先を(memdisk)にしていることに注意。
GRUBを更新。
$ sudo update-grub
これで準備が整った。
GRUBのアップデート対応
どうにか動くようになったけれども、GRUBがアップデートされたらどうなるのか。
これでシミュレーションといえるのかどうか分からないが、以下をやってみたところ、grubx64.efiは置き換えられた。
$ sudo apt reinstall grub-efi-amd64-signed
$ ls -l /boot/efi/EFI/ubuntu
-rwxr-xr-x 1 root root 108 Sep 16 07:18 BOOTX64.CSV
-rwxr-xr-x 1 root root 126 Sep 16 07:18 grub.cfg
-rwxr-xr-x 1 root root 2594696 Sep 16 07:18 grubx64.efi
-rwxr-xr-x 1 root root 860824 Sep 16 07:18 mmx64.efi
-rwxr-xr-x 1 root root 960472 Sep 16 07:18 shimx64.efi
※ファイルのタイムスタンプが「今」になっている、知らなかった。
以下のファイルは変化しなかった。
/etc/default/grub
/etc/grub.d/40_custom
当然といえば当然の結果だが、こうなるとGRUBに施したカスタマイズがなくなってしまう。
どう復旧するかというと、my-grub-mkimageを再実行すればOK。
そのために今まで準備をしてきたのだ。
$ sudo my-grub-mkimage $ reboot
ということで、/boot/efi/EFI/ubuntu/grubx64.efiが更新されたら、my-grub-mkimageを動作させる仕組みを作る。
ファイルの変更を監視するユニット。
/etc/systemd/system/my-grub-update.path
[Unit] Description=Rebuild EFI when GRUB is updated [Path] PathChanged=/boot/efi/EFI/ubuntu/grubx64.efi [Install] WantedBy=multi-user.target WantedBy=system-update.target
ファイルが変更されたらコマンドを実行するユニット。
/etc/systemd/system/my-grub-update.service
[Unit] Description=Rebuild EFI when GRUB is updated [Service] Type=oneshot ExecStart=/usr/local/bin/my-grub-mkimage systemd
このユニット達を動作させるために、my-grub-update.pathを起動しておく。
そうすると、ファイルが変更されたときにmy-grub-update.serviceが起動される。
(~.serviceは有効にできなかった)
$ sudo systemctl enable my-grub-update.path $ sudo systemctl start my-grub-update.path
早速、GRUBのアップデートをシミュレーションしてみる。
$ sudo apt reinstall grub-efi-amd64-signed ※Ubuntu 20.04では apt install --reinstall grub-efi-amd64-signed $ ls -l /boot/efi/EFI/ubuntu -rwxr-xr-x 1 root root 108 Sep 16 19:43 BOOTX64.CSV -rwxr-xr-x 1 root root 126 Sep 16 19:43 grub.cfg -rwxr-xr-x 1 root root 1898752 Sep 16 19:43 grubx64.efi -rwxr-xr-x 1 root root 860824 Sep 16 19:43 mmx64.efi -rwxr-xr-x 1 root root 960472 Sep 16 19:43 shimx64.efi $ ls -l /usr/local/lib/grub/ ※作成したgrubx64.efiがある場所 -rw-r--r-- 1 root root 1896448 Sep 16 19:43 grubx64.efi -rw-r--r-- 1 root root 1898752 Sep 16 19:43 grubx64.efi.signed -rw-r--r-- 1 root root 69632 Sep 16 19:43 memdisk.squashfs -rw-r--r-- 1 root root 221 Sep 16 19:43 sbat.csv $ ls -l /usr/lib/grub/x86_64-efi-signed/ ※配布されているgrubx64.efiがある場所 -rw-r--r-- 1 root root 2275208 Jan 30 2023 gcdx64.efi.signed -rw-r--r-- 1 root root 2291592 Jan 30 2023 grubnetx64.efi.signed -rw-r--r-- 1 root root 2594696 Jan 30 2023 grubx64.efi.signed -rw-r--r-- 1 root root 17 Jan 30 2023 version
※ファイルのタイムスタンプが「今」になっている、知らなかった。
きれいに置き換わっている。
一応、my-grub-mkimageには、文字列"systemd"をパラメーターで渡されたら、作成済みのgrubx64.efi.signedと、/boot/efi/EFI/ubuntu/grubx64.efiを比較し、同じだったら起動しない仕掛けを入れておいた。
(自分で更新したのを検知して、また呼び出される…という繰り返しを起こさないように)
でも、/var/log/syslogを見ると、そのようなミスはsystemd側で想定しているようで、連続で呼び出されるようなことはなかった。
ということで、GRUBのアップデート対応は、これで一旦の完成としておく。
後は運用してみないと分からない。
何か問題が発生したら、その都度対策を入れていこう。
調べたこと
試行錯誤を繰り返しており、色々とやったので、メモしておく。
update-grub
update-grub2は、update-grubのシンボリックリンクだった。
$ ll /usr/sbin/update-grub* -rwxr-xr-x 1 root root 64 Dec 3 2022 /usr/sbin/update-grub* lrwxrwxrwx 1 root root 11 Dec 19 2022 /usr/sbin/update-grub2 -> update-grub*
update-grubは、grub-mkconfigを呼び出していた。
/usr/sbin/update-grub
#!/bin/sh set -e exec grub-mkconfig -o /boot/grub/grub.cfg "$@"
/usr/sbin/grub-mkconfigは構成ファイルを作成するスクリプト。
/etc/grub.dにあるスクリプトを順に呼び出している。
$ ls -l /etc/grub.d/ total 136 -rwxr-xr-x 1 root root 10627 Dec 19 2022 00_header -rwxr-xr-x 1 root root 6260 Dec 3 2022 05_debian_theme -rwxr-xr-x 1 root root 18683 Dec 19 2022 10_linux -rwxr-xr-x 1 root root 43031 Dec 19 2022 10_linux_zfs -rwxr-xr-x 1 root root 14387 Dec 19 2022 20_linux_xen -rwxr-xr-x 1 root root 13369 Dec 19 2022 30_os-prober -rwxr-xr-x 1 root root 1372 Dec 19 2022 30_uefi-firmware -rwxr-xr-x 1 root root 700 Sep 20 2022 35_fwupd -rwxr-xr-x 1 root root 273 Sep 15 20:02 40_custom -rwxr-xr-x 1 root root 215 Dec 19 2022 41_custom -rw-r--r-- 1 root root 483 Dec 19 2022 README
/etc/grub.d/README
All executable files in this directory are processed in shell expansion order. 訳:このディレクトリにある実行可能ファイルはすべて、シェル展開順に処理される。 00_*: Reserved for 00_header. 10_*: Native boot entries. 20_*: Third party apps (e.g. memtest86+). The number namespace in-between is configurable by system installer and/or administrator. For example, you can add an entry to boot another OS as 01_otheros, 11_otheros, etc, depending on the position you want it to occupy in the menu; and then adjust the default setting via /etc/default/grub. 訳:その中間の番号の名前空間は、システムインストーラや管理者が設定できる。 例えば、他のOSを起動するためのエントリーを、メニューのどの位置に置くかによって 01_otheros、11_otherosなどと追加し、/etc/default/grubでデフォルトの設定を 調整することができる。
※翻訳はDeepL先生。
これらのスクリプトから標準出力に文字を出すと、grub.cfgにそれが出力される。
ユーザーにメッセージを表示したいときは、エラー出力に文字を出せば良いようだ。
/etc/grub.d/40_custom
#!/bin/sh exec tail -n +3 $0 # This file provides an easy way to add custom menu entries. Simply type the # menu entries you want to add after this comment. Be careful not to change # the 'exec tail' line above.
※3行目から先をそのまま出力するようになっている。dashでこんなこともできるのか…
/etc/grub.d/41_custom
#!/bin/sh cat <<EOF if [ -f \${config_directory}/custom.cfg ]; then source \${config_directory}/custom.cfg elif [ -z "\${config_directory}" -a -f \$prefix/custom.cfg ]; then source \$prefix/custom.cfg fi EOF
grub-mkconfigの中で grub_cfg という編集に出力先となるファイル名が入るようなのだけれども、スクリプトの中でそれにアクセスしても値が取れなかった。できあがったgrub.cfgを直接触ることはできそうもない(そういう思想で作られていない感じ)。
systemd-boot
GRUBのフォントを変えたいというニーズは、時々あるようだけれども、解決方法は見つからなかった。
そして、しばしばsystemd-bootに移行したよ、という話が書かれていたりする。
そこで、systemd-bootについて探してみたら、以下の記事を発見した。
ここまでサクサクできる人は、PCが思い通りにできて、操作していて面白いんだろうなー。
いぶろぐのガジェット日記 / Ubuntu 20.04でsystemd-bootを試してみたら、けっこういい感じだった
- Ubuntuは/boot/efiにESPをマウントしている。
- Ubuntuが/bootに配置するカーネルをsystemd-bootはロードできないので、/boot/efiにコピーする必要がある。
- だから、systemdでカーネルが更新されるのを監視して、更新されたらカーネルをコピーする。
- /etc/systemd/system/hoge.path で監視。[Path]セクションPathChangedで監視対象を指定。
- /etc/systemd/system/hoge.service でコピー。[Service]セクションでType=oneshotとし、ExecStartを複数並べて必要ファイルをコピー。
こんなことできるのかー、ということで、本編のGRUBのアップデート対応でこの方法を使わせてもらった。
セキュアブートしていることの確認
幾つかの方法がある。
Debian Wiki / SecureBoot VirtualMachine
mokutil
$ mokutil --sb-state SecureBoot enabled
bootctl
$ bootctl systemd-boot not installed in ESP. System: Firmware: n/a (n/a) Secure Boot: enabled Setup Mode: user TPM2 Support: no Boot into FW: supported ...
ただ、Shimによる検証が有効なのかどうかを判断するコマンドを見つけることはできなかった。
起動時に
Shim有効: EFI stub: UEFI Secure Boot is enabled.
Shim無効: Booting in insecure mode
という表示がされるのを確認するくらいだった。
EFIバイナリが署名されていることの確認
sbverifyで確認することができた。
配布さているファイルはこんな結果になる。
$ sbverify --list /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed signature 1 image signature issuers: - /C=GB/ST=Isle of Man/L=Douglas/O=Canonical Ltd./CN=Canonical Ltd. Master Certificate Authority image signature certificates: - subject: /C=GB/ST=Isle of Man/O=Canonical Ltd./OU=Secure Boot/CN=Canonical Ltd. Secure Boot Signing (2022 v1) issuer: /C=GB/ST=Isle of Man/L=Douglas/O=Canonical Ltd./CN=Canonical Ltd. Master Certificate Authority
今回署名したファイルはこんな結果になる。
$ sbverify --list /usr/local/lib/grub/grubx64.efi.signed signature 1 image signature issuers: - /CN=ROHHIE image signature certificates: - subject: /CN=ROHHIE issuer: /CN=ROHHIE
署名されていない場合はこんな結果になる。
$ sbverify --list /usr/lib/grub/x86_64-efi/monolithic/grubx64.efi No signature table present
SBATで起動しない
適当なsbat.csvをダウンロードしてきて設定したところ、grubx64.efiが起動しなかった。
/usr/local/lib/grub/sbat.csv
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md grub,1,Free Software Foundation,grub,@UPSTREAM_VERSION@,https://www.gnu.org/software/grub/ grub.ubuntu,1,Ubuntu,grub2,@DEB_VERSION@,https://www.ubuntu.com/
本来は、@UPSTREAM_VERSION@と@DEB_VERSION@をバージョン情報に置き換える必要がある。
ということで、以下の通りに置き換えてやってみた。
/usr/local/lib/grub/sbat.csv
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md grub,1,Free Software Foundation,grub,2.06,https://www.gnu.org/software/grub/ grub.ubuntu,1,Ubuntu,grub2,2.06-2ubuntu14.1,https://www.ubuntu.com/
置き換えには、こんなスクリプトを使ってみた。
deb_version=`dpkg -s grub-efi-amd64 | grep "^Version" | sed -e "s/^Version: //"` upstream_version=`echo $deb_version | sed -e "s/-[^-]*$//"` sed -e "s/@DEB_VERSION@/${deb_version}/g" \ -e "s/@UPSTREAM_VERSION@/${upstream_version}/g" \ $DIR_SHARE/sbat.ubuntu.csv > $DIR_SHARE/sbat.csv
起動しない理由はきっとこれだ…
$ mokutil --list-sbat-revocations sbat,1,2022052400 grub,2
ちゃんと調べていないけれど、2行目
grub,1...を
grub,3...
に書き換えたところ起動した。
以上のことから、本編では現在配布されているgrubx64.efiからSBATを切り出すことで、同じバージョンであることを示すことにしたのだった。
grub-mkimageで--sbatが使えない
Ubuntu 20.04 LTSに入っているgrub-mkimageでは、--sbatパラメーターが指定できなかった。
$ grub-mkimage --version grub-mkimage (GRUB) 2.04-1ubuntu26.17
どうにかして、.sbatファイルを追加しなければ。
Github / rhboot / shim / SBAT.md
/usr/local/bin/my-grub-mkimage
... grub-mkimage \ -O x86_64-efi \ -o $DIR_LIB/grubx64.efi \ -m $DIR_LIB/memdisk.squashfs \ -p /EFI/ubuntu \ $GRUB_MODULES objcopy --set-section-alignment '.sbat=4096' \ --add-section .sbat=$DIR_LIB/sbat.csv \ $DIR_LIB/grubx64.efi ...
※grub-mkimageの--sbatパラメーターを削除し、objcopyでsbat.csvを組み込む。
署名するときに、こんなエラーメッセージが出ている。
warning: gap in section table: .sbat : 0x00000250 - 0x00001250, .text : 0x00002000 - 0x0000e000, gaps in the section table may result in different checksums warning: data remaining[1876560 vs 1880064]: gaps between PE/COFF sections? Signing Unsigned original image
このGRUBバイナリに差し替えたところ、起動時にこんなメッセージが表示され、GRUBが起動しなかった。
Section 0 is inside image headers Malformed section header Failed to load image: Unsupported start_image() returned Unsupported
確認してみると、以下の違いがあった。
$ objdump -h /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed: ファイル形式 pei-x86-64 セクション: Idx Name Size VMA LMA File off Algn 0 .text 0000c000 0000000000001000 0000000000001000 00001000 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .data 00010000 000000000000d000 000000000000d000 0000d000 2**4 CONTENTS, ALLOC, LOAD, DATA 2 mods 0025a000 000000000001d000 000000000001d000 0001d000 2**2 CONTENTS, ALLOC, LOAD, DATA 3 .sbat 00001000 0000000000277000 0000000000277000 00277000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .reloc 00001000 0000000000278000 0000000000278000 00278000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA
$ objdump -h /usr/local/lib/grub/grubx64.efi.signed /usr/local/lib/grub/grubx64.efi.signed: ファイル形式 pei-x86-64 セクション: Idx Name Size VMA LMA File off Algn 0 .sbat 000000dd 0000000000000000 0000000000000000 00000250 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 0000c000 0000000000001000 0000000000001000 00002000 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .data 00010000 000000000000d000 000000000000d000 0000e000 2**4 CONTENTS, ALLOC, LOAD, DATA 3 mods 001ac000 000000000001d000 000000000001d000 0001e000 2**2 CONTENTS, ALLOC, LOAD, DATA 4 .reloc 00001000 00000000001c9000 00000000001c9000 001ca000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA
- セクション0が.sbatになっている(これがGRUBが起動しない直接的な原因)
- サイズが0xC000から0x00ddに縮小している。
- VMAとLMAの状態が変わっている。(VMA:Virtual Memory Address, LMA:Load Memory Address?)
スクリプトをもう少し改造。
- .sbatを最後に追加する。4番目にしたかったが、うまくできなかった。実害はなさそう。
Github / rhboot / shim / objcopy for SBAT doesn't work? - 配布されているgrubx64.efiからsbat.csvを取り出したとき、NULLをトリミングしていたのをやめる。
- VMAとLMAは.relocセクションが終了した位置に合わせる。
/usr/local/bin/my-grub-mkimage
... tail -c +$SBAT_OFFSET /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed \ | head -c $SBAT_SIZE > $DIR_LIB/sbat.csv grub-mkimage \ -O x86_64-efi \ -o $DIR_LIB/grubx64.efi \ -m $DIR_LIB/memdisk.squashfs \ -p /EFI/ubuntu \ $GRUB_MODULES SBAT_INSPOS=$((16#$(objdump -h $DIR_LIB/grubx64.efi | grep \.reloc | sed -e "s/^ \+[0-9]\+ \+[a-zA-Z.]\+ \+[0-9a-f]\+ \+[0-9a-f]\+ \+[0-9a-f]\+ \+\([0-9a-f]\+\) \+.\+/\1/"))) SBAT_INSSIZ=$((16#$(objdump -h $DIR_LIB/grubx64.efi | grep \.reloc | sed -e "s/^ \+[0-9]\+ \+[a-zA-Z.]\+ \+\([0-9a-f]\+\) \+[0-9a-f]\+ \+[0-9a-f]\+ \+[0-9a-f]\+ \+.\+/\1/"))) objcopy --set-section-alignment '.sbat=4096' \ --add-section .sbat=$DIR_LIB/sbat.csv \ --adjust-section-vma .sbat=$(($SBAT_INSPOS+$SBAT_INSSIZ)) \ $DIR_LIB/grubx64.efi ...
これで、署名のときに発生していた警告はなくなり、ちゃんと起動するGRUBバイナリになった。
$ objdump -h /usr/local/lib/grub/grubx64.efi.signed /usr/local/lib/grub/grubx64.efi.signed: ファイル形式 pei-x86-64 セクション: Idx Name Size VMA LMA File off Algn 0 .text 0000c000 0000000000001000 0000000000001000 00001000 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .data 00010000 000000000000d000 000000000000d000 0000d000 2**4 CONTENTS, ALLOC, LOAD, DATA 2 mods 001ac000 000000000001d000 000000000001d000 0001d000 2**2 CONTENTS, ALLOC, LOAD, DATA 3 .reloc 00001000 00000000001c9000 00000000001c9000 001c9000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .sbat 00001000 00000000001ca000 00000000001ca000 001ca000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA
GRUBに関するファイルが置かれている場所
ちょっと調べれば分かることではあるけれど、メモしておく。
GRUBのモジュールや、GRUBバイナリはここに置かれている。
/usr/lib/grub/ |-- grub-mkconfig_lib -> ../../share/grub/grub-mkconfig_lib |-- grub-multi-install |-- x86_64-efi | |-- acpi.mod | |-- adler32.mod ... | |-- monolithic | | |-- gcdx64.efi | | |-- grubnetx64.efi | | `-- grubx64.efi ... | `-- zstd.mod `-- x86_64-efi-signed |-- gcdx64.efi.signed |-- grubnetx64.efi.signed |-- grubx64.efi.signed `-- version
ここに、幾つかのフォント、Canonicalの証明書などが入っている。
/usr/share/grub/ |-- ascii.h |-- ascii.pf2 |-- canonical-uefi-ca.crt |-- default | |-- grub | `-- grub.md5sum |-- euro.pf2 |-- grub-check-signatures |-- grub-mkconfig_lib |-- unicode.pf2 `-- widthspec.h
これを参考に、本編で書いたディレクトリ構成を決めた。
GPGキーの利用(断念)
フォントが読み込めないので、フォントに署名すれば良いのかなと考えた。
その観点で探していると、フォントに署名をする場合は、GPGキーを使うと教えてくれている。
Arch Linux BBS / [SOLVED] prohibited by secure boot policy after grub update
そして、これが大変なので、systemd-bootに移行したんだよ、とも書かれていた。
結論からすると、この方法は断念していて、本編でやったようにmemdiskにフォントを入れて、それを内蔵したgrubx64.efiに署名することで読み込めるようにした。
それでも結構色々やったので、フォントへの署名に至るまでに何をやって、結局何で断念したのかを整理しておこうと思う。
GPGキーの生成
作業ディレクトリを作成。
$ mkdir gpgkey $ chmod 700 gpgkey
作業ディレクトリで鍵を作る。
$ gpg --homedir gpgkey --full-generate-key gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. gpg: keybox '/home/rohhie/work/image/gpgkey/pubring.kbx' created Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (14) Existing key from card Your selection? [Enter] RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (3072) 4096[Enter] Requested keysize is 4096 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) [Enter] Key does not expire at all Is this correct? (y/N) y[Enter] GnuPG needs to construct a user ID to identify your key. Real name: rohhie[Enter] ※自分の名前 Email address: rohhie@rohhie.net[Enter] ※自分のメールアドレス Comment: https://rohhie.net[Enter] ※これは何でも良いと思う You selected this USER-ID: "rohhie (https://rohhie.net) <rohhie@rohhie.net>" Change (N)ame, (E)mail, or (O)kay/(Q)uit? O[Enter]
パスワードなしでキーペアを作る。
╔══════════════════════════════════════════════════════╗ ║ Please enter the passphrase to ║ ║ protect your new key ║ ║ ║ ║ Passphrase: ________________________________________ ║ ║ ║ ║ <OK> <Cancel> ║ ╚══════════════════════════════════════════════════════╝
パスワードなしは良くない考え!と指摘されるが、ここでは無視しておく。
╔═══════════════════════════════════════════════════════════════════════════════════════════════╗ ║ You have not entered a passphrase - this is in general a bad idea! ║ ║ Please confirm that you do not want to have any protection on your key. ║ ║ ║ ║ <Yes, protection is not needed> <Enter new passphrase> ║ ╚═══════════════════════════════════════════════════════════════════════════════════════════════╝
無期限の鍵ができあがった。
... public and secret key created and signed. pub rsa4096 2023-09-09 [SC] 182DD7AC3199AB362ECAFABC307C6DEA85B47223 uid rohhie (https://rohhie.net) <rohhie@rohhie.net> sub rsa4096 2023-09-09 [E]
公開鍵はGRUBに登録するので、取り出しておく。
$ gpg --homedir gpgkey --export > gpgpub.key
鍵の状態を確認
公開鍵と秘密鍵の状態を確認。
署名するときには、鍵の番号を使用する。
$ gpg --homedir gpgkey --list-public-keys --keyid-format long
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
/home/rohhie/work/image/gpgkey/pubring.kbx
------------------------------------------
pub rsa4096/307C6DEA85B47223 2023-09-09 [SC]
182DD7AC3199AB362ECAFABC307C6DEA85B47223
uid [ultimate] rohhie (https://rohhie.net) <rohhie@rohhie.net>
sub rsa4096/B720FEBC86D44E01 2023-09-09 [E]
$ gpg --homedir gpgkey --list-secret-keys --keyid-format long
/home/rohhie/work/image/gpgkey/pubring.kbx
------------------------------------------
sec rsa4096/307C6DEA85B47223 2023-09-09 [SC]
182DD7AC3199AB362ECAFABC307C6DEA85B47223
uid [ultimate] rohhie (https://rohhie.net) <rohhie@rohhie.net>
ssb rsa4096/B720FEBC86D44E01 2023-09-09 [E]
フォントへの署名
作業用フォルダにフォントをコピーしてくる。
$ cp /boot/grub/fonts/DejaVuSansMono.pf2 ./
切り離された署名を作成。
$ gpg --detach-sign --local-user 307C6DEA85B47223 ./DejaVuSansMono.pf2 $ ll *.sig -rw-rw-r-- 1 rohhie rohhie 566 Sep 17 13:06 DejaVuSansMono.pf2.sig
署名を/boot/grub/fontsに書き戻す。
$ sudo cp *.sig /boot/grub/fonts
署名を検証するための鍵を含めたgrubx64.efiを生成
署名を検証するためのgpgpub.keyを含める形で、grubx64.efiを生成し、署名した。
$ grub-mkimage \ -O x86_64-efi \ -o /usr/local/lib/grub/grubx64.efi \ -m /usr/local/lib/grub/memdisk.squashfs \ -p /EFI/ubuntu \ -k ./gpgpub.key --sbat $DIR_LIB/sbat.csv \ $GRUB_MODULES $ sbsign --key /var/lib/shim-signed/mok/MOK.priv --cert /var/lib/shim-signed/mok/MOK.pem \ --output /usr/local/lib/grub/grubx64.efi.signed /usr/local/lib/grub/grubx64.efi
これを、/boot/efi/EFI/ubuntu/grubx64.efiと差し替える。
GRUBの設定
フォントを読み込むように設定を変更。
/etc/default/grub
GRUB_FONT="/boot/grub/fonts/DejaVuSansMono.pf2"
GRUBを更新。
$ sudo update-grub
動作の確認
再起動したところ、メニューが表示されなくなった。
解像度も指定通りにはならなかったみたい。
以下の2つを実行してみたけれど、画面がクリアされ、真っ黒い画面に grub> _ とプロンプトだけが表示される。
grub> configfile (hd0,gpt1)/efi/ubuntu/grub.cfg grub> configfile (hd0,gpt2)/boot/grub/grub.cfg
もしかしてと思い、grub.cfgを表示しようとしたら、sigファイルがないと怒られた。
grub> cat (hd0,gpt2)/boot/grub/grub.cfg error: file `/boot/grub/grub.cfg.sig' not found.
もしかしたらば、使うファイル全てに署名しておけば、使えるようになるかもしれない。
それって延々と署名を続けるの?update-grubする度に署名するの?と考えてしまった。
ということで、ここで調査を打ち切って、フォントの変更は諦めようと思った。
しかし、最後の最後、grubx64.efiのビルドスクリプトをみて、memdiskを含めていることに気付いた。
そうしてやっと本編の手順にたどり着いたのだった。
ファームウェアに鍵を登録する(断念)
今まで何度もshimx64.efiやmmx64.efiというのを目にしてきたのに、それがなんなのか分かっていなかった。
それぞれ、Shim(Secure Boot chain-loading bootloader)とMokManager(Machine Owner Key Manager)であって、shim-signedパッケージに含まれている。
これをちゃんと理解していれば、こんな調査は始めなかったんだけれど…
フォントが読み込めないと悩んでいて、Shimに証明書を登録してもダメってことは、ファームウェアに登録しろってこと?等とあらぬ方向に検討を進めていった。
後から考えれば、秘密鍵、証明書(PEM, DER)を作成して登録しようとしているわけで、Shimでは手順が簡略化されていて便利といえる。
登録手順
ほぼ、こちらで教えてくれていることをやっただけ。
ArchLinux / Unified Extensible Firmware Interface/セキュアブート
efitoolsをインストールする。
$ sudo apt install efitools
EFI変数をバックアップする。
$ for var in PK KEK db dbx; do efi-readvar -v $var -o old_${var}.esl; done $ ll *.esl -rw------- 1 rohhie rohhie 5161 Sep 8 07:32 old_db.esl -rw------- 1 rohhie rohhie 12844 Sep 8 07:32 old_dbx.esl -rw------- 1 rohhie rohhie 1560 Sep 8 07:32 old_KEK.esl -rw------- 1 rohhie rohhie 45 Sep 8 07:32 old_PK.esl
所有者を識別するGUIDを作成。
$ uuidgen --random > GUID.txt $ cat GUID.txt 4076aa09-4636-41df-b62d-410e24f90311
秘密鍵と証明書を生成。
$ openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=ROHHIE" -out PK.crt $ openssl x509 -in PK.crt -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 50:75:c2:2f:33:70:8e:59:ce:99:b9:f4:78:9a:ec:14:22:3f:7e:64 Signature Algorithm: sha256WithRSAEncryption Issuer: CN = ROHHIE Validity Not Before: Sep 9 01:09:15 2023 GMT Not After : Sep 6 01:09:15 2033 GMT Subject: CN = ROHHIE ... $ openssl pkey -in PK.key -noout -text Private-Key: (4096 bit, 2 primes) modulus: 00:bb:13:e3:5f:f8:08:3d:6f:6e:e4:23:63:d1:a3: f2:fd:29:28:d9:7e:be:89:83:1e:16:16:d3:dc:c3: 4a:52:bb:04:49:bc:76:5b:c6:11:4c:b4:be:db:9d: ...
※証明書は10年間有効、秘密鍵にパスフレーズはなかった。
DER形式の証明書を作成。
$ openssl x509 -outform DER -in PK.crt -out PK.cer
opensslの証明書をEFI署名リストに変換。
$ cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
EFI署名リストに署名する。
$ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth Timestamp is 2023-9-9 02:05:21 Authentication Payload size 1371 Signature of size 1928 Signature at: 40
空ファイルに署名。
$ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK /dev/null noPK.auth
同じように、Key Exchange KeyとSignature Database keyを作成。
$ openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=ROHHIE/" -out KEK.crt $ openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=ROHHIE/" -out db.crt $ openssl x509 -outform DER -in KEK.crt -out KEK.cer $ openssl x509 -outform DER -in db.crt -out db.cer $ cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl $ cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl $ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth $ sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth
作ったファイルを所定のディレクトリに保管。
$ sudo mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK} $ sudo cp db.auth /etc/secureboot//keys/db $ sudo cp KEK.auth /etc/secureboot/keys/KEK $ sudo cp PK.auth /etc/secureboot/keys/PK
加える変更を確認。
$ sudo sbkeysync --pk --dry-run --verbose Filesystem keystore: /etc/secureboot/keys/db/db.auth [3299 bytes] /etc/secureboot/keys/KEK/KEK.auth [3299 bytes] /etc/secureboot/keys/PK/PK.auth [3299 bytes] ... 80b4d96931bf0d02fd91a61e19d14f1da452e66db2408ca8604d411f92659f0a filesystem keys: PK: /CN=ROHHIE from /etc/secureboot/keys/PK/PK.auth KEK: /CN=ROHHIE from /etc/secureboot/keys/KEK/KEK.auth db: /CN=ROHHIE from /etc/secureboot/keys/db/db.auth dbx: New keys in filesystem: /etc/secureboot/keys/db/db.auth /etc/secureboot/keys/KEK/KEK.auth /etc/secureboot/keys/PK/PK.auth
更新してみる…がうまくいかない。
$ sudo sbkeysync --verbose Filesystem keystore: /etc/secureboot/keys/db/db.auth [3299 bytes] /etc/secureboot/keys/KEK/KEK.auth [3299 bytes] /etc/secureboot/keys/PK/PK.auth [3299 bytes] ... New keys in filesystem: /etc/secureboot/keys/db/db.auth /etc/secureboot/keys/KEK/KEK.auth /etc/secureboot/keys/PK/PK.auth Inserting key update /etc/secureboot/keys/db/db.auth into db Error writing key update: Invalid argument Error syncing keystore file /etc/secureboot/keys/db/db.auth Inserting key update /etc/secureboot/keys/KEK/KEK.auth into KEK Error writing key update: Invalid argument Error syncing keystore file /etc/secureboot/keys/KEK/KEK.auth
ここで調査を止めているのだけれど、
- ファームウェアをセットアップモードにしておかなければならない。
- VMware Playerにはセットアップモードがない。
証明書を登録するときには、vmxファイルにそれを定義する必要がある。
ということだった。
VMwareでファームウェアの鍵を操作する
vmxファイルに設定を入れて、同じディレクトリに各証明書を入れておく。
uefi.allowAuthBypass = "TRUE" uefi.secureBoot.dbDefault.file0 = "db.crt" uefi.secureBoot.KEKDefault.file0 = "KEK.crt" uefi.secureBoot.PKDefault.file0 = "PK.crt"
これで、追加の証明書を入れることができるようだ。
VMTN Communities / How to replace default certificate for Secure Boot Virtual Machine?
IBM / Installing the HMC virtual appliance enabled with secure boot by using VMware ESXi
BOOTX64.CSVの中身
結局これは何だろうと気になり、vimで開いてみても読めないと思ったが、
shimx64.efi,ubuntu,,This is the boot entry for ubuntu
と書かれていた。
$ ll BOOTX64.CSV -rwxr-xr-x 1 root root 108 9月 18 18:14 BOOTX64.CSV* $ hexdump -cx BOOTX64.CSV 0000000 s \0 h \0 i \0 m \0 x \0 6 \0 4 \0 . \0 0000000 0073 0068 0069 006d 0078 0036 0034 002e 0000010 e \0 f \0 i \0 , \0 u \0 b \0 u \0 n \0 0000010 0065 0066 0069 002c 0075 0062 0075 006e 0000020 t \0 u \0 , \0 , \0 T \0 h \0 i \0 s \0 0000020 0074 0075 002c 002c 0054 0068 0069 0073 0000030 \0 i \0 s \0 \0 t \0 h \0 e \0 \0 0000030 0020 0069 0073 0020 0074 0068 0065 0020 0000040 b \0 o \0 o \0 t \0 \0 e \0 n \0 t \0 0000040 0062 006f 006f 0074 0020 0065 006e 0074 0000050 r \0 y \0 \0 f \0 o \0 r \0 \0 u \0 0000050 0072 0079 0020 0066 006f 0072 0020 0075 0000060 b \0 u \0 n \0 t \0 u \0 \n \0 0000060 0062 0075 006e 0074 0075 000a 000006c
改めてvimで開いてみると、記号は入るものの読める。
これで同じディレクトリにあるShimが読み込まれるのかな。
GeForce GTX 1060 3GB
メインPCはWindows 11と同居のため、セキュアブートが有効になっている。
何も対策しない状態だとvideoinfoが使えないので、一時的にセキュアブートを無効にして、情報をメモしておいた。
grub> videoinfo List of supported video modes: Legend: mask/position=red/green/blue/reserved Adapter `Bochs PCI Video Driver': No info available Adapter `Cirrus CLGD 5446 PCI Video Driver': No info available Adapter `EFI GOP driver': 0x000 3840 x 2160 x 32 (15360) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x001 640 x 480 x 32 (2560) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x002 800 x 600 x 32 (3200) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 * 0x003 1024 x 768 x 32 (4096) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x004 1280 x 720 x 32 (5120) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x005 1280 x 800 x 32 (5120) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x006 1280 x 1024 x 32 (5120) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x007 1440 x 900 x 32 (5760) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x008 1400 x 1050 x 32 (5600) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x009 1600 x 1200 x 32 (6400) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x00a 1680 x 1050 x 32 (6720) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x00b 1920 x 1200 x 32 (7680) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 0x00c 2048 x 1536 x 32 (8192) Direct color, mask: 8/8/8/8 pos: 16/8/0/24 EDID version: 1.3 Preferred mode: 3840x2160
今になれば「いつでも見られる」訳だけれども、/etc/default/grubを編集するときに見るかもしれないから残しておく。
さいごに
もしかしたら、セキュアブート環境におけるGRUBのカスタマイズについて教えてくれるサイトが既にあるかもしれないが、それを見つけることはできなかったし、今も見つけることができていない。
手順を整理してみれば、そんなに難しいわけでもなく、いう程の手間も掛からない。
5万文字を超える記事になったけど、やることだけを抜き出せば大した話ではない。
だけど、試行錯誤の連続で整理するのが大変だった。
思うに、分かっている人はちょっと調べれば実現できるが、まとめるのがメンドクサイ。
分からない人にとってみれば、そもそも何を言っているのかが分からず、ハードルが高いことだったのかもしれない。
それでいて、できるようになったことは、
- OSが起動する前に気に入った写真を表示させること。
- フォントを見やすい大きさにできたこと。
- セキュアブートでは使えなかったコマンドが、いくつか使えるようになること。
程度であり、いわゆるコスパの悪い調査だった。
まぁでも、「魂は細部に宿る」というし、将来やりたいことにつながるかもしれないので、良しとしよう。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他