From 22f93b35ab9f79a97c58be3b90a3f780a7dffadf Mon Sep 17 00:00:00 2001 From: Ravi kumar Veeramally Date: Fri, 28 Feb 2020 14:30:59 +0200 Subject: [PATCH] net: ipv4: Fix parsing of IPv4 header options If IPv4 header options has wrong options length (e.g. options length is more that actual data), then parser decrements opts_len without checking actual data length. Which crashes the network stack. Signed-off-by: Ravi kumar Veeramally --- subsys/net/ip/ipv4.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index ac0dd7927c4..692302cfb98 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -116,7 +116,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt, { struct net_pkt_cursor cur; u8_t opt_data[NET_IPV4_HDR_OPTNS_MAX_LEN]; - u8_t opts_len; + u8_t total_opts_len; if (!cb) { return -EINVAL; @@ -129,9 +129,9 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt, return -EINVAL; } - opts_len = net_pkt_ipv4_opts_len(pkt); + total_opts_len = net_pkt_ipv4_opts_len(pkt); - while (opts_len) { + while (total_opts_len) { u8_t opt_len = 0U; u8_t opt_type; @@ -139,7 +139,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt, return -EINVAL; } - opts_len--; + total_opts_len--; if (!(opt_type == NET_IPV4_OPTS_EO || opt_type == NET_IPV4_OPTS_NOP)) { @@ -147,11 +147,15 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt, return -EINVAL; } + if (opt_len < 2U || total_opts_len < 1U) { + return -EINVAL; + } + opt_len -= 2U; - opts_len--; + total_opts_len--; } - if (opt_len > opts_len) { + if (opt_len > total_opts_len) { return -EINVAL; } @@ -187,7 +191,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt, break; } - opts_len -= opt_len; + total_opts_len -= opt_len; } net_pkt_cursor_restore(pkt, &cur); @@ -239,6 +243,10 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr)); opts_len = hdr_len - sizeof(struct net_ipv4_hdr); + if (opts_len > NET_IPV4_HDR_OPTNS_MAX_LEN) { + return -EINVAL; + } + net_pkt_set_ipv4_opts_len(pkt, opts_len); pkt_len = ntohs(hdr->len);