httpd: check the port index /counters.json is given

The handler took one raw character of the request line and passed it to
send_counters(), which uses it to index machine.phys_to_log_port. That
array has nine entries and the character is whatever the client sent, so
the read ran up to 246 entries past the end and the result went on to
STAT_GET as a port number. is_word() accepts any request whose name is
followed by a question mark, so nothing constrained the byte to a digit.

Bounding it where it is read keeps the check beside the assumption it
protects and needs nothing from the machine description. sdcc leaves
plain char unsigned and the subtraction wraps in eight bits, so a byte
below '0' comes out above 200 and one upper test covers both ends:
exactly '0' to '8' now reach send_counters. The compiled test is
add a,#0xf7 followed by jnc, which I read back out of the assembly rather
than assuming.

Out of range answers 400 by the path the other malformed requests already
take, rather than an empty array. An empty array would have been worse
than useless here, since the statistics page calls BigInt on the first
element before it looks at the length. The page asks only for index zero
to the port count minus one, so nothing that answered before stops
answering, and a non-200 reply makes its handler do nothing at all.

11 bytes of BANK1, nothing in the common segment, BANK2, xdata or
internal RAM. Built for SWTGW218AS and KP_9000_6XHML_X2 on sdcc 4.5.0.
This commit is contained in:
d00f
2026-08-15 00:49:21 +02:00
parent 787d593996
commit 0503e7952d
+10 -1
View File
@@ -664,7 +664,16 @@ void httpd_appcall(void)
parse_short(q + 15);
send_vlan(short_parsed);
} else if (is_word(q, "/counters.json")) {
send_counters(q[20]-'0');
/* The port is one raw character of the request line and
* indexes a nine entry table, so bound it here instead
* of trusting the client to have sent a digit. Anything
* below '0' wraps well past eight, so the one test
* covers both ends. */
uint8_t cport = q[20] - '0';
if (cport > 8)
send_bad_request();
else
send_counters(cport);
} else if (is_word(q, "/eee.json")) {
send_eee();
} else if (is_word(q, "/bandwidth.json")) {