Skip to content

Commit 0630117

Browse files
BasharRadyagalnoam
authored andcommitted
issue: 4607536 Fix a race condition
Fixing a race condition, between Internal-Thread and a thread performing the tcp_listen_input, causing list corruption and worker crash with double free warning. And, removing some redundant params. Signed-off-by: Bashar Abdelgafer <[email protected]>
1 parent d362151 commit 0630117

File tree

6 files changed

+63
-5
lines changed

6 files changed

+63
-5
lines changed

src/vma/lwip/tcp.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,18 @@ tcp_syn_handled(struct tcp_pcb_listen *pcb, tcp_syn_handled_fn syn_handled)
12361236
pcb->syn_handled_cb = syn_handled;
12371237
}
12381238

1239+
/**
1240+
* Used for specifying the function that should be when a accepted pcb is ready.
1241+
*
1242+
* @param pcb Listen pcb
1243+
* @param accepted_pcb Callback function to call when the accepted pcb is ready.
1244+
*/
1245+
void
1246+
tcp_accepted_pcb(struct tcp_pcb_listen *pcb, tcp_accepted_pcb_fn accepted_pcb)
1247+
{
1248+
pcb->accepted_pcb = accepted_pcb;
1249+
}
1250+
12391251
/**
12401252
* Used for specifying the function that should be called to clone pcb
12411253
*

src/vma/lwip/tcp.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ typedef err_t (*tcp_syn_handled_fn)(void *arg, struct tcp_pcb *newpcb, err_t err
129129
*/
130130
typedef err_t (*tcp_clone_conn_fn)(void *arg, struct tcp_pcb **newpcb, err_t err);
131131

132+
/** Function prototype for tcp new-pcb callback functions.
133+
* Called when a new pcb is ready as part of tcp_listen_input handling.
134+
* @param newpcb The new connection pcb
135+
*/
136+
typedef void (*tcp_accepted_pcb_fn)(struct tcp_pcb *accepted_pcb);
132137

133138
/** Function prototype for tcp receive callback functions. Called when data has
134139
* been received.
@@ -416,7 +421,7 @@ struct tcp_pcb {
416421
#ifdef VMA_NO_TCP_PCB_LISTEN_STRUCT
417422
tcp_syn_handled_fn syn_handled_cb;
418423
tcp_clone_conn_fn clone_conn;
419-
424+
tcp_accepted_pcb_fn accepted_pcb;
420425
#endif /* VMA_NO_TCP_PCB_LISTEN_STRUCT */
421426

422427
/* Delayed ACK control: number of quick acks */
@@ -453,6 +458,7 @@ struct tcp_pcb_listen {
453458
TCP_PCB_COMMON(struct tcp_pcb_listen);
454459
tcp_syn_handled_fn syn_handled_cb;
455460
tcp_clone_conn_fn clone_conn;
461+
tcp_accepted_pcb_fn accepted_pcb;
456462
};
457463
#endif /* VMA_NO_TCP_PCB_LISTEN_STRUCT */
458464

@@ -488,6 +494,7 @@ void tcp_ip_output (struct tcp_pcb *pcb, ip_output_fn ip_ou
488494
void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept);
489495
void tcp_syn_handled (struct tcp_pcb_listen *pcb, tcp_syn_handled_fn syn_handled);
490496
void tcp_clone_conn (struct tcp_pcb_listen *pcb, tcp_clone_conn_fn clone_conn);
497+
void tcp_accepted_pcb (struct tcp_pcb_listen *pcb, tcp_accepted_pcb_fn accepted_pcb);
491498
void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv);
492499
void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent);
493500
void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval);

src/vma/lwip/tcp_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ PACK_STRUCT_END
218218
else (ret) = ERR_ARG; \
219219
} while (0)
220220

221+
222+
#define TCP_EVENT_ACCEPTED_PCB(pcb, newpcb) \
223+
do { \
224+
if ((pcb)->accepted_pcb != NULL) \
225+
(pcb)->accepted_pcb((newpcb)); \
226+
} while (0)
227+
228+
221229
#define TCP_EVENT_SENT(pcb,space,ret) \
222230
do { \
223231
if((pcb)->sent != NULL) \

src/vma/lwip/tcp_in.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,11 +422,13 @@ tcp_listen_input(struct tcp_pcb_listen *pcb, tcp_in_data* in_data)
422422

423423
/* Send a SYN|ACK together with the MSS option. */
424424
rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
425-
if (rc != ERR_OK) {
425+
if (rc == ERR_OK) {
426+
rc = tcp_output(npcb);
427+
}else{
426428
tcp_abandon(npcb, 0);
427-
return rc;
428429
}
429-
return tcp_output(npcb);
430+
TCP_EVENT_ACCEPTED_PCB(pcb, npcb);
431+
return rc;
430432
}
431433
return ERR_OK;
432434
}

src/vma/sock/sockinfo_tcp.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ bool sockinfo_tcp::prepare_to_close(bool process_shutdown /* = false */)
491491
tcp_accept(&m_pcb, 0);
492492
tcp_syn_handled((struct tcp_pcb_listen*)(&m_pcb), 0);
493493
tcp_clone_conn((struct tcp_pcb_listen*)(&m_pcb), 0);
494+
tcp_accepted_pcb((struct tcp_pcb_listen*)(&m_pcb), 0);
494495
prepare_listen_to_close(); //close pending to accept sockets
495496
} else {
496497
tcp_recv(&m_pcb, sockinfo_tcp::rx_drop_lwip_cb);
@@ -2452,7 +2453,7 @@ int sockinfo_tcp::listen(int backlog)
24522453
tcp_accept(&m_pcb, sockinfo_tcp::accept_lwip_cb);
24532454
tcp_syn_handled((struct tcp_pcb_listen*)(&m_pcb), sockinfo_tcp::syn_received_lwip_cb);
24542455
tcp_clone_conn((struct tcp_pcb_listen*)(&m_pcb), sockinfo_tcp::clone_conn_cb);
2455-
2456+
tcp_accepted_pcb((struct tcp_pcb_listen*)(&m_pcb), sockinfo_tcp::accepted_pcb_cb);
24562457
bool success = attach_as_uc_receiver(ROLE_TCP_SERVER);
24572458

24582459
if (!success) {
@@ -2699,6 +2700,11 @@ sockinfo_tcp *sockinfo_tcp::accept_clone()
26992700
return 0;
27002701
}
27012702

2703+
// This method is called from a flow which assumes that the socket is locked
2704+
// (tcp_listen_input, L3_level_tcp_input).
2705+
// Since we created a new socket and we are about to add it to the timers,
2706+
// we need to make sure it is also locked for further processing.
2707+
si->lock_tcp_con();
27022708
si->m_parent = this;
27032709

27042710
si->m_sock_state = TCP_SOCK_BOUND;
@@ -2943,6 +2949,15 @@ err_t sockinfo_tcp::clone_conn_cb(void *arg, struct tcp_pcb **newpcb, err_t err)
29432949
return ret_val;
29442950
}
29452951

2952+
void sockinfo_tcp::accepted_pcb_cb(struct tcp_pcb *accepted_pcb)
2953+
{
2954+
// A new pcb is always locked. When this callback is called the new pcb is ready
2955+
// and all related processing is done. Now it must be unlocked.
2956+
sockinfo_tcp *accepted_sock = reinterpret_cast<sockinfo_tcp *>(accepted_pcb->my_container);
2957+
ASSERT_LOCKED(accepted_sock->m_tcp_con_lock);
2958+
accepted_sock->unlock_tcp_con();
2959+
}
2960+
29462961
err_t sockinfo_tcp::syn_received_lwip_cb(void *arg, struct tcp_pcb *newpcb, err_t err)
29472962
{
29482963
sockinfo_tcp *listen_sock = (sockinfo_tcp *)((arg));
@@ -2978,6 +2993,10 @@ err_t sockinfo_tcp::syn_received_lwip_cb(void *arg, struct tcp_pcb *newpcb, err_
29782993
if (!is_new_offloaded) {
29792994
new_sock->setPassthrough();
29802995
set_tcp_state(&new_sock->m_pcb, CLOSED);
2996+
// This method is called from a flow (tcp_listen_input, L3_level_tcp_input) which priorly
2997+
// called clone_conn_cb which creates a locked new socket. Before we call to close() we need
2998+
// to unlock the socket, so close() can perform as a regular close() call.
2999+
new_sock->unlock_tcp_con();
29813000
close(new_sock->get_fd());
29823001
listen_sock->m_tcp_con_lock.lock();
29833002
return ERR_ABRT;
@@ -3019,6 +3038,11 @@ err_t sockinfo_tcp::syn_received_drop_lwip_cb(void *arg, struct tcp_pcb *newpcb,
30193038
tcp_arg(&(new_sock->m_pcb), new_sock);
30203039
new_sock->abort_connection();
30213040
}
3041+
// This method is called from a flow (tcp_listen_input, L3_level_tcp_input) which priorly called
3042+
// clone_conn_cb which creates a locked new socket. Before we call to close() we need to unlock
3043+
// the socket, so close() can perform as a regular close() call.
3044+
new_sock->unlock_tcp_con();
3045+
30223046
close(new_sock->get_fd());
30233047

30243048
listen_sock->m_tcp_con_lock.lock();

src/vma/sock/sockinfo_tcp.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,11 @@ class sockinfo_tcp : public sockinfo, public timer_handler
308308

309309
static err_t clone_conn_cb(void *arg, struct tcp_pcb **newpcb, err_t err);
310310

311+
312+
// Called by L3_level_tcp_input to unlock a new pcb/socket.
313+
// @param newpcb The new pcb. Can be nullptr.
314+
static void accepted_pcb_cb(struct tcp_pcb *newpcb);
315+
311316
int accept_helper(struct sockaddr *__addr, socklen_t *__addrlen, int __flags = 0);
312317

313318
// clone socket in accept call

0 commit comments

Comments
 (0)