Skip to content

Commit 06a2236

Browse files
committed
Merge tag 'v6.15rc-part2-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: "Four ksmbd SMB3 server fixes, all also for stable" * tag 'v6.15rc-part2-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: fix null pointer dereference in alloc_preauth_hash() ksmbd: validate zero num_subauth before sub_auth is accessed ksmbd: fix overflow in dacloffset bounds check ksmbd: fix session use-after-free in multichannel connection
2 parents 6cb0bd9 + c8b5b7c commit 06a2236

File tree

5 files changed

+55
-20
lines changed

5 files changed

+55
-20
lines changed

fs/smb/server/auth.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -1016,9 +1016,9 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
10161016

10171017
ses_enc_key = enc ? sess->smb3encryptionkey :
10181018
sess->smb3decryptionkey;
1019-
if (enc)
1020-
ksmbd_user_session_get(sess);
10211019
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
1020+
if (!enc)
1021+
ksmbd_user_session_put(sess);
10221022

10231023
return 0;
10241024
}

fs/smb/server/connection.h

+11
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ enum {
2727
KSMBD_SESS_EXITING,
2828
KSMBD_SESS_NEED_RECONNECT,
2929
KSMBD_SESS_NEED_NEGOTIATE,
30+
KSMBD_SESS_NEED_SETUP,
3031
KSMBD_SESS_RELEASING
3132
};
3233

@@ -187,6 +188,11 @@ static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn)
187188
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE;
188189
}
189190

191+
static inline bool ksmbd_conn_need_setup(struct ksmbd_conn *conn)
192+
{
193+
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_SETUP;
194+
}
195+
190196
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn)
191197
{
192198
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT;
@@ -217,6 +223,11 @@ static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn)
217223
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE);
218224
}
219225

226+
static inline void ksmbd_conn_set_need_setup(struct ksmbd_conn *conn)
227+
{
228+
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_SETUP);
229+
}
230+
220231
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn)
221232
{
222233
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT);

fs/smb/server/mgmt/user_session.c

+10-8
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
181181
down_write(&sessions_table_lock);
182182
down_write(&conn->session_lock);
183183
xa_for_each(&conn->sessions, id, sess) {
184-
if (atomic_read(&sess->refcnt) == 0 &&
184+
if (atomic_read(&sess->refcnt) <= 1 &&
185185
(sess->state != SMB2_SESSION_VALID ||
186186
time_after(jiffies,
187187
sess->last_active + SMB2_SESSION_TIMEOUT))) {
@@ -233,7 +233,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
233233
down_write(&conn->session_lock);
234234
xa_erase(&conn->sessions, sess->id);
235235
up_write(&conn->session_lock);
236-
ksmbd_session_destroy(sess);
236+
if (atomic_dec_and_test(&sess->refcnt))
237+
ksmbd_session_destroy(sess);
237238
}
238239
}
239240
}
@@ -252,7 +253,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
252253
if (xa_empty(&sess->ksmbd_chann_list)) {
253254
xa_erase(&conn->sessions, sess->id);
254255
hash_del(&sess->hlist);
255-
ksmbd_session_destroy(sess);
256+
if (atomic_dec_and_test(&sess->refcnt))
257+
ksmbd_session_destroy(sess);
256258
}
257259
}
258260
up_write(&conn->session_lock);
@@ -328,8 +330,8 @@ void ksmbd_user_session_put(struct ksmbd_session *sess)
328330

329331
if (atomic_read(&sess->refcnt) <= 0)
330332
WARN_ON(1);
331-
else
332-
atomic_dec(&sess->refcnt);
333+
else if (atomic_dec_and_test(&sess->refcnt))
334+
ksmbd_session_destroy(sess);
333335
}
334336

335337
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
@@ -372,13 +374,13 @@ void destroy_previous_session(struct ksmbd_conn *conn,
372374
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_RECONNECT);
373375
err = ksmbd_conn_wait_idle_sess_id(conn, id);
374376
if (err) {
375-
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE);
377+
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
376378
goto out;
377379
}
378380

379381
ksmbd_destroy_file_table(&prev_sess->file_table);
380382
prev_sess->state = SMB2_SESSION_EXPIRED;
381-
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE);
383+
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
382384
ksmbd_launch_ksmbd_durable_scavenger();
383385
out:
384386
up_write(&conn->session_lock);
@@ -436,7 +438,7 @@ static struct ksmbd_session *__session_create(int protocol)
436438
xa_init(&sess->rpc_handle_list);
437439
sess->sequence_number = 1;
438440
rwlock_init(&sess->tree_conns_lock);
439-
atomic_set(&sess->refcnt, 1);
441+
atomic_set(&sess->refcnt, 2);
440442

441443
ret = __init_smb2_session(sess);
442444
if (ret)

fs/smb/server/smb2pdu.c

+15-6
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
12491249
}
12501250

12511251
conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode);
1252-
ksmbd_conn_set_need_negotiate(conn);
1252+
ksmbd_conn_set_need_setup(conn);
12531253

12541254
err_out:
12551255
ksmbd_conn_unlock(conn);
@@ -1271,6 +1271,9 @@ static int alloc_preauth_hash(struct ksmbd_session *sess,
12711271
if (sess->Preauth_HashValue)
12721272
return 0;
12731273

1274+
if (!conn->preauth_info)
1275+
return -ENOMEM;
1276+
12741277
sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue,
12751278
PREAUTH_HASHVALUE_SIZE, KSMBD_DEFAULT_GFP);
12761279
if (!sess->Preauth_HashValue)
@@ -1674,6 +1677,11 @@ int smb2_sess_setup(struct ksmbd_work *work)
16741677

16751678
ksmbd_debug(SMB, "Received smb2 session setup request\n");
16761679

1680+
if (!ksmbd_conn_need_setup(conn) && !ksmbd_conn_good(conn)) {
1681+
work->send_no_response = 1;
1682+
return rc;
1683+
}
1684+
16771685
WORK_BUFFERS(work, req, rsp);
16781686

16791687
rsp->StructureSize = cpu_to_le16(9);
@@ -1909,7 +1917,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
19091917
if (try_delay) {
19101918
ksmbd_conn_set_need_reconnect(conn);
19111919
ssleep(5);
1912-
ksmbd_conn_set_need_negotiate(conn);
1920+
ksmbd_conn_set_need_setup(conn);
19131921
}
19141922
}
19151923
smb2_set_err_rsp(work);
@@ -2235,14 +2243,15 @@ int smb2_session_logoff(struct ksmbd_work *work)
22352243
return -ENOENT;
22362244
}
22372245

2238-
ksmbd_destroy_file_table(&sess->file_table);
22392246
down_write(&conn->session_lock);
22402247
sess->state = SMB2_SESSION_EXPIRED;
22412248
up_write(&conn->session_lock);
22422249

2243-
ksmbd_free_user(sess->user);
2244-
sess->user = NULL;
2245-
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
2250+
if (sess->user) {
2251+
ksmbd_free_user(sess->user);
2252+
sess->user = NULL;
2253+
}
2254+
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_SETUP);
22462255

22472256
rsp->StructureSize = cpu_to_le16(4);
22482257
err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));

fs/smb/server/smbacl.c

+17-4
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ static int sid_to_id(struct mnt_idmap *idmap,
270270
return -EIO;
271271
}
272272

273+
if (psid->num_subauth == 0) {
274+
pr_err("%s: zero subauthorities!\n", __func__);
275+
return -EIO;
276+
}
277+
273278
if (sidtype == SIDOWNER) {
274279
kuid_t uid;
275280
uid_t id;
@@ -1026,7 +1031,9 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10261031
struct dentry *parent = path->dentry->d_parent;
10271032
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
10281033
int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
1029-
int rc = 0, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
1034+
int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size;
1035+
unsigned int dacloffset;
1036+
size_t dacl_struct_end;
10301037
u16 num_aces, ace_cnt = 0;
10311038
char *aces_base;
10321039
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
@@ -1035,8 +1042,11 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10351042
parent, &parent_pntsd);
10361043
if (pntsd_size <= 0)
10371044
return -ENOENT;
1045+
10381046
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
1039-
if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) {
1047+
if (!dacloffset ||
1048+
check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) ||
1049+
dacl_struct_end > (size_t)pntsd_size) {
10401050
rc = -EINVAL;
10411051
goto free_parent_pntsd;
10421052
}
@@ -1240,7 +1250,9 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12401250
struct smb_ntsd *pntsd = NULL;
12411251
struct smb_acl *pdacl;
12421252
struct posix_acl *posix_acls;
1243-
int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
1253+
int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size;
1254+
unsigned int dacl_offset;
1255+
size_t dacl_struct_end;
12441256
struct smb_sid sid;
12451257
int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
12461258
struct smb_ace *ace;
@@ -1259,7 +1271,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12591271

12601272
dacl_offset = le32_to_cpu(pntsd->dacloffset);
12611273
if (!dacl_offset ||
1262-
(dacl_offset + sizeof(struct smb_acl) > pntsd_size))
1274+
check_add_overflow(dacl_offset, sizeof(struct smb_acl), &dacl_struct_end) ||
1275+
dacl_struct_end > (size_t)pntsd_size)
12631276
goto err_out;
12641277

12651278
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));

0 commit comments

Comments
 (0)