When upgrading OpenWrt using sysupgrade, only the header image of the firmware is checked for validity, and the integrity of the firmware is not verified. Therefore, if the firmware has a valid header but other parts are corrupted or modified, it poses a risk, and upgrading could lead to bricking the device.
To verify the integrity and legality of the firmware, there are two methods of protection.
- Add a checksum file packaged with the firmware
- Append checksum information before/after the original firmware
Method 1: Compression and Decompression Check Upgrade
1. Compression
After compiling to generate sysupgrade.bin, calculate the md5sum/sha256sum of the firmware, and write the checksum value along with the model, version, and other information into a checksum file, as follows:
check_file
md5sum:63be2932ff52dfb99ece030338b51ec6
model:ZHAAA
version:1.0.0
Thus, the upgrade package will contain two files:
sysupgrade.bin
check_file
2. Decompression Check
When upgrading with sysupgrade, first decompress the package, then check if the model is consistent and if the firmware’s md5sum matches. If they match, proceed with the normal upgrade writing logic.
Method 2: Signing and Verification Upgrade
The above method has a significant drawback: it occupies two memory spaces. The downloaded compressed package is one file, and decompressing it requires additional memory.
Therefore, the checksum information can be directly appended to the firmware, and when writing to flash, the checksum information can be stripped away.
1. Signing Process
A set of signing tools needs to be written, such as my zsign.
At the end of the OpenWrt compilation, the BuildFirmware function in <span>./target/linux/mtk/image/Makefile</span>
will be called, as follows:
# u-boot: 512K
# config: 512K
# factory: 256K
# firmware: 32MB
# kpanic: 512K
# bdinfo: 512K
# reserve: 512K
# opt: ~
define BuildFirmware/zrNAND
@mkdir -p $(BIN_DIR)/$(2)/$(ROM_PREFIX)
$(call MkImageLzma,$(2),$(3),$(5))
$(call Sysupgrade/KRuImage,$(1),$(2),$(4),128k)
$(eval BUILD_TIME:= $(shell cat $(TARGET_DIR)/etc/zihome_build_time))
$(eval DEST_PREFIX:= $(BIN_DIR)/$(2)/$(ROM_PREFIX)/$(2)-$(ROM_PREFIX)_$(BUILD_TIME))
$(CP) $(call sysupname,$(1),$(2)) $(DEST_PREFIX)-sysupgrade.bin; \
if [ -f "$(BIN_DIR)/$(2)-uboot.bin" ]; then \
$(CP) $(BIN_DIR)/$(2)-uboot.bin $(DEST_PREFIX)-uboot.bin; \
if [ -f $(TOPDIR)/zkeys/rom-keys/zihome.key -a $(TOPDIR)/zkeys/rom-keys/zihome.crt ]; then \
(dd if=$(DEST_PREFIX)-uboot.bin bs=524288 conv=sync;)>$(DEST_PREFIX)-uboot-pad.bin; \
$(STAGING_DIR_HOST)/bin/zsign -b $(DEST_PREFIX)-uboot-pad.bin -s $(DEST_PREFIX)-sysupgrade.bin -o $(DEST_PREFIX)-sign -k $(TOPDIR)/zkeys/rom-keys/zihome.key;\
(dd if=$(DEST_PREFIX)-uboot-pad.bin bs=524288 conv=sync; dd if=$(DEST_PREFIX)-sign)>$(DEST_PREFIX)-uboot-sign.bin; \
(dd if=$(DEST_PREFIX)-uboot-sign.bin bs=1310720 conv=sync; dd if=$(DEST_PREFIX)-sysupgrade.bin )>$(DEST_PREFIX)-flash.bin; \
$(STAGING_DIR_HOST)/bin/mt7621-nand-ecc e 204864 $(DEST_PREFIX)-flash.bin $(DEST_PREFIX)-factory.bin >/dev/null 2>&1; \
rm -rf $(DEST_PREFIX)-sysupgrade.bin; \
rm -rf $(DEST_PREFIX)-uboot-pad.bin $(DEST_PREFIX)-uboot-sign.bin $(DEST_PREFIX)-sign $(DEST_PREFIX)-uboot.bin; \
else \
(dd if=$(DEST_PREFIX)-uboot.bin bs=1310720 conv=sync; dd if=$(DEST_PREFIX)-sysupgrade.bin )>$(DEST_PREFIX)-flash.bin; \
fi; \
fi;
$(call DebugRoot/prepare,$(DEST_PREFIX)-debug-root.tar.gz)
endef
- Use
<span>zsign -b $(DEST_PREFIX)-uboot-pad.bin -s $(DEST_PREFIX)-sysupgrade.bin -o $(DEST_PREFIX)-sign -k $(TOPDIR)/zkeys/rom-keys/zihome.key</span>
to generate the signature file - Append the signature file to the uboot partition (512K)
- Append the sysupgrade file to the firmware partition (512+512+256=1280K) at the beginning, resulting in flash.bin firmware
- Use the mt7621-nand-ecc command to convert the flash firmware into factory firmware (specific to NAND FLASH, requires appending oob information)
The above command uses zsign to generate the final firmware <span>$(DEST_PREFIX)-flash.bin</span>
and <span>$(DEST_PREFIX)-factory.bin</span>
2. Firmware Verification
1. Verification Process
A corresponding verification tool needs to be written, such as my zcheck.
During sysupgrade, use zcheck to verify if it is normal.
./lib/upgrade/platform.sh:40: zcheck -b “$board” -R -o 0x80000 -f “$1” >>$UPGRADE_LOG_FILE 2>&1
If it is normal, when writing to flash, it will skip the first 1280K and only read the sysupgrade information for writing.
# skip 1280K
get_image "$1" | dd bs=2k skip=640 conv=sync 2>/dev/null | mtd write - "${PART_NAME:-image}" >>$UPGRADE_LOG_FILE 2>&1