httpd: stop a firmware upload at the end of the image area

edc469f made max_upload count, which bounds how many bytes a request may
carry. Nothing bounds where those bytes land. The two are not the same
check: the first watches the request, the second watches the flash address.

uptr walks forward one page at a time from FIRMWARE_UPLOAD_START and has no
ceiling. A body whose closing boundary never arrives keeps writing page after
page past the staging region, and on a flash exactly twice FIRMWARE_UPLOAD_START
the address wraps onto the running image at zero, so a bad upload takes the
working firmware with it. That commit's own message notes the related hazard:
flash_write_bytes() carries the address in three bytes and drops what does not
fit.

Bound it where uptr actually moves: refuse the next page once it would leave
the area check_and_flash_update_image() reads back, and answer 400. A partial
image left behind is harmless - boot rejects it on CRC and erases it.

This rebase drops the part of the original patch that removed max_upload;
the length limit and the address limit now sit side by side.
This commit is contained in:
DrDoof authored and d00f committed 2026-09-22 20:04:44 +02:00
1 parent 7e6577a811
commit 09ce4b391b
1 file changed
+13
+13
View File
@@ -532,6 +532,19 @@ uint8_t stream_upload(void)
crc16_bank1(upload_settings.p + upload_settings.bptr); crc16_bank1(upload_settings.p + upload_settings.bptr);
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++]; flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
if (write_len >= FLASH_PAGE_SIZE) { if (write_len >= FLASH_PAGE_SIZE) {
/* The staged image spans FIRMWARE_UPLOAD_START to twice that,
* the span check_and_flash_update_image() reads back. Nothing
* else bounds uptr: a body whose closing boundary never arrives
* keeps writing, and on a flash exactly this size the address
* wraps onto the running image at zero. */
if (uptr >= (uint32_t)FIRMWARE_UPLOAD_START * 2) {
print_string("Upload runs past the image area! Aborting.\n");
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 30\r\n"
"Content-Type: text/plain\r\n\r\n"
"NO: upload exceeds image area\n");
s->tstate = TSTATE_NONE;
return 0;
}
dbg_string("len: "); dbg_short(write_len); dbg_char(' '); dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n'); dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
if (uptr % FLASH_SECTOR_SIZE == 0) { if (uptr % FLASH_SECTOR_SIZE == 0) {