CVE-2017-7177 (C, published 2017-03-18T20:59Z)
Description: value: Suricata before 3.2.1 has an IPv4 defragmentation evasion issue caused by lack of a check for the IP protocol during fragment matching.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-358 \u2014 Improperly Implemented Security Check for Standard
The product does not implement or incorrectly implements one or more security-relevant checks as specified by the design of a standardized algorithm, protocol, or technique.
Repository: https://github.com/inliniac/suricata
Files changed:
src/defrag-hash.c
src/defrag.c
src/defrag.h
Commit message: defrag - take protocol into account during re-assembly

The IP protocol was not being used to match fragments with
their packets allowing a carefully constructed packet
with a different protocol to be matched, allowing re-assembly
to complete, creating a packet that would not be re-assembled
by the destination host.


Vulnerable code:
BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content,
    int content_len)
    ip4h.ip_proto = IPPROTO_ICMP;
    if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP)
IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content,
    int content_len)
    fh->ip6fh_nxt = IPPROTO_ICMP;
    p1 = BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(id, 2, 0, 'C', 3);
    p1 = BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
    packets[0] = BuildTestPacket(id, 0, 1, 'A', 24);
    packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
    packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
    packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
    packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
    packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
    packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
    packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
    packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
    packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
    packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
    packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
    packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
    packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
    packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
    packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
    packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
    packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24);
    packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
    packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
    packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
    packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
    packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
    packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
    packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
    packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
    packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
    packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
    packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
    packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
    packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
    packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
    packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
    packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
        Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16);
    Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16);
    p = BuildTestPacket(id, 1, 0, 'A', 0);
    p = BuildTestPacket(1, 8183, 0, 'A', 71);
    p1 = BuildTestPacket(1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(id, 0, 0, 'A', 8);
    Packet *p1 = BuildTestPacket(ip_id, 2, 1, 'C', 8);
    Packet *p2 = BuildTestPacket(ip_id, 0, 1, 'A', 8);
    Packet *p3 = BuildTestPacket(ip_id, 1, 0, 'B', 8);
    Packet *p1 = IPV6BuildTestPacket(ip_id, 2, 1, 'C', 8);
    Packet *p2 = IPV6BuildTestPacket(ip_id, 0, 1, 'A', 8);
    Packet *p3 = IPV6BuildTestPacket(ip_id, 1, 0, 'B', 8);

Fixed code:
    dt->proto = IP_GET_IPPROTO(p);
     (d1)->proto == IP_GET_IPPROTO(p) &&        \
BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
    const char content, int content_len)
    ip4h.ip_proto = proto;
    if (IPV4_GET_IPPROTO(p) != proto)
IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf,
    const char content, int content_len)
    fh->ip6fh_nxt = proto;
    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
    packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
    packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
    packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
    packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
    packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
    packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
    packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
    packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
    packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
    packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
    packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
    packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
    packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
    packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
    packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
    packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
    packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
    packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
    packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
    packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
    packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
    packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
    packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
    packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
    packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
    packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
    packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
    packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
    packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
    packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
    packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
    packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
    packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
    packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
        Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
    Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
    p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
    p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
    p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
    Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
    Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
    Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
    Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
    Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
    Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
/**
 * \brief Test that fragments that match other than the proto don't
 * actually get matched.
 */
static int DefragTestBadProto(void)
{
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
    int id = 12;

    DefragInit();

    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
    FAIL_IF_NULL(p1);
    p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
    FAIL_IF_NULL(p2);
    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
    FAIL_IF_NULL(p3);

    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1, NULL));
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2, NULL));
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3, NULL));

    if (p1 != NULL)
        SCFree(p1);
    if (p2 != NULL)
        SCFree(p2);
    if (p3 != NULL)
        SCFree(p3);

    DefragDestroy();
    PASS;
}

    UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
    uint8_t proto; /**< IP protocol for this tracker. */