diff --git a/libnetutil/netutil.cc b/libnetutil/netutil.cc index 545863621..bfefd0f7a 100644 --- a/libnetutil/netutil.cc +++ b/libnetutil/netutil.cc @@ -721,6 +721,8 @@ const u8 *ipv4_get_data(const struct ip *ip, const u8 *p, unsigned int *len) const u8 *ipv4_get_data(const u8 *p, unsigned int *len) { struct ip ip; + if (*len < sizeof(ip)) + return NULL; memcpy(&ip, p, sizeof(ip)); return ipv4_get_data(&ip, p, len); } @@ -736,6 +738,8 @@ const u8 *ipv6_get_data(const struct ip6_hdr *ip6, const u8 *p, unsigned int *le const u8 *ipv6_get_data(const u8 *p, unsigned int *len, u8 *nxt) { struct ip6_hdr ip6; + if (*len < sizeof(ip6)) + return NULL; memcpy(&ip6, p, sizeof(ip6)); return ipv6_get_data(&ip6, p, len, nxt); } @@ -751,6 +755,8 @@ const u8 *ipv6_get_data_any(const struct ip6_hdr *ip6, const u8 *p, unsigned int const u8 *ipv6_get_data_any(const u8 *p, unsigned int *len, u8 *nxt) { struct ip6_hdr ip6; + if (*len < sizeof(ip6)) + return NULL; memcpy(&ip6, p, sizeof(ip6)); return ipv6_get_data_any(&ip6, p, len, nxt); } @@ -759,6 +765,8 @@ const u8 *icmp_get_data(const u8 *icmp, unsigned int *len) { unsigned int header_len; struct icmp_hdr hdr; + if (*len < sizeof(hdr)) + return NULL; memcpy(&hdr, icmp, sizeof(hdr)); if (hdr.icmp_type == ICMP_TIMEXCEED || hdr.icmp_type == ICMP_UNREACH) @@ -776,6 +784,8 @@ const u8 *icmpv6_get_data(const u8 *icmpv6, unsigned int *len) { unsigned int header_len; struct icmpv6_hdr hdr; + if (*len < sizeof(hdr)) + return NULL; memcpy(&hdr, icmpv6, sizeof(hdr)); if (hdr.icmpv6_type == ICMPV6_TIMEXCEED || hdr.icmpv6_type == ICMPV6_UNREACH) diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc index f05391191..8bc3602cf 100644 --- a/scan_engine_raw.cc +++ b/scan_engine_raw.cc @@ -441,19 +441,12 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (sockaddr_storage_cmp(USI->SourceSockAddr(), &hdr.dst) != 0) continue; - struct ip ip_tmp; - memcpy(&ip_tmp, pkt, sizeof(ip_tmp)); - /* First check if it is ICMP, TCP, or UDP */ if (hdr.proto == IPPROTO_ICMP || hdr.proto == IPPROTO_ICMPV6) { /* if it is our response */ - if (bytes < 8U) { - if (!ip_tmp.ip_off) - error("Supposed ping packet is only %d bytes long!", bytes); - continue; - } - struct ppkt ping; + if (datalen < sizeof(ppkt)) + continue; memcpy(&ping, data, sizeof(ping)); current_reason = icmp_to_reason(hdr.proto, ping.type, ping.code); @@ -559,12 +552,16 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if ((encaps_hdr.proto == IPPROTO_ICMP || encaps_hdr.proto == IPPROTO_ICMPV6) && USI->ptech.rawicmpscan) { /* The response was based on a ping packet we sent */ + if (encaps_len < ICMP_LEN_MIN) + continue; struct icmp icmp; - memcpy(&icmp, encaps_data, sizeof(icmp)); + memcpy(&icmp, encaps_data, MIN(encaps_len, sizeof(icmp))); if (probe->icmpid() != ntohs(icmp.icmp_id)) continue; } else if (encaps_hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) { struct tcp_hdr tcp; + if (encaps_len < sizeof(tcp)) + continue; memcpy(&tcp, encaps_data, sizeof(tcp)); if (probe->dport() != ntohs(tcp.th_dport) || probe->sport() != ntohs(tcp.th_sport) || @@ -572,12 +569,16 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { continue; } else if (encaps_hdr.proto == IPPROTO_UDP && USI->ptech.rawudpscan) { struct udp_hdr udp; + if (encaps_len < sizeof(udp)) + continue; memcpy(&udp, encaps_data, sizeof(udp)); if (probe->dport() != ntohs(udp.uh_dport) || probe->sport() != ntohs(udp.uh_sport)) continue; } else if (encaps_hdr.proto == IPPROTO_SCTP && USI->ptech.rawsctpscan) { struct sctp_hdr sctp; + if (encaps_len < sizeof(sctp)) + continue; memcpy(&sctp, encaps_data, sizeof(sctp)); if (probe->dport() != ntohs(sctp.sh_dport) || probe->sport() != ntohs(sctp.sh_sport) || @@ -658,6 +659,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { } } else if (hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) { struct tcp_hdr tcp; + if (datalen < sizeof(tcp)) + continue; memcpy(&tcp, data, sizeof(tcp)); /* Check that the packet has useful flags. */ if (o.discovery_ignore_rst @@ -709,7 +712,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { } } else if (hdr.proto == IPPROTO_UDP && USI->ptech.rawudpscan) { struct udp_hdr udp; - memcpy(&udp, data, sizeof(udp)); + if (datalen < sizeof(udp)) + continue; /* Search for this host on the incomplete list */ hss = USI->findHost(&hdr.src); if (!hss) @@ -719,6 +723,7 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { listsz = hss->num_probes_outstanding(); goodone = false; + memcpy(&udp, data, sizeof(udp)); u16 sport = ntohs(udp.uh_sport); u16 dport = ntohs(udp.uh_dport); @@ -745,6 +750,10 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { log_write(LOG_STDOUT, "In response to UDP-ping, we got UDP packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), sport, probe->get_tryno()); } } else if (hdr.proto == IPPROTO_SCTP && USI->ptech.rawsctpscan) { + struct sctp_hdr sctp; + struct dnet_sctp_chunkhdr chunk; + if (datalen < sizeof(sctp) + sizeof(chunk)) + continue; /* Search for this host on the incomplete list */ hss = USI->findHost(&hdr.src); if (!hss) @@ -753,10 +762,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { listsz = hss->num_probes_outstanding(); goodone = false; - struct sctp_hdr sctp; memcpy(&sctp, data, sizeof(sctp)); - struct dnet_sctp_chunkhdr chunk; - memcpy(&chunk, (u8 *)data + 12, sizeof(chunk)); + memcpy(&chunk, (u8 *)data + sizeof(sctp), sizeof(chunk)); u16 sport = ntohs(sctp.sh_sport); u16 dport = ntohs(sctp.sh_dport); diff --git a/tcpip.cc b/tcpip.cc index 54aa15428..48de9c722 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -1312,17 +1312,13 @@ static bool validateTCPhdr(const u8 *tcpc, unsigned len) { */ static bool validatepkt(const u8 *ipc, unsigned *len) { struct ip ip; + if (*len < sizeof(ip)) + return false; memcpy(&ip, ipc, sizeof(ip)); const void *data; unsigned int datalen, iplen; u8 hdr; - if (*len < 1) { - if (o.debugging >= 3) - error("Rejecting tiny, supposed IP packet (size %u)", *len); - return false; - } - if (ip.ip_v == 4) { unsigned fragoff, iplen; @@ -1352,6 +1348,8 @@ static bool validatepkt(const u8 *ipc, unsigned *len) { hdr = ip.ip_p; } else if (ip.ip_v == 6) { struct ip6_hdr ip6; + if (*len < sizeof(ip6)) + return false; memcpy(&ip6, ipc, sizeof(ip6)); datalen = *len; diff --git a/traceroute.cc b/traceroute.cc index 3903ede23..e4b24ff13 100644 --- a/traceroute.cc +++ b/traceroute.cc @@ -1132,6 +1132,8 @@ static bool decode_reply(const u8 *ip, unsigned int len, Reply *reply) { if (hdr.version == 4 && hdr.proto == IPPROTO_ICMP) { /* ICMP responses comprise all the TTL exceeded messages we expect from all probe types, as well as actual replies from ICMP probes. */ + if (len < ICMP_LEN_MIN) + return false; ALIGN_HEADER(struct icmp_hdr, icmp, data, 0, len); if ((icmp.icmp_type == ICMP_TIMEXCEED && icmp.icmp_code == ICMP_TIMEXCEED_INTRANS) @@ -1158,6 +1160,8 @@ static bool decode_reply(const u8 *ip, unsigned int len, Reply *reply) { } else if (hdr.version == 6 && hdr.proto == IP_PROTO_ICMPV6) { /* ICMPv6 responses comprise all the TTL exceeded messages we expect from all probe types, as well as actual replies from ICMP probes. */ + if (len < ICMP_LEN_MIN) + return false; ALIGN_HEADER(struct icmpv6_hdr, icmpv6, data, 0, len); /* TIMEXCEED, UNREACH */ if ((icmpv6.icmpv6_type == ICMPV6_TIMEXCEED @@ -1181,14 +1185,20 @@ static bool decode_reply(const u8 *ip, unsigned int len, Reply *reply) { return false; } } else if (hdr.proto == IPPROTO_TCP) { + if (len < sizeof(struct tcp_hdr)) + return false; ALIGN_HEADER(struct tcp_hdr, tcp, data, 0, len); reply->token = ntohs(tcp.th_dport) ^ global_id; reply->target_addr = reply->from_addr; } else if (hdr.proto == IPPROTO_UDP) { + if (len < sizeof(struct udp_hdr)) + return false; ALIGN_HEADER(struct udp_hdr, udp, data, 0, len); reply->token = ntohs(udp.uh_dport) ^ global_id; reply->target_addr = reply->from_addr; } else if (hdr.proto == IPPROTO_SCTP) { + if (len < sizeof(struct sctp_hdr)) + return false; ALIGN_HEADER(struct sctp_hdr, sctp, data, 0, len); reply->token = ntohs(sctp.sh_dport) ^ global_id; reply->target_addr = reply->from_addr;