fixed bug #45559: Window scaling casts u32_t to u16_t without checks

This commit is contained in:
goldsimon 2015-08-28 09:23:10 +02:00
parent b79c3aadd2
commit 06d8dba4a0
7 changed files with 50 additions and 36 deletions

View File

@ -249,6 +249,9 @@ HISTORY
++ Bugfixes:
2015-08-28: Simon Goldschmidt
* tcp: fixed bug #45559: Window scaling casts u32_t to u16_t without checks
2015-08-26: Simon Goldschmidt
* ip6_frag.h/.c: fixed bug bug #41009: IPv6 reassembly broken on 64-bit platforms:
define IPV6_FRAG_COPYHEADER==1 on these platforms to copy the IPv6 header

View File

@ -175,7 +175,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
err_t err;
if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND_MAX(pcb))) {
/* Not all data received by application, send RST to tell the remote
side about this. */
LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED);
@ -673,15 +673,15 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
pcb->state != LISTEN);
pcb->rcv_wnd += len;
if (pcb->rcv_wnd > TCP_WND) {
pcb->rcv_wnd = TCP_WND;
if (pcb->rcv_wnd > TCP_WND_MAX(pcb)) {
pcb->rcv_wnd = TCP_WND_MAX(pcb);
} else if(pcb->rcv_wnd == 0) {
/* rcv_wnd overflowed */
if ((pcb->state == CLOSE_WAIT) || (pcb->state == LAST_ACK)) {
/* In passive close, we allow this, since the FIN bit is added to rcv_wnd
by the stack itself, since it is not mandatory for an application
to call tcp_recved() for the FIN bit, but e.g. the netconn API does so. */
pcb->rcv_wnd = TCP_WND;
pcb->rcv_wnd = TCP_WND_MAX(pcb);
} else {
LWIP_ASSERT("tcp_recved: len wrapped rcv_wnd\n", 0);
}
@ -699,7 +699,7 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
}
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: received %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
len, pcb->rcv_wnd, TCP_WND_MAX(pcb) - pcb->rcv_wnd));
}
/**
@ -814,8 +814,9 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
pcb->snd_nxt = iss;
pcb->lastack = iss - 1;
pcb->snd_lbb = iss - 1;
pcb->rcv_wnd = TCP_WND;
pcb->rcv_ann_wnd = TCP_WND;
/* Start with a window that does not need scaling. When window scaling is
enabled and used, the window is enlarged when both sides agree on scaling. */
pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND);
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
pcb->snd_wnd = TCP_WND;
/* As initial send MSS, we use TCP_MSS but limit it to 536.
@ -1204,7 +1205,7 @@ tcp_process_refused_data(struct tcp_pcb *pcb)
) {
/* correct rcv_wnd as the application won't call tcp_recved()
for the FIN's seqno */
if (pcb->rcv_wnd != TCP_WND) {
if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) {
pcb->rcv_wnd++;
}
TCP_EVENT_CLOSED(pcb, err);
@ -1474,8 +1475,9 @@ tcp_alloc(u8_t prio)
pcb->prio = prio;
pcb->snd_buf = TCP_SND_BUF;
pcb->snd_queuelen = 0;
pcb->rcv_wnd = TCP_WND;
pcb->rcv_ann_wnd = TCP_WND;
/* Start with a window that does not need scaling. When window scaling is
enabled and used, the window is enlarged when both sides agree on scaling. */
pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND);
#if LWIP_WND_SCALE
/* snd_scale and rcv_scale are zero unless both sides agree to use scaling */
pcb->snd_scale = 0;

View File

@ -460,7 +460,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
} else {
/* correct rcv_wnd as the application won't call tcp_recved()
for the FIN's seqno */
if (pcb->rcv_wnd != TCP_WND) {
if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) {
pcb->rcv_wnd++;
}
TCP_EVENT_CLOSED(pcb, err);
@ -1341,7 +1341,8 @@ tcp_receive(struct tcp_pcb *pcb)
TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) & ~(unsigned int)TCP_FIN);
}
/* Adjust length of segment to fit in the window. */
inseg.len = pcb->rcv_wnd;
TCPWND_CHECK16(pcb->rcv_wnd);
inseg.len = (u16_t)pcb->rcv_wnd;
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
inseg.len -= 1;
}
@ -1643,8 +1644,6 @@ tcp_receive(struct tcp_pcb *pcb)
} else {
/* Segments with length 0 is taken care of here. Segments that
fall out of the window are ACKed. */
/*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
tcp_ack_now(pcb);
}
@ -1725,6 +1724,10 @@ tcp_parseopt(struct tcp_pcb *pcb)
}
pcb->rcv_scale = TCP_RCV_SCALE;
pcb->flags |= TF_WND_SCALE;
/* window scaling is enabled, we can use the full receive window */
LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND));
LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND));
pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND;
}
break;
#endif

View File

@ -121,7 +121,7 @@ tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
tcphdr->seqno = seqno_be;
tcphdr->ackno = htonl(pcb->rcv_nxt);
TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
tcphdr->wnd = htons(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd));
tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
tcphdr->chksum = 0;
tcphdr->urgp = 0;
@ -387,7 +387,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
#endif /* TCP_CHECKSUM_ON_COPY */
err_t err;
/* don't allocate segments bigger than half the maximum window we ever received */
u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2);
u16_t mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max/2));
mss_local = mss_local ? mss_local : pcb->mss;
#if LWIP_NETIF_TX_SINGLE_PBUF
@ -1141,11 +1141,11 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
if (seg->flags & TF_SEG_OPTS_WND_SCALE) {
/* The Window field in a SYN segment itself (the only type where we send
the window scale option) is never scaled. */
seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
seg->tcphdr->wnd = htons(TCPWND_MIN16(pcb->rcv_ann_wnd));
} else
#endif /* LWIP_WND_SCALE */
{
seg->tcphdr->wnd = htons(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd));
seg->tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
}
pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;

View File

@ -1245,7 +1245,7 @@
* explicit window update
*/
#ifndef TCP_WND_UPDATE_THRESHOLD
#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4)
#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4))
#endif
/**

View File

@ -129,12 +129,14 @@ typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);
#define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale))
#define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale))
#define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF))
#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND)))
typedef u32_t tcpwnd_size_t;
typedef u16_t tcpflags_t;
#else
#define RCV_WND_SCALE(pcb, wnd) (wnd)
#define SND_WND_SCALE(pcb, wnd) (wnd)
#define TCPWND16(x) (x)
#define TCP_WND_MAX(pcb) TCP_WND
typedef u16_t tcpwnd_size_t;
typedef u8_t tcpflags_t;
#endif

View File

@ -334,9 +334,13 @@ struct tcp_seg {
#if LWIP_WND_SCALE
#define TCPWNDSIZE_F U32_F
#define TCPWND_MAX 0xFFFFFFFFU
#define TCPWND_CHECK16(x) LWIP_ASSERT("window size > 0xFFFF", (x) <= 0xFFFF)
#define TCPWND_MIN16(x) ((u16_t)LWIP_MIN((x), 0xFFFF))
#else /* LWIP_WND_SCALE */
#define TCPWNDSIZE_F U16_F
#define TCPWND_MAX 0xFFFFU
#define TCPWND_CHECK16(x)
#define TCPWND_MIN16(x) x
#endif /* LWIP_WND_SCALE */
/* Global variables: */