みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

YoctoProject kirkstone + RPi4Bでdm-verity環境を試す

はじめに

YoctoProject dm-verity環境を試すでYoctoProjectを使用してqemu環境でdm-verityを試した。

今回は実機で使用する際にどの様なことが必要か考えてみる。

ターゲットはラズベリーパイ4 モデルB

使用するブランチはkirkstone

環境構築

作業環境

作業ディレクトリは~/yocto/rpi-kirkstone-securityとする。

$ mkdir -p ~/yocto/rpi-kirkstone-security
$ cd ~/yocto/rpi-kirkstone-security

pokyの取得

下記コマンドを実行してpokyおよびビルド環境を取得する。

$ git clone -b kirkstone git://git.yoctoproject.org/poky.git

環境変数の設定

bitbakeを実行可能にするため環境変数を設定する。

$ source poky/oe-init-build-env

meta-raspberrypiの取得

meta-raspberrypiを取得する。

$ bitbake-layers layerindex-fetch meta-raspberrypi

meta-securityの取得

meta-securityと依存するレイヤを取得する。

$ bitbake-layers layerindex-fetch meta-security meta-oe meta-python meta-networking meta-perl

wksを作成

マイクロSDにveirty用のルートFSを書き込むためにwksファイルを作成する。 wksを格納するための作業用レイヤを作成する。

$ bitbake-layers create-layer meta-work
$ mkdir meta-work/wic
$ rm -rf meta-work/wic/recipes-example
$ mv ./meta-work ../poky
$ bitbake-layers add-layer ../poky/meta-work

meta-work/wic/sdimage-raspberrypi-dm.wks.inを下記の内容で作成する。

part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20
part / --source rawcopy --ondisk mmcblk0 --sourceparams="file=${IMGDEPLOYDIR}/${DM_VERITY_IMAGE}-${MACHINE}.${DM_VERITY_IMAGE_TYPE}.verity" --fstype=ext4

wksファイルの拡張子をwks.inとすることにより、bitbake内で使用できる変数を記述することができる。 変数を含んだwks.inから、変数が解決されたwksが作成され、wicツールに渡されるような流れとなる。

local.confを編集

conf/local.confに下記の部分を追加

MACHINE = "raspberrypi4-64"
DL_DIR = "${TOPDIR}/../downloads"

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES:append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# dm-verity
DM_VERITY_IMAGE = "core-image-base"
DM_VERITY_IMAGE_TYPE = "ext4"
IMAGE_CLASSES += "dm-verity-img"

INITRAMFS_IMAGE = "dm-verity-image-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"

# use the kernel that bundled initramfs
IMAGE_BOOT_FILES = " \
  ${BOOTFILES_DIR_NAME}/* \
  ${@make_dtb_boot_files(d)} \
  ${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.bin;${SDIMG_KERNELIMAGE} \
"

# enable kernel features for dm-verity
KERNEL_FEATURES:append = " features/device-mapper/dm-verity.scc"

WKS_FILE = "sdimage-raspberrypi-dm.wks.in"

dm-verity用イメージ作成の設定

dm-veirty用のイメージを作成するための設定は下記の部分となる。

# dm-verity
DM_VERITY_IMAGE = "core-image-base"
DM_VERITY_IMAGE_TYPE = "ext4"
IMAGE_CLASSES += "dm-verity-img"

dm-verity検証用initramfs作成の設定

起動時にdm-verityを使用してルートFSのデバイスを検証するための initramfsを作成するための設定は下記の部分となる。

INITRAMFS_IMAGE = "dm-verity-image-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"

ここでは、initramfsはカーネルにバンドルするようにしている。

initramfsをバンドルしたカーネルを使う設定は下記の部分となる。

# use the kernel that bundled initramfs
IMAGE_BOOT_FILES = " \
    ${BOOTFILES_DIR_NAME}/* \
    ${@make_dtb_boot_files(d)} \
    ${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.bin;${SDIMG_KERNELIMAGE} \
"

カーネルのdm-verity関連の機能を有効化

dm-veirty関連のドライバをカーネルに組み込むために下記の行を追加している。

# enable kernel features for dm-verity
KERNEL_FEATURES:append = " features/device-mapper/dm-verity.scc"

veirty用のwksを使用

今回作成したwksを使用するように下記を設定している。

WKS_FILE = "sdimage-raspberrypi-dm.wks.in"

ビルド

core-image-baseをビルドする。

$ bitbake core-image-base

動作確認

作成されたイメージを書き込んだマイクロSDでラズベリーパイ4を起動する。

root@raspberrypi4-64:~# mount | grep '/ '
/dev/mapper/rootfs on / type ext4 (ro,relatime)
root@raspberrypi4-64:~#

dm-verity関連のログ

筆者環境では下記のようなログが出力されているが、システムが起動できているのでひとまず気にしないことにしている。

[    5.070957] random: veritysetup: uninitialized urandom read (2 bytes read)
[    5.078808] device-mapper: verity: sha256 using implementation "sha256-generic"
[    5.179765] device-mapper: verity: 179:2: data block 2048 is corrupted
[    5.187192] device-mapper: verity: 179:2: data block 2048 is corrupted
[    5.193909] Buffer I/O error on dev dm-0, logical block 512, async page read
Verity device detected corruption after activation.

注意点

dm-verity用のルートFSを書き込んだマイクロSDは、書き込み後PCなどでマウントしてしまうと、 ハッシュが変わってしまうため、起動しなくなるので注意すること。

まとめ

YoctoProjectで作成したdm-verityの環境を実機で動かしてみた。 エラーっぽいメッセージも見られたが、一応は動作しているようだ。

性質上、ルートFSはリードオンリーでマウントされるため、 実用するには、overlayfsなどを使用して書き込み可能な領域を重ねるか、 書き込み可能領域をどこかにマウントするなど対応が必要となる。