突然LUKS(dm-crypt)起動ドライブの暗号化が解除できなくなった話

絶望の場面
絶望の場面

仕事に使ってるメインのマシンでもnobleの開発版を使ってるんですが、月曜日の昼飯前に再起動かけたら暗号化ドライブの解除パスワードを何度入力しても

cryptsetup: ERROR: dm_crypt-0: cryptsetup failed, bad password or options?

と言われてしまってデスクトップまでたどり着けない。何かしらのリグレッションで暗号化ドライブのヘッダが壊れたのではと思い、これは再インストールしてバックアップから切り戻すしかないのではと絶望。簡単にできるようにしてあるとは言え1時間以上はかかるので。

すぐには諦めきれなかったのでまずはUSBメモリでUbuntuのLive sessionを立ち上げると、暗号化ドライブがあっさりマウントできてしまった。ということはドライブ自体が破損しているわけではないので、パッケージのリグレッションで暗号化が解除できない状況に陥っているのでは、と/var/log/apt/history.logとにらめっこ。いかんせん開発版なので、前回正常に起動できたときからのアップデートはバイナリパッケージの単位で412個。それなのに、cryptsetupとかそれっぽいパッケージのアップデートはないし、カーネルを一個前のにしてもダメ。かろうじてlibgcrypt20というinitramfsにも入る、かつcrypt関連のパッケージのアップデートがあったので、これをダウングレードしてみることに。

USB起動中に、元のマシンのinitramfsの再生成ってどうやるんだっけと調べつつ

$ sudo cryptsetup open /dev/nvme0n1p3 dm_crypt-0

$ sudo mount /dev/mapper/ubuntu--vg-ubuntu--lv /mnt
$ sudo mount /dev/nvme0n1p2 /mnt/boot
$ sudo mount /dev/nvme0n1p1 /mnt/boot/efi

$ for name in proc sys dev run; do
    sudo mount --bind /$name /mnt/$name
done

$ sudo chroot /mnt/

という感じでDebian Wikiを見ながらchrootした。ここでの鍵はopenするときにdm_crypt-0という名前でなければ後々不都合があり、なぜならそれは/etc/crypttabdm_crypt-0と書かれているから。ただ、crypttabはopenした後にしか読めないので名前を覚えてなくて何回かやり直した。

ここまでくればパッケージのダウンロードやダウングレードも簡単で、initramfsの再生成も

$ sudo update-initramfs -u -k all

とするだけ。

でも再起動しても問題は解決していない。。。libgcrypt20が違うんだったら412個全部のパッケージをダウングレードして切り分けするのもしんどいので諦めようかと思ったそのとき、ネット上でリカバリーモード(シングルユーザーモード)なら解除できる時あるよっていう情報を見かけて、そんなはずはないでしょと思ってリカバリーモードで起動したら解除できた!crypt関連のモジュール関係ないじゃん!Plymouthじゃん!そこは考えてなかったよ!

ということで/etc/default/grubからsplashを除いてPlymouthなしで起動するようにして応急処置完了。

ただ、重要そうな問題のような気がしたので再現環境を作りたかったけど、シンプルなパスワードを設定すると100%解除に成功してしまって再現できない。何がトリガーなのかよくわからないまま、PlymouthをダウングレードしてPlymouthのリグレッションであることを確認したりしていた。

ふと、Yubikeyがコンマ何秒の間に30文字以上を一気にタイプするからではと思い、Yubikeyを再フォーマットしてクリーンな状態でやったら無事再現できた。ただここで自分のYubikeyの使い方に関して補足しておくと、LUKSのパスフレーズ打つときにYubikeyから出力される文字列だけで解除しているわけではなくて(それだとYubikeyとノートPCを強奪されたらだれでも解除できちゃうので)、自分でパスフレーズを手打ちしてそれを打ち終わったらYubikeyのボタンをタッチして続けて打ち込む、という一つのパスフレーズボックスでなんちゃって二要素認証っぽいことにしている。

自分で打った文字列 + Yubikeyから出力される文字列(30文字以上) + <ENTER>

もうちょっとちゃんとやるなら毎回同じ文字列をYubikeyから出すんじゃなくて、Challenge-response形式にするyubikey-luksとかを使うのもあるけど今のところは固定文字列で落ち着いてる。

とにかく再現手順がはっきりしたのでupstreamへ。

“Typing passphrase pretty quickly using Yubikey fails to unlock a LUKS partition”
https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/243

そこでありがたいことにこのコミットで直った問題じゃない?って教えてくれて、

That leads to keystrokes getting eaten.

This commit makes the terminal more careful about setting the keyboard mode. It now only changes it when plymouth thinks its necessary to do so.

コミットメッセージ見てもキーストロークがどっかいっちゃうってのは納得。

カーネルパラメーターにplymouth.debugつけて/var/log/plymouth-debug.logを提供したら色々フィードバックをくれて、今のところの理解だと、

  1. splashをつけなければPlymouthがそもそも使われないので回避される
  2. 23.360.11じゃなくて24.004.60なら今回の問題(リグレッション)が修正されているので問題なくなる
  3. UbuntuとかDebianがまだinitramfsに入れてない/usr/share/X11/xkbを入れるようにすれば、今までのvt consoleじゃなくてxkb consoleを使うようになるからそれでも回避される

ちなみにdownstreamレポートはここ。
https://bugs.launchpad.net/ubuntu/+source/plymouth/+bug/2051478

それにしてもPlymouth高機能になりすぎててすごい。