| From 5ec13dc4ed1c536de9711cb05af88609d073abf9 Mon Sep 17 00:00:00 2001 |
| From: Stefan Hajnoczi <stefanha@redhat.com> |
| Date: Fri, 31 Jul 2015 15:59:42 +0200 |
| Subject: [PATCH 07/13] rtl8139: avoid nested ifs in IP header parsing |
| (CVE-2015-5165) |
| |
| Message-id: <1438358388-10575-2-git-send-email-stefanha@redhat.com> |
| Patchwork-id: 67236 |
| O-Subject: [RHEL-7.1.z qemu-kvm EMBARGOED PATCH 1/7] rtl8139: avoid nested ifs in IP header parsing (CVE-2015-5165) |
| Bugzilla: 1248766 |
| RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
| RH-Acked-by: Xiao Wang <jasowang@redhat.com> |
| RH-Acked-by: Laszlo Ersek <lersek@redhat.com> |
| |
| Transmit offload needs to parse packet headers. If header fields have |
| unexpected values the offload processing is skipped. |
| |
| The code currently uses nested ifs because there is relatively little |
| input validation. The next patches will add missing input validation |
| and a goto label is more appropriate to avoid deep if statement nesting. |
| |
| Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
| Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com> |
| |
| hw/net/rtl8139.c | 41 ++++++++++++++++++++++------------------- |
| 1 file changed, 22 insertions(+), 19 deletions(-) |
| |
| diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c |
| index d08106b..e3b594f 100644 |
| |
| |
| @@ -2152,28 +2152,30 @@ 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) |
| { |
| - DPRINTF("+++ C+ mode has IP packet\n"); |
| - |
| - /* not aligned */ |
| - eth_payload_data = saved_buffer + ETH_HLEN; |
| - eth_payload_len = saved_size - ETH_HLEN; |
| - |
| - ip = (ip_header*)eth_payload_data; |
| - |
| - if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { |
| - DPRINTF("+++ C+ mode packet has bad IP version %d " |
| - "expected %d\n", IP_HEADER_VERSION(ip), |
| - IP_HEADER_VERSION_4); |
| - ip = NULL; |
| - } else { |
| - hlen = IP_HEADER_LENGTH(ip); |
| - ip_protocol = ip->ip_p; |
| - ip_data_len = be16_to_cpu(ip->ip_len) - hlen; |
| - } |
| + goto skip_offload; |
| } |
| |
| + DPRINTF("+++ C+ mode has IP packet\n"); |
| + |
| + /* not aligned */ |
| + eth_payload_data = saved_buffer + ETH_HLEN; |
| + eth_payload_len = saved_size - ETH_HLEN; |
| + |
| + ip = (ip_header*)eth_payload_data; |
| + |
| + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { |
| + DPRINTF("+++ C+ mode packet has bad IP version %d " |
| + "expected %d\n", IP_HEADER_VERSION(ip), |
| + IP_HEADER_VERSION_4); |
| + goto skip_offload; |
| + } |
| + |
| + hlen = IP_HEADER_LENGTH(ip); |
| + ip_protocol = ip->ip_p; |
| + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; |
| + |
| if (ip) |
| { |
| if (txdw0 & CP_TX_IPCS) |
| @@ -2369,6 +2371,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) |
| } |
| } |
| |
| +skip_offload: |
| /* update tally counter */ |
| ++s->tally_counters.TxOk; |
| |
| -- |
| 1.8.3.1 |
| |