Skip to content

Commit b39a183

Browse files
namjaejeonsmfrench
authored andcommitted
ksmbd: fix use-after-free in ksmbd_tree_connect_put under concurrency
Under high concurrency, A tree-connection object (tcon) is freed on a disconnect path while another path still holds a reference and later executes *_put()/write on it. Reported-by: Qianchang Zhao <pioooooooooip@gmail.com> Reported-by: Zhitong Liu <liuzhitong1993@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 3316a8f commit b39a183

3 files changed

Lines changed: 4 additions & 18 deletions

File tree

fs/smb/server/mgmt/tree_connect.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
7878
tree_conn->t_state = TREE_NEW;
7979
status.tree_conn = tree_conn;
8080
atomic_set(&tree_conn->refcount, 1);
81-
init_waitqueue_head(&tree_conn->refcount_q);
8281

8382
ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn,
8483
KSMBD_DEFAULT_GFP));
@@ -100,14 +99,8 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
10099

101100
void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
102101
{
103-
/*
104-
* Checking waitqueue to releasing tree connect on
105-
* tree disconnect. waitqueue_active is safe because it
106-
* uses atomic operation for condition.
107-
*/
108-
if (!atomic_dec_return(&tcon->refcount) &&
109-
waitqueue_active(&tcon->refcount_q))
110-
wake_up(&tcon->refcount_q);
102+
if (atomic_dec_and_test(&tcon->refcount))
103+
kfree(tcon);
111104
}
112105

113106
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
@@ -119,14 +112,11 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
119112
xa_erase(&sess->tree_conns, tree_conn->id);
120113
write_unlock(&sess->tree_conns_lock);
121114

122-
if (!atomic_dec_and_test(&tree_conn->refcount))
123-
wait_event(tree_conn->refcount_q,
124-
atomic_read(&tree_conn->refcount) == 0);
125-
126115
ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id);
127116
ksmbd_release_tree_conn_id(sess, tree_conn->id);
128117
ksmbd_share_config_put(tree_conn->share_conf);
129-
kfree(tree_conn);
118+
if (atomic_dec_and_test(&tree_conn->refcount))
119+
kfree(tree_conn);
130120
return ret;
131121
}
132122

fs/smb/server/mgmt/tree_connect.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ struct ksmbd_tree_connect {
3333
int maximal_access;
3434
bool posix_extensions;
3535
atomic_t refcount;
36-
wait_queue_head_t refcount_q;
3736
unsigned int t_state;
3837
};
3938

fs/smb/server/smb2pdu.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,7 +2190,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
21902190
goto err_out;
21912191
}
21922192

2193-
WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount));
21942193
tcon->t_state = TREE_DISCONNECTED;
21952194
write_unlock(&sess->tree_conns_lock);
21962195

@@ -2200,8 +2199,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
22002199
goto err_out;
22012200
}
22022201

2203-
work->tcon = NULL;
2204-
22052202
rsp->StructureSize = cpu_to_le16(4);
22062203
err = ksmbd_iov_pin_rsp(work, rsp,
22072204
sizeof(struct smb2_tree_disconnect_rsp));

0 commit comments

Comments
 (0)