On Mon, Feb 5, 2018 at 7:35 PM, David Laight <David.Laight@xxxxxxxxxx> wrote: > From: Sasha Levin >> Sent: 03 February 2018 18:01 >> [ Upstream commit 5c468674d17056148da06218d4da5d04baf22eac ] >> >> Now when reneging events in sctp_ulpq_renege(), the variable freed >> could be increased by a __u16 value twice while freed is of __u16 >> type. It means freed may overflow at the second addition. >> >> This patch is to fix it by using __u32 type for 'freed', while at >> it, also to remove 'if (chunk)' check, as all renege commands are >> generated in sctp_eat_data and it can't be NULL. >> >> Reported-by: Marcelo Ricardo Leitner <marcelo.leitner@xxxxxxxxx> >> Signed-off-by: Xin Long <lucien.xin@xxxxxxxxx> >> Acked-by: Neil Horman <nhorman@xxxxxxxxxxxxx> >> Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx> >> Signed-off-by: Sasha Levin <alexander.levin@xxxxxxxxxxxxx> >> --- >> net/sctp/ulpqueue.c | 24 ++++++++---------------- >> 1 file changed, 8 insertions(+), 16 deletions(-) >> >> diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c >> index a71be33f3afe..e36ec5dd64c6 100644 >> --- a/net/sctp/ulpqueue.c >> +++ b/net/sctp/ulpqueue.c >> @@ -1084,29 +1084,21 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, >> void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, >> gfp_t gfp) >> { >> - struct sctp_association *asoc; >> - __u16 needed, freed; >> - >> - asoc = ulpq->asoc; >> + struct sctp_association *asoc = ulpq->asoc; >> + __u32 freed = 0; >> + __u16 needed; >> >> - if (chunk) { >> - needed = ntohs(chunk->chunk_hdr->length); >> - needed -= sizeof(struct sctp_data_chunk); >> - } else >> - needed = SCTP_DEFAULT_MAXWINDOW; >> - >> - freed = 0; >> + needed = ntohs(chunk->chunk_hdr->length) - >> + sizeof(struct sctp_data_chunk); >> >> if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { >> freed = sctp_ulpq_renege_order(ulpq, needed); >> - if (freed < needed) { >> + if (freed < needed) >> freed += sctp_ulpq_renege_frags(ulpq, needed - freed); >> - } >> } >> /* If able to free enough room, accept this chunk. */ >> - if (chunk && (freed >= needed)) { >> - int retval; >> - retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); >> + if (freed >= needed) { >> + int retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); >> /* >> * Enter partial delivery if chunk has not been >> * delivered; otherwise, drain the reassembly queue. > > Hmmm... > ISTM that all the maths should be done using 'unsigned int' to avoid horrid > masking operations on many cpus.... You meant 'if (u32 >= u16)' is not good ? If so, I did some tests: # x.c int main() { unsigned int a = 1; unsigned short b = 1; if (a > b) <---- a++; } # y.c int main() { unsigned int a = 1; unsigned int b = 1; if (a > b) <---- a++; } # x.s movl $1, -4(%rbp) movw $1, -6(%rbp) movzwl -6(%rbp), %eax cmpl -4(%rbp), %eax # y.s movl $1, -4(%rbp) movl $1, -8(%rbp) movl -4(%rbp), %eax cmpl -8(%rbp), %eax So looks like x.c vs y.c is: movzwl vs movl does it matter?