From b34096a4fa568c7a13e0c5d4f251ee79e8a2e454 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 29 Nov 2020 23:16:12 -0800 Subject: [PATCH] net/tcp/tcp_input.c: Correct bad check of urgent data length Urgent data preceded "normal" data in the TCP payload. If the urgent data is larger than the size of the TCP payload, this indicates that the entire payload is urgent data and that urgent data continues in the next packet. This case was handled correctly for the case where urgent data was present but was not being handled correctly in the case where the urgent data was NOT present. --- net/tcp/tcp_input.c | 51 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index 09fee452fe..14f3a8e5db 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -794,13 +794,13 @@ found: return; } - /* Check the URG flag. If this is set, the segment carries urgent +#ifdef CONFIG_NET_TCPURGDATA + /* Check the URG flag. If this is set, the segment carries urgent * data that we must pass to the application. */ if ((tcp->flags & TCP_URG) != 0) { -#ifdef CONFIG_NET_TCPURGDATA dev->d_urglen = (tcp->urgp[0] << 8) | tcp->urgp[1]; if (dev->d_urglen > dev->d_len) { @@ -809,6 +809,16 @@ found: dev->d_urglen = dev->d_len; } + /* The d_len field contains the length of the incoming data. + * d_urgdata points to the "urgent" data at the beginning of + * the payload; d_appdata field points to the any "normal" data + * that may follow the urgent data. + * + * NOTE: If the urgent data continues in the next packet, then + * d_len will be zero and d_appdata will point past the end of + * the payload (which is OK). + */ + net_incr32(conn->rcvseq, dev->d_urglen); dev->d_len -= dev->d_urglen; dev->d_urgdata = dev->d_appdata; @@ -816,14 +826,41 @@ found: } else { + /* No urgent data */ + dev->d_urglen = 0; -#else /* CONFIG_NET_TCPURGDATA */ - dev->d_appdata = ((FAR uint8_t *)dev->d_appdata) + - ((tcp->urgp[0] << 8) | tcp->urgp[1]); - dev->d_len -= (tcp->urgp[0] << 8) | tcp->urgp[1]; -#endif /* CONFIG_NET_TCPURGDATA */ } +#else /* CONFIG_NET_TCPURGDATA */ + /* Check the URG flag. If this is set, We must gracefully ignore + * and discard the urgent data. + */ + + if ((tcp->flags & TCP_URG) != 0) + { + uint16_t urglen = (tcp->urgp[0] << 8) | tcp->urgp[1]; + if (urglen > dev->d_len) + { + /* There is more urgent data in the next segment to come. */ + + urglen = dev->d_len; + } + + /* The d_len field contains the length of the incoming data; + * The d_appdata field points to the any "normal" data that + * may follow the urgent data. + * + * NOTE: If the urgent data continues in the next packet, then + * d_len will be zero and d_appdata will point past the end of + * the payload (which is OK). + */ + + net_incr32(conn->rcvseq, urglen); + dev->d_len -= urglen; + dev->d_appdata += urglen; + } +#endif /* CONFIG_NET_TCPURGDATA */ + #ifdef CONFIG_NET_TCP_KEEPALIVE /* If the established socket receives an ACK or any kind of data * from the remote peer (whether we accept it or not), then reset