Quantcast
Channel: aimdevel’s blog
Viewing all articles
Browse latest Browse all 35

initramfs + dm-verityでrootfsを検証する

$
0
0

初めに

前回はBuildrootでinitramfsを作成し起動する方法を試した。

aimdevel.hatenablog.com

今回は、本番用rootfsをinitramfs + dm-verityで検証することで改ざんを検知できるようにしていく。

dm-verityとは

dm-verityとは、linux kernelに備えられたブロックデバイスを検証する仕組みのこと。
詳しくは以下の公式ドキュメントなどを参照してください。
https://docs.kernel.org/6.1/admin-guide/device-mapper/verity.html

作るもの

以下の流れでrootfsを検証し起動するように作成する。
1. initramfsのinitスクリプトを起動
2. initramfsに含めたroot hashと別のパーティションに格納したhash treeを用いてrootfsの入っているパーティションを検証
3. device-mapperでread onlyのデバイスとしてrootfsの入っているパーティションが認識されるので、適当な場所にマウント
4. switch_rootでrootfsを切り替え

実施環境

  • ビルド環境
    windows11のwslでubuntu24.04を使用してビルドなどを行い、sdカードの操作はwindows側で行った。
  • 実機
    ラズパイ4B
  • 対象バージョン
    ラズパイOSの公式イメージ「2024-03-15-raspios-bookworm-arm64-lite.img.xz」と同等。
    • raspi OS
      bookworm
    • linux kernel
      linux-stable_20240423

手順

まずは開発環境で作業を行う。

sdカードイメージのマウント

sdカードイメージを編集するのでラズパイOSのimgファイルの各パーティションをマウントしておく。
せっかくなのでマウントには自作ツールを使用する。
使い方は以下を参照。本記事ではこのツールがホームディレクトリに配置してある前提で話を進める。
losetupコマンドなどを使って手動でマウントを行っても問題ない。
https://aimdevel.hatenablog.com/entry/2023/08/05/232643

mkdir ~/dm-verity-work
cd ~/dm-verity-work/
mkdir boot rootfs
wget https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-raspios-bookworm-arm64-lite.img.xz
xz -d 2024-03-15-raspios-bookworm-arm64-lite.img.xz
sudo ~/part-mount -p1 2024-03-15-raspios-bookworm-arm64-lite.img boot
sudo ~/part-mount -p2 2024-03-15-raspios-bookworm-arm64-lite.img rootfs

rootfsの準備

ラズパイOSのrootfsをそのまま流用する。
まずはどこにrootfsが入っているパーティションがあるか確認する。

df -h | grep dm-verity-work/rootfs

上記のコマンドの出力が以下のようになり、/dev/loop1がrootfsのパーティションに対応したループデバイスであることがわかる。このデバイスをダンプする。

/dev/loop1      2.0G  1.6G  313M  84% /home/ubuntu/dm-verity-work/rootfs

/dev/loop1をダンプする場合は以下のように実行する。

sudo e2image -raf -p /dev/loop1 rootfs.img

sdカードイメージを使い終わったら一度アンマウントしておく。

sudo umount boot
sudo umount rootfs

hash treeの作成

以下のサイトを参考に作業し、検証が成功することを確認する。
https://qiita.com/propella/items/f7cb0534a0a19f51b09b

truncate -s 100M hash.img
veritysetup -v --debug format rootfs.img hash.img

以下のような出力が得られる。Root hashの値を使用するのでメモっておくこと。

VERITY header information for hash.img
UUID:                   bca5d298-31dd-429d-bc98-0f545b033c61
Hash type:              1
Data blocks:            543744
Data block size:        4096
Hash blocks:            4283
Hash block size:        4096
Hash algorithm:         sha256
Salt:                   672d635155bc264a61c92640f2351decccbb58d32dc8793ce6c3fec139ef1209
Root hash:              3d203e1917909149841a8465e71a50f23e27d8b5e191ebea04b90ba442fe6891 <== ここをメモっておく。  
Hash device size:       17547264 [bytes]
# Releasing crypt device hash.img context.
# Releasing device-mapper backend.
# Closing read write fd for hash.img.
Command successful.

検証を試す。<your Root hash>には先ほどメモしたRoot hashの値を使用する。

mkdir verity-test
sudo veritysetup open rootfs.img verity-test hash.img <your Root hash>
sudo mount -o noload /dev/mapper/verity-test verity-test

成功すると/dev/mapper/verity-testが、read onlyで~/dm-verity-work/verity-testにマウントされる。

確認したらマウントやdevice-mapperを掃除しておく。

sudo umount verity-test
sudo veritysetup close verity-test

以上でdm-verityの試用は終わり。
次はsdカードイメージを作成していく。


rootfs.imgとhash.imgの格納

sdカードイメージにhash.imgを格納する。
新規にパーティションを作成してそこに書き込む。

truncate -s 4G 2024-03-15-raspios-bookworm-arm64-lite.img
sudo fdisk 2024-03-15-raspios-bookworm-arm64-lite.img

fdiskで以下のように操作して新しいパーティションを作成する。セクタの値などはラズパイOSのバージョンによって異なるかもしないので、適宜変更する。

Welcome to fdisk (util-linux 2.39.3).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk 2024-03-15-raspios-bookworm-arm64-lite.img: 4 GiB, 4294967296 bytes, 8388608 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: dos
Disk identifier: 0xfb33757d

Device                                      Boot   Start     End Sectors  Size Id Ty
2024-03-15-raspios-bookworm-arm64-lite.img1         8192 1056767 1048576  512M  c W9
2024-03-15-raspios-bookworm-arm64-lite.img2      1056768 5406719 4349952  2.1G 83 Li

Command (m for help): n
Partition type
   p   primary (2 primary, 0 extended, 2 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (3,4, default 3): 
First sector (2048-8388607, default 2048): 5439488
Last sector, +/-sectors or +/-size{K,M,G,T,P} (5439488-8388607, default 8388607): +200M

Created a new partition 3 of type 'Linux' and of size 200 MiB.

Command (m for help): w
The partition table has been altered.
Syncing disks.

次に、rootfs.imghash.imgをそれぞれ書き込む。
一度各パーティションをloopデバイスとして見える状態にしておく。 以下のコマンドで空いているloopデバイスを確認し、

sudo losetup -f

以下のコマンドで設定、書き込みを行う。自分の環境では/dev/loop0が空いていた。第二パーティションrootfs.imgを、第三パーティションhash.imgを書き込む。

sudo losetup -P /dev/loop0 2024-03-15-raspios-bookworm-arm64-lite.img
sudo dd if=rootfs.img of=/dev/loop0p2
sudo dd if=hash.img of=/dev/loop0p3
sudo losetup -d /dev/loop0

Linux kernelのビルド

ラズパイ用のdefconfigファイルではdm-verityが無効なので、これを有効にしたLinux kernelをビルドする。
過去のビルド結果が残っている場合はそれを使いまわしてもよい。

まずはソースコードを取得する。

wget https://github.com/raspberrypi/linux/archive/refs/tags/stable_20240423.tar.gz
tar xf stable_20240423.tar.gz
cd linux-stable_20240423

以下のようにしてarch/arm64/configs/bcm2711_defconfigに追記する。

echo "CONFIG_DM_VERITY=y" >> arch/arm64/configs/bcm2711_defconfig

ビルドする。

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig  
make -j`nproc` ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

initramfsの作成

ベースとなるrootfsは、前回作成したveritysetupがインストールされたものを使用する。
今回は前回のinitramfsに、/initファイルの修正とkernelモジュールのインストールを行う。

/initを以下の内容にする。変数VERITY_ROOTHASHに各自のroot hashを指定するようにしている。

#!/bin/sh

VERITY_ROOTHASH=3d203e1917909149841a8465e71a50f23e27d8b5e191ebea04b90ba442fe6891

mount -v --bind /dev /dev
mount -v --bind /dev/pts /dev/pts
mount -vt proc proc /proc
mount -vt sysfs sysfs /sys
mount -vt tmpfs tmpfs /run

mdev -s

echo "start switch_root!"

# parse cmdline
cmdline=$(cat /proc/cmdline)

for param in $cmdline; do
    echo $param
    case $param in
        root=*)
        ROOT=`echo $param | sed 's/.*=//'`
        ;;
    esac
done

# wait rootfs
for i in {1..30}
do
  /sbin/mdev -s
  TMP=`ls -l /dev/ | grep $ROOT`
  if [ -n "${TMP}" ];then
    break
  fi
  echo "waiting rootfs..."
  sleep 1 
done

# veritysetup
veritysetup open $ROOT verity-root /dev/mmcblk0p3 $VERITY_ROOTHASH

# mount mrootfs.
mkdir -p /dev/root
mount -o noload /dev/mapper/verity-root /dev/root

# switch root
exec switch_root -c /dev/console /dev/root /sbin/init

さらに以下のコマンドでkernel moduleをインストールする。インストール先は前回の記事で使用したrootfsとしている。

cd ~/dm-verity-work/linux-stable_20240423
make modules_install INSTALL_MOD_PATH=~/initramfs-buildroot/buildroot-2024.02.3/output/target/

FIT imageの作成

前回までと同様に上記のinitスクリプトを含んだFIT imageを作成する。ここは前回から変更なしなので、コマンドは割愛。

ファイルの格納

必要なファイルをsdカードイメージに格納する。ここでもimgファイルをマウントして作業する。
今回はsdカードイメージに直接手を加えたので、bootパーティション(第一パーティション)に以下の作業をすべて行う。

  • FITImage格納
    作成したFITImageを格納する。
  • u-boot.binの格納
    以前の記事で作成したu-boot.binを格納する。

aimdevel.hatenablog.com

  • config.txt編集
    config.txtの以下の設定を行う。

      enable_uart=1
      arm_64bit=1
      kernel=u-boot.bin
    

sdカードイメージを圧縮(任意)

sdカードイメージを圧縮してサイズを小さくしておくと容量を食わなくてよい。
多分動作確認後にやることだとは思うが。

gzip 2024-03-15-raspios-bookworm-arm64-lite.img

sdカードイメージのフラッシュ

sdカードイメージが完成したので、sdカードにフラッシュする。
windowsの場合はRapsberry Pi Imagerなどで書き込める。


以降の作業はラズパイ実機で行う。
作成したsdカードを使用して起動する。

u-bootの設定を変更する。

u-bootコンソールで以下の設定を行う。

setenv bootargs "coherent_pool=1M 8250.nr_uarts=1 root=/dev/mmcblk0p2 rw rootwait"
setenv bootcmd "fatload mmc 0:1 0x1000000 FITImage;bootm 0x1000000;"
saveenv

起動する

以下のようなログが出てdm-verityで検証してマウントされていることを確認できる。

[    4.450015] device-mapper: ioctl: 4.48.0-ioctl (2023-03-01) initialised: dm-devel@redhat.com
[    4.480041] device-mapper: verity: sha256 using implementation "sha256-generic"
[    4.504788] EXT4-fs: Mount option(s) incompatible with ext2
[    4.520125] EXT4-fs (dm-0): mounted filesystem 93c89e92-8f2e-4522-ad32-68faed883d2f ro without journal. Quota mode: none

そのままラズパイOSが起動するが、うまくログインできない。ラズパイOSのデフォルトユーザってpiでパスワードraspberryじゃなかったっけ?rootfsのro化の影響?
まあ、とりあえず起動までは試せたので今回はここまでにしておく。

終わりに

Linuxのrootfsをdm-verityで検証できるようにした。
ただ、このままだとログインできないし、ファイルも書き込めないので、次は書き込み可能領域を作成して再挑戦してみようかと思う。

参考資料


Viewing all articles
Browse latest Browse all 35

Trending Articles