lkml.org 
[lkml]   [2018]   [Feb]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    Date
    SubjectRe: [PATCH AUTOSEL for 4.14 019/110] sctp: fix the issue that a __u16 variable may overflow in sctp_ulpq_renege
    On Mon, Feb 5, 2018 at 7:35 PM, David Laight <David.Laight@aculab.com> 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@gmail.com>
    >> Signed-off-by: Xin Long <lucien.xin@gmail.com>
    >> Acked-by: Neil Horman <nhorman@tuxdriver.com>
    >> Signed-off-by: David S. Miller <davem@davemloft.net>
    >> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
    >> ---
    >> 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?

    \
     
     \ /
      Last update: 2018-02-06 11:43    [W:6.087 / U:3.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site