Jetson Nano Dev Boardを使ってSDカード暗号化をテスト(initramfs 調査編)


initramfsとは

前回でLUKSに必要なコマンド操作の基本を抑え、ユーザーパスワード操作を鍵ファイルの取り扱いに置き換える方法をまとめた。

今回は2、Linuxの起動プロセスの間へ復号処理を割り込ませる部分を検討していく。

initramfsがポイントになるようだが、これはどういう仕組みだろうか。

Ubuntu Weekly Recipe第384回 Initramfsのしくみにわかりやすく説明されていた。
「Initramfsの役割

Ubuntuはさまざまなディスクデバイスにルートファイルシステムをインストールし,起動するOSです。カーネルはブートローダーによって起動されたあと,ルートファイルシステムをマウントするために,サポートしているすべてのディスクデバイスのドライバを持っている必要があります。

しかしながらこのドライバをすべてカーネルに組み込んでしまうと,カーネルが肥大化してしまいます。しかもそのほとんどは,今使っているディスクデバイスでは不要なドライバです。必要なドライバを必要に応じてロードする仕組みとして「カーネルモジュール」がありますが,今度はその「カーネルモジュール」をどこに保存するのかという問題が発生します。当然のことながら,この時点でルートファイルシステムにはアクセスできません。

そこで出てくるのが「Initramfs」という仕組みです。

Ubuntuに限らずほとんどのLinuxディストリビューションでは,「⁠ミニルート」とも呼ばれるメモリ上に展開可能な,小さなサイズのルートファイルシステムを持っています。このミニルートには,ルートファイルシステムをマウントするために必要なカーネルモジュールやスクリプトが保存されているのです。ブートローダーはカーネルと一緒にこのミニルートをメモリ上に展開し,カーネルにそのアドレスを伝えます。カーネルはそのアドレスを元にミニルートをマウントし,その中にあるスクリプトを実行することで本来のルートファイルシステムをマウントします。

「Initramfs」は,現在はデスクトップLinuxでもっとも使われているミニルートのファイルフォーマットの1つです(注1⁠)⁠。Ubnutuだと「/boot/initrd.img-3.19.0-23-generic」などのカーネルバージョンごとファイルになります。」

initramfsでLUKSパーティションを復号し、ルートファイルシステムとしてマウントさせられれば目的は達せられそうだ。

Jetson Nanoでのinitramfs

Jetson Nanoではどのようにinitramfsが使われているだろうか。
ルートファイルシステムを壊れやすいSDカードでなく、外付けUSBのSSDに保存したいという事例が見つかった。
Jetson Nanoの/をUSBドライブにしてSDカードを長生きさせる

この中で触れられているrootOnUSBが、
1、ルートファイルシステムをUSBに丸ごとコピーする
2、USBをマウントできるようにinitramfsを改変する

上記をやっている。
これを参考にすればinitramfsへの組み込みができそう。

Jetson Nano上で上記を行うスクリプトを考えてみる。
kmwebnet/makeinitramfs

このスクリプトではinitramfsに対して、
1、cryptsetupの組み込み
2、LUKSパーティションに事前に設定されているパスワードを使って、前回作成した
ATECC608Aの鍵を保存してあるスロットへアクセスし、IO保護キーで通信経路を暗号化しながら読み出してstdoutに出力するプログラム(keyout)と入れ替えるスクリプト
3、上記に必要な、事前設定パスワードとkeyoutプログラム

上記を組み込み、最後に
$ sudo mkinitramfs -o /boot/initrd.img-4.9.140-tegra
を実行する。

これで、cryptsetupが組み込まれたinitramfsが/boot/initrd.img-4.9.140-tegraとして出来上がった。

デバイスツリーの準備他

$ sudo /opt/nvidia/jetson-io/jetson-io.py

上記を実行して、i2s4を使えるように設定する。
詳細は、JetPack 4.3 (r32.3.1) で追加された Jetson-IO tool を使用して Pinmux テーブルを設定してみた。を参照。そうすると、
/boot/extlinux/extlinux.conf内が下記のようになる。

LABEL JetsonIO
        MENU LABEL Custom 40-pin Header Config
        LINUX /boot/Image
        FDT /boot/tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb
        INITRD /boot/initrd
        APPEND ${cbootargs}

上記にある
/boot/Image
/boot/tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb
また、先ほど作成した
/boot/initrd.img-4.9.140-tegra

この3つが後ほど必要になるため、Jetson Nanoを停止して、SDカードを取りだしUSBで変換する。
Jetson Nano Dev Boardを使ってSDカード暗号化をテスト(Jetson Nano secureboot編)で用意したJetson Nanoファームウェア構築用UbuntuPCを使用し、上記SDカードをUSB変換を使い、マウントしUbuntuPCに3つを保存しておく。

理由としては、Jetson Nanoのパーティション定義が、/bootと/が1つのパーティションで、ルートファイルシステムの暗号化を行った場合、/bootごと暗号化され、起動ができないためだ。

また、これに対応するルートファイルシステムを準備する。

r32.4.2が新規に書き込まれたSDカードを作成する。
Jetson Nanoで使えるSDカードのイメージファイルまとめとイメージ書き込み方法
書き込み終わったら、Jetson Nano にSDカードを入れる前にルートファイルシステムを吸い出す。

Jetson Nano Dev Boardを使ってSDカード暗号化をテスト(Jetson Nano secureboot編)で用意したJetson Nanoファームウェア構築用UbuntuPCを使用し、上記SDカードをUSB変換を使い、マウントする。

”Linux_for_Tegra”ディレクトリ上から操作を開始する。
ddで13GBくらいのルートファイルシステムのイメージの入れ物を作り、ループバックでマウントし、luksFormatを行う。
その後、SDカードからルートファイルシステムをrsyncでコピーをかける流れ。
SDカードは/dev/sdaで認識した。

$ dd if=/dev/zero of=system.img.raw bs=1M count=0 seek=13312 
$ sudo losetup -f system.img.raw 
$ losetup -l //ループバックデバイス番号を確認する。
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE                         DIO LOG-SEC
/dev/loop5
             0      0         0  0 
Linux_for_Tegra/system.img.raw

$ sudo apt install cryptsetup
$ sudo cryptsetup luksFormat /dev/loop5


WARNING!
========
This will overwrite data on /dev/loop1 irrevocably.

Are you sure? (Type uppercase yes): YES<大文字YES>
Enter passphrase for /dev/loop5: <”test”と入力> 
Verify passphrase: <”test”と入力>
$ sudo cryptsetup luksOpen /dev/loop5 luks
Enter passphrase for /dev/loop5:<”test”と入力> 
$ ls /dev/mapper/
control  luks
$ sudo mkfs.ext4 /dev/mapper/luks 
mke2fs 1.44.1 (24-Mar-2018)
Creating filesystem with 2096640 4k blocks and 524288 inodes
Filesystem UUID: b71b1ee2-993e-44b8-b5e5-5d6ab4346b6b
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done 

$ sudo mkdir /media/luks
$ sudo mount /dev/mapper/luks /media/luks

$ sudo mkdir /media/usb
$ sudo fdisk -l /dev/sda
GPT PMBR size mismatch (26865663 != 249737215) will be corrected by w(rite).
Disk /dev/sda: 119.1 GiB, 127865454592 bytes, 249737216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4C9B6CD1-8AEA-46F2-B51E-D99B485C0E4A

Device     Start      End  Sectors  Size Type
/dev/sda1  28672 26861567 26832896 12.8G Linux filesystem
/dev/sda2   2048     2303      256  128K Linux filesystem
/dev/sda3   4096     4991      896  448K Linux filesystem
/dev/sda4   6144     7295     1152  576K Linux filesystem
/dev/sda5   8192     8319      128   64K Linux filesystem
/dev/sda6  10240    10623      384  192K Linux filesystem
/dev/sda7  12288    13055      768  384K Linux filesystem
/dev/sda8  14336    14463      128   64K Linux filesystem
/dev/sda9  16384    17279      896  448K Linux filesystem
/dev/sda10 18432    19327      896  448K Linux filesystem
/dev/sda11 20480    22015     1536  768K Linux filesystem
/dev/sda12 22528    22655      128   64K Linux filesystem
/dev/sda13 24576    24735      160   80K Linux filesystem
/dev/sda14 26624    26879      256  128K Linux filesystem

Partition table entries are not in disk order.
$ sudo mount /dev/sda1 /media/usb

sudo apt-get install rsync -y 
sudo rsync -axHAWX --numeric-ids --info=progress2 /media/usb/ /media/luks

コピー完了後、マウントした先が下記のようにルートファイルシステムになっていることを確認する。

$ ls -alr /media/luks/
合計 100
drwx------   2 root root  4096  5月 29 15:07 var
drwxr-xr-x  12 root root  4096  4月 29 19:53 usr
drwxrwxrwt   2 root root  4096  4月 29 19:55 tmp
drwxr-xr-x   2 root root  4096  4月 24  2018 sys
drwxr-xr-x   2 root root  4096  4月 27  2018 srv
drwxr-xr-x   2 root root  4096  5月 11  2018 snap
drwxr-xr-x   2 root root  4096  2月 20 19:42 sbin
drwxr-xr-x  17 root root  4096  9月 11  2019 run
drwx------   2 root root  4096  4月 27  2018 root
drwxr-xr-x   2 root root  4096  4月 24  2018 proc
drwxr-xr-x   4 root root  4096  4月 29 19:44 opt
drwxr-xr-x   2 root root  4096  4月 27  2018 mnt
drwxr-xr-x   2 root root  4096  8月  6  2018 media
drwx------   2 root root  4096  4月 29 19:55 lost+found
drwxr-xr-x  21 root root  4096  4月 29 19:44 lib
drwxr-xr-x   2 root root  4096  4月 24  2018 home
drwxr-xr-x 136 root root 12288  4月 29 19:55 etc
drwxr-xr-x   2 root root  4096  4月 29 19:55 dev
drwxr-xr-x   4 root root  4096  4月 29 19:45 boot
drwxr-xr-x   2 root root  4096  2月 20 19:46 bin
-rw-rw-rw-   1 root root    62  4月  9 10:21 README.txt
drwxr-xr-x   5 root root  4096  5月 29 14:49 ..
drwxr-xr-x  22 root root  4096  4月 29 19:56 .

問題なければ、イメージファイルをUSBケーブル経由でJetson Nanoへ流しこめるように準備する。

$ sudo umount /media/luks 
$ sudo cryptsetup luksClose /dev/mapper/luks
$ sudo losetup -d /dev/loop5
$ mv system.img.raw  bootloader/

$ sudo bootloader/mksparse -v -fillpattern=0 bootloader/system.img.raw bootloader/system.img

mksparseというのは転送用にイメージファイルを圧縮するプログラム。
これで生成されるsystem.imgが実際に転送されるイメージ
これでbootloaderにルートファイルシステムのファイルを置くことができた。

ここまででinitramfs、および暗号化済みのルートファイルシステムの準備ができた。
次はJetson Nano Dev Boardを使ってSDカード暗号化をテスト(起動シーケンス作成編)

Jetson Nano Dev Boardを使ってSDカード暗号化をテスト 記事インデックス

概要編
Jetson Nano secureboot編
LUKS 調査編
initramfs 調査編 <いまここ
起動シーケンス作成編