Skip to content

Commit 1229e2e

Browse files
committed
Merge tag 'v7.2-rc3-smb3-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: "ksmbd server fixes, mostly addressing malformed SMB request handling and connection/session lifetime issues, including two information-disclosure or memory-safety bugs in the SMB2 request/response paths. - validate FILE_ALLOCATION_INFORMATION before block rounding to prevent a client-controlled overflow from truncating a file. - pin connections while asynchronous oplock and lease-break notifications are pending. - initialize compound SMB2 READ alignment padding, preventing disclosure of uninitialized heap bytes. - release the allocated alternate-stream xattr name after rename. - size multichannel binding session-key buffers for the largest permitted key, avoiding a stack buffer overflow. - remove a disconnecting connection's channels from every session, including channels whose binding state has since changed. - serialize binding preauthentication-session lookup and update against its teardown. - check that every compound request element contains StructureSize2 before reading it" * tag 'v7.2-rc3-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: validate compound request size before reading StructureSize2 ksmbd: lock the binding preauth session in smb3_preauth_hash_rsp ksmbd: remove stale channels from all sessions on teardown ksmbd: fix stack buffer overflow in multichannel session-key copy ksmbd: fix memory leak of xattr_stream_name in smb2_rename() ksmbd: zero the smb2_read alignment tail to avoid an infoleak ksmbd: pin conn during async oplock break notification ksmbd: fix integer overflow in set_file_allocation_info()
2 parents 94dc07d + 15b3817 commit 1229e2e

5 files changed

Lines changed: 56 additions & 32 deletions

File tree

fs/smb/server/mgmt/user_session.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -457,22 +457,19 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
457457
{
458458
struct ksmbd_session *sess;
459459
unsigned long id;
460+
struct hlist_node *tmp;
461+
int bkt;
460462

461463
down_write(&sessions_table_lock);
462-
if (conn->binding) {
463-
int bkt;
464-
struct hlist_node *tmp;
465-
466-
hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
467-
if (!ksmbd_chann_del(conn, sess) &&
468-
xa_empty(&sess->ksmbd_chann_list)) {
469-
hash_del(&sess->hlist);
470-
down_write(&conn->session_lock);
471-
xa_erase(&conn->sessions, sess->id);
472-
up_write(&conn->session_lock);
473-
if (atomic_dec_and_test(&sess->refcnt))
474-
ksmbd_session_destroy(sess);
475-
}
464+
hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
465+
if (!ksmbd_chann_del(conn, sess) &&
466+
xa_empty(&sess->ksmbd_chann_list)) {
467+
hash_del(&sess->hlist);
468+
down_write(&conn->session_lock);
469+
xa_erase(&conn->sessions, sess->id);
470+
up_write(&conn->session_lock);
471+
if (atomic_dec_and_test(&sess->refcnt))
472+
ksmbd_session_destroy(sess);
476473
}
477474
}
478475

fs/smb/server/mgmt/user_session.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
struct ksmbd_file_table;
2020

2121
struct channel {
22-
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
22+
char sess_key[CIFS_KEY_SIZE];
2323
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
2424
struct ksmbd_conn *conn;
2525
};

fs/smb/server/oplock.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
875875
out:
876876
ksmbd_free_work_struct(work);
877877
ksmbd_conn_r_count_dec(conn);
878+
ksmbd_conn_put(conn);
878879
}
879880

880881
/**
@@ -910,7 +911,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
910911
br_info->open_trunc = opinfo->open_trunc;
911912

912913
work->request_buf = (char *)br_info;
913-
work->conn = conn;
914+
work->conn = ksmbd_conn_get(conn);
914915
work->sess = opinfo->sess;
915916

916917
ksmbd_conn_r_count_inc(conn);
@@ -985,6 +986,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
985986
out:
986987
ksmbd_free_work_struct(work);
987988
ksmbd_conn_r_count_dec(conn);
989+
ksmbd_conn_put(conn);
988990
}
989991

990992
/**
@@ -1034,7 +1036,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo, bool wait_ack,
10341036
memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);
10351037

10361038
work->request_buf = (char *)br_info;
1037-
work->conn = conn;
1039+
work->conn = ksmbd_conn_get(conn);
10381040
work->sess = opinfo->sess;
10391041

10401042
ksmbd_conn_r_count_inc(conn);

fs/smb/server/smb2misc.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
407407
return 1;
408408
}
409409

410+
if (len < __SMB2_HEADER_STRUCTURE_SIZE + sizeof(__le16)) {
411+
ksmbd_debug(SMB, "Message is too small for StructureSize2\n");
412+
return 1;
413+
}
414+
410415
if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
411416
if (!(command == SMB2_OPLOCK_BREAK_HE &&
412417
(le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 ||

fs/smb/server/smb2pdu.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
16891689
struct ksmbd_conn *conn = work->conn;
16901690
struct ksmbd_session *sess = work->sess;
16911691
struct ksmbd_user *user;
1692-
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
1692+
char channel_key[CIFS_KEY_SIZE] = {};
16931693
char *auth_key = conn->binding ? channel_key : sess->sess_key;
16941694
u64 prev_id;
16951695
bool binding = conn->binding;
@@ -1826,7 +1826,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
18261826
struct ksmbd_conn *conn = work->conn;
18271827
struct ksmbd_session *sess = work->sess;
18281828
char *in_blob, *out_blob;
1829-
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
1829+
char channel_key[CIFS_KEY_SIZE] = {};
18301830
char *auth_key = conn->binding ? channel_key : sess->sess_key;
18311831
u64 prev_sess_id;
18321832
bool binding = conn->binding;
@@ -6597,9 +6597,8 @@ static int smb2_rename(struct ksmbd_work *work,
65976597
pr_err("failed to store stream name in xattr: %d\n",
65986598
rc);
65996599
rc = -EINVAL;
6600-
goto out;
66016600
}
6602-
6601+
kfree(xattr_stream_name);
66036602
goto out;
66046603
}
66056604

@@ -6781,6 +6780,7 @@ static int set_file_allocation_info(struct ksmbd_work *work,
67816780
*/
67826781

67836782
loff_t alloc_blks;
6783+
u64 alloc_size;
67846784
struct inode *inode;
67856785
struct kstat stat;
67866786
int rc;
@@ -6796,7 +6796,19 @@ static int set_file_allocation_info(struct ksmbd_work *work,
67966796
if (rc)
67976797
return rc;
67986798

6799-
alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9;
6799+
/*
6800+
* AllocationSize is fully client-controlled (the caller only
6801+
* validates the fixed 8-byte buffer length). Reject values that
6802+
* would overflow the "round up to 512-byte blocks" conversion
6803+
* below instead of silently wrapping it to a tiny block count,
6804+
* which would truncate the file to a size the client never
6805+
* asked for.
6806+
*/
6807+
alloc_size = le64_to_cpu(file_alloc_info->AllocationSize);
6808+
if (alloc_size > MAX_LFS_FILESIZE - 511)
6809+
return -EINVAL;
6810+
6811+
alloc_blks = (alloc_size + 511) >> 9;
68006812
inode = file_inode(fp->filp);
68016813

68026814
if (alloc_blks > stat.blocks) {
@@ -7433,6 +7445,15 @@ int smb2_read(struct ksmbd_work *work)
74337445
goto out;
74347446
}
74357447

7448+
/*
7449+
* ksmbd_vfs_read() fills only nbytes; the [nbytes, ALIGN(nbytes, 8))
7450+
* tail of the un-zeroed buffer is transmitted as compound-response
7451+
* alignment padding, leaking uninitialized kernel memory to the
7452+
* client. Zero just that tail.
7453+
*/
7454+
if (nbytes & 7)
7455+
memset(aux_payload_buf + nbytes, 0, ALIGN(nbytes, 8) - nbytes);
7456+
74367457
if ((nbytes == 0 && length != 0) || nbytes < mincount) {
74377458
kvfree(aux_payload_buf);
74387459
rsp->hdr.Status = STATUS_END_OF_FILE;
@@ -9787,22 +9808,21 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
97879808
}
97889809

97899810
if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) {
9790-
__u8 *hash_value;
9811+
ksmbd_conn_lock(conn);
97919812

97929813
if (conn->binding) {
97939814
struct preauth_session *preauth_sess;
97949815

97959816
preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
9796-
if (!preauth_sess)
9797-
return;
9798-
hash_value = preauth_sess->Preauth_HashValue;
9799-
} else {
9800-
hash_value = sess->Preauth_HashValue;
9801-
if (!hash_value)
9802-
return;
9817+
if (preauth_sess)
9818+
ksmbd_gen_preauth_integrity_hash(conn,
9819+
work->response_buf,
9820+
preauth_sess->Preauth_HashValue);
9821+
} else if (sess->Preauth_HashValue) {
9822+
ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,
9823+
sess->Preauth_HashValue);
98039824
}
9804-
ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,
9805-
hash_value);
9825+
ksmbd_conn_unlock(conn);
98069826
}
98079827
}
98089828

0 commit comments

Comments
 (0)