From: Xin Long > Sent: 06 February 2018 10:43 > To: David Laight > > 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? Compile it for something other than x86. David