From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53329) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZMEY0-0002OS-01 for qemu-devel@nongnu.org; Mon, 03 Aug 2015 08:08:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZMEXv-0008EG-Vw for qemu-devel@nongnu.org; Mon, 03 Aug 2015 08:08:51 -0400 From: Stefan Hajnoczi Date: Mon, 3 Aug 2015 13:08:36 +0100 Message-Id: <1438603721-28320-3-git-send-email-stefanha@redhat.com> In-Reply-To: <1438603721-28320-1-git-send-email-stefanha@redhat.com> References: <1438603721-28320-1-git-send-email-stefanha@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PULL for-2.4 2/7] rtl8139: drop tautologous if (ip) {...} statement (CVE-2015-5165) List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Peter Maydell , Jason Wang , qemu-stable@nongnu.org, Stefan Hajnoczi The previous patch stopped using the ip pointer as an indicator that the IP header is present. When we reach the if (ip) {...} statement we know ip is always non-NULL. Remove the if statement to reduce nesting. Reported-by: =E6=9C=B1=E4=B8=9C=E6=B5=B7(=E5=90=AF=E8=B7=AF) Reviewed-by: Jason Wang Signed-off-by: Stefan Hajnoczi --- hw/net/rtl8139.c | 309 +++++++++++++++++++++++++++----------------------= ------ 1 file changed, 153 insertions(+), 156 deletions(-) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 8731a30..db36b65 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -2184,198 +2184,195 @@ static int rtl8139_cplus_transmit_one(RTL8139St= ate *s) ip_protocol =3D ip->ip_p; ip_data_len =3D be16_to_cpu(ip->ip_len) - hlen; =20 - if (ip) + if (txdw0 & CP_TX_IPCS) { - if (txdw0 & CP_TX_IPCS) - { - DPRINTF("+++ C+ mode need IP checksum\n"); + DPRINTF("+++ C+ mode need IP checksum\n"); =20 - if (hleneth_payload_len) = {/* min header length */ - /* bad packet header len */ - /* or packet too short */ - } - else - { - ip->ip_sum =3D 0; - ip->ip_sum =3D ip_checksum(ip, hlen); - DPRINTF("+++ C+ mode IP header len=3D%d checksum= =3D%04x\n", - hlen, ip->ip_sum); - } + if (hleneth_payload_len) {/* = min header length */ + /* bad packet header len */ + /* or packet too short */ } - - if ((txdw0 & CP_TX_LGSEN) && ip_protocol =3D=3D IP_PROTO= _TCP) + else { - int large_send_mss =3D (txdw0 >> 16) & CP_TC_LGSEN_M= SS_MASK; + ip->ip_sum =3D 0; + ip->ip_sum =3D ip_checksum(ip, hlen); + DPRINTF("+++ C+ mode IP header len=3D%d checksum=3D%= 04x\n", + hlen, ip->ip_sum); + } + } =20 - DPRINTF("+++ C+ mode offloaded task TSO MTU=3D%d IP = data %d " - "frame data %d specified MSS=3D%d\n", ETH_MTU, - ip_data_len, saved_size - ETH_HLEN, large_send_m= ss); + if ((txdw0 & CP_TX_LGSEN) && ip_protocol =3D=3D IP_PROTO_TCP= ) + { + int large_send_mss =3D (txdw0 >> 16) & CP_TC_LGSEN_MSS_M= ASK; =20 - int tcp_send_offset =3D 0; - int send_count =3D 0; + DPRINTF("+++ C+ mode offloaded task TSO MTU=3D%d IP data= %d " + "frame data %d specified MSS=3D%d\n", ETH_MTU, + ip_data_len, saved_size - ETH_HLEN, large_send_mss); =20 - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; + int tcp_send_offset =3D 0; + int send_count =3D 0; =20 - /* save IP header template; data area is used in tcp= checksum calculation */ - memcpy(saved_ip_header, eth_payload_data, hlen); + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; =20 - /* a placeholder for checksum calculation routine in= tcp case */ - uint8_t *data_to_checksum =3D eth_payload_data += hlen - 12; - // size_t data_to_checksum_len = =3D eth_payload_len - hlen + 12; + /* save IP header template; data area is used in tcp che= cksum calculation */ + memcpy(saved_ip_header, eth_payload_data, hlen); =20 - /* pointer to TCP header */ - tcp_header *p_tcp_hdr =3D (tcp_header*)(eth_payload_= data + hlen); + /* a placeholder for checksum calculation routine in tcp= case */ + uint8_t *data_to_checksum =3D eth_payload_data + hle= n - 12; + // size_t data_to_checksum_len =3D = eth_payload_len - hlen + 12; =20 - int tcp_hlen =3D TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + /* pointer to TCP header */ + tcp_header *p_tcp_hdr =3D (tcp_header*)(eth_payload_data= + hlen); =20 - /* ETH_MTU =3D ip header len + tcp header len + payl= oad */ - int tcp_data_len =3D ip_data_len - tcp_hlen; - int tcp_chunk_size =3D ETH_MTU - hlen - tcp_hlen; + int tcp_hlen =3D TCP_HEADER_DATA_OFFSET(p_tcp_hdr); =20 - DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d = TCP " - "data len %d TCP chunk size %d\n", ip_data_len, - tcp_hlen, tcp_data_len, tcp_chunk_size); + /* ETH_MTU =3D ip header len + tcp header len + payload = */ + int tcp_data_len =3D ip_data_len - tcp_hlen; + int tcp_chunk_size =3D ETH_MTU - hlen - tcp_hlen; =20 - /* note the cycle below overwrites IP header data, - but restores it from saved_ip_header before sendi= ng packet */ + DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP = " + "data len %d TCP chunk size %d\n", ip_data_len, + tcp_hlen, tcp_data_len, tcp_chunk_size); =20 - int is_last_frame =3D 0; + /* note the cycle below overwrites IP header data, + but restores it from saved_ip_header before sending p= acket */ =20 - for (tcp_send_offset =3D 0; tcp_send_offset < tcp_da= ta_len; tcp_send_offset +=3D tcp_chunk_size) - { - uint16_t chunk_size =3D tcp_chunk_size; - - /* check if this is the last frame */ - if (tcp_send_offset + tcp_chunk_size >=3D tcp_da= ta_len) - { - is_last_frame =3D 1; - chunk_size =3D tcp_data_len - tcp_send_offse= t; - } - - DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", - be32_to_cpu(p_tcp_hdr->th_seq)); - - /* add 4 TCP pseudoheader fields */ - /* copy IP source and destination fields */ - memcpy(data_to_checksum, saved_ip_header + 12, 8= ); - - DPRINTF("+++ C+ mode TSO calculating TCP checksu= m for " - "packet with %d bytes data\n", tcp_hlen + - chunk_size); - - if (tcp_send_offset) - { - memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint= 8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); - } - - /* keep PUSH and FIN flags only for the last fra= me */ - if (!is_last_frame) - { - TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_P= USH|TCP_FLAG_FIN); - } - - /* recalculate TCP checksum */ - ip_pseudo_header *p_tcpip_hdr =3D (ip_pseudo_hea= der *)data_to_checksum; - p_tcpip_hdr->zeros =3D 0; - p_tcpip_hdr->ip_proto =3D IP_PROTO_TCP; - p_tcpip_hdr->ip_payload =3D cpu_to_be16(tcp_hlen= + chunk_size); - - p_tcp_hdr->th_sum =3D 0; - - int tcp_checksum =3D ip_checksum(data_to_checksu= m, tcp_hlen + chunk_size + 12); - DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", - tcp_checksum); - - p_tcp_hdr->th_sum =3D tcp_checksum; - - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); - - /* set IP data length and recalculate IP checksu= m */ - ip->ip_len =3D cpu_to_be16(hlen + tcp_hlen + chu= nk_size); - - /* increment IP id for subsequent frames */ - ip->ip_id =3D cpu_to_be16(tcp_send_offset/tcp_ch= unk_size + be16_to_cpu(ip->ip_id)); - - ip->ip_sum =3D 0; - ip->ip_sum =3D ip_checksum(eth_payload_data, hle= n); - DPRINTF("+++ C+ mode TSO IP header len=3D%d " - "checksum=3D%04x\n", hlen, ip->ip_sum); - - int tso_send_size =3D ETH_HLEN + hlen + tcp_hlen= + chunk_size; - DPRINTF("+++ C+ mode TSO transferring packet siz= e " - "%d\n", tso_send_size); - rtl8139_transfer_frame(s, saved_buffer, tso_send= _size, - 0, (uint8_t *) dot1q_buffer); - - /* add transferred count to TCP sequence number = */ - p_tcp_hdr->th_seq =3D cpu_to_be32(chunk_size + b= e32_to_cpu(p_tcp_hdr->th_seq)); - ++send_count; - } + int is_last_frame =3D 0; =20 - /* Stop sending this frame */ - saved_size =3D 0; - } - else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + for (tcp_send_offset =3D 0; tcp_send_offset < tcp_data_l= en; tcp_send_offset +=3D tcp_chunk_size) { - DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + uint16_t chunk_size =3D tcp_chunk_size; =20 - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; - memcpy(saved_ip_header, eth_payload_data, hlen); + /* check if this is the last frame */ + if (tcp_send_offset + tcp_chunk_size >=3D tcp_data_l= en) + { + is_last_frame =3D 1; + chunk_size =3D tcp_data_len - tcp_send_offset; + } =20 - uint8_t *data_to_checksum =3D eth_payload_data += hlen - 12; - // size_t data_to_checksum_len = =3D eth_payload_len - hlen + 12; + DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", + be32_to_cpu(p_tcp_hdr->th_seq)); =20 /* add 4 TCP pseudoheader fields */ /* copy IP source and destination fields */ memcpy(data_to_checksum, saved_ip_header + 12, 8); =20 - if ((txdw0 & CP_TX_TCPCS) && ip_protocol =3D=3D IP_P= ROTO_TCP) - { - DPRINTF("+++ C+ mode calculating TCP checksum fo= r " - "packet with %d bytes data\n", ip_data_len); - - ip_pseudo_header *p_tcpip_hdr =3D (ip_pseudo_hea= der *)data_to_checksum; - p_tcpip_hdr->zeros =3D 0; - p_tcpip_hdr->ip_proto =3D IP_PROTO_TCP; - p_tcpip_hdr->ip_payload =3D cpu_to_be16(ip_data_= len); - - tcp_header* p_tcp_hdr =3D (tcp_header *) (data_t= o_checksum+12); - - p_tcp_hdr->th_sum =3D 0; - - int tcp_checksum =3D ip_checksum(data_to_checksu= m, ip_data_len + 12); - DPRINTF("+++ C+ mode TCP checksum %04x\n", - tcp_checksum); + DPRINTF("+++ C+ mode TSO calculating TCP checksum fo= r " + "packet with %d bytes data\n", tcp_hlen + + chunk_size); =20 - p_tcp_hdr->th_sum =3D tcp_checksum; - } - else if ((txdw0 & CP_TX_UDPCS) && ip_protocol =3D=3D= IP_PROTO_UDP) + if (tcp_send_offset) { - DPRINTF("+++ C+ mode calculating UDP checksum fo= r " - "packet with %d bytes data\n", ip_data_len); + memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*= )p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); + } =20 - ip_pseudo_header *p_udpip_hdr =3D (ip_pseudo_hea= der *)data_to_checksum; - p_udpip_hdr->zeros =3D 0; - p_udpip_hdr->ip_proto =3D IP_PROTO_UDP; - p_udpip_hdr->ip_payload =3D cpu_to_be16(ip_data_= len); + /* keep PUSH and FIN flags only for the last frame *= / + if (!is_last_frame) + { + TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|= TCP_FLAG_FIN); + } =20 - udp_header *p_udp_hdr =3D (udp_header *) (data_t= o_checksum+12); + /* recalculate TCP checksum */ + ip_pseudo_header *p_tcpip_hdr =3D (ip_pseudo_header = *)data_to_checksum; + p_tcpip_hdr->zeros =3D 0; + p_tcpip_hdr->ip_proto =3D IP_PROTO_TCP; + p_tcpip_hdr->ip_payload =3D cpu_to_be16(tcp_hlen + c= hunk_size); =20 - p_udp_hdr->uh_sum =3D 0; + p_tcp_hdr->th_sum =3D 0; =20 - int udp_checksum =3D ip_checksum(data_to_checksu= m, ip_data_len + 12); - DPRINTF("+++ C+ mode UDP checksum %04x\n", - udp_checksum); + int tcp_checksum =3D ip_checksum(data_to_checksum, t= cp_hlen + chunk_size + 12); + DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", + tcp_checksum); =20 - p_udp_hdr->uh_sum =3D udp_checksum; - } + p_tcp_hdr->th_sum =3D tcp_checksum; =20 /* restore IP header */ memcpy(eth_payload_data, saved_ip_header, hlen); + + /* set IP data length and recalculate IP checksum */ + ip->ip_len =3D cpu_to_be16(hlen + tcp_hlen + chunk_s= ize); + + /* increment IP id for subsequent frames */ + ip->ip_id =3D cpu_to_be16(tcp_send_offset/tcp_chunk_= size + be16_to_cpu(ip->ip_id)); + + ip->ip_sum =3D 0; + ip->ip_sum =3D ip_checksum(eth_payload_data, hlen); + DPRINTF("+++ C+ mode TSO IP header len=3D%d " + "checksum=3D%04x\n", hlen, ip->ip_sum); + + int tso_send_size =3D ETH_HLEN + hlen + tcp_hlen + c= hunk_size; + DPRINTF("+++ C+ mode TSO transferring packet size " + "%d\n", tso_send_size); + rtl8139_transfer_frame(s, saved_buffer, tso_send_siz= e, + 0, (uint8_t *) dot1q_buffer); + + /* add transferred count to TCP sequence number */ + p_tcp_hdr->th_seq =3D cpu_to_be32(chunk_size + be32_= to_cpu(p_tcp_hdr->th_seq)); + ++send_count; } + + /* Stop sending this frame */ + saved_size =3D 0; + } + else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, eth_payload_data, hlen); + + uint8_t *data_to_checksum =3D eth_payload_data + hle= n - 12; + // size_t data_to_checksum_len =3D = eth_payload_len - hlen + 12; + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + if ((txdw0 & CP_TX_TCPCS) && ip_protocol =3D=3D IP_PROTO= _TCP) + { + DPRINTF("+++ C+ mode calculating TCP checksum for " + "packet with %d bytes data\n", ip_data_len); + + ip_pseudo_header *p_tcpip_hdr =3D (ip_pseudo_header = *)data_to_checksum; + p_tcpip_hdr->zeros =3D 0; + p_tcpip_hdr->ip_proto =3D IP_PROTO_TCP; + p_tcpip_hdr->ip_payload =3D cpu_to_be16(ip_data_len)= ; + + tcp_header* p_tcp_hdr =3D (tcp_header *) (data_to_ch= ecksum+12); + + p_tcp_hdr->th_sum =3D 0; + + int tcp_checksum =3D ip_checksum(data_to_checksum, i= p_data_len + 12); + DPRINTF("+++ C+ mode TCP checksum %04x\n", + tcp_checksum); + + p_tcp_hdr->th_sum =3D tcp_checksum; + } + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol =3D=3D IP_= PROTO_UDP) + { + DPRINTF("+++ C+ mode calculating UDP checksum for " + "packet with %d bytes data\n", ip_data_len); + + ip_pseudo_header *p_udpip_hdr =3D (ip_pseudo_header = *)data_to_checksum; + p_udpip_hdr->zeros =3D 0; + p_udpip_hdr->ip_proto =3D IP_PROTO_UDP; + p_udpip_hdr->ip_payload =3D cpu_to_be16(ip_data_len)= ; + + udp_header *p_udp_hdr =3D (udp_header *) (data_to_ch= ecksum+12); + + p_udp_hdr->uh_sum =3D 0; + + int udp_checksum =3D ip_checksum(data_to_checksum, i= p_data_len + 12); + DPRINTF("+++ C+ mode UDP checksum %04x\n", + udp_checksum); + + p_udp_hdr->uh_sum =3D udp_checksum; + } + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); } } =20 --=20 2.4.3