net: Reject invalid characters in port ranges

Fixes issue #22469 where port strings such as '0x00' get accepted, not
because the string gets converted to hex, but because the string is
silently truncated past the invalid character 'x'. This also causes
issues for strings such as '0x01-0x02' which look like a hex port range,
but in reality gets truncated to '0', which is definitely not what a
user intends.

Warn and reject such port strings as invalid.

Also, since we're throwing that "malformed port" warning a lot in the
function, wrap it up in a nice goto.

Fixes #22469
This commit is contained in:
c 2020-10-09 03:10:24 +00:00 committed by David Goulet
parent 3c13886317
commit 6ada3be8f1
2 changed files with 48 additions and 11 deletions

View File

@ -2005,20 +2005,15 @@ parse_port_range(const char *port, uint16_t *port_min_out,
char *endptr = NULL; char *endptr = NULL;
port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr); port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr);
if (!ok) { if (!ok) {
log_warn(LD_GENERAL, goto malformed_port;
"Malformed port %s on address range; rejecting.", } else if (endptr && *endptr != '\0') {
escaped(port)); if (*endptr != '-')
return -1; goto malformed_port;
} else if (endptr && *endptr == '-') {
port = endptr+1; port = endptr+1;
endptr = NULL; endptr = NULL;
port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr); port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr);
if (!ok) { if (!ok)
log_warn(LD_GENERAL, goto malformed_port;
"Malformed port %s on address range; rejecting.",
escaped(port));
return -1;
}
} else { } else {
port_max = port_min; port_max = port_min;
} }
@ -2037,6 +2032,11 @@ parse_port_range(const char *port, uint16_t *port_min_out,
*port_max_out = (uint16_t) port_max; *port_max_out = (uint16_t) port_max;
return 0; return 0;
malformed_port:
log_warn(LD_GENERAL,
"Malformed port %s on address range; rejecting.",
escaped(port));
return -1;
} }
/** Given a host-order <b>addr</b>, call tor_inet_ntop() on it /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it

View File

@ -1326,6 +1326,42 @@ test_address_dirserv_router_addr_private(void *opt_dir_allow_private)
UNMOCK(get_options); UNMOCK(get_options);
} }
static void
test_address_parse_port_range(void *arg)
{
int ret;
uint16_t min_out = 0;
uint16_t max_out = 0;
(void) arg;
/* Invalid. */
ret = parse_port_range("0x00", &min_out, &max_out);
tt_int_op(ret, OP_EQ, -1);
ret = parse_port_range("0x01", &min_out, &max_out);
tt_int_op(ret, OP_EQ, -1);
ret = parse_port_range("1817161", &min_out, &max_out);
tt_int_op(ret, OP_EQ, -1);
ret = parse_port_range("65536", &min_out, &max_out);
tt_int_op(ret, OP_EQ, -1);
ret = parse_port_range("1-65536", &min_out, &max_out);
tt_int_op(ret, OP_EQ, -1);
/* Valid. */
ret = parse_port_range("65535", &min_out, &max_out);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(min_out, OP_EQ, 65535);
tt_int_op(max_out, OP_EQ, 65535);
ret = parse_port_range("1-65535", &min_out, &max_out);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(min_out, OP_EQ, 1);
tt_int_op(max_out, OP_EQ, 65535);
done:
;
}
#define ADDRESS_TEST(name, flags) \ #define ADDRESS_TEST(name, flags) \
{ #name, test_address_ ## name, flags, NULL, NULL } { #name, test_address_ ## name, flags, NULL, NULL }
#define ADDRESS_TEST_STR_ARG(name, flags, str_arg) \ #define ADDRESS_TEST_STR_ARG(name, flags, str_arg) \
@ -1364,5 +1400,6 @@ struct testcase_t address_tests[] = {
ADDRESS_TEST(tor_node_in_same_network_family, 0), ADDRESS_TEST(tor_node_in_same_network_family, 0),
ADDRESS_TEST(dirserv_router_addr_private, 0), ADDRESS_TEST(dirserv_router_addr_private, 0),
ADDRESS_TEST_STR_ARG(dirserv_router_addr_private, 0, "allow_private"), ADDRESS_TEST_STR_ARG(dirserv_router_addr_private, 0, "allow_private"),
ADDRESS_TEST(parse_port_range, 0),
END_OF_TESTCASES END_OF_TESTCASES
}; };