From 7d1b7332024ce91bcfcade1532da962b095a9f8e Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Fri, 26 May 2023 16:44:34 +0800 Subject: [PATCH] net/tcp: Add flag for tcp_close to avoid double free Problem: When tcp_close_work starts to run in LPWORK, if another event comes and calls tcp_free before tcp_close_work takes net_lock, the tcp_free will be called twice and cause double free. Signed-off-by: Zhe Weng --- net/tcp/tcp.h | 5 +++-- net/tcp/tcp_close.c | 4 +++- net/tcp/tcp_conn.c | 9 ++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 255dbe4c96..eb989e5fa9 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -106,12 +106,13 @@ #define TCP_WSCALE 0x01U /* Window Scale option enabled */ #define TCP_SACK 0x02U /* Selective ACKs enabled */ +#define TCP_CLOSE_ARRANGED 0x04U /* Connection is arranged to be freed */ #ifdef CONFIG_NET_TCP_CC_NEWRENO /* The TCP flags for congestion control */ -#define TCP_INFR 0x04U /* The flag in Fast Recovery */ -#define TCP_INFT 0x08U /* The flag in Fast Transmitted */ +#define TCP_INFR 0x08U /* The flag in Fast Recovery */ +#define TCP_INFT 0x10U /* The flag in Fast Transmitted */ #endif diff --git a/net/tcp/tcp_close.c b/net/tcp/tcp_close.c index 3892d898c7..bc1e424bd7 100644 --- a/net/tcp/tcp_close.c +++ b/net/tcp/tcp_close.c @@ -53,7 +53,8 @@ static void tcp_close_work(FAR void *param) net_lock(); - if (conn && conn->crefs == 0) + conn->flags &= ~TCP_CLOSE_ARRANGED; + if (conn->crefs == 0) { /* Stop the network monitor for all sockets */ @@ -186,6 +187,7 @@ end_wait: /* Free network resources */ + conn->flags |= TCP_CLOSE_ARRANGED; work_queue(LPWORK, &conn->clswork, tcp_close_work, conn, 0); return flags; diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index b421d9d453..d786646707 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -842,7 +842,14 @@ void tcp_free(FAR struct tcp_conn_s *conn) /* Cancel close work */ - work_cancel(LPWORK, &conn->clswork); + if ((conn->flags & TCP_CLOSE_ARRANGED) && + work_cancel(LPWORK, &conn->clswork) != OK) + { + /* Close work is already running, tcp_free will be called again. */ + + net_unlock(); + return; + } /* Cancel tcp timer */