From 353185cd3642d62dadfc9d9be020a4f729400e41 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 1 Sep 2021 16:00:19 +0200 Subject: dhcpv6: Fix parsing for IA_ADDR suboptions of IA_NA/IA_TA Once we're past the IA_NA or IA_TA option itself, before we start looking for IA_ADDR suboptions, we need to subtract the length of the option we parsed so far, otherwise we might end up reading past the end of the message, or miss some parts. While at it, streamline calculations in dhcpv6_opt(). Signed-off-by: Stefano Brivio --- dhcpv6.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dhcpv6.c b/dhcpv6.c index f982cde..c4f7a9a 100644 --- a/dhcpv6.c +++ b/dhcpv6.c @@ -295,15 +295,17 @@ static struct resp_not_on_link_t { static struct opt_hdr *dhcpv6_opt(struct opt_hdr *o, uint16_t type, size_t *len) { while (*len >= sizeof(struct opt_hdr)) { - if (ntohs(o->l) > *len) + unsigned int opt_len = ntohs(o->l) + sizeof(struct opt_hdr); + + if (opt_len > *len) return NULL; - *len -= ntohs(o->l) + sizeof(struct opt_hdr); + *len -= opt_len; if (o->t == type) return o; - o = (struct opt_hdr *)((uint8_t *)(o + 1) + ntohs(o->l)); + o = (struct opt_hdr *)((uint8_t *)o + opt_len); } return NULL; @@ -335,15 +337,17 @@ ia_ta: size_t ia_len = ntohs(ia->l); if (ia_type == OPT_IA_NA) { - struct opt_ia_na *opts = (struct opt_ia_na *)ia + 1; + struct opt_ia_na *subopt = (struct opt_ia_na *)ia + 1; - ia_addr = (struct opt_hdr *)opts; + ia_addr = (struct opt_hdr *)subopt; } else if (ia_type == OPT_IA_TA) { - struct opt_ia_ta *opts = (struct opt_ia_ta *)ia + 1; + struct opt_ia_ta *subopt = (struct opt_ia_ta *)ia + 1; - ia_addr = (struct opt_hdr *)opts; + ia_addr = (struct opt_hdr *)subopt; } + ia_len -= sizeof(struct opt_ia_na) - sizeof(struct opt_hdr); + while ((ia_addr = dhcpv6_opt(ia_addr, OPT_IAAADR, &ia_len))) { struct opt_ia_addr *next; -- cgit v1.2.3