Skip to content

Commit 8828003

Browse files
committed
Merge tag '6.4-rc4-smb3-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: "Eight server fixes (most also for stable): - Two fixes for uninitialized pointer reads (rename and link) - Fix potential UAF in oplock break - Two fixes for potential out of bound reads in negotiate - Fix crediting bug - Two fixes for xfstests (allocation size fix for test 694 and lookup issue shown by test 464)" * tag '6.4-rc4-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: call putname after using the last component ksmbd: fix incorrect AllocationSize set in smb2_get_info ksmbd: fix UAF issue from opinfo->conn ksmbd: fix multiple out-of-bounds read during context decoding ksmbd: fix slab-out-of-bounds read in smb2_handle_negotiate ksmbd: fix credit count leakage ksmbd: fix uninitialized pointer read in smb2_create_link() ksmbd: fix uninitialized pointer read in ksmbd_vfs_rename()
2 parents 929ed21 + 6fe55c2 commit 8828003

File tree

3 files changed

+100
-77
lines changed

3 files changed

+100
-77
lines changed

fs/smb/server/oplock.c

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,42 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
157157
rcu_read_lock();
158158
opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,
159159
op_entry);
160-
if (opinfo && !atomic_inc_not_zero(&opinfo->refcount))
161-
opinfo = NULL;
160+
if (opinfo) {
161+
if (!atomic_inc_not_zero(&opinfo->refcount))
162+
opinfo = NULL;
163+
else {
164+
atomic_inc(&opinfo->conn->r_count);
165+
if (ksmbd_conn_releasing(opinfo->conn)) {
166+
atomic_dec(&opinfo->conn->r_count);
167+
atomic_dec(&opinfo->refcount);
168+
opinfo = NULL;
169+
}
170+
}
171+
}
172+
162173
rcu_read_unlock();
163174

164175
return opinfo;
165176
}
166177

178+
static void opinfo_conn_put(struct oplock_info *opinfo)
179+
{
180+
struct ksmbd_conn *conn;
181+
182+
if (!opinfo)
183+
return;
184+
185+
conn = opinfo->conn;
186+
/*
187+
* Checking waitqueue to dropping pending requests on
188+
* disconnection. waitqueue_active is safe because it
189+
* uses atomic operation for condition.
190+
*/
191+
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
192+
wake_up(&conn->r_count_q);
193+
opinfo_put(opinfo);
194+
}
195+
167196
void opinfo_put(struct oplock_info *opinfo)
168197
{
169198
if (!atomic_dec_and_test(&opinfo->refcount))
@@ -666,13 +695,6 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
666695

667696
out:
668697
ksmbd_free_work_struct(work);
669-
/*
670-
* Checking waitqueue to dropping pending requests on
671-
* disconnection. waitqueue_active is safe because it
672-
* uses atomic operation for condition.
673-
*/
674-
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
675-
wake_up(&conn->r_count_q);
676698
}
677699

678700
/**
@@ -706,7 +728,6 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
706728
work->conn = conn;
707729
work->sess = opinfo->sess;
708730

709-
atomic_inc(&conn->r_count);
710731
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
711732
INIT_WORK(&work->work, __smb2_oplock_break_noti);
712733
ksmbd_queue_work(work);
@@ -776,13 +797,6 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
776797

777798
out:
778799
ksmbd_free_work_struct(work);
779-
/*
780-
* Checking waitqueue to dropping pending requests on
781-
* disconnection. waitqueue_active is safe because it
782-
* uses atomic operation for condition.
783-
*/
784-
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
785-
wake_up(&conn->r_count_q);
786800
}
787801

788802
/**
@@ -822,7 +836,6 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
822836
work->conn = conn;
823837
work->sess = opinfo->sess;
824838

825-
atomic_inc(&conn->r_count);
826839
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
827840
list_for_each_safe(tmp, t, &opinfo->interim_list) {
828841
struct ksmbd_work *in_work;
@@ -1144,28 +1157,30 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
11441157
}
11451158
prev_opinfo = opinfo_get_list(ci);
11461159
if (!prev_opinfo ||
1147-
(prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx))
1160+
(prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {
1161+
opinfo_conn_put(prev_opinfo);
11481162
goto set_lev;
1163+
}
11491164
prev_op_has_lease = prev_opinfo->is_lease;
11501165
if (prev_op_has_lease)
11511166
prev_op_state = prev_opinfo->o_lease->state;
11521167

11531168
if (share_ret < 0 &&
11541169
prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
11551170
err = share_ret;
1156-
opinfo_put(prev_opinfo);
1171+
opinfo_conn_put(prev_opinfo);
11571172
goto err_out;
11581173
}
11591174

11601175
if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
11611176
prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
1162-
opinfo_put(prev_opinfo);
1177+
opinfo_conn_put(prev_opinfo);
11631178
goto op_break_not_needed;
11641179
}
11651180

11661181
list_add(&work->interim_entry, &prev_opinfo->interim_list);
11671182
err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
1168-
opinfo_put(prev_opinfo);
1183+
opinfo_conn_put(prev_opinfo);
11691184
if (err == -ENOENT)
11701185
goto set_lev;
11711186
/* Check all oplock was freed by close */
@@ -1228,14 +1243,14 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
12281243
return;
12291244
if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
12301245
brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
1231-
opinfo_put(brk_opinfo);
1246+
opinfo_conn_put(brk_opinfo);
12321247
return;
12331248
}
12341249

12351250
brk_opinfo->open_trunc = is_trunc;
12361251
list_add(&work->interim_entry, &brk_opinfo->interim_list);
12371252
oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
1238-
opinfo_put(brk_opinfo);
1253+
opinfo_conn_put(brk_opinfo);
12391254
}
12401255

12411256
/**
@@ -1263,6 +1278,13 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
12631278
list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {
12641279
if (!atomic_inc_not_zero(&brk_op->refcount))
12651280
continue;
1281+
1282+
atomic_inc(&brk_op->conn->r_count);
1283+
if (ksmbd_conn_releasing(brk_op->conn)) {
1284+
atomic_dec(&brk_op->conn->r_count);
1285+
continue;
1286+
}
1287+
12661288
rcu_read_unlock();
12671289
if (brk_op->is_lease && (brk_op->o_lease->state &
12681290
(~(SMB2_LEASE_READ_CACHING_LE |
@@ -1292,7 +1314,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
12921314
brk_op->open_trunc = is_trunc;
12931315
oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
12941316
next:
1295-
opinfo_put(brk_op);
1317+
opinfo_conn_put(brk_op);
12961318
rcu_read_lock();
12971319
}
12981320
rcu_read_unlock();

fs/smb/server/smb2pdu.c

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -326,13 +326,9 @@ int smb2_set_rsp_credits(struct ksmbd_work *work)
326326
if (hdr->Command == SMB2_NEGOTIATE)
327327
aux_max = 1;
328328
else
329-
aux_max = conn->vals->max_credits - credit_charge;
329+
aux_max = conn->vals->max_credits - conn->total_credits;
330330
credits_granted = min_t(unsigned short, credits_requested, aux_max);
331331

332-
if (conn->vals->max_credits - conn->total_credits < credits_granted)
333-
credits_granted = conn->vals->max_credits -
334-
conn->total_credits;
335-
336332
conn->total_credits += credits_granted;
337333
work->credits_granted += credits_granted;
338334

@@ -849,13 +845,14 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
849845

850846
static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
851847
struct smb2_preauth_neg_context *pneg_ctxt,
852-
int len_of_ctxts)
848+
int ctxt_len)
853849
{
854850
/*
855851
* sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt,
856852
* which may not be present. Only check for used HashAlgorithms[1].
857853
*/
858-
if (len_of_ctxts < MIN_PREAUTH_CTXT_DATA_LEN)
854+
if (ctxt_len <
855+
sizeof(struct smb2_neg_context) + MIN_PREAUTH_CTXT_DATA_LEN)
859856
return STATUS_INVALID_PARAMETER;
860857

861858
if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
@@ -867,15 +864,23 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
867864

868865
static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
869866
struct smb2_encryption_neg_context *pneg_ctxt,
870-
int len_of_ctxts)
867+
int ctxt_len)
871868
{
872-
int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
873-
int i, cphs_size = cph_cnt * sizeof(__le16);
869+
int cph_cnt;
870+
int i, cphs_size;
871+
872+
if (sizeof(struct smb2_encryption_neg_context) > ctxt_len) {
873+
pr_err("Invalid SMB2_ENCRYPTION_CAPABILITIES context size\n");
874+
return;
875+
}
874876

875877
conn->cipher_type = 0;
876878

879+
cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
880+
cphs_size = cph_cnt * sizeof(__le16);
881+
877882
if (sizeof(struct smb2_encryption_neg_context) + cphs_size >
878-
len_of_ctxts) {
883+
ctxt_len) {
879884
pr_err("Invalid cipher count(%d)\n", cph_cnt);
880885
return;
881886
}
@@ -923,15 +928,22 @@ static void decode_compress_ctxt(struct ksmbd_conn *conn,
923928

924929
static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
925930
struct smb2_signing_capabilities *pneg_ctxt,
926-
int len_of_ctxts)
931+
int ctxt_len)
927932
{
928-
int sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
929-
int i, sign_alos_size = sign_algo_cnt * sizeof(__le16);
933+
int sign_algo_cnt;
934+
int i, sign_alos_size;
935+
936+
if (sizeof(struct smb2_signing_capabilities) > ctxt_len) {
937+
pr_err("Invalid SMB2_SIGNING_CAPABILITIES context length\n");
938+
return;
939+
}
930940

931941
conn->signing_negotiated = false;
942+
sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
943+
sign_alos_size = sign_algo_cnt * sizeof(__le16);
932944

933945
if (sizeof(struct smb2_signing_capabilities) + sign_alos_size >
934-
len_of_ctxts) {
946+
ctxt_len) {
935947
pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt);
936948
return;
937949
}
@@ -969,18 +981,16 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
969981
len_of_ctxts = len_of_smb - offset;
970982

971983
while (i++ < neg_ctxt_cnt) {
972-
int clen;
973-
974-
/* check that offset is not beyond end of SMB */
975-
if (len_of_ctxts == 0)
976-
break;
984+
int clen, ctxt_len;
977985

978986
if (len_of_ctxts < sizeof(struct smb2_neg_context))
979987
break;
980988

981989
pctx = (struct smb2_neg_context *)((char *)pctx + offset);
982990
clen = le16_to_cpu(pctx->DataLength);
983-
if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts)
991+
ctxt_len = clen + sizeof(struct smb2_neg_context);
992+
993+
if (ctxt_len > len_of_ctxts)
984994
break;
985995

986996
if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {
@@ -991,7 +1001,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
9911001

9921002
status = decode_preauth_ctxt(conn,
9931003
(struct smb2_preauth_neg_context *)pctx,
994-
len_of_ctxts);
1004+
ctxt_len);
9951005
if (status != STATUS_SUCCESS)
9961006
break;
9971007
} else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) {
@@ -1002,7 +1012,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
10021012

10031013
decode_encrypt_ctxt(conn,
10041014
(struct smb2_encryption_neg_context *)pctx,
1005-
len_of_ctxts);
1015+
ctxt_len);
10061016
} else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) {
10071017
ksmbd_debug(SMB,
10081018
"deassemble SMB2_COMPRESSION_CAPABILITIES context\n");
@@ -1021,9 +1031,10 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
10211031
} else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) {
10221032
ksmbd_debug(SMB,
10231033
"deassemble SMB2_SIGNING_CAPABILITIES context\n");
1034+
10241035
decode_sign_cap_ctxt(conn,
10251036
(struct smb2_signing_capabilities *)pctx,
1026-
len_of_ctxts);
1037+
ctxt_len);
10271038
}
10281039

10291040
/* offsets must be 8 byte aligned */
@@ -1057,16 +1068,16 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
10571068
return rc;
10581069
}
10591070

1060-
if (req->DialectCount == 0) {
1061-
pr_err("malformed packet\n");
1071+
smb2_buf_len = get_rfc1002_len(work->request_buf);
1072+
smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
1073+
if (smb2_neg_size > smb2_buf_len) {
10621074
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
10631075
rc = -EINVAL;
10641076
goto err_out;
10651077
}
10661078

1067-
smb2_buf_len = get_rfc1002_len(work->request_buf);
1068-
smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
1069-
if (smb2_neg_size > smb2_buf_len) {
1079+
if (req->DialectCount == 0) {
1080+
pr_err("malformed packet\n");
10701081
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
10711082
rc = -EINVAL;
10721083
goto err_out;
@@ -4358,21 +4369,6 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
43584369
return 0;
43594370
}
43604371

4361-
static unsigned long long get_allocation_size(struct inode *inode,
4362-
struct kstat *stat)
4363-
{
4364-
unsigned long long alloc_size = 0;
4365-
4366-
if (!S_ISDIR(stat->mode)) {
4367-
if ((inode->i_blocks << 9) <= stat->size)
4368-
alloc_size = stat->size;
4369-
else
4370-
alloc_size = inode->i_blocks << 9;
4371-
}
4372-
4373-
return alloc_size;
4374-
}
4375-
43764372
static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
43774373
struct ksmbd_file *fp, void *rsp_org)
43784374
{
@@ -4387,7 +4383,7 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
43874383
sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
43884384
delete_pending = ksmbd_inode_pending_delete(fp);
43894385

4390-
sinfo->AllocationSize = cpu_to_le64(get_allocation_size(inode, &stat));
4386+
sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
43914387
sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
43924388
sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
43934389
sinfo->DeletePending = delete_pending;
@@ -4452,7 +4448,7 @@ static int get_file_all_info(struct ksmbd_work *work,
44524448
file_info->Attributes = fp->f_ci->m_fattr;
44534449
file_info->Pad1 = 0;
44544450
file_info->AllocationSize =
4455-
cpu_to_le64(get_allocation_size(inode, &stat));
4451+
cpu_to_le64(inode->i_blocks << 9);
44564452
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
44574453
file_info->NumberOfLinks =
44584454
cpu_to_le32(get_nlink(&stat) - delete_pending);
@@ -4641,7 +4637,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
46414637
file_info->ChangeTime = cpu_to_le64(time);
46424638
file_info->Attributes = fp->f_ci->m_fattr;
46434639
file_info->AllocationSize =
4644-
cpu_to_le64(get_allocation_size(inode, &stat));
4640+
cpu_to_le64(inode->i_blocks << 9);
46454641
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
46464642
file_info->Reserved = cpu_to_le32(0);
46474643
rsp->OutputBufferLength =
@@ -5506,7 +5502,7 @@ static int smb2_create_link(struct ksmbd_work *work,
55065502
{
55075503
char *link_name = NULL, *target_name = NULL, *pathname = NULL;
55085504
struct path path;
5509-
bool file_present = true;
5505+
bool file_present = false;
55105506
int rc;
55115507

55125508
if (buf_len < (u64)sizeof(struct smb2_file_link_info) +
@@ -5539,8 +5535,8 @@ static int smb2_create_link(struct ksmbd_work *work,
55395535
if (rc) {
55405536
if (rc != -ENOENT)
55415537
goto out;
5542-
file_present = false;
5543-
}
5538+
} else
5539+
file_present = true;
55445540

55455541
if (file_info->ReplaceIfExists) {
55465542
if (file_present) {

0 commit comments

Comments
 (0)