diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index 9e25d784..83431724 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -1642,8 +1642,8 @@ dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) again: q = p; while ((q != NULL) && (options_idx >= q->len)) { - options_idx -= q->len; - options_idx_max -= q->len; + options_idx = (u16_t)(options_idx - q->len); + options_idx_max = (u16_t)(options_idx_max - q->len); q = q->next; } if (q == NULL) { @@ -1658,7 +1658,11 @@ again: u8_t len; u8_t decode_len = 0; int decode_idx = -1; - u16_t val_offset = offset + 2; + u16_t val_offset = (u16_t)(offset + 2); + if (val_offset < offset) { + /* overflow */ + return ERR_BUF; + } /* len byte might be in the next pbuf */ if ((offset + 1) < q->len) { len = options[offset + 1]; @@ -1735,7 +1739,11 @@ again: LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op)); break; } - offset += len + 2; + if ((u32_t)(offset + len + 2) > 0xFFFF) { + /* overflow */ + return ERR_BUF; + } + offset = (u16_t)(offset + len + 2); if (decode_len > 0) { u32_t value = 0; u16_t copy_len; @@ -1748,11 +1756,17 @@ decode_next: } if (decode_len > 4) { /* decode more than one u32_t */ + u16_t next_val_offset; LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;); dhcp_got_option(dhcp, decode_idx); dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value)); - decode_len -= 4; - val_offset += 4; + decode_len = (u8_t)(decode_len - 4); + next_val_offset = (u16_t)(val_offset + 4); + if (next_val_offset < val_offset) { + /* overflow */ + return ERR_BUF; + } + val_offset = next_val_offset; decode_idx++; goto decode_next; } else if (decode_len == 4) { @@ -1766,8 +1780,8 @@ decode_next: } } if (offset >= q->len) { - offset -= q->len; - offset_max -= q->len; + offset = (u16_t)(offset - q->len); + offset_max = (u16_t)(offset_max - q->len); if ((offset < offset_max) && offset_max) { q = q->next; LWIP_ERROR("next pbuf was null", q != NULL, return ERR_VAL;);