• Xufeng Zhang's avatar
    ipv6/udp: Use the correct variable to determine non-blocking condition · 32c90254
    Xufeng Zhang authored
    udpv6_recvmsg() function is not using the correct variable to determine
    whether or not the socket is in non-blocking operation, this will lead
    to unexpected behavior when a UDP checksum error occurs.
    
    Consider a non-blocking udp receive scenario: when udpv6_recvmsg() is
    called by sock_common_recvmsg(), MSG_DONTWAIT bit of flags variable in
    udpv6_recvmsg() is cleared by "flags & ~MSG_DONTWAIT" in this call:
    
        err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
                       flags & ~MSG_DONTWAIT, &addr_len);
    
    i.e. with udpv6_recvmsg() getting these values:
    
    	int noblock = flags & MSG_DONTWAIT
    	int flags = flags & ~MSG_DONTWAIT
    
    So, when udp checksum error occurs, the execution will go to
    csum_copy_err, and then the problem happens:
    
        csum_copy_err:
                ...............
                if (flags & MSG_DONTWAIT)
                        return -EAGAIN;
                goto try_again;
                ...............
    
    But it will always go to try_again as MSG_DONTWAIT has been cleared
    from flags at call time -- only noblock contains the original value
    of MSG_DONTWAIT, so the test should be:
    
                if (noblock)
                        return -EAGAIN;
    
    This is also consistent with what the ipv4/udp code does.
    Signed-off-by: default avatarXufeng Zhang <xufeng.zhang@windriver.com>
    Signed-off-by: default avatarPaul Gortmaker <paul.gortmaker@windriver.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    32c90254
udp.c 37.3 KB