ota: bounds check on /api/flash only covers the first chunk, and runs after init_ota - #2189
ota: bounds check on /api/flash only covers the first chunk, and runs after init_ota#2189DrDoof wants to merge 2 commits into
Conversation
…_ota Two things went wrong here, both reachable from one POST to /api/flash/<addr>. The bounds check tested writelen, which is only the part of the body that arrived with the headers, usually well under a kilobyte. The loop underneath then writes towrite bytes, which comes from Content-Length, advancing startaddr as it goes and never checking again. A large Content-Length with a small first chunk therefore walks straight past maxaddr. Check towrite, since that is what actually gets written. The check also ran after init_ota, which clears flash write protection and mallocs the sector buffer. Bailing out at that point returns without close_ota(), so the buffer is never freed and protection is never restored. init_ota refuses to start while sector is non-null, so one rejected upload leaves OTA broken until the next reboot. Validate first, then init.
|
@openshwprojects @DeDaMrAzR @NonPIayerCharacter @divadiow flagging this one since Short version: the bounds check in Only the Beken HAL has the check at all, the others take |
|
|
startaddr + towrite is signed arithmetic, so a large content length can wrap it negative and the sum then compares below maxaddr, passing the check it was meant to fail. Compare with a subtraction instead, with the operands guarded first so maxaddr - startaddr cannot go negative, and reject a zero length in the same condition so an empty post no longer reaches init_ota.
|
Good catch on the overflow, you're right that the signed sum can wrap and then sail straight past the check it was supposed to trip. Reworked it as a subtraction. The operands get guarded first, so Went with the subtraction rather than a 64-bit compare mostly to keep the arithmetic 32-bit on these parts, but either would do the job. |
http_rest_post_flashin the Beken HAL has a bounds check that doesn't cover whatactually gets written, and it runs too late to be safe when it does reject something.
The check is this:
writelenisrequest->bodylen, which is only the part of the body that arrivedalong with the headers. The loop underneath writes
towritebytes, which comes fromContent-Length, pulling the rest off the socket withrecvand bumpingstartaddreach time round. It never checks again, and nothing below it does either:
add_otadatawalksaddrforward per sector andstore_sectorgoes straight toCMD_FLASH_ERASE_SECTORfollowed byflash_write. So a POST to/api/flash/<addr>with a large
Content-Lengthand a small first chunk passes the check and then erasesits way past
maxaddr. That endpoint takes the start address from the URL and onlyrequires it to be at or above the OTA partition.
The second half is the ordering.
init_otaclears flash write protection and mallocsthe sector buffer before the check happens, and the error path returns without
close_ota(), which is the only place that frees the buffer and puts protection back.init_otaalso refuses to run whilesectoris non-null, so one rejected uploadleaves write protection off and OTA unusable until the device reboots.
I moved the check above
init_otaand pointed it attowrite. Nothing else in thefunction changed. I left the -20 error code alone in case anything depends on it, but
reworded the message, since it named a constant that isn't what's being compared.
Only the Beken HAL has this check at all. The other HALs take
maxaddrand ignore it,which is worth a separate look, but I didn't want to touch platforms I can't test.
Tested on BK7252N.