summaryrefslogtreecommitdiff
path: root/libdhcp
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-22 18:51:59 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-05-06 11:53:17 -0600
commit24e5d0ec1219e2dbb4b9510ef20833092a2b3871 (patch)
tree01bbcc34c6190fa1c35b2625e9ba1744b1447606 /libdhcp
parentf09b7435b3a5222597d27238226d23ec0cbd5bd2 (diff)
wip: Build with -Wconversionlukeshu/safe-conversion
I think this found a real bug in the dhcp packet parser. I don't think anything called lib9p_str{,n}() values that could be big enough, but their bounds-checking was broken.
Diffstat (limited to 'libdhcp')
-rw-r--r--libdhcp/dhcp_client.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c
index 2d0ebe6..2c9bd40 100644
--- a/libdhcp/dhcp_client.c
+++ b/libdhcp/dhcp_client.c
@@ -312,7 +312,9 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
switch (msgtyp) {
case DHCP_MSGTYP_DISCOVER: case DHCP_MSGTYP_INFORM:
case DHCP_MSGTYP_REQUEST:
- secs = (LO_CALL(bootclock, get_time_ns) - client->time_ns_init)/NS_PER_S;
+ uint64_t secs64 = (LO_CALL(bootclock, get_time_ns) - client->time_ns_init)/NS_PER_S;
+ assert(secs64 < UINT16_MAX); /* 18 hours */
+ secs = LM_SAFEDOWNCAST(uint16_t, secs64);
if (!secs)
/* systemd's sd-dhcp-client.c asserts that some
* servers are broken and require .secs to be
@@ -438,15 +440,16 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
assert(val.len);
if (val.len) {
assert(val.len <= UINT16_MAX);
- for (size_t done = 0; done < val.len;) {
- uint8_t len = val.len - done > UINT8_MAX
+ uint16_t len16 = (uint16_t)val.len;
+ for (uint16_t done = 0; done < len16;) {
+ uint8_t len8 = (len16 - done > UINT8_MAX)
? UINT8_MAX
- : val.len - done;
+ : LM_SAFEDOWNCAST(uint8_t, len16 - done);
scratch_msg->options[optlen++] = opt;
- scratch_msg->options[optlen++] = len;
- memcpy(&scratch_msg->options[optlen], &((char*)val.ptr)[done], len);
- optlen += len;
- done += len;
+ scratch_msg->options[optlen++] = len8;
+ memcpy(&scratch_msg->options[optlen], &((char*)val.ptr)[done], len8);
+ optlen += len8;
+ done += len8;
}
}
break;
@@ -484,7 +487,8 @@ struct dhcp_recv_msg {
/** @return whether there is an error */
static inline bool _dhcp_client_recv_measure_opts(struct dhcp_recv_msg *ret, uint8_t *optoverload, uint8_t *dat, size_t len, bool require_pad) {
- for (size_t pos = 0, opt_len; pos < len; pos += opt_len) {
+ uint8_t opt_len;
+ for (size_t pos = 0; pos < len; pos += opt_len) {
uint8_t opt_typ = dat[pos++];
switch (opt_typ) {
case DHCP_OPT_END:
@@ -511,7 +515,8 @@ static inline bool _dhcp_client_recv_measure_opts(struct dhcp_recv_msg *ret, uin
}
static inline void _dhcp_client_recv_consolidate_opts(struct dhcp_recv_msg *ret, uint8_t *dat, size_t len) {
- for (size_t pos = 0, opt_len; pos < len; pos += opt_len) {
+ uint8_t opt_len;
+ for (size_t pos = 0; pos < len; pos += opt_len) {
uint8_t opt_typ = dat[pos++];
switch (opt_typ) {
case DHCP_OPT_END:
@@ -573,15 +578,17 @@ static inline enum requirement dhcp_table3(uint8_t req_msgtyp, uint8_t resp_msgt
static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg *ret) {
struct net_ip4_addr srv_addr;
uint16_t srv_port;
- ssize_t msg_len;
+ ssize_t _msg_len;
+ size_t msg_len;
assert(client);
ignore:
- msg_len = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port);
- if (msg_len < 0)
+ _msg_len = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port);
+ if (_msg_len < 0)
/* msg_len is -errno */
- return msg_len;
+ return _msg_len;
+ msg_len = LM_SAFEDOWNCAST(size_t, _msg_len);
/* Validate L3: IP */
/* Don't validate that srv_addr matches client->server_id
@@ -594,10 +601,10 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
goto ignore;
/* Validate L5: DHCP. */
- if ((size_t)msg_len < DHCP_MSG_BASE_SIZE + sizeof(dhcp_magic_cookie))
+ if (msg_len < DHCP_MSG_BASE_SIZE + sizeof(dhcp_magic_cookie))
/* ignore impossibly short message */
goto ignore;
- if ((size_t)msg_len > sizeof(ret->raw))
+ if (msg_len > sizeof(ret->raw))
/* ignore message that is larger than the specified
* DHCP_OPT_DHCP_MAX_MSG_SIZE */
goto ignore;
@@ -646,7 +653,8 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
true))
goto ignore;
/* Validate sizes, allocate buffers. */
- for (uint8_t opt = 1, allocated = 0; opt < 255; opt++) {
+ uint16_t allocated = 0;
+ for (uint8_t opt = 1; opt < 255; opt++) {
if (!ret->options[opt].len)
continue;
if (!dhcp_opt_length_is_valid(opt, ret->options[opt].len))