WXR-2533DHPのブート不可問題あれこれ

5chでの報告によって気付き対処にあたった、WXR-2533DHPが最近のファームではブートしなくなっていた問題についての備忘録。

発端

5chのOpenWrt現行スレにて、 “最新のsnapshotでブートできない” と書き込みがあり、2019/09/06 0時頃スレを見に行った際それに気付いた。

原因予想

そこから寝るまで、あれこれ思考開始。とりあえず思い当たるところを色々考えつつ、 openwrt/openwrt のcommitを target/linux/ipq806x 中心に見てみる。
が、特にブートを阻害するような変更は見つからず。

WXR-2533DHPはブート時にU-BootがRootFSの末尾に付加されるchecksumをチェックし、それがRootFSから実際に算出した値と一致していれば正常としてブートを行う。全く確証は無いものの、これで問題が起きている可能性もあるかなーとぼんやり。

しかしながら、 downloads.openwrt.org からダウンロードしてきたイメージをtarで展開し、 “root” を確認しても末尾のチェックサムは正しく付加されており、手元で実際に算出した値とも一致した。わけわかめ。

実機検証

2019/09/06は外出から帰宅後気力が尽きており、検証は7日に持ち越し。

翌7日にWXR-2533DHPを引っ張り出し、OpenWrt公式のイメージを使用してFlashに書き込みブートを試行。すると、以下のエラーによりU-BootがOpenWrtのブートに失敗していた。

Hit any key to stop autoboot:  0 
Checking Bank1 Image ... 
Creating 1 MTD partitions on "nand0":
0x000000000000-0x000004000000 : "mtd=0"
Rootfs Checksum Error
Bank1 Image is fail

U-BootがNAND Flashに2組格納されているOSイメージのうち最初の “Bank1” をチェックした際、RootFSのchecksumが正しくないとしてエラーを吐いていた。
本来ならば “Bank2” も存在するためメーカーファームではBank2から正常なファームウェアがBank1へ書き込まれて復旧しブートするが、OpenWrtでは諸事情によりファームウェアのアップグレード時にBank2については消去を行っている。このため、上記ログの後Bank2のチェックに移るが、Bank2も正常ではないため結局どうにもできず、WXR-2533DHPのLANポートに何らかの接続がある場合はTFTPによる待ち受けが開始され、無ければそのまま再起動される。

原因探し/特定

ブートできない問題が何故引き起こされているのかは分かったが、それの原因についてはこの時点では未だ不明。
NAND Flash内にUBIによってボリュームが作成される際、checksumがボリューム内の最後に来なければならないのかと推測したものの、WXR-2533DHPのサポート作業初期に取ったメーカーファームのバックアップを確認したところ、特に最後ではなかった。残念。

とここで、問題のあるOpenWrtファームウェアとバックアップ済みのメーカーファームで、RootFS内のchecksumの位置が異なることに気付く。メーカーファームではRootFSのデータ本体と思われる部分のすぐ後にchecksumが付加されていた

WXR-2533DHP Ver.1.33
末尾 D3 がchecksum

        00010203 04050607 08090A0B 0C0D0E0F  0123456789ABCDEF
E864A0  87A841C7 D8E8DCF2 046C4252 669CC63B  ..A......lBRf..;
E864B0  164BDAC2 3D59E88F A96CD931 92BAF43D  .K..=Y...l.1...=
E864C0  B9EFD51F 0E747DE0 7B5081FC 985296CC  .....t}.{P...R..
E864D0  A245A256 CA52D000 000052A7 91A50001  .E.V.R....R.....
E864E0  9608D020 00003B95 03263E30 0D8B0200  ... ..;..&>0....
E864F0  00000001 595ABC41 E8000000 00006649  ....YZ.A......fI
E86500  E8000000 0000D050 E8000000 00000659  .......P.......Y
E86510  E8000000 0000B860 E8000000 00000480  .......`........
E86520  00000000 1E65E800 00000000 D3        .....e.......   

が、OpenWrtファームウェアではデータ本体部分と思われる後、さらにpaddingと思われる部分が続き、その後ろにchecksumが付加されていた。

問題のあるOpenWrtファームウェア(再現)
末尾 A3 がchecksum

        00010203 04050607 08090A0B 0C0D0E0F  0123456789ABCDEF
BDD4F0  00000000 00000000 00000000 00000000  ................
BDD500  00000000 00000000 00000000 00000000  ................
BDD510  00000000 00000000 00000000 00000000  ................
BDD520  00000000 00000000 00000000 00000000  ................
BDD530  00000000 00000000 00000000 00000000  ................
BDD540  00000000 00000000 00000000 00000000  ................
BDD550  00000000 00000000 00000000 00000000  ................
BDD560  00000000 00000000 00000000 00000000  ................
BDD570  A3                                   .       

で、確かsquashfsはヘッダ内にsquashfsのサイズ値を持っていたはず…と思い出し、binwalkで確認したところ、メーカーファームではsquashfsのサイズ値とchecksumのoffsetが一致していた。対照的に問題のあるOpenWrtファームウェアでは、サイズ値とoffsetが一致しない。どうも、paddingされているサイズだけchecksumのoffsetが後ろにズレているのでは…とぼんやり。

とぼんやりしていたら、最近というか少し前くらいにML (openwrt-devel) 辺りで “squashfsのpaddingがどうのこうの” というやり取りがされていたことを思い出した。
たぶん自分には関係ないなと特段気にしてはいなかったが、しばらく見かけていなかったから気になりopenwrt/openwrtのcommitを確認。すると、以下のcommitを見つけた。

build: remove harmful -nopad option from mksquashfs
Fri, 30 Aug 2019 16:52:25 +0200
commit: 1c0290c5cc6258c48b8ba46b4f9c85a21de4f875

機種によっては正しくsquashfsが読み取れずにマウントに失敗し、ブートが止まるらしく、これの解決の為mksquashfsから -nopad オプションが削除されていた。この結果、mksquashfsによりsquashfsが生成される際に、出力データが4KiBで割り切れるサイズまでpaddingされるようになった模様。
ただし、この際問題になるのがsquashfsのヘッダに記録されるサイズ値であり、paddingの有無にかかわらず実データのサイズを格納する模様。その結果、paddingが行われるようになってもpadding前のサイズでサイズ値が記録されてしまい、WXR-2533DHPで必要なRootFS末尾のchecksumのoffsetと合わなくなってしまっていた。
雑に表すと以下のような感じ。

       OpenWrt (incorrect state)                                stock firmware
+---------------------------------------+         +---------------------------------------+
|                                       |         |                                       |
|                                       |         |                                       |
|            squashfs data              |         |            squashfs data              |
|                                       |         |                                       |
|                                       |         |                                       |
|                   +-------------------+         |                   +-------------------+
|                   |                   |         |                   |  |  <- checksum
+-------------------+                   |         +-------------------+--+
|                padding                |
+---------------------------------------+         size value      = data size
|  |  <- checksum                                 checksum offset = data size
+--+
                                                  size value = checksum offset
size value      = data size
checksum offset = data size + padding size

squashfs size ≠ checksum offset

このため、WXR-2533DHPのU-Bootがsquashfsのヘッダに格納されているサイズ値を元に取得したchecksumは末尾に付加された正しいものではなく、paddingにより付加された “0x00” であり、その結果不正なchecksumであるとしてBankのイメージが正しくないと判定されていた。
一旦当該commitをrevertしてビルドしたところ正常にブートしたため、これが原因となっていると確定。

対処

原因となったcommitもトラブルを起こす機種の修正という目的をもって取り込まれたものであり、どちらかというとchecksumを必要とするWXR-2533DHPが特殊であるため、-nopadオプションを削除したcommitはそのままで対処する方針とした。

結局のところsquashfsのヘッダ内に格納されるサイズ値をoffsetとした場所にchecksumが存在していれば良いのであり、その結果ビルド時にsquashfsヘッダからサイズ値を読み取って、そのoffsetにddコマンドでchecksumを埋め込むこととした。

以下は変更内容

WXR-2533DHPのsysupgradeイメージを生成する際squashfsにchecksumを付加するために用意した、既存の Build/buffalo-rootfs-cksum に改変を加える

 target/linux/ipq806x/image/Makefile | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/target/linux/ipq806x/image/Makefile b/target/linux/ipq806x/image/Makefile
index 81f14b47567..0d704cf8e95 100644
--- a/target/linux/ipq806x/image/Makefile
+++ b/target/linux/ipq806x/image/Makefile
@@ -5,9 +5,11 @@ include $(INCLUDE_DIR)/image.mk
 
 define Build/buffalo-rootfs-cksum
 	( \
-		echo -ne "\x$$(od -A n -t u1 $@ | tr -s ' ' '\n' | \
-			$(STAGING_DIR_HOST)/bin/awk '{s+=$$0}END{printf "%x", 255-s%256}')"; \
-	) >> $@
+		squashfs_size="$$(dd if=$@ bs=4 skip=10 count=1 2> /dev/null | od -An -tu4 | tr -d ' \n')"; \
+		od -An -tu1 $@ | tr -s ' ' '\n' | \
+			$(STAGING_DIR_HOST)/bin/awk '{s+=$$0}END{printf "%c", 255-s%256}' | \
+				dd of=$@ bs=1 seek=$${squashfs_size} count=1 conv=notrunc 2> /dev/null; \
+	)
 endef
 
 define Device/Default

上記を実際にビルドして確認の上、openwrt/openwrtのPRに投げ込んだ。

その後

PRを投げ込んだまでは良かったが、その後なんとなくopenwrt/openwrtのcommitを見に行ったら、なんとまぁ、今回の問題の原因になった -nopad オプションを削除するcommitがrevertされていた。なんてこったい。
どうもsquashfsをpaddingされると今度は別でトラブルが引き起こされる環境が出てくるらしく、それでrevertとなった模様。

結局、投げたPRの方は特段何も無いまま原因が消失してしまったので、そのままクローズ。
あっけなく解決してしまい、えぇ…という感じだけれども、まあ問題は無くなったのだから良し。以上。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中