lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <a3ecf04de4fded7c71284a9695b7146d284d1f22.camel@kurtz.be>
Date:   Wed, 23 May 2018 13:15:42 +0200
From:   Alexander Kurtz <alexander@...tz.be>
To:     linux-kernel@...r.kernel.org
Subject: Expected result when racing listen(2) on two sockets bound to the
 same address

[Please keep me CC'ed; I'm not subscribed to the list]

Hi!

The program shown below (also available at [0]) does the following:

 * Create two sockets
 * Enable SO_REUSEADDR on both
 * Bind both sockets to [::1]:12345
 * Spawn two threads which both call listen(2) on one socket each
 * Check that at least one thread succeeded

Unfortunately, when running this program on Linux 4.16, it is sometimes
possible that neither thread succeeds in calling listen(2):

    $ uname -a
    Linux shepard 4.16.0-1-amd64 #1 SMP Debian 4.16.5-1 (2018-04-29) x86_64 GNU/Linux
    $ time make
    cc -Wall -Wextra -pedantic -Werror -O3    listenrace.c  -lpthread -o listenrace
    for i in `seq 10000`; do ./listenrace; done
    listenrace: listenrace.c:58: main: Assertion `result1 == 0 || result2 == 0' failed.
    Aborted
    listenrace: listenrace.c:58: main: Assertion `result1 == 0 || result2 == 0' failed.
    Aborted
    listenrace: listenrace.c:58: main: Assertion `result1 == 0 || result2 == 0' failed.
    Aborted

    real	0m8.201s
    user	0m6.801s
    sys	0m2.141s
    $ 

As can be seen, on 3 runs (out of 10000) calling listen(2) failed in
*both* threads. Is this to be expected (i.e. "don't do this then") or
could this be some race condition in the Linux kernel?

Best regards

Alexander Kurtz

[0] https://github.com/AlexanderKurtz/listenrace

==> Makefile <==
CFLAGS = -Wall -Wextra -pedantic -Werror -O3
LDLIBS = -lpthread

all: listenrace
	for i in `seq 10000`; do ./listenrace; done

listenrace: listenrace.c

clean:
	rm 'listenrace'

.PHONY: all clean

==> listenrace.c <==
#include <assert.h>      // for assert
#include <netdb.h>       // for addrinfo, getaddrinfo
#include <pthread.h>     // for pthread_create, pthread_join, pthread_t
#include <stdint.h>      // for intptr_t
#include <stdio.h>       // for NULL
#include <sys/socket.h>  // for bind, setsockopt, listen, socket, AF_INET6

int my_socket (struct addrinfo* address) {
    // Create socket
    int fd = socket (address->ai_family, address->ai_socktype, 0);
    assert (fd >= 0);

    // Enable SO_REUSEADDR
    assert (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, & (int) { 1 }, sizeof (int)) == 0);

    // Bind socket
    assert (bind (fd, address->ai_addr, address->ai_addrlen) == 0);

    // Return socket
    return fd;
}

void* my_listen (void* data) {
    int fd = (intptr_t) data;

    intptr_t result = listen (fd, 64);

    return (void*) result;
}

int main () {
    // Create sockaddr struct
    struct addrinfo hints = {
        .ai_family   = AF_INET6,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo* address = NULL;
    assert (getaddrinfo ("::1", "12345", &hints, &address) == 0);
    assert (address);

    // Create sockets
    int socket1 = my_socket (address);
    int socket2 = my_socket (address);

    // Create threads
    pthread_t thread1;
    pthread_t thread2;
    assert (pthread_create (&thread1, NULL, my_listen, (void*) (intptr_t) socket1) == 0);
    assert (pthread_create (&thread2, NULL, my_listen, (void*) (intptr_t) socket2) == 0);

    // Wait for the threads
    void* result1 = NULL;
    void* result2 = NULL;
    assert (pthread_join (thread1, &result1) == 0);
    assert (pthread_join (thread2, &result2) == 0);

    // Check that at least one thread could successfully call listen
    assert (result1 == 0 || result2 == 0);

    return 0;
}
Download attachment "signature.asc" of type "application/pgp-signature" (834 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ