Re: [PATCH net 16/20] can: softing: fw_parse(): validate firmware record spans
[email protected] Thu, 30 Jul 2026 10:29:58 +0000
| Newsgroups | org.kernel.vger.linux-can |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 3 potential issue(= s) to consider: Pre-existing issues: - [High] Unaligned memory dereference in `fw_parse()` triggers alignment fa= ults. - [High] Truncated or malformed firmware causes silent failure by returning= 0 on error paths. - [High] Unaligned MMIO accesses to DPRAM via `iowrite32` cause hardware ex= ceptions. -- --- Patch [16]: [PATCH net 16/20] can: softing: fw_parse(): validate firmwa= re record spans --- commit dd9e23c1084e29145c02ec85df264fc5faf868da Author: Pengpeng Hou <[email protected]> can: softing: fw_parse(): validate firmware record spans This commit improves bounds checking when parsing softing firmware records to prevent out-of-bounds reads and writes. It passes the firmware end to the parser and validates the source record length before doing DPRAM staging copies. Link: https://patch.msgid.link/[email protected] > diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softi= ng/softing_fw.c > index 721df91cdbfbc..282570daf3efe 100644 > --- a/drivers/net/can/softing/softing_fw.c > +++ b/drivers/net/can/softing/softing_fw.c [ ... ] > @@ -114,14 +114,21 @@ static int fw_parse(const uint8_t **pmem, uint16_t = *ptype, uint32_t *paddr, > * endianness & alignment. > */ > mem =3D *pmem; > + /* A record needs an 8-byte prefix and a 2-byte checksum. */ > + if (mem > limit || limit - mem < 10) > + return -EINVAL; > + > *ptype =3D le16_to_cpup((void *)&mem[0]); > *paddr =3D le32_to_cpup((void *)&mem[2]); > *plen =3D le16_to_cpup((void *)&mem[6]); [Severity: High] This is a pre-existing issue, but does using le16_to_cpup() and le32_to_cpup() on an unaligned byte stream cause alignment faults? Firmware records are packed without padding, meaning mem could rest on an o= dd address. The leXX_to_cpup functions directly dereference the pointer, which can trigger a fatal alignment fault exception (kernel oops) on architectures that lack hardware unaligned access support. Should fw_parse() use get_unaligned_le16() and get_unaligned_le32() here instead? > + if (*plen > limit - mem - 10) > + return -EINVAL; > + > *pdat =3D &mem[8]; > /* verify checksum */ > - end =3D &mem[8 + *plen]; > - checksum[0] =3D le16_to_cpup((void *)end); > - for (checksum[1] =3D 0; mem < end; ++mem) > + record_end =3D &mem[8 + *plen]; > + checksum[0] =3D le16_to_cpup((void *)record_end); > + for (checksum[1] =3D 0; mem < record_end; ++mem) > checksum[1] +=3D *mem; [ ... ] > @@ -279,6 +291,12 @@ int softing_load_app_fw(const char *file, struct sof= ting *card) > /* work in 16bit (target) */ > sum &=3D 0xffff; > =20 > + if (card->pdat->app.offs > card->dpram_size || > + len > card->dpram_size - card->pdat->app.offs) { > + ret =3D -EINVAL; > + goto failed; > + } > + > memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len); > iowrite32(card->pdat->app.offs + card->pdat->app.addr, > &card->dpram[DPRAM_COMMAND + 2]); [Severity: High] This is a pre-existing issue, but does using iowrite32() on unaligned offsets cause hardware exceptions? These iowrite32() calls target DPRAM addresses shifted by unaligned offsets like DPRAM_COMMAND + 2 and DPRAM_COMMAND + 6. Standard 32-bit I/O accessors mandate 4-byte alignment on the target memory address. Executing an unaligned MMIO write triggers a hardware alignment fault or bus error on non-x86 architectures. Should these operations be split into sequential 16-bit writes using iowrite16()? [Severity: High] This is a pre-existing issue, but does a truncated or malformed firmware blob cause a silent failure by returning 0? In both softing_load_fw() and softing_load_app_fw(), if the firmware blob does not contain an EOF record or an entrypoint record, the parsing loop terminates without encountering an error: softing_fw.c:softing_load_app_fw() { ... while (mem < end) { ret =3D fw_parse(&mem, end, &type, &addr, &len, &dat); if (ret) goto failed; ... } if (!type_end || !type_entrypoint) goto failed; ... failed: ... return ret; } Because fw_parse() returns 0 on success, ret is left at 0 when the loop finishes naturally. The code then detects the missing record and jumps to the failed label, but since ret is 0, it incorrectly returns success to the caller. This leaves the device uninitialized. Could ret be set to an error code like -EINVAL before the goto? --=20 Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260729102802.5051= [email protected]?part=3D16