前回の記事で行ったラズパイのアップデートについて、内容を説明する。
対象の資材
以下のリポジトリのmeta-my-securityディレクトリが対象。
https://github.com/aimdevel/meta-my-raspberrypi
各設定の説明
Linuxのアップデートを行うために作成した箇所について説明する。
partitionの設定
sdカードのパーティション設定は、meta-my-security/wic/my-security-dual.wks.in
に記載してある。
meta-raspberrypiのwksファイルをベースに作成した。
以下のパーティション構成と同じになるように設定してある。
name | size | format | description |
---|---|---|---|
mmcblk0p1 | 128MB | vfat | ブートパーティション。u-bootを格納 |
mmcblk0p2 | 128MB | vfat | linuxを格納。アップデートA面 |
mmcblk0p3 | 128MB | vfat | linuxを格納。アップデートB面 |
mmcblk0p4 | none | none | 拡張パーティション |
mmcblk0p5 | 512MB | none | rootfs。この領域をdm-verityで検証する。アップデートA面 |
mmcblk0p6 | 512MB | none | rootfs。この領域をdm-verityで検証する。アップデートB面 |
mmcblk0p7 | 500MB | ext4 | 書き込み用暗号化領域。初回起動時にdm-cryptで暗号化する。アップデート後もデータが保持される領域として使用する。 |
mmcblk0p8 | 20MB | ext4 | dm-crypt用ファイル置場。キーファイルや初回起動フラグなど。 |
part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20 part / --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" part / --ondisk mmcblk0 --size 100M part / --ondisk mmcblk0 --size 500M part / --ondisk mmcblk0 --fstype=ext4 --size 20M
このファイルの書き方は以下のページを参考にした。
https://docs.yoctoproject.org/ref-manual/kickstart.html
また、この設定を使用するためにlocal.conf
に以下の設定を追加。
WKS_FILE = "my-security-dual.wks.in"
u-boot用の設定
u-boot scriptをraucに対応させる。
raucでu-bootを使う場合には起動時の面管理をu-boot環境変数BOOT_ORDERで行っている。そのため、以下のファイルをベースにBOOT_ORDERの値で起動面を切り替えるスクリプトを追加する。
https://github.com/rauc/meta-rauc-community/blob/master/meta-rauc-raspberrypi/recipes-bsp/rpi-u-boot-scr/files/boot.cmd.in
作成したものは以下。
BOOT_ORDERがAの場合はkernelをmmc 0:2
から取り出しmmcblk0p5をrootfsとして使用する。
BOOT_ORDERがBの場合はkernelをmmc 0:3
から取り出しmmcblk0p6をrootfsとして使用する。
test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "A B" test -n "${BOOT_A_LEFT}" || setenv BOOT_A_LEFT 3 test -n "${BOOT_B_LEFT}" || setenv BOOT_B_LEFT 3 test -n "${BOOT_DEV}" || setenv BOOT_DEV "mmc 0:1" setenv bootpart setenv raucslot setenv kernel_addr_r 0x4000000 for BOOT_SLOT in "${BOOT_ORDER}"; do if test "x${bootpart}" != "x"; then # skip remaining slots elif test "x${BOOT_SLOT}" = "xA"; then if itest ${BOOT_A_LEFT} -gt 0; then setexpr BOOT_A_LEFT ${BOOT_A_LEFT} - 1 echo "Found valid RAUC slot A" setenv bootpart "/dev/mmcblk0p5" setenv raucslot "A" setenv BOOT_DEV "mmc 0:2" fi elif test "x${BOOT_SLOT}" = "xB"; then if itest ${BOOT_B_LEFT} -gt 0; then setexpr BOOT_B_LEFT ${BOOT_B_LEFT} - 1 echo "Found valid RAUC slot B" setenv bootpart "/dev/mmcblk0p6" setenv raucslot "B" setenv BOOT_DEV "mmc 0:3" fi fi done if test -n "${bootpart}"; then setenv bootargs "${bootargs} root=${bootpart} rauc.slot=${raucslot}" saveenv else echo "No valid RAUC slot found. Resetting tries to 3" setenv BOOT_A_LEFT 3 setenv BOOT_B_LEFT 3 saveenv reset fi setenv bootargs "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1 smsc95xx.macaddr=DC:A6:32:6D:32:59 vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 dwc_otg.lpm_enable=0 console=ttyS0,115200 root=${bootpart} rauc.slot=${raucslot} rootfstype=ext4 rootwait debug verbose" fatload ${BOOT_DEV} ${kernel_addr_r} @@KERNEL_IMAGETYPE@@ saveenv @@KERNEL_BOOTCMD@@
Linux kernelの設定
linux kernelをデプロイ用のディレクトリに格納する設定を行う。
local.confに以下の設定を加える。
IMAGE_BOOT_FILES:append = " fitImage-my-initramfs-raspberrypi4-64-raspberrypi4-64"
マウント設定
fstabを以下のように編集してbase-filesレシピで取り込む。
# stock fstab - you probably want to override this with a machine specific one /dev/root / auto defaults 1 1 proc /proc proc defaults 0 0 devpts /dev/pts devpts mode=0620,ptmxmode=0666,gid=5 0 0 tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 tmpfs /var/volatile tmpfs defaults 0 0 # uncomment this if your device has a SD/MMC/Transflash slot #/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0 /dev/mmcblk0p1 /boot auto defaults 1 1 tmpfs /mnt tmpfs defaults 0 0
デフォルトの設定に加えて以下の設定をしている。
- /dev/mmcblk0p1を/bootにマウント
raucがuboot.env書き換えるため、uboot.envの入っているこのパーティションlinuxから見えるようにしておく必要がある。
- /mntにtmpfsをマウント
raucが/mnt下を使用するためwriteできるようにしておく必要がある。
rauc用鍵の作成
meta-raucに用意されているツールを使用する。
以下のreadmeの通りに作業して鍵を作成し、自身のレイヤに取り込んだ。
https://github.com/rauc/meta-rauc/blob/kirkstone/scripts/README
$ ./openssl-ca.sh $ cp openssl-ca/dev/ca.cert.pem ../../../meta-my-raspberrypi/meta-my-security/recipes-core/rauc/files/ $ cp openssl-ca/dev/development-1.cert.pem ../../../meta-my-raspberrypi/meta-my-security/recipes-core/bundles/files/ $ cp openssl-ca/dev/private/development-1.key.pem ../../.. /meta-my-raspberrypi/meta-my-security/recipes-core/bundles/files/
アップデート設定
デバイスのどの領域をアップデートするかの設定は以下に記述してある。
https://github.com/aimdevel/meta-my-raspberrypi/blob/main/meta-my-security/recipes-core/rauc/files/system.conf
ここで指定したスロット名やtypeはupdate-bundleを作成する際に使用する。
[system] compatible=raspberrypi4-64 bootloader=uboot <== u-bootを使うことを指定。 data-directory=/var/data [keyring] path=/etc/rauc/ca.cert.pem <== 鍵の場所を指定 [slot.kerneldir.0] <== A面のkerneldirスロットの設定 device=/dev/mmcblk0p2 type=vfat parent=rootfs.0 [slot.kerneldir.1] <== B面のkerneldirスロットの設定 device=/dev/mmcblk0p3 type=vfat parent=rootfs.1 [slot.rootfs.0] <== A面のrootfsスロットの設定 device=/dev/mmcblk0p5 type=raw bootname=A [slot.rootfs.1] <== B面のrootfsスロットの設定 device=/dev/mmcblk0p6 type=raw bootname=B
update-bundleの作成
raucのアップデートに使用する資材をまとめたものである.raucbファイルの設定は以下のディレクトリにあるファイルに書かれている。
https://github.com/aimdevel/meta-my-raspberrypi/tree/main/meta-my-security/recipes-core/bundles
kernel-dir.bb
このファイルはlinux kernelをvfatのファイルに格納する処理を行っている。
作成したvfatファイルはraucbを作成するとき使用する。update-bundle.bb
このファイルでアップデートの詳細を記載する。
内容は以下である。
DESCRIPTION = "RAUC bundle generator" FILESEXTRAPATHS:prepend := "${THISDIR}/files:" DEPENDS = "linux-raspberrypi" inherit bundle RAUC_BUNDLE_COMPATIBLE = "${MACHINE}" RAUC_BUNDLE_VERSION = "v20241104" RAUC_BUNDLE_DESCRIPTION = "RAUC Demo Bundle" RAUC_BUNDLE_FORMAT = "verity" RAUC_BUNDLE_SLOTS = "rootfs kerneldir" RAUC_SLOT_kerneldir = "kernel-dir" RAUC_SLOT_kerneldir[file] = "kernel-dir.vfat" RAUC_SLOT_kerneldir[type] = "file" RAUC_SLOT_kerneldir[fstype] = "vfat" RAUC_SLOT_rootfs = "core-image-base" RAUC_SLOT_rootfs[file] = "core-image-base-raspberrypi4-64.ext4.verity" RAUC_SLOT_rootfs[rename] = "rootfs.img" RAUC_KEY_FILE ?= "${THISDIR}/files/development-1.key.pem" RAUC_CERT_FILE ?= "${THISDIR}/files/development-1.cert.pem"
RAUC_SLOT_*
でアップデートするスロットを指定する。このスロットとはデバイス内で定義されたどの領域をアップデートするかを表している。これはアップデート設定の内容と対応させる必要がある。
そしてスロットごとにどのような資材をインストールするかをRAUC_SLOT_*[file]
、RAUC_SLOT_*[type]
、RAUC_SLOT_*[fstype]
で指定する。ここの設定はもっと良い書き方があるかもしれない。
先ほど説明したkernel-dirで作成したvfatファイルもここで指定することでraucbに取り込んでいる。
妥協した点
- bootパーティションの内容
ラズパイの起動に必要なファイルがどれなのか調べてないので、不要なファイルも含まれている。 - kernelパーティションAの内容
yoctoで格納するファイルを指定する方法がわからなかったので、bootパーティションと同じ内容。
アップデートすればクリアされる。 - dm-cryptの鍵置き場
sdカード上に鍵をおいてあるが、本当はeFuseなどのsdカード以外の領域おかなければならない。
このままだとsdカードを持ち去られたら普通に復号されてしまう。
終わりに
kernelも含めてラズパイのアップデートを試した際の設定を説明した。
アップデート時にデバイスに設定するべき大まかな項目はわかったので、さらに細かい設定を見ていくか、それかOTAを試すべくraucbを配信するサーバを立てるかなど次に何をやるか考えたい。