diff --git a/sys/netgraph7/ng_nat.c b/sys/netgraph7/ng_nat.c --- a/sys/netgraph7/ng_nat.c +++ b/sys/netgraph7/ng_nat.c @@ -689,6 +689,12 @@ m = NGI_M(item); + /* Reject anything too short to be an IP packet. */ + if (m->m_pkthdr.len < sizeof(struct ip)) { + NG_FREE_ITEM(item); + return (EINVAL); + } + if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) { NGI_M(item) = NULL; /* avoid double free */ NG_FREE_ITEM(item); @@ -700,6 +706,17 @@ c = mtod(m, char *); ip = mtod(m, struct ip *); + /* + * Validate ip_hl and ip_len against the actual packet before + * we trust any field of the header. + */ + if (ip->ip_hl < 5 || + ntohs(ip->ip_len) < (ip->ip_hl << 2) || + ntohs(ip->ip_len) > m->m_pkthdr.len) { + NG_FREE_ITEM(item); + return (EINVAL); + } + KASSERT(m->m_pkthdr.len == ntohs(ip->ip_len), ("ng_nat: ip_len != m_pkthdr.len")); @@ -722,7 +739,8 @@ m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len); if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && - ip->ip_p == IPPROTO_TCP) { + ip->ip_p == IPPROTO_TCP && + ntohs(ip->ip_len) >= (u_int)(ip->ip_hl << 2) + sizeof(struct tcphdr)) { struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));