[openwrt/openwrt] mvebu: improve sysupgrade for FortiGate/FortiWiFi devices
LEDE Commits
lede-commits at lists.infradead.org
Sun Sep 22 06:30:14 PDT 2024
hauke pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/06fed85948b1cb4e44664fdd31dba3d7f1f1b0fd
commit 06fed85948b1cb4e44664fdd31dba3d7f1f1b0fd
Author: INAGAKI Hiroshi <musashino.open at gmail.com>
AuthorDate: Tue Sep 17 05:43:58 2024 +0900
mvebu: improve sysupgrade for FortiGate/FortiWiFi devices
Update sysupgrade script (fortinet.sh) for Fortinet devices in
mvebu/cortexa9 and fix the following issues,
- Some individuals of FortiGate/FortiWiFi 30E/5xE devices has wrong
kernel/rootfs offsets in "firmware-info" partition and they are not
updated with the current sysupgrade script for Fortinet devices
(fortinet.sh).
As a result, the bootloader tries to load kernel data from the wrong
address and boot with it after OpenWrt installation.
The new script handles offsets in addition to length values.
and improve the following points.
- Only 2 bytes are handled with the current sysupgrade script
(fortinet.sh) for kernel/rootfs length. The new script handles 4 bytes
instead.
- The image names of image0/image1 are not handled and not updated when
sysupgrade. The new sysupgrade script handles it and update to
"<dist> <version> <revision>" if firmware metadata is available.
(ex.: "OpenWrt SNAPSHOT r27440-25384026")
log of new sysupgrade script (fortinet.sh):
Tue Sep 17 10:29:16 UTC 2024 upgrade: Performing system upgrade...
Image Index: 0
Image Name : "OpenWrt SNAPSHOT r27440-25384026"
--> "OpenWrt SNAPSHOT r27441-b3a0806a05"
kernel:
old: 0x003c4e00 at 0x00200000
new: 0x003c4e00 at 0x00200000
rootfs:
old: 0x005c0200 at 0x00800000
new: 0x005c0200 at 0x00800000
Unlocking kernel ...
Signed-off-by: INAGAKI Hiroshi <musashino.open at gmail.com>
Link: https://github.com/openwrt/openwrt/pull/16409
Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
.../cortexa9/base-files/lib/upgrade/fortinet.sh | 162 +++++++++++++++++++--
.../cortexa9/base-files/lib/upgrade/platform.sh | 2 +-
2 files changed, 148 insertions(+), 16 deletions(-)
diff --git a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh
index a2742aa374..3badb0583a 100644
--- a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh
+++ b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/fortinet.sh
@@ -1,31 +1,129 @@
. /lib/functions.sh
-fortinet_fwinfo_blocks() {
+fortinet_bswap32() {
+ local val="$(printf %08x $(($1)))"
+
+ # swap and print in hex
+ echo "0x${val:6:2}${val:4:2}${val:2:2}${val:0:2}"
+}
+
+fortinet_by2bl() {
+ local blks="$(($1 / 0x200))"
+ [ $(($1 % 0x200)) -gt 0 ] && blks=$((blks + 1))
+
+ printf "0x%08x" $blks
+}
+
+fortinet_bl2by() {
+ printf "0x%08x" $(($1 * 0x200))
+}
+
+fortinet_build_partmap() {
+ local new="$1" old="$2"
+ local len="${old%%@*}" ofs="${old##*@}"
+
+ case "$new" in
+ @*) ofs="$(fortinet_by2bl ${new##@})" ;; # "@<offset>"
+
+ *@*) len="$(fortinet_by2bl ${new%%@*})" # "<length>@<offset>"
+ ofs="$(fortinet_by2bl ${new##*@})" ;;
+
+ "") ;; # "" (empty)
+
+ *) len="$(fortinet_by2bl ${new%%@*})" ;; # "<length>"
+ esac
+
+ # print N blocks of length/offset in dec
+ echo "${len}@${ofs}"
+}
+
+# Update firmware information in "firmware-info" partition
+#
+# parameters:
+# $1: image index (0/1)
+# $2: new image name (up to 32 characters)
+# $3: length and/or offset for kernel (bytes)
+# $4: length and/or offset for rootfs (bytes)
+#
+# Note: $3 and $4 support multiple formats:
+#
+# - <length>@<offset>: set <length> and <rootfs>
+# - <length> : set <length> and keep the current offset
+# - @<offset> : set <offset> and keep the current length
+# - "" (empty) : keep the current length and offset
+fortinet_update_fwinfo() {
local fwinfo_mtd="$(find_mtd_part firmware-info)"
- local offset="$1"
- local len="$2"
- local blks
+ local index="$1"
+ local name="$2"
+ local offset
+ local old_kr
+ local old new tmp part pos
+ local output
if [ -z "$fwinfo_mtd" ]; then
- echo "WARN: MTD device \"firmware-info\" not found"
+ echo "ERROR: MTD device \"firmware-info\" not found"
return 1
fi
- blks=$((len / 0x200))
- [ $((len % 0x200)) -gt 0 ] && blks=$((blks + 1))
- blks=$(printf "%04x" $blks)
- printf "fwinfo: offset-> 0x%x, blocks-> 0x%s (len: 0x%08x)\n" \
- $offset $blks $len
+ # Image Name
+ case "$index" in
+ 0) offset=0x10 ;;
+ 1) offset=0x30 ;;
+ *) echo "ERROR: invalid image index specified!"; return 1 ;;
+ esac
+
+ printf "Image Index: %d\n" $index
+
+ old="$(dd bs=16 count=2 skip=$((offset / 16)) if=$fwinfo_mtd 2>/dev/null)"
+ printf "Image Name : \"%s\"\n" "$old"
+ if [ -n "$name" ]; then
+ echo -n "$name" | \
+ dd bs=32 count=1 oflag=seek_bytes seek=$((offset)) \
+ conv=sync,notrunc of=$fwinfo_mtd 2>/dev/null
+ printf " --> \"%s\"\n\n" "$name"
+ else
+ printf "\n"
+ fi
+
+ # length/offset values of kernel/rootfs
+ case "$index" in
+ 0) offset=0x180 ;;
+ 1) offset=0x190 ;;
+ esac
+
+ # <kernel offset:4><kernel length:4><rootfs offset:4><rootfs length:4>
+ old_kr="$(hexdump -n 16 -v -s $((offset)) -e '1/4 "%08x"' $fwinfo_mtd)"
+
+ pos=0
+ for part in kernel rootfs; do
+ old="0x${old_kr:$((8 + pos)):8}@0x${old_kr:$((0 + pos)):8}"
+ new="$(fortinet_build_partmap "$3" "$old")"
+ shift
+
+ printf " %s:\n" $part
+ printf " old: 0x%08x at 0x%08x\n" \
+ $(fortinet_bl2by ${old%%@*}) $(fortinet_bl2by ${old##*@})
+ printf " new: 0x%08x at 0x%08x\n\n" \
+ $(fortinet_bl2by ${new%%@*}) $(fortinet_bl2by ${new##*@})
- printf "\x${blks:2:2}\x${blks:0:2}" | \
- dd bs=2 count=1 seek=$((offset / 2)) conv=notrunc of=${fwinfo_mtd}
+ tmp="$(fortinet_bswap32 ${new%%@*})@$(fortinet_bswap32 ${new##*@})"
+ new="$(echo $tmp | sed 's/0x\([0-9a-f]\{8\}\)@0x\([0-9a-f]\{8\}\)/\2\1/')"
+ output="${output}${new}"
+
+ pos=$((pos + 16))
+ done
+
+ data_2bin "$output" | \
+ dd bs=16 count=1 seek=$((offset / 16)) conv=notrunc \
+ of=$fwinfo_mtd 2>/dev/null
}
fortinet_do_upgrade() {
local board_dir="$(tar tf "$1" | grep -m 1 '^sysupgrade-.*/$')"
local kern_mtd="$(find_mtd_part kernel)"
local root_mtd="$(find_mtd_part rootfs)"
- local kern_len root_len
+ local kern_len kern_ofs root_len root_ofs
+ local imgname
board_dir="${board_dir%/}"
@@ -34,6 +132,14 @@ fortinet_do_upgrade() {
umount -a
reboot -f
fi
+ kern_ofs=$(cat /sys/class/mtd/${kern_mtd//\/dev\/mtdblock/mtd}/offset)
+ root_ofs=$(cat /sys/class/mtd/${root_mtd//\/dev\/mtdblock/mtd}/offset)
+
+ if [ -z "$kern_ofs" ] || [ -z "$root_ofs" ]; then
+ echo "ERROR: failed to get offset of kernel or rootfs"
+ umount -a
+ reboot -f
+ fi
kern_len=$( (tar xOf "$1" "$board_dir/kernel" | wc -c) 2> /dev/null)
root_len=$( (tar xOf "$1" "$board_dir/root" | wc -c) 2> /dev/null)
@@ -44,8 +150,34 @@ fortinet_do_upgrade() {
reboot -f
fi
- fortinet_fwinfo_blocks "0x184" "$kern_len"
- fortinet_fwinfo_blocks "0x18c" "$root_len"
+ # try to load and parse /tmp/sysupgrade.meta for image name
+ if [ -r "/tmp/sysupgrade.meta" ]; then
+ local key value
+
+ sed -e 's/, \{1,2\}\"/\n"/g' \
+ -e 's/{ \{1,2\}/\n/g' \
+ -e 's/ \{1,2\}}/\n/g' < /tmp/sysupgrade.meta \
+ > /tmp/sysupgrade.meta.tmp
+ while read key value; do
+ key="${key//\"/}"
+ value="${value//\"/}"
+
+ [ -z "$value" ] && continue
+ case "$key" in
+ dist:|\
+ version:|\
+ revision:) imgname="${imgname}$value " ;;
+ esac
+ done < /tmp/sysupgrade.meta.tmp
+ else
+ imgname="OpenWrt"
+ fi
+
+ fortinet_update_fwinfo 0 "${imgname%% }" \
+ "${kern_len}@${kern_ofs}" "${root_len}@${root_ofs}" || {
+ umount -a
+ reboot -f
+ }
tar xOf "$1" "$board_dir/kernel" | \
mtd write - "kernel"
diff --git a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh
index a15823d8c6..049f8eeb8c 100755
--- a/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh
+++ b/target/linux/mvebu/cortexa9/base-files/lib/upgrade/platform.sh
@@ -3,7 +3,7 @@
# Copyright (C) 2016 LEDE-Project.org
#
-RAMFS_COPY_BIN='fw_printenv fw_setenv strings'
+RAMFS_COPY_BIN='fw_printenv fw_setenv seq strings'
RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
PART_NAME=firmware
More information about the lede-commits
mailing list