net: tcp: Fix possible race condition in connection establishment

When connect() is called on a TCP socket, tcp_in() is called with a NULL
packet to start establishing a connection. That in turn leads to a SYN
packet being produced which, depending on the Ethernet driver, may
result in a synchronous transmit of that packet. After that, the
connect() implementation, which at this point is executing
net_tcp_connect() starts waiting to take a semaphore until the
connection timeout is reached. However, if the transmit of the SYN
packet results in a RST packet being returned from the connection
destination (due to there being no listening socket) very quickly on a
local network, the device driver may deliver an interrupt which can
cause the receive path of the network stack to run, resulting in the
tcp_in() of the RST packet via the network RX thread. That can cause
tcp_conn_unref() to be called before the connecting thread has gotten
to the point of acquiring (or failing to) the semaphore, which results
in a deinitialized semaphore being accessed.

This commit fixes the possible race condition by ensuring that the
connection lock mutex is held until after the connection state moves
to "in connect."

Fixes #44186

Signed-off-by: Berend Ozceri <berend@recogni.com>
This commit is contained in:
Berend Ozceri 2022-03-30 15:13:35 -07:00 committed by Maureen Helm
commit 782c7b6026

View file

@ -2404,11 +2404,10 @@ int net_tcp_connect(struct net_context *context,
/* Input of a (nonexistent) packet with no flags set will cause
* a TCP connection to be established
*/
conn->in_connect = !IS_ENABLED(CONFIG_NET_TEST_PROTOCOL);
tcp_in(conn, NULL);
if (!IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)) {
conn->in_connect = true;
if (k_sem_take(&conn->connect_sem, timeout) != 0 &&
conn->state != TCP_ESTABLISHED) {
conn->in_connect = false;