Commit 2a3612cc authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch...


Merge remote-tracking branch 'remotes/stefanha/tags/rtl8139-cplus-tx-input-validation-pull-request' into staging

Pull request

# gpg: Signature made Mon Aug  3 13:08:25 2015 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/rtl8139-cplus-tx-input-validation-pull-request:
  rtl8139: check TCP Data Offset field (CVE-2015-5165)
  rtl8139: skip offload on short TCP header (CVE-2015-5165)
  rtl8139: check IP Total Length field (CVE-2015-5165)
  rtl8139: check IP Header Length field (CVE-2015-5165)
  rtl8139: skip offload on short Ethernet/IP header (CVE-2015-5165)
  rtl8139: drop tautologous if (ip) {...} statement (CVE-2015-5165)
  rtl8139: avoid nested ifs in IP header parsing (CVE-2015-5165)

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents bd80b596 8357946b
Loading
Loading
Loading
Loading
+190 −173
Original line number Diff line number Diff line
@@ -2150,6 +2150,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
        {
            DPRINTF("+++ C+ mode offloaded task checksum\n");

            /* Large enough for Ethernet and IP headers? */
            if (saved_size < ETH_HLEN + sizeof(ip_header)) {
                goto skip_offload;
            }

            /* ip packet header */
            ip_header *ip = NULL;
            int hlen = 0;
@@ -2160,8 +2165,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
            size_t   eth_payload_len  = 0;

            int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
            if (proto == ETH_P_IP)
            if (proto != ETH_P_IP)
            {
                goto skip_offload;
            }

            DPRINTF("+++ C+ mode has IP packet\n");

            /* not aligned */
@@ -2174,35 +2182,39 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                DPRINTF("+++ C+ mode packet has bad IP version %d "
                    "expected %d\n", IP_HEADER_VERSION(ip),
                    IP_HEADER_VERSION_4);
                    ip = NULL;
                } else {
                goto skip_offload;
            }

            hlen = IP_HEADER_LENGTH(ip);
                    ip_protocol = ip->ip_p;
                    ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
            if (hlen < sizeof(ip_header) || hlen > eth_payload_len) {
                goto skip_offload;
            }

            ip_protocol = ip->ip_p;

            ip_data_len = be16_to_cpu(ip->ip_len);
            if (ip_data_len < hlen || ip_data_len > eth_payload_len) {
                goto skip_offload;
            }
            ip_data_len -= hlen;

            if (ip)
            {
            if (txdw0 & CP_TX_IPCS)
            {
                DPRINTF("+++ C+ mode need IP checksum\n");

                    if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
                        /* bad packet header len */
                        /* or packet too short */
                    }
                    else
                    {
                ip->ip_sum = 0;
                ip->ip_sum = ip_checksum(ip, hlen);
                DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
                    hlen, ip->ip_sum);
            }
                }

            if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
            {
                /* Large enough for the TCP header? */
                if (ip_data_len < sizeof(tcp_header)) {
                    goto skip_offload;
                }

                int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;

                DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
@@ -2227,6 +2239,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)

                int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);

                /* Invalid TCP data offset? */
                if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) {
                    goto skip_offload;
                }

                /* ETH_MTU = ip header len + tcp header len + payload */
                int tcp_data_len = ip_data_len - tcp_hlen;
                int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
@@ -2375,8 +2392,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
                memcpy(eth_payload_data, saved_ip_header, hlen);
            }
        }
        }

skip_offload:
        /* update tally counter */
        ++s->tally_counters.TxOk;