Skip to content

Commit

Permalink
Fix race in tfw_sock_srv_disconnect.
Browse files Browse the repository at this point in the history
There was a race between `tfw_sock_srv_disconnect` and
`tfw_srv_conn_release` when last one is called from
`ss_conn_drop_guard_exit` when we process FIN from
remote peer. Connection can be released after we check
that connection refcount is not equal to TFW_CONN_DEATHCNT
and before we call `tfw_connection_close`. Later we
increment connection reference counter (for already
stopped connection, which is equal to zero) and put it
again. This leads to second connection release and
extra decrement of struct server reference counter.
We need to call `__tfw_connection_get_if_live` instead
of simple check that connection reference counter is
not equal to TFW_CONN_DEATHCNT before connection closing.

Closes #2047 #2054
  • Loading branch information
EvgeniiMekhanik committed Feb 29, 2024
1 parent 20b905c commit 9480c71
Showing 1 changed file with 6 additions and 3 deletions.
9 changes: 6 additions & 3 deletions fw/sock_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,9 @@ tfw_sock_srv_disconnect(TfwConn *conn)
* restored already. If the connection is closed already, then
* check its stop bit.
*/
if (atomic_read(&conn->refcnt) != TFW_CONN_DEATHCNT) {
if (__tfw_connection_get_if_live(conn)) {
TfwServer *srv = (TfwServer *)conn->peer;
int r = 0;

/*
* We set TFW_CFG_B_DEL flag when we gracefully
Expand All @@ -521,10 +522,12 @@ tfw_sock_srv_disconnect(TfwConn *conn)
*/
if (test_bit(TFW_CFG_B_DEL, &srv->flags)) {
tfw_connection_abort(conn);
return 0;
} else {
r = tfw_connection_close(conn, true);
}

return tfw_connection_close(conn, true);
tfw_connection_put(conn);
return r;
}
/*
* If stop flag is set, we can exit. Otherwise, continue waiting
Expand Down

0 comments on commit 9480c71

Please sign in to comment.