2021/02/13

USBブートLinuxの改修(暗号化されたSquashFSの利用時)

 USBブートのLinuxの中身をアップデートしようと思い、中身を取り出したときのメモ。


暗号化されたファイルシステムをいじるのでdm-cryptカーネルモジュールを読み込む。(メモ:dm-cryptの名称は、Device-Mapper と CRYPTographic でできているらしい。)

# modprobe dm-crypt

鍵を探すため、initramfsの中身を取り出す。ここではlsinitrdコマンドを使うが、取り出せない場合もある。その場合、こちらを参照。

$ lsinitrd --unpack initrd.lz

おそらく、cryptsetupを使っていると思われるので、initramfsを展開した中にcryptsetupコマンドが使われているところがないかを検索する。
その他、ファイルが書き込まれないようにするためcasperを使っていることも考えられるので、cryptsetupでそれっぽいのが見つからなかったらcasperをキーワードに検索するのも良いかもしれない。

$ grep -r cryptsetup *
grep: etc/ld.so.cache: binary file matches
grep: sbin/cryptsetup: binary file matches
scripts/casper:    cryptsetup luksOpen -q -d ${fskey} -l ${fskey_size} ${fsimg} ${mapname}
scripts/casper:    cryptsetup luksClose ${mapname}
grep: var/cache/ldconfig/aux-cache: binary file matches

ここでは、scripts/casperの中でcryptsetupをluksOpenで使っているところがあり、この中で-dオプション(暗号化鍵ファイルの指定)を使っているので$fskeyに含まれるファイル名のファイルが鍵であることが分かる。

cryptsetupは暗号化デバイスを作成・管理するdm-cryptを使うためのコマンドラインツール。LUKSはLinux Unified Key Setupの略。

scripts/casperのなかでfskeyを定義しているところを探す。見つからなければ、ファイルを開いて中身を見る。

# grep "fskey *=" scripts/casper
    local fskey="/conf/fs.key"

/conf/fs.keyが鍵ファイルのようであるので、このファイルを利用できるように取っておく。

一度ファイルを特定しておくと、あとからinitramfsで取り出すときはコマンド一発。

$ lsinitrd initrd64.lz -f conf/fs.key > fs.key

続いて、USBブートLinuxのメインとなるファイルシステムを開く。

# cryptsetup open --type luks main_fs.img usbfs --key-file fs.key

main_fs.imgはメインのファイルシステム、usbfsはブロックデバイスになったときの名前の指定。

cryptsetupでopenすると、指定したブロックデバイス名で/dev/mapperの下にデバイスが作成されるので、マウント。

# mkdir /mnt/fs
# mount /dev/mapper/usbfs /mnt/fs
# ls /mnt/fs
./  ../  filesystem.squashfs  lost+found/

マウントしたディスクイメージの中にはSquashFSでディスクが作られている。

unsquashfsを使って中身を展開。ただし、/mnt/fsにマウントしたディスクイメージに空き容量があまりないと思うので、適当な場所にfilesystem.squashfsをコピーして作業を続ける。

# cp -a filesystem.squashfs /work/
# cd /work/
# unsquashfs filesystem.squashfs
Parallel unsquashfs: Using 8 processors
118271 inodes (122926 blocks) to write

[================================================================/] 122926/122926 100%

created 87359 files
created 13100 directories
created 30811 symlinks
created 79 devices
created 0 fifos
created 0 sockets

# ls -l
total 12
drwxr-xr-x.  3 root root 4096 Feb 13 13:07 ./
drwxr-xr-x.  5 root root 4096 Feb 13 13:06 ../
drwxr-xr-x. 21 root root 4096 Jan 18 00:10 squashfs-root/

squashfs-rootの中に中身が展開されている。

あとは好きに、中身を改修する。chrootしても良い。

# cd squashfs-root/
# mount --bind /dev/ dev/
# chroot squashfs-root
[chrooted]/# mount -t proc none /proc
[chrooted]/# mount -t sysfs none /sys
[chrooted]/# mount -t devpts none /dev/pts

参考)initramfsの中にだけしか存在しないファイルもあるかもしれないので、必要に応じて、先に展開したinitrdの中身をメインのファイルシステムにコピーしてきても良いと思う。

今回利用したUSBはUbuntuベースだった(/etc/os-releaseにバージョンとともに書いてあった。)ので、まずはパッケージのアップデート。アップデートのリポジトリの設定がなかったので、以下のような感じで作成した。

[chrooted]/# cd /etc/apt/
[chrooted]/# mv sources.list sources.list.orig
[chrooted]/# wget https://gist.githubusercontent.com/rohitrawat/60a04e6ebe4a9ec1203eac3a11d4afc1/raw/fcdfde2ab57e455ba9b37077abf85a81c504a4a9/sources.list
[chrooted]/# sed -i.bak -e "s%http://us.archive.ubuntu.com/ubuntu/%http://ftp.iij.ad.jp/pub/linux/ubuntu/archive/%g" /etc/apt/sources.list
[chrooted]/# mkdir -p /tmp/.private/root
[chrooted]/# export LANG=C
[chrooted]/# apt update
[chrooted]/# apt list --upgradable
[chrooted]/# apt full-upgrade

メモ:途中でGrubのインストールを促すメッセージが出た場合、どのパーティションにもインストールしないこと。Chrootしているので、書き込んだらchroot前のパーティションに書き込まれてしまう。

一通り作業が終わったら、更新したファイルシステムをSquashFSに戻していく作業を開始する。

一連の作業が終わり、起動させたときに以下のようなエラーが出た場合、SquashFSを展開するメモリサイズが十分に確保されていない可能性がある。
その場合、展開先のメモリサイズを指定している設定を変更する必要がある。その設定はinitramfsの中でされているので、initramfsを再構築する必要がある。(再構築前に展開先メモリサイズを更新すること)

  cp: write error: No space left on device
  mount: mounting /dev/loop0 on //filesystem.squashfs failed: Invalid argument
  Can not mount /dev/loop0 (/cdrom/casper/filesystem.squashfs) on //filesystem.squashfs

どこで展開先メモリサイズが設定されているかを見つけるのは大変かもしれない。今回利用したUSBでは、initramfsの中の/scripts/casperの中にsize=として設定があった。

initramfsを作成する。

[chrooted]/# mkinitramfs -v -k -c lzma -o /initrd.lz 4.15.0-132-generic

最後の部分は、Kernelの最新バージョンを入れる。

ファイルシステムのサイズを小さくするために、不要なファイルは削除しておくことを推奨。例えばこんな感じ。

[chrooted]/# apt autoremove --purge
[chrooted]/# apt autoclean
[chrooted]/# apt clean
[chrooted]/# rm /var/lib/apt/lists/ftp.iij.ad.jp_pub_linux_ubuntu_archive_dists_xenial*
[chrooted]/# rm /var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_xenial-security_*
[chrooted]/# rm -fr /tmp/.private/*
[chrooted]/# rm -fr /var/tmp/*
[chrooted]/# rm -fr /tmp/*
[chrooted]/# umount /proc || umount -lf /proc
[chrooted]/# umount /sys
[chrooted]/# umount /dev/pts
[chrooted]/# umount /dev
[chrooted]/# exit
# rm  squashfs-root/root/.bash_history

SquashFSを作成する。前にあったものは不要なので削除しつつ、作成したinitramfsを取り出しておく。

# rm filesystem.squashfs
# mv squashfs-root/initrd64.lz ../usb_copy/
# mksquashfs squashfs-root filesystem.squashfs -comp xz

filesystem.squashfsが入っていたディスクイメージ(/mnt/fsにマウントされているもの)は、空き容量がなく改修したSquashFSは入り切らないため、新しくイメージを作成する。

# dd if=/dev/zero of=main_fs_new.img bs=4k count=200k

# ls -l /dev/loop*
crw-rw---- 1 root disk 10, 237 May 12 08:37 /dev/loop-control

# mknod -m 0660 /dev/loop0 b 7 0

# ls -l /dev/loop*
crw-rw---- 1 root disk 10, 237 May 12 08:37 /dev/loop-control
brw-rw---- 1 root root  7,   0 May 16 16:42 /dev/loop0

# losetup /dev/loop0 main_fs_new.img

ddで作成したmain_fs_new.imgのサイズは800M(= 4k x 200k)。ここではmknodを使ってやってみたが、もっと楽なやり方もある。こちらを参照。

ディスクイメージがデバイス/dev/loop0でマウントされているので、ここにLUKSでフォーマットを作る。

# cryptsetup luksFormat /dev/loop0 --type luks1 --key-file fs.key

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

Are you sure? (Type 'yes' in capital letters): YES

fs.keyは最初の方でinitramfsから取り出した鍵ファイル。

作成したファイルシステムを開く。

# cryptsetup open --type luks1 /dev/loop0 usbfs_new --key-file fs.key

更にその中にext4でファイルシステムを作る。

# ls /dev/mapper/
./  ../  control  usbfs@  usbfs_new@

# mkfs.ext4 /dev/mapper/usbfs_new
mke2fs 1.45.5 (07-Jan-2020)
Creating filesystem with 200704 4k blocks and 50176 inodes
Filesystem UUID: d46c6069-aac5-4ec0-a525-f9ba94c44438
Superblock backups stored on blocks:
        32768, 98304, 163840

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

続いて、作成したSquashFSを書き込む。

# mkdir /mnt/usbfs_new
# mount /dev/mapper/usbfs_new /mnt/usbfs_new
# cp -a /work/filesystem.squashfs /mnt/usvfs_new

開いていたものを閉じていく。

# umount /mnt/usbfs_new
# cryptsetup close usbfs_new
# losetup -d /dev/loop0
# umount /mnt/usbfs
# cryptsetup close usbfs

ちなみに、LUKS FSで作ったmain_fs_new.imgの拡張はsys-apps/coreutilsに入っているtruncateコマンドで簡単にできる。

# ls -lh main_fs_new.img
-rw-r--r-- 1 root root 800M May 16 16:58 main_fs_new.img

# truncate -s 890M main_fs_new.img

# ls -lh main_fs_new.img
-rw-r--r-- 1 root root 890M May 16 17:09 main_fs_new.img

# losetup /dev/loop0 main_fs_new.img

# cryptsetup open --type luks /dev/loop0 usbfs_new --key-file fs.key

# resize2fs /dev/mapper/usbfs_new
resize2fs 1.45.5 (07-Jan-2020)
Please run 'e2fsck -f /dev/mapper/usbfs_new' first.

# e2fsck -f /dev/mapper/usbfs_new
e2fsck 1.45.5 (07-Jan-2020)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/usbfs_new: 12/50176 files (0.0% non-contiguous), 196690/200704 blocks

# resize2fs /dev/mapper/usbfs_new
resize2fs 1.45.5 (07-Jan-2020)
Resizing the filesystem on /dev/mapper/usbfs_new to 223744 (4k) blocks.
Number of free blocks: 4014/27054, Needed: 0
The filesystem on /dev/mapper/usbfs_new is now 223744 (4k) blocks long.

更新したディスクイメージで起動できるかをテストしたい場合、ISOファイルを作りたければmkisofsで作成できる

mkisofs -D -r -cache-inodes -J -l -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -o ../hagiwara_new.iso .
Size of boot image is 4 sectors -> No emulation
  0.58% done, estimate finish Sat May 16 17:55:49 2020
  1.15% done, estimate finish Sat May 16 17:55:49 2020
  1.73% done, estimate finish Sat May 16 17:55:49 2020
    ~中略~
 98.59% done, estimate finish Sat May 16 17:55:57 2020
 99.17% done, estimate finish Sat May 16 17:55:57 2020
 99.74% done, estimate finish Sat May 16 17:55:57 2020
Total translation table size: 2048
Total rockridge attributes bytes: 24943
Total directory bytes: 45056
Path table size(bytes): 90
Max brk space used 44000
867251 extents written (1693 MB)

0 件のコメント:

コメントを投稿