• Anton Blanchard's avatar
    net: unix socket code abuses csum_partial · 0a13404d
    Anton Blanchard authored
    The unix socket code is using the result of csum_partial to
    hash into a lookup table:
    
    	unix_hash_fold(csum_partial(sunaddr, len, 0));
    
    csum_partial is only guaranteed to produce something that can be
    folded into a checksum, as its prototype explains:
    
     * returns a 32-bit number suitable for feeding into itself
     * or csum_tcpudp_magic
    
    The 32bit value should not be used directly.
    
    Depending on the alignment, the ppc64 csum_partial will return
    different 32bit partial checksums that will fold into the same
    16bit checksum.
    
    This difference causes the following testcase (courtesy of
    Gustavo) to sometimes fail:
    
    #include <sys/socket.h>
    #include <stdio.h>
    
    int main()
    {
    	int fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0);
    
    	int i = 1;
    	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, 4);
    
    	struct sockaddr addr;
    	addr.sa_family = AF_LOCAL;
    	bind(fd, &addr, 2);
    
    	listen(fd, 128);
    
    	struct sockaddr_storage ss;
    	socklen_t sslen = (socklen_t)sizeof(ss);
    	getsockname(fd, (struct sockaddr*)&ss, &sslen);
    
    	fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0);
    
    	if (connect(fd, (struct sockaddr*)&ss, sslen) == -1){
    		perror(NULL);
    		return 1;
    	}
    	printf("OK\n");
    	return 0;
    }
    
    As suggested by davem, fix this by using csum_fold to fold the
    partial 32bit checksum into a 16bit checksum before using it.
    Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    0a13404d
af_unix.c 57 KB