[openwrt/openwrt] firmware-utils/tplink-safeloader: add compat level

LEDE Commits lede-commits at lists.infradead.org
Wed Sep 9 13:42:58 EDT 2020


stintel pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/14464e1128924e127f82df38865734136008f532

commit 14464e1128924e127f82df38865734136008f532
Author: Sander Vanheule <sander at svanheule.net>
AuthorDate: Sat Jul 11 23:06:54 2020 +0200

    firmware-utils/tplink-safeloader: add compat level
    
    TP-Link has introduced a compatibility level to prevent certain
    downgrades. This information is stored in the soft-version partition,
    changing the data length from 0xc to 0x10.
    
    The compatibility level doesn't change frequently. For example, it has
    the following values for the EAP245v3 (released 2018-Q4):
    * FW v2.2.0  (2019-05-30): compat_level=0
    * FW v2.3.0  (2019-07-31): compat_level=0
    * FW v2.3.1  (2019-10-29): compat_level=1
    * FW v2.20.0 (2020-04-23): compat_level=1
    
    Empty flash values (0xffffffff) are interpreted as compat_level=0.
    If a firmware upgrade file has a soft-version block without
    compatibility level (data length < 0x10), this is also interpreted as
    compat_level=0.
    
    By including a high enough compatibility level in factory images, stock
    firmware can be convinced to accept the image. A compatibility level
    aware firmware will keep the original value.
    
    Example upgrade log of TP-Link EAP245v3 FWv2.3.0 to FWv2.20.0:
        [NM_Debug](nm_fwup_verifyFwupFile) 02073: curSoftVer:2.3.0 Build
            20190731 Rel. 51932,newSoftVer:2.20.0 Build 20200423 Rel. 36779
        ...
        AddiHardwareVer check: NEW(0x1) >= CUR(0x0), Success.
        ...
        [NM_NOTICE](updateDataToNvram) 00575: Restore old additionalHardVer:
        0x0.(new 0x1)
        [NM_NOTICE](updateDataToNvram) 00607: PTN 07: name = soft-version,
            base = 0x00092000, size = 0x00000100 Bytes, upDataType = 1,
            upDataStart = 7690604b, upDataLen = 00000018
        [NM_Debug](updateDataToNvram) 00738: PTN 07: write bytes = 000002eb
    
    Other firmware upgrades have been observed to modify the compabitility
    stored level (e.g. TP-Link EAP225-Outdoor FWv1.4.1 to FWv1.7.0).
    Therefore, it seems to be the safest option to set the OpenWrt
    compatibility level to the highest known value instead of the highest
    possible value (0xfffffffe), to ensure users do not get unexpectedly
    refused firmware upgrades when using a device reverted back to stock.
    
    To remain compatible with existing devices and not produce different
    images, the image builder doesn't store a compatibility level if it is
    zero.
    
    Signed-off-by: Sander Vanheule <sander at svanheule.net>
---
 tools/firmware-utils/src/tplink-safeloader.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c
index 145e80855a..9005ffa487 100644
--- a/tools/firmware-utils/src/tplink-safeloader.c
+++ b/tools/firmware-utils/src/tplink-safeloader.c
@@ -77,6 +77,7 @@ struct device_info {
 	const char *support_list;
 	char support_trail;
 	const char *soft_ver;
+	uint32_t soft_ver_compat_level;
 	struct flash_partition_entry partitions[MAX_PARTITIONS+1];
 	const char *first_sysupgrade_partition;
 	const char *last_sysupgrade_partition;
@@ -95,7 +96,6 @@ struct __attribute__((__packed__)) soft_version {
 	uint8_t month;
 	uint8_t day;
 	uint32_t rev;
-	uint8_t pad2;
 };
 
 
@@ -2140,8 +2140,13 @@ static inline uint8_t bcd(uint8_t v) {
 
 
 /** Generates the soft-version partition */
-static struct image_partition_entry make_soft_version(uint32_t rev) {
-	struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version));
+static struct image_partition_entry make_soft_version(struct device_info *info, uint32_t rev) {
+	size_t part_len = sizeof(struct soft_version);
+	if (info->soft_ver_compat_level > 0)
+		part_len += sizeof(uint32_t);
+
+	struct image_partition_entry entry =
+	    alloc_image_partition("soft-version", part_len+1);
 	struct soft_version *s = (struct soft_version *)entry.data;
 
 	time_t t;
@@ -2168,7 +2173,11 @@ static struct image_partition_entry make_soft_version(uint32_t rev) {
 	s->day = bcd(tm->tm_mday);
 	s->rev = htonl(rev);
 
-	s->pad2 = 0xff;
+	if (info->soft_ver_compat_level > 0)
+		*(uint32_t *)(entry.data + sizeof(struct soft_version)) =
+		    htonl(info->soft_ver_compat_level);
+
+	entry.data[entry.size-1] = 0xff;
 
 	return entry;
 }
@@ -2480,7 +2489,7 @@ static void build_image(const char *output,
 	if (info->soft_ver)
 		parts[1] = make_soft_version_from_string(info->soft_ver);
 	else
-		parts[1] = make_soft_version(rev);
+		parts[1] = make_soft_version(info, rev);
 
 	parts[2] = make_support_list(info);
 	parts[3] = read_file("os-image", kernel_image, false, NULL);



More information about the lede-commits mailing list