OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From 237ea0d4762cc14d0fc80e80d61f0f08e1050c7f Mon Sep 17 00:00:00 2001 |
2 | From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> |
||
3 | Date: Thu, 12 Apr 2018 07:24:52 +0200 |
||
4 | Subject: [PATCH] mtd: bcm47xxpart: improve handling TRX partition size |
||
5 | MIME-Version: 1.0 |
||
6 | Content-Type: text/plain; charset=UTF-8 |
||
7 | Content-Transfer-Encoding: 8bit |
||
8 | |||
9 | When bcm47xxpart finds a TRX partition (container) it's supposed to jump |
||
10 | to the end of it and keep looking for more partitions. TRX and its |
||
11 | subpartitions are handled by a separate parser. |
||
12 | |||
13 | The problem with old code was relying on the length specified in a TRX |
||
14 | header. That isn't reliable as TRX is commonly modified to have checksum |
||
15 | cover only non-changing subpartitions. Otherwise modifying e.g. a rootfs |
||
16 | would result in CRC32 mismatch and bootloader refusing to boot a |
||
17 | firmware. |
||
18 | |||
19 | Fix it by trying better to figure out a real TRX size. We can securely |
||
20 | assume that TRX has to cover all subpartitions and the last one is at |
||
21 | least of a block size in size. Then compare it with a length field. |
||
22 | |||
23 | This makes code more optimal & reliable thanks to skipping data that |
||
24 | shouldn't be parsed. |
||
25 | |||
26 | Signed-off-by: Rafał Miłecki <rafal@milecki.pl> |
||
27 | Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> |
||
28 | --- |
||
29 | drivers/mtd/bcm47xxpart.c | 22 ++++++++++++++++++---- |
||
30 | 1 file changed, 18 insertions(+), 4 deletions(-) |
||
31 | |||
32 | --- a/drivers/mtd/bcm47xxpart.c |
||
33 | +++ b/drivers/mtd/bcm47xxpart.c |
||
34 | @@ -186,6 +186,8 @@ static int bcm47xxpart_parse(struct mtd_ |
||
35 | /* TRX */ |
||
36 | if (buf[0x000 / 4] == TRX_MAGIC) { |
||
37 | struct trx_header *trx; |
||
38 | + uint32_t last_subpart; |
||
39 | + uint32_t trx_size; |
||
40 | |||
41 | if (trx_num >= ARRAY_SIZE(trx_parts)) |
||
42 | pr_warn("No enough space to store another TRX found at 0x%X\n", |
||
43 | @@ -195,11 +197,23 @@ static int bcm47xxpart_parse(struct mtd_ |
||
44 | bcm47xxpart_add_part(&parts[curr_part++], "firmware", |
||
45 | offset, 0); |
||
46 | |||
47 | - /* Jump to the end of TRX */ |
||
48 | + /* |
||
49 | + * Try to find TRX size. The "length" field isn't fully |
||
50 | + * reliable as it could be decreased to make CRC32 cover |
||
51 | + * only part of TRX data. It's commonly used as checksum |
||
52 | + * can't cover e.g. ever-changing rootfs partition. |
||
53 | + * Use offsets as helpers for assuming min TRX size. |
||
54 | + */ |
||
55 | trx = (struct trx_header *)buf; |
||
56 | - offset = roundup(offset + trx->length, blocksize); |
||
57 | - /* Next loop iteration will increase the offset */ |
||
58 | - offset -= blocksize; |
||
59 | + last_subpart = max3(trx->offset[0], trx->offset[1], |
||
60 | + trx->offset[2]); |
||
61 | + trx_size = max(trx->length, last_subpart + blocksize); |
||
62 | + |
||
63 | + /* |
||
64 | + * Skip the TRX data. Decrease offset by block size as |
||
65 | + * the next loop iteration will increase it. |
||
66 | + */ |
||
67 | + offset += roundup(trx_size, blocksize) - blocksize; |
||
68 | continue; |
||
69 | } |
||
70 |