From a71c5359a52d30567fba342a873b2ae972d30127 Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Fri, 18 Sep 2026 14:00:51 -0500 Subject: [PATCH 1/2] httpd: refuse an unauthenticated firmware upload before it changes state The multipart branch for /config tests authenticated before it touches anything; the branch for /upload does not, and the 401 for it is only raised further down at the dispatch. By then the request has already set config_upload, uptr, verify_crc, max_upload and pre_acc, and announced a firmware upload on the console. Those five are globals while the transfer state they steer is per connection, and the stack is built for ten connections, so a request that is about to be rejected can still retarget an upload another client is in the middle of: a configuration upload continues as a firmware one and its remaining parts are written to the staging area instead of the configuration sector. Apply the same test the neighbouring branch uses, before the assignments. --- httpd/httpd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/httpd/httpd.c b/httpd/httpd.c index 74c11148..761d6863 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -750,6 +750,10 @@ void handle_post(void) return; } if (is_word(request_path, "upload")) { + if (!authenticated) { + send_unauthorized(); + return; + } if (flash_size < FIRMWARE_UPLOAD_START*2) { print_string("Flash too small for firmware upload!\n"); From edc469fe2957212d8ff28cc13c4be53bdd1998ed Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Fri, 18 Sep 2026 14:01:03 -0500 Subject: [PATCH 2/2] httpd: make the firmware upload length limit count max_upload was armed once when the upload began and never reduced, so `max_upload - uip_len > 0` was an unsigned expression that only went false when a segment arrived whose length matched the limit exactly. The write pointer climbed from the staging address with nothing to stop it, while flash_write_bytes() carries the address in three bytes and drops whatever does not fit. Subtract each segment as it is taken and compare before subtracting, which is what the comment there described. The limit was only ever armed for firmware uploads; configuration uploads keep the bound their own buffer already imposes. --- httpd/httpd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index 761d6863..cfcf58e5 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -902,8 +902,9 @@ void httpd_appcall(void) reset_chip(); } } else if (uip_newdata() && s->tstate == TSTATE_POST) { - // Check here maxupload by subtracting uip_len and close socekt if fails! - if (max_upload - uip_len > 0) { + if (config_upload || uip_len <= max_upload) { + if (!config_upload) + max_upload -= uip_len; upload_settings.p = uip_appdata; upload_settings.bptr = 0; upload_settings.plen = uip_len;