提交 3349c272 编写于 作者: J Jakub Kicinski

Merge branch 'tipc-fix-two-race-issues-in-tipc_conn_alloc'

Xin Long says:

====================
tipc: fix two race issues in tipc_conn_alloc

The race exists beteen tipc_topsrv_accept() and tipc_conn_close(),
one is allocating the con while the other is freeing it and there
is no proper lock protecting it. Therefore, a null-pointer-defer
and a use-after-free may be triggered, see details on each patch.
====================

Link: https://lore.kernel.org/r/cover.1668807842.git.lucien.xin@gmail.comSigned-off-by: NJakub Kicinski <kuba@kernel.org>
...@@ -176,7 +176,7 @@ static void tipc_conn_close(struct tipc_conn *con) ...@@ -176,7 +176,7 @@ static void tipc_conn_close(struct tipc_conn *con)
conn_put(con); conn_put(con);
} }
static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s) static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s, struct socket *sock)
{ {
struct tipc_conn *con; struct tipc_conn *con;
int ret; int ret;
...@@ -202,10 +202,12 @@ static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s) ...@@ -202,10 +202,12 @@ static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s)
} }
con->conid = ret; con->conid = ret;
s->idr_in_use++; s->idr_in_use++;
spin_unlock_bh(&s->idr_lock);
set_bit(CF_CONNECTED, &con->flags); set_bit(CF_CONNECTED, &con->flags);
con->server = s; con->server = s;
con->sock = sock;
conn_get(con);
spin_unlock_bh(&s->idr_lock);
return con; return con;
} }
...@@ -467,7 +469,7 @@ static void tipc_topsrv_accept(struct work_struct *work) ...@@ -467,7 +469,7 @@ static void tipc_topsrv_accept(struct work_struct *work)
ret = kernel_accept(lsock, &newsock, O_NONBLOCK); ret = kernel_accept(lsock, &newsock, O_NONBLOCK);
if (ret < 0) if (ret < 0)
return; return;
con = tipc_conn_alloc(srv); con = tipc_conn_alloc(srv, newsock);
if (IS_ERR(con)) { if (IS_ERR(con)) {
ret = PTR_ERR(con); ret = PTR_ERR(con);
sock_release(newsock); sock_release(newsock);
...@@ -479,11 +481,11 @@ static void tipc_topsrv_accept(struct work_struct *work) ...@@ -479,11 +481,11 @@ static void tipc_topsrv_accept(struct work_struct *work)
newsk->sk_data_ready = tipc_conn_data_ready; newsk->sk_data_ready = tipc_conn_data_ready;
newsk->sk_write_space = tipc_conn_write_space; newsk->sk_write_space = tipc_conn_write_space;
newsk->sk_user_data = con; newsk->sk_user_data = con;
con->sock = newsock;
write_unlock_bh(&newsk->sk_callback_lock); write_unlock_bh(&newsk->sk_callback_lock);
/* Wake up receive process in case of 'SYN+' message */ /* Wake up receive process in case of 'SYN+' message */
newsk->sk_data_ready(newsk); newsk->sk_data_ready(newsk);
conn_put(con);
} }
} }
...@@ -577,17 +579,17 @@ bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower, ...@@ -577,17 +579,17 @@ bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
sub.filter = filter; sub.filter = filter;
*(u64 *)&sub.usr_handle = (u64)port; *(u64 *)&sub.usr_handle = (u64)port;
con = tipc_conn_alloc(tipc_topsrv(net)); con = tipc_conn_alloc(tipc_topsrv(net), NULL);
if (IS_ERR(con)) if (IS_ERR(con))
return false; return false;
*conid = con->conid; *conid = con->conid;
con->sock = NULL;
rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub); rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub);
if (rc >= 0) if (rc)
return true; conn_put(con);
conn_put(con); conn_put(con);
return false; return !rc;
} }
void tipc_topsrv_kern_unsubscr(struct net *net, int conid) void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册