[openwrt/openwrt] kernel: mtd: bcm47xxpart: improve handling TRX partition size

LEDE Commits lede-commits at lists.infradead.org
Wed Apr 11 23:25:39 PDT 2018


rmilecki pushed a commit to openwrt/openwrt.git, branch master:
https://git.lede-project.org/f5195e72c0fcf2949f7d6296a5db081eb58f8e32

commit f5195e72c0fcf2949f7d6296a5db081eb58f8e32
Author: Rafał Miłecki <rafal at milecki.pl>
AuthorDate: Thu Apr 12 08:25:17 2018 +0200

    kernel: mtd: bcm47xxpart: improve handling TRX partition size
    
    This is important fix for flash parsing in some corner cases. In case
    of TRX subpartition with rootfs being aligned to the flash block size it
    was incorrectly registered twice. Detecting & registering it as a
    standalone partition was resulting in an incorrect "firmware" partition
    size and possibly broken sysupgrade.
    
    It wasn't noticed before because "rootfs" alignment depends on a kernel
    size. It can happen though - depending on the configuration and the
    kernel size.
    
    Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
---
 ...m947xx-cfe-partitions-binding-for-Broadco.patch |  2 +-
 ...m947xx-cfe-partitions-binding-for-Broadco.patch |  2 +-
 ...xpart-improve-handling-TRX-partition-size.patch | 65 ++++++++++++++++++++++
 ...xpart-improve-handling-TRX-partition-size.patch | 65 ++++++++++++++++++++++
 ...xpart-improve-handling-TRX-partition-size.patch | 65 ++++++++++++++++++++++
 5 files changed, 197 insertions(+), 2 deletions(-)

diff --git a/target/linux/bcm53xx/patches-4.14/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch b/target/linux/bcm53xx/patches-4.14/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch
index 0eae14f..edb0ed1 100644
--- a/target/linux/bcm53xx/patches-4.14/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch
+++ b/target/linux/bcm53xx/patches-4.14/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch
@@ -34,7 +34,7 @@ Subject: [PATCH] Use "brcm,bcm947xx-cfe-partitions" binding for Broadcom
  
 --- a/drivers/mtd/bcm47xxpart.c
 +++ b/drivers/mtd/bcm47xxpart.c
-@@ -300,9 +300,16 @@ static int bcm47xxpart_parse(struct mtd_
+@@ -314,9 +314,16 @@ static int bcm47xxpart_parse(struct mtd_
  	return curr_part;
  };
  
diff --git a/target/linux/bcm53xx/patches-4.9/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch b/target/linux/bcm53xx/patches-4.9/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch
index 0eae14f..edb0ed1 100644
--- a/target/linux/bcm53xx/patches-4.9/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch
+++ b/target/linux/bcm53xx/patches-4.9/410-Use-brcm-bcm947xx-cfe-partitions-binding-for-Broadco.patch
@@ -34,7 +34,7 @@ Subject: [PATCH] Use "brcm,bcm947xx-cfe-partitions" binding for Broadcom
  
 --- a/drivers/mtd/bcm47xxpart.c
 +++ b/drivers/mtd/bcm47xxpart.c
-@@ -300,9 +300,16 @@ static int bcm47xxpart_parse(struct mtd_
+@@ -314,9 +314,16 @@ static int bcm47xxpart_parse(struct mtd_
  	return curr_part;
  };
  
diff --git a/target/linux/generic/pending-4.14/142-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch b/target/linux/generic/pending-4.14/142-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch
new file mode 100644
index 0000000..60c8ecb
--- /dev/null
+++ b/target/linux/generic/pending-4.14/142-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch
@@ -0,0 +1,65 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal at milecki.pl>
+Subject: [PATCH] mtd: bcm47xxpart: improve handling TRX partition size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When bcm47xxpart finds a TRX partition (container) it's supposed to jump
+to the end of it and keep looking for more partitions. TRX and its
+subpartitions are handled be a separated parser.
+
+The problem with old code was relying on the length specified in a TRX
+header. That isn't reliable as TRX is commonly modified to have checksum
+cover only non-changing subpartitions. Otherwise modifying e.g. a rootfs
+would result in CRC32 mismatch and bootloader refusing to boot a
+firmware.
+
+Fix it by trying better to figure out a real TRX size. We can securely
+assume that TRX has to cover all subpartitions and the last one is at
+least of a block size in size. Then compare it with a length field.
+
+This makes code more optimal & reliable thanks to skipping data that
+shouldn't be parsed.
+
+Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
+---
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -186,6 +186,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
+ 			struct trx_header *trx;
++			uint32_t last_subpart;
++			uint32_t trx_size;
+ 
+ 			if (trx_num >= ARRAY_SIZE(trx_parts))
+ 				pr_warn("No enough space to store another TRX found at 0x%X\n",
+@@ -195,11 +197,23 @@ static int bcm47xxpart_parse(struct mtd_
+ 			bcm47xxpart_add_part(&parts[curr_part++], "firmware",
+ 					     offset, 0);
+ 
+-			/* Jump to the end of TRX */
++			/*
++			 * Try to find TRX size. The "length" field isn't fully
++			 * reliable as it could be decreased to make CRC32 cover
++			 * only part of TRX data. It's commonly used as checksum
++			 * can't cover e.g. ever-changing rootfs partition.
++			 * Use offsets as helpers for assuming min TRX size.
++			 */
+ 			trx = (struct trx_header *)buf;
+-			offset = roundup(offset + trx->length, blocksize);
+-			/* Next loop iteration will increase the offset */
+-			offset -= blocksize;
++			last_subpart = max3(trx->offset[0], trx->offset[1],
++					    trx->offset[2]);
++			trx_size = max(trx->length, last_subpart + blocksize);
++
++			/*
++			 * Skip the TRX data. Decrease offset by block size as
++			 * the next loop iteration will increase it.
++			 */
++			offset += roundup(trx_size, blocksize) - blocksize;
+ 			continue;
+ 		}
+ 
diff --git a/target/linux/generic/pending-4.4/141-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch b/target/linux/generic/pending-4.4/141-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch
new file mode 100644
index 0000000..31acebf
--- /dev/null
+++ b/target/linux/generic/pending-4.4/141-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch
@@ -0,0 +1,65 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal at milecki.pl>
+Subject: [PATCH] mtd: bcm47xxpart: improve handling TRX partition size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When bcm47xxpart finds a TRX partition (container) it's supposed to jump
+to the end of it and keep looking for more partitions. TRX and its
+subpartitions are handled be a separated parser.
+
+The problem with old code was relying on the length specified in a TRX
+header. That isn't reliable as TRX is commonly modified to have checksum
+cover only non-changing subpartitions. Otherwise modifying e.g. a rootfs
+would result in CRC32 mismatch and bootloader refusing to boot a
+firmware.
+
+Fix it by trying better to figure out a real TRX size. We can securely
+assume that TRX has to cover all subpartitions and the last one is at
+least of a block size in size. Then compare it with a length field.
+
+This makes code more optimal & reliable thanks to skipping data that
+shouldn't be parsed.
+
+Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
+---
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -268,6 +268,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
+ 			struct trx_header *trx;
++			uint32_t last_subpart;
++			uint32_t trx_size;
+ 
+ 			if (trx_num >= ARRAY_SIZE(trx_parts))
+ 				pr_warn("No enough space to store another TRX found at 0x%X\n",
+@@ -277,11 +279,23 @@ static int bcm47xxpart_parse(struct mtd_
+ 			bcm47xxpart_add_part(&parts[curr_part++], "firmware",
+ 					     offset, 0);
+ 
+-			/* Jump to the end of TRX */
++			/*
++			 * Try to find TRX size. The "length" field isn't fully
++			 * reliable as it could be decreased to make CRC32 cover
++			 * only part of TRX data. It's commonly used as checksum
++			 * can't cover e.g. ever-changing rootfs partition.
++			 * Use offsets as helpers for assuming min TRX size.
++			 */
+ 			trx = (struct trx_header *)buf;
+-			offset = roundup(offset + trx->length, blocksize);
+-			/* Next loop iteration will increase the offset */
+-			offset -= blocksize;
++			last_subpart = max3(trx->offset[0], trx->offset[1],
++					    trx->offset[2]);
++			trx_size = max(trx->length, last_subpart + blocksize);
++
++			/*
++			 * Skip the TRX data. Decrease offset by block size as
++			 * the next loop iteration will increase it.
++			 */
++			offset += roundup(trx_size, blocksize) - blocksize;
+ 			continue;
+ 		}
+ 
diff --git a/target/linux/generic/pending-4.9/142-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch b/target/linux/generic/pending-4.9/142-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch
new file mode 100644
index 0000000..60c8ecb
--- /dev/null
+++ b/target/linux/generic/pending-4.9/142-mtd-bcm47xxpart-improve-handling-TRX-partition-size.patch
@@ -0,0 +1,65 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal at milecki.pl>
+Subject: [PATCH] mtd: bcm47xxpart: improve handling TRX partition size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When bcm47xxpart finds a TRX partition (container) it's supposed to jump
+to the end of it and keep looking for more partitions. TRX and its
+subpartitions are handled be a separated parser.
+
+The problem with old code was relying on the length specified in a TRX
+header. That isn't reliable as TRX is commonly modified to have checksum
+cover only non-changing subpartitions. Otherwise modifying e.g. a rootfs
+would result in CRC32 mismatch and bootloader refusing to boot a
+firmware.
+
+Fix it by trying better to figure out a real TRX size. We can securely
+assume that TRX has to cover all subpartitions and the last one is at
+least of a block size in size. Then compare it with a length field.
+
+This makes code more optimal & reliable thanks to skipping data that
+shouldn't be parsed.
+
+Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
+---
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -186,6 +186,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
+ 			struct trx_header *trx;
++			uint32_t last_subpart;
++			uint32_t trx_size;
+ 
+ 			if (trx_num >= ARRAY_SIZE(trx_parts))
+ 				pr_warn("No enough space to store another TRX found at 0x%X\n",
+@@ -195,11 +197,23 @@ static int bcm47xxpart_parse(struct mtd_
+ 			bcm47xxpart_add_part(&parts[curr_part++], "firmware",
+ 					     offset, 0);
+ 
+-			/* Jump to the end of TRX */
++			/*
++			 * Try to find TRX size. The "length" field isn't fully
++			 * reliable as it could be decreased to make CRC32 cover
++			 * only part of TRX data. It's commonly used as checksum
++			 * can't cover e.g. ever-changing rootfs partition.
++			 * Use offsets as helpers for assuming min TRX size.
++			 */
+ 			trx = (struct trx_header *)buf;
+-			offset = roundup(offset + trx->length, blocksize);
+-			/* Next loop iteration will increase the offset */
+-			offset -= blocksize;
++			last_subpart = max3(trx->offset[0], trx->offset[1],
++					    trx->offset[2]);
++			trx_size = max(trx->length, last_subpart + blocksize);
++
++			/*
++			 * Skip the TRX data. Decrease offset by block size as
++			 * the next loop iteration will increase it.
++			 */
++			offset += roundup(trx_size, blocksize) - blocksize;
+ 			continue;
+ 		}
+ 



More information about the lede-commits mailing list