Skip to content

Commit 2e1e133

Browse files
committed
Merge tag '6.4-rc-ksmbd-server-fixes-part2' of git://git.samba.org/ksmbd
Pull ksmbd server fixes from Steve French: "Ten ksmbd server fixes, including some important security fixes: - Two use after free fixes - Fix RCU callback race - Deadlock fix - Three patches to prevent session setup attacks - Prevent guest users from establishing multichannel sessions - Fix null pointer dereference in query FS info - Memleak fix" * tag '6.4-rc-ksmbd-server-fixes-part2' of git://git.samba.org/ksmbd: ksmbd: call rcu_barrier() in ksmbd_server_exit() ksmbd: fix racy issue under cocurrent smb2 tree disconnect ksmbd: fix racy issue from smb2 close and logoff with multichannel ksmbd: not allow guest user on multichannel ksmbd: fix deadlock in ksmbd_find_crypto_ctx() ksmbd: block asynchronous requests when making a delay on session setup ksmbd: destroy expired sessions ksmbd: fix racy issue from session setup and logoff ksmbd: fix NULL pointer dereference in smb2_get_info_filesystem() ksmbd: fix memleak in session setup
2 parents ed23734 + eb307d0 commit 2e1e133

File tree

11 files changed

+250
-110
lines changed

11 files changed

+250
-110
lines changed

fs/ksmbd/auth.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,22 +221,22 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
221221
{
222222
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
223223
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
224-
struct ksmbd_crypto_ctx *ctx;
224+
struct ksmbd_crypto_ctx *ctx = NULL;
225225
char *construct = NULL;
226226
int rc, len;
227227

228-
ctx = ksmbd_crypto_ctx_find_hmacmd5();
229-
if (!ctx) {
230-
ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
231-
return -ENOMEM;
232-
}
233-
234228
rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
235229
if (rc) {
236230
ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
237231
goto out;
238232
}
239233

234+
ctx = ksmbd_crypto_ctx_find_hmacmd5();
235+
if (!ctx) {
236+
ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
237+
return -ENOMEM;
238+
}
239+
240240
rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx),
241241
ntlmv2_hash,
242242
CIFS_HMAC_MD5_HASH_SIZE);
@@ -272,6 +272,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
272272
ksmbd_debug(AUTH, "Could not generate md5 hash\n");
273273
goto out;
274274
}
275+
ksmbd_release_crypto_ctx(ctx);
276+
ctx = NULL;
275277

276278
rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp);
277279
if (rc) {
@@ -282,7 +284,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
282284
if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0)
283285
rc = -EINVAL;
284286
out:
285-
ksmbd_release_crypto_ctx(ctx);
287+
if (ctx)
288+
ksmbd_release_crypto_ctx(ctx);
286289
kfree(construct);
287290
return rc;
288291
}

fs/ksmbd/connection.c

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static DEFINE_MUTEX(init_lock);
2020
static struct ksmbd_conn_ops default_conn_ops;
2121

2222
LIST_HEAD(conn_list);
23-
DEFINE_RWLOCK(conn_list_lock);
23+
DECLARE_RWSEM(conn_list_lock);
2424

2525
/**
2626
* ksmbd_conn_free() - free resources of the connection instance
@@ -32,9 +32,9 @@ DEFINE_RWLOCK(conn_list_lock);
3232
*/
3333
void ksmbd_conn_free(struct ksmbd_conn *conn)
3434
{
35-
write_lock(&conn_list_lock);
35+
down_write(&conn_list_lock);
3636
list_del(&conn->conns_list);
37-
write_unlock(&conn_list_lock);
37+
up_write(&conn_list_lock);
3838

3939
xa_destroy(&conn->sessions);
4040
kvfree(conn->request_buf);
@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
5656
return NULL;
5757

5858
conn->need_neg = true;
59-
conn->status = KSMBD_SESS_NEW;
59+
ksmbd_conn_set_new(conn);
6060
conn->local_nls = load_nls("utf8");
6161
if (!conn->local_nls)
6262
conn->local_nls = load_nls_default();
@@ -84,9 +84,9 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
8484
spin_lock_init(&conn->llist_lock);
8585
INIT_LIST_HEAD(&conn->lock_list);
8686

87-
write_lock(&conn_list_lock);
87+
down_write(&conn_list_lock);
8888
list_add(&conn->conns_list, &conn_list);
89-
write_unlock(&conn_list_lock);
89+
up_write(&conn_list_lock);
9090
return conn;
9191
}
9292

@@ -95,15 +95,15 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
9595
struct ksmbd_conn *t;
9696
bool ret = false;
9797

98-
read_lock(&conn_list_lock);
98+
down_read(&conn_list_lock);
9999
list_for_each_entry(t, &conn_list, conns_list) {
100100
if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
101101
continue;
102102

103103
ret = true;
104104
break;
105105
}
106-
read_unlock(&conn_list_lock);
106+
up_read(&conn_list_lock);
107107
return ret;
108108
}
109109

@@ -147,19 +147,47 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
147147
return ret;
148148
}
149149

150-
static void ksmbd_conn_lock(struct ksmbd_conn *conn)
150+
void ksmbd_conn_lock(struct ksmbd_conn *conn)
151151
{
152152
mutex_lock(&conn->srv_mutex);
153153
}
154154

155-
static void ksmbd_conn_unlock(struct ksmbd_conn *conn)
155+
void ksmbd_conn_unlock(struct ksmbd_conn *conn)
156156
{
157157
mutex_unlock(&conn->srv_mutex);
158158
}
159159

160-
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
160+
void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
161161
{
162+
struct ksmbd_conn *conn;
163+
164+
down_read(&conn_list_lock);
165+
list_for_each_entry(conn, &conn_list, conns_list) {
166+
if (conn->binding || xa_load(&conn->sessions, sess_id))
167+
WRITE_ONCE(conn->status, status);
168+
}
169+
up_read(&conn_list_lock);
170+
}
171+
172+
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id)
173+
{
174+
struct ksmbd_conn *bind_conn;
175+
162176
wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
177+
178+
down_read(&conn_list_lock);
179+
list_for_each_entry(bind_conn, &conn_list, conns_list) {
180+
if (bind_conn == conn)
181+
continue;
182+
183+
if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) &&
184+
!ksmbd_conn_releasing(bind_conn) &&
185+
atomic_read(&bind_conn->req_running)) {
186+
wait_event(bind_conn->req_running_q,
187+
atomic_read(&bind_conn->req_running) == 0);
188+
}
189+
}
190+
up_read(&conn_list_lock);
163191
}
164192

165193
int ksmbd_conn_write(struct ksmbd_work *work)
@@ -243,7 +271,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
243271
if (!ksmbd_server_running())
244272
return false;
245273

246-
if (conn->status == KSMBD_SESS_EXITING)
274+
if (ksmbd_conn_exiting(conn))
247275
return false;
248276

249277
if (kthread_should_stop())
@@ -303,7 +331,7 @@ int ksmbd_conn_handler_loop(void *p)
303331
pdu_size = get_rfc1002_len(hdr_buf);
304332
ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
305333

306-
if (conn->status == KSMBD_SESS_GOOD)
334+
if (ksmbd_conn_good(conn))
307335
max_allowed_pdu_size =
308336
SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
309337
else
@@ -312,7 +340,7 @@ int ksmbd_conn_handler_loop(void *p)
312340
if (pdu_size > max_allowed_pdu_size) {
313341
pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n",
314342
pdu_size, max_allowed_pdu_size,
315-
conn->status);
343+
READ_ONCE(conn->status));
316344
break;
317345
}
318346

@@ -360,10 +388,10 @@ int ksmbd_conn_handler_loop(void *p)
360388
}
361389

362390
out:
391+
ksmbd_conn_set_releasing(conn);
363392
/* Wait till all reference dropped to the Server object*/
364393
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
365394

366-
367395
if (IS_ENABLED(CONFIG_UNICODE))
368396
utf8_unload(conn->um);
369397
unload_nls(conn->local_nls);
@@ -407,7 +435,7 @@ static void stop_sessions(void)
407435
struct ksmbd_transport *t;
408436

409437
again:
410-
read_lock(&conn_list_lock);
438+
down_read(&conn_list_lock);
411439
list_for_each_entry(conn, &conn_list, conns_list) {
412440
struct task_struct *task;
413441

@@ -416,14 +444,14 @@ static void stop_sessions(void)
416444
if (task)
417445
ksmbd_debug(CONN, "Stop session handler %s/%d\n",
418446
task->comm, task_pid_nr(task));
419-
conn->status = KSMBD_SESS_EXITING;
447+
ksmbd_conn_set_exiting(conn);
420448
if (t->ops->shutdown) {
421-
read_unlock(&conn_list_lock);
449+
up_read(&conn_list_lock);
422450
t->ops->shutdown(t);
423-
read_lock(&conn_list_lock);
451+
down_read(&conn_list_lock);
424452
}
425453
}
426-
read_unlock(&conn_list_lock);
454+
up_read(&conn_list_lock);
427455

428456
if (!list_empty(&conn_list)) {
429457
schedule_timeout_interruptible(HZ / 10); /* 100ms */

fs/ksmbd/connection.h

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ enum {
2626
KSMBD_SESS_GOOD,
2727
KSMBD_SESS_EXITING,
2828
KSMBD_SESS_NEED_RECONNECT,
29-
KSMBD_SESS_NEED_NEGOTIATE
29+
KSMBD_SESS_NEED_NEGOTIATE,
30+
KSMBD_SESS_RELEASING
3031
};
3132

3233
struct ksmbd_stats {
@@ -140,10 +141,10 @@ struct ksmbd_transport {
140141
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
141142

142143
extern struct list_head conn_list;
143-
extern rwlock_t conn_list_lock;
144+
extern struct rw_semaphore conn_list_lock;
144145

145146
bool ksmbd_conn_alive(struct ksmbd_conn *conn);
146-
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
147+
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id);
147148
struct ksmbd_conn *ksmbd_conn_alloc(void);
148149
void ksmbd_conn_free(struct ksmbd_conn *conn);
149150
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
@@ -162,50 +163,69 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
162163
int ksmbd_conn_handler_loop(void *p);
163164
int ksmbd_conn_transport_init(void);
164165
void ksmbd_conn_transport_destroy(void);
166+
void ksmbd_conn_lock(struct ksmbd_conn *conn);
167+
void ksmbd_conn_unlock(struct ksmbd_conn *conn);
165168

166169
/*
167170
* WARNING
168171
*
169172
* This is a hack. We will move status to a proper place once we land
170173
* a multi-sessions support.
171174
*/
172-
static inline bool ksmbd_conn_good(struct ksmbd_work *work)
175+
static inline bool ksmbd_conn_good(struct ksmbd_conn *conn)
173176
{
174-
return work->conn->status == KSMBD_SESS_GOOD;
177+
return READ_ONCE(conn->status) == KSMBD_SESS_GOOD;
175178
}
176179

177-
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_work *work)
180+
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn)
178181
{
179-
return work->conn->status == KSMBD_SESS_NEED_NEGOTIATE;
182+
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE;
180183
}
181184

182-
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_work *work)
185+
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn)
183186
{
184-
return work->conn->status == KSMBD_SESS_NEED_RECONNECT;
187+
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT;
185188
}
186189

187-
static inline bool ksmbd_conn_exiting(struct ksmbd_work *work)
190+
static inline bool ksmbd_conn_exiting(struct ksmbd_conn *conn)
188191
{
189-
return work->conn->status == KSMBD_SESS_EXITING;
192+
return READ_ONCE(conn->status) == KSMBD_SESS_EXITING;
190193
}
191194

192-
static inline void ksmbd_conn_set_good(struct ksmbd_work *work)
195+
static inline bool ksmbd_conn_releasing(struct ksmbd_conn *conn)
193196
{
194-
work->conn->status = KSMBD_SESS_GOOD;
197+
return READ_ONCE(conn->status) == KSMBD_SESS_RELEASING;
195198
}
196199

197-
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_work *work)
200+
static inline void ksmbd_conn_set_new(struct ksmbd_conn *conn)
198201
{
199-
work->conn->status = KSMBD_SESS_NEED_NEGOTIATE;
202+
WRITE_ONCE(conn->status, KSMBD_SESS_NEW);
200203
}
201204

202-
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_work *work)
205+
static inline void ksmbd_conn_set_good(struct ksmbd_conn *conn)
203206
{
204-
work->conn->status = KSMBD_SESS_NEED_RECONNECT;
207+
WRITE_ONCE(conn->status, KSMBD_SESS_GOOD);
205208
}
206209

207-
static inline void ksmbd_conn_set_exiting(struct ksmbd_work *work)
210+
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn)
208211
{
209-
work->conn->status = KSMBD_SESS_EXITING;
212+
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE);
210213
}
214+
215+
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn)
216+
{
217+
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT);
218+
}
219+
220+
static inline void ksmbd_conn_set_exiting(struct ksmbd_conn *conn)
221+
{
222+
WRITE_ONCE(conn->status, KSMBD_SESS_EXITING);
223+
}
224+
225+
static inline void ksmbd_conn_set_releasing(struct ksmbd_conn *conn)
226+
{
227+
WRITE_ONCE(conn->status, KSMBD_SESS_RELEASING);
228+
}
229+
230+
void ksmbd_all_conn_set_status(u64 sess_id, u32 status);
211231
#endif /* __CONNECTION_H__ */

fs/ksmbd/mgmt/tree_connect.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,15 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
109109
struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
110110
unsigned int id)
111111
{
112-
return xa_load(&sess->tree_conns, id);
112+
struct ksmbd_tree_connect *tcon;
113+
114+
tcon = xa_load(&sess->tree_conns, id);
115+
if (tcon) {
116+
if (test_bit(TREE_CONN_EXPIRE, &tcon->status))
117+
tcon = NULL;
118+
}
119+
120+
return tcon;
113121
}
114122

115123
struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess,
@@ -129,6 +137,9 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
129137
struct ksmbd_tree_connect *tc;
130138
unsigned long id;
131139

140+
if (!sess)
141+
return -EINVAL;
142+
132143
xa_for_each(&sess->tree_conns, id, tc)
133144
ret |= ksmbd_tree_conn_disconnect(sess, tc);
134145
xa_destroy(&sess->tree_conns);

fs/ksmbd/mgmt/tree_connect.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ struct ksmbd_share_config;
1414
struct ksmbd_user;
1515
struct ksmbd_conn;
1616

17+
#define TREE_CONN_EXPIRE 1
18+
1719
struct ksmbd_tree_connect {
1820
int id;
1921

@@ -25,6 +27,7 @@ struct ksmbd_tree_connect {
2527

2628
int maximal_access;
2729
bool posix_extensions;
30+
unsigned long status;
2831
};
2932

3033
struct ksmbd_tree_conn_status {

0 commit comments

Comments
 (0)